Merge "Remove all calls to getComponent(StatusBar.class)"
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 47118a8..2931f33 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2576,10 +2576,12 @@
PendingIntent.setOnMarshaledListener(
(PendingIntent intent, Parcel out, int outFlags) -> {
if (parcel == out) {
- if (allPendingIntents == null) {
- allPendingIntents = new ArraySet<>();
+ synchronized (this) {
+ if (allPendingIntents == null) {
+ allPendingIntents = new ArraySet<>();
+ }
+ allPendingIntents.add(intent);
}
- allPendingIntents.add(intent);
}
});
}
@@ -2587,8 +2589,10 @@
// IMPORTANT: Add marshaling code in writeToParcelImpl as we
// want to intercept all pending events written to the parcel.
writeToParcelImpl(parcel, flags);
- // Must be written last!
- parcel.writeArraySet(allPendingIntents);
+ synchronized (this) {
+ // Must be written last!
+ parcel.writeArraySet(allPendingIntents);
+ }
} finally {
if (collectPendingIntents) {
PendingIntent.setOnMarshaledListener(null);
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 11d321f..bc1cc09 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -158,6 +158,7 @@
static jclass gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
+static jmethodID gBitmapConfig_nativeToConfigMethodID;
static jclass gBitmapRegionDecoder_class;
static jmethodID gBitmapRegionDecoder_constructorMethodID;
@@ -345,6 +346,54 @@
bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
}
+AndroidBitmapFormat GraphicsJNI::getFormatFromConfig(JNIEnv* env, jobject jconfig) {
+ ALOG_ASSERT(env);
+ if (NULL == jconfig) {
+ return ANDROID_BITMAP_FORMAT_NONE;
+ }
+ ALOG_ASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class));
+ jint javaConfigId = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
+
+ const AndroidBitmapFormat config2BitmapFormat[] = {
+ ANDROID_BITMAP_FORMAT_NONE,
+ ANDROID_BITMAP_FORMAT_A_8,
+ ANDROID_BITMAP_FORMAT_NONE, // Previously Config.Index_8
+ ANDROID_BITMAP_FORMAT_RGB_565,
+ ANDROID_BITMAP_FORMAT_RGBA_4444,
+ ANDROID_BITMAP_FORMAT_RGBA_8888,
+ ANDROID_BITMAP_FORMAT_RGBA_F16,
+ ANDROID_BITMAP_FORMAT_NONE // Congfig.HARDWARE
+ };
+ return config2BitmapFormat[javaConfigId];
+}
+
+jobject GraphicsJNI::getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) {
+ ALOG_ASSERT(env);
+ jint configId = kNo_LegacyBitmapConfig;
+ switch (format) {
+ case ANDROID_BITMAP_FORMAT_A_8:
+ configId = kA8_LegacyBitmapConfig;
+ break;
+ case ANDROID_BITMAP_FORMAT_RGB_565:
+ configId = kRGB_565_LegacyBitmapConfig;
+ break;
+ case ANDROID_BITMAP_FORMAT_RGBA_4444:
+ configId = kARGB_4444_LegacyBitmapConfig;
+ break;
+ case ANDROID_BITMAP_FORMAT_RGBA_8888:
+ configId = kARGB_8888_LegacyBitmapConfig;
+ break;
+ case ANDROID_BITMAP_FORMAT_RGBA_F16:
+ configId = kRGBA_16F_LegacyBitmapConfig;
+ break;
+ default:
+ break;
+ }
+
+ return env->CallStaticObjectMethod(gBitmapConfig_class,
+ gBitmapConfig_nativeToConfigMethodID, configId);
+}
+
SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
ALOG_ASSERT(env);
if (NULL == jconfig) {
@@ -634,6 +683,9 @@
gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap$Config"));
gBitmapConfig_nativeInstanceID = GetFieldIDOrDie(env, gBitmapConfig_class, "nativeInt", "I");
+ gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class,
+ "nativeToConfig",
+ "(I)Landroid/graphics/Bitmap$Config;");
gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index f80651c..6e7d9e7 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -76,6 +76,8 @@
or kUnknown_SkColorType if the java object is null.
*/
static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig);
+ static AndroidBitmapFormat getFormatFromConfig(JNIEnv* env, jobject jconfig);
+ static jobject getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format);
static bool isHardwareConfig(JNIEnv* env, jobject jconfig);
static jint hardwareLegacyBitmapConfig();
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp
index 96cc5db..a328def 100644
--- a/core/jni/android/graphics/apex/android_bitmap.cpp
+++ b/core/jni/android/graphics/apex/android_bitmap.cpp
@@ -17,6 +17,7 @@
#include "android/graphics/bitmap.h"
#include "Bitmap.h"
#include "TypeCast.h"
+#include "GraphicsJNI.h"
#include <hwui/Bitmap.h>
@@ -104,3 +105,11 @@
}
return bitmap->pixels();
}
+
+AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj) {
+ return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj);
+}
+
+jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) {
+ return GraphicsJNI::getConfigFromFormat(env, format);
+}
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
index bfa4c8d..dea5517 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
@@ -38,6 +38,9 @@
void* ABitmap_getPixels(ABitmap* bitmap);
+AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj);
+jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format);
+
__END_DECLS
#ifdef __cplusplus
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 5b9b703..7da2752 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1093,6 +1093,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "200829729": {
+ "message": "ScreenRotationAnimation onAnimationEnd",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+ },
"221540118": {
"message": "mUserActivityTimeout set to %d",
"level": "DEBUG",
@@ -1159,6 +1165,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "292555239": {
+ "message": "ScreenRotation sill animating: mDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+ },
"292904800": {
"message": "Deferring rotation, animation in progress.",
"level": "VERBOSE",
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index bc4bceb..a5c62cb 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -22,7 +22,7 @@
#include <assert.h>
#include <utils/Log.h>
#include <utils/threads.h>
-#include <SkBitmap.h>
+#include <android/graphics/bitmap.h>
#include <media/IMediaHTTPService.h>
#include <media/mediametadataretriever.h>
#include <media/mediascanner.h>
@@ -36,8 +36,6 @@
#include "android_media_Streams.h"
#include "android_util_Binder.h"
-#include "android/graphics/GraphicsJNI.h"
-
using namespace android;
struct fields_t {
@@ -45,8 +43,6 @@
jclass bitmapClazz; // Must be a global ref
jmethodID createBitmapMethod;
jmethodID createScaledBitmapMethod;
- jclass configClazz; // Must be a global ref
- jmethodID createConfigMethod;
jclass bitmapParamsClazz; // Must be a global ref
jfieldID inPreferredConfig;
jfieldID outActualConfig;
@@ -263,7 +259,7 @@
static jobject getBitmapFromVideoFrame(
JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height,
- SkColorType outColorType) {
+ AndroidBitmapFormat outColorType) {
ALOGV("getBitmapFromVideoFrame: dimension = %dx%d, displaySize = %dx%d, bytes = %d",
videoFrame->mWidth,
videoFrame->mHeight,
@@ -271,11 +267,7 @@
videoFrame->mDisplayHeight,
videoFrame->mSize);
- ScopedLocalRef<jobject> config(env,
- env->CallStaticObjectMethod(
- fields.configClazz,
- fields.createConfigMethod,
- GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
+ ScopedLocalRef<jobject> config(env, ABitmapConfig_getConfigFromFormat(env, outColorType));
uint32_t width, height, displayWidth, displayHeight;
bool swapWidthAndHeight = false;
@@ -306,10 +298,9 @@
return NULL;
}
- SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
+ graphics::Bitmap bitmap(env, jBitmap);
- if (outColorType == kRGB_565_SkColorType) {
+ if (outColorType == ANDROID_BITMAP_FORMAT_RGB_565) {
rotate((uint16_t*)bitmap.getPixels(),
(uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
videoFrame->mWidth,
@@ -350,37 +341,26 @@
return jBitmap;
}
-static int getColorFormat(JNIEnv *env, jobject options,
- int defaultPreferred = HAL_PIXEL_FORMAT_RGBA_8888) {
+static AndroidBitmapFormat getColorFormat(JNIEnv *env, jobject options,
+ AndroidBitmapFormat defaultPreferred = ANDROID_BITMAP_FORMAT_RGBA_8888) {
if (options == NULL) {
return defaultPreferred;
}
ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
- SkColorType prefColorType = GraphicsJNI::getNativeBitmapColorType(env, inConfig.get());
+ AndroidBitmapFormat format = ABitmapConfig_getFormatFromConfig(env, inConfig.get());
- if (prefColorType == kRGB_565_SkColorType) {
- return HAL_PIXEL_FORMAT_RGB_565;
+ if (format == ANDROID_BITMAP_FORMAT_RGB_565) {
+ return ANDROID_BITMAP_FORMAT_RGB_565;
}
- return HAL_PIXEL_FORMAT_RGBA_8888;
+ return ANDROID_BITMAP_FORMAT_RGBA_8888;
}
-static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options) {
- SkColorType outColorType = kN32_SkColorType;
- if (colorFormat == HAL_PIXEL_FORMAT_RGB_565) {
- outColorType = kRGB_565_SkColorType;
- }
-
+static void setOutConfig(JNIEnv *env, jobject options, AndroidBitmapFormat colorFormat) {
if (options != NULL) {
- ScopedLocalRef<jobject> config(env,
- env->CallStaticObjectMethod(
- fields.configClazz,
- fields.createConfigMethod,
- GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
-
+ ScopedLocalRef<jobject> config(env, ABitmapConfig_getConfigFromFormat(env, colorFormat));
env->SetObjectField(options, fields.outActualConfig, config.get());
}
- return outColorType;
}
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
@@ -394,9 +374,9 @@
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return NULL;
}
- // For getFrameAtTime family of calls, default to HAL_PIXEL_FORMAT_RGB_565
+ // For getFrameAtTime family of calls, default to ANDROID_BITMAP_FORMAT_RGB_565
// to keep the behavior consistent with older releases
- int colorFormat = getColorFormat(env, params, HAL_PIXEL_FORMAT_RGB_565);
+ AndroidBitmapFormat colorFormat = getColorFormat(env, params, ANDROID_BITMAP_FORMAT_RGB_565);
// Call native method to retrieve a video frame
VideoFrame *videoFrame = NULL;
@@ -413,9 +393,8 @@
return NULL;
}
- SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
- return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType);
+ setOutConfig(env, params, colorFormat);
+ return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, colorFormat);
}
static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
@@ -428,7 +407,7 @@
return NULL;
}
- int colorFormat = getColorFormat(env, params);
+ AndroidBitmapFormat colorFormat = getColorFormat(env, params);
// Call native method to retrieve an image
VideoFrame *videoFrame = NULL;
@@ -445,9 +424,8 @@
return NULL;
}
- SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
- return getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
+ setOutConfig(env, params, colorFormat);
+ return getBitmapFromVideoFrame(env, videoFrame, -1, -1, colorFormat);
}
static jobject android_media_MediaMetadataRetriever_getThumbnailImageAtIndex(
@@ -461,7 +439,7 @@
return NULL;
}
- int colorFormat = getColorFormat(env, params);
+ AndroidBitmapFormat colorFormat = getColorFormat(env, params);
jint dst_width = -1, dst_height = -1;
// Call native method to retrieve an image
@@ -508,9 +486,8 @@
// thumbnails extracted by BitmapFactory APIs.
videoFrame->mRotationAngle = 0;
- SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
- return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType);
+ setOutConfig(env, params, colorFormat);
+ return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, colorFormat);
}
static jobject android_media_MediaMetadataRetriever_getFrameAtIndex(
@@ -532,8 +509,8 @@
return NULL;
}
- int colorFormat = getColorFormat(env, params);
- SkColorType outColorType = setOutColorType(env, colorFormat, params);
+ AndroidBitmapFormat colorFormat = getColorFormat(env, params);
+ setOutConfig(env, params, colorFormat);
size_t i = 0;
for (; i < numFrames; i++) {
sp<IMemory> frame = retriever->getFrameAtIndex(frameIndex + i, colorFormat);
@@ -546,7 +523,7 @@
// Either document why it is safe in this case or address the
// issue (e.g. by copying).
VideoFrame *videoFrame = static_cast<VideoFrame *>(frame->unsecurePointer());
- jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
+ jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, colorFormat);
env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
env->DeleteLocalRef(bitmapObj);
}
@@ -671,21 +648,6 @@
return;
}
- clazz.reset(env->FindClass("android/graphics/Bitmap$Config"));
- if (clazz.get() == NULL) {
- return;
- }
- fields.configClazz = (jclass) env->NewGlobalRef(clazz.get());
- if (fields.configClazz == NULL) {
- return;
- }
- fields.createConfigMethod =
- env->GetStaticMethodID(fields.configClazz, "nativeToConfig",
- "(I)Landroid/graphics/Bitmap$Config;");
- if (fields.createConfigMethod == NULL) {
- return;
- }
-
clazz.reset(env->FindClass("android/media/MediaMetadataRetriever$BitmapParams"));
if (clazz.get() == NULL) {
return;
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 21b52c1..06aba40 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -38,7 +38,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.Dependency;
@@ -106,7 +105,7 @@
updateCarrierText();
}
- public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+ public void onSimStateChanged(int subId, int slotId, int simState) {
if (slotId < 0 || slotId >= mSimSlotsNumber) {
Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId
+ " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable));
@@ -191,7 +190,7 @@
CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) {
final CharSequence carrier = "";
CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
- IccCardConstants.State.CARD_IO_ERROR, carrier);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier);
// mSimErrorState has the state of each sim indexed by slotID.
for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) {
if (!mSimErrorState[index]) {
@@ -288,7 +287,7 @@
carrierNames[i] = "";
subsIds[i] = subId;
subOrderBySlot[subs.get(i).getSimSlotIndex()] = i;
- IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
+ int simState = mKeyguardUpdateMonitor.getSimState(subId);
CharSequence carrierName = subs.get(i).getCarrierName();
CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
if (DEBUG) {
@@ -298,7 +297,7 @@
allSimsMissing = false;
carrierNames[i] = carrierTextForSimState;
}
- if (simState == IccCardConstants.State.READY) {
+ if (simState == TelephonyManager.SIM_STATE_READY) {
ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
// hack for WFC (IWLAN) not turning off immediately once
@@ -406,8 +405,7 @@
*
* @return Carrier text if not in missing state, null otherwise.
*/
- private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
- CharSequence text) {
+ private CharSequence getCarrierTextForSimState(int simState, CharSequence text) {
CharSequence carrierText = null;
CarrierTextController.StatusMode status = getStatusForIccState(simState);
switch (status) {
@@ -498,37 +496,32 @@
/**
* Determine the current status of the lock screen given the SIM state and other stuff.
*/
- private CarrierTextController.StatusMode getStatusForIccState(IccCardConstants.State simState) {
- // Since reading the SIM may take a while, we assume it is present until told otherwise.
- if (simState == null) {
- return CarrierTextController.StatusMode.Normal;
- }
-
+ private CarrierTextController.StatusMode getStatusForIccState(int simState) {
final boolean missingAndNotProvisioned =
!Dependency.get(KeyguardUpdateMonitor.class).isDeviceProvisioned()
- && (simState == IccCardConstants.State.ABSENT
- || simState == IccCardConstants.State.PERM_DISABLED);
+ && (simState == TelephonyManager.SIM_STATE_ABSENT
+ || simState == TelephonyManager.SIM_STATE_PERM_DISABLED);
// Assume we're NETWORK_LOCKED if not provisioned
- simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
+ simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState;
switch (simState) {
- case ABSENT:
+ case TelephonyManager.SIM_STATE_ABSENT:
return CarrierTextController.StatusMode.SimMissing;
- case NETWORK_LOCKED:
+ case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
return CarrierTextController.StatusMode.SimMissingLocked;
- case NOT_READY:
+ case TelephonyManager.SIM_STATE_NOT_READY:
return CarrierTextController.StatusMode.SimNotReady;
- case PIN_REQUIRED:
+ case TelephonyManager.SIM_STATE_PIN_REQUIRED:
return CarrierTextController.StatusMode.SimLocked;
- case PUK_REQUIRED:
+ case TelephonyManager.SIM_STATE_PUK_REQUIRED:
return CarrierTextController.StatusMode.SimPukLocked;
- case READY:
+ case TelephonyManager.SIM_STATE_READY:
return CarrierTextController.StatusMode.Normal;
- case PERM_DISABLED:
+ case TelephonyManager.SIM_STATE_PERM_DISABLED:
return CarrierTextController.StatusMode.SimPermDisabled;
- case UNKNOWN:
+ case TelephonyManager.SIM_STATE_UNKNOWN:
return CarrierTextController.StatusMode.SimUnknown;
- case CARD_IO_ERROR:
+ case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
return CarrierTextController.StatusMode.SimIoError;
}
return CarrierTextController.StatusMode.SimUnknown;
@@ -575,7 +568,7 @@
return list;
}
- private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
+ private CharSequence getCarrierHelpTextForSimState(int simState,
String plmn, String spn) {
int carrierHelpTextId = 0;
CarrierTextController.StatusMode status = getStatusForIccState(simState);
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index ecd8c8d..867014b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -37,7 +37,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
@@ -59,7 +58,7 @@
KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@Override
- public void onSimStateChanged(int subId, int slotId, State simState) {
+ public void onSimStateChanged(int subId, int slotId, int simState) {
updateEmergencyCallButton();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 64b4d32..17abfae 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -20,8 +20,8 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
-import com.android.internal.telephony.IccCardConstants;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
@@ -66,12 +66,12 @@
KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId(
- monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))) {
+ monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED))) {
return SecurityMode.SimPuk;
}
if (SubscriptionManager.isValidSubscriptionId(
- monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED))) {
+ monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED))) {
return SecurityMode.SimPin;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index b1502b9..b960de5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -38,8 +38,6 @@
import android.widget.ImageView;
import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -66,10 +64,10 @@
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
- public void onSimStateChanged(int subId, int slotId, State simState) {
+ public void onSimStateChanged(int subId, int slotId, int simState) {
if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
switch(simState) {
- case READY: {
+ case TelephonyManager.SIM_STATE_READY: {
mRemainingAttempts = -1;
resetState();
break;
@@ -157,7 +155,7 @@
private void handleSubInfoChangeIfNeeded() {
KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
- int subId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
+ int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED);
if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
mSubId = subId;
mShowDefaultMessage = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 70237a0..7e08ab3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -37,8 +37,6 @@
import android.widget.ImageView;
import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -69,12 +67,12 @@
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
- public void onSimStateChanged(int subId, int slotId, State simState) {
+ public void onSimStateChanged(int subId, int slotId, int simState) {
if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
switch(simState) {
// If the SIM is unlocked via a key sequence through the emergency dialer, it will
// move into the READY state and the PUK lock keyguard should be removed.
- case READY: {
+ case TelephonyManager.SIM_STATE_READY: {
mRemainingAttempts = -1;
mShowDefaultMessage = true;
// mCallback can be null if onSimStateChanged callback is called when keyguard
@@ -210,7 +208,7 @@
private void handleSubInfoChangeIfNeeded() {
KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
- int subId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
+ int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED);
if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
mSubId = subId;
mShowDefaultMessage = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0b0922a..1d4b9ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -93,7 +93,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.widget.LockPatternUtils;
@@ -1055,7 +1054,7 @@
// and processed previously.
if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
// Guarantee mTelephonyCapable state after SysUI crash and restart
- if (args.simState == State.ABSENT) {
+ if (args.simState == TelephonyManager.SIM_STATE_ABSENT) {
mHandler.obtainMessage(MSG_TELEPHONY_CAPABLE, true).sendToTarget();
}
return;
@@ -1226,18 +1225,18 @@
* the intent and provide a {@link SimCard.State} result.
*/
private static class SimData {
- public State simState;
+ public int simState;
public int slotId;
public int subId;
- SimData(State state, int slot, int id) {
+ SimData(int state, int slot, int id) {
simState = state;
slotId = slot;
subId = id;
}
static SimData fromIntent(Intent intent) {
- State state;
+ int state;
if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
}
@@ -1251,33 +1250,33 @@
if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
absentReason)) {
- state = IccCardConstants.State.PERM_DISABLED;
+ state = TelephonyManager.SIM_STATE_PERM_DISABLED;
} else {
- state = IccCardConstants.State.ABSENT;
+ state = TelephonyManager.SIM_STATE_ABSENT;
}
} else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
- state = IccCardConstants.State.READY;
+ state = TelephonyManager.SIM_STATE_READY;
} else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
final String lockedReason = intent
.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
- state = IccCardConstants.State.PIN_REQUIRED;
+ state = TelephonyManager.SIM_STATE_PIN_REQUIRED;
} else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- state = IccCardConstants.State.PUK_REQUIRED;
+ state = TelephonyManager.SIM_STATE_PUK_REQUIRED;
} else {
- state = IccCardConstants.State.UNKNOWN;
+ state = TelephonyManager.SIM_STATE_UNKNOWN;
}
} else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
- state = IccCardConstants.State.NETWORK_LOCKED;
+ state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
} else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
- state = IccCardConstants.State.CARD_IO_ERROR;
+ state = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
} else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
|| IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
// This is required because telephony doesn't return to "READY" after
// these state transitions. See bug 7197471.
- state = IccCardConstants.State.READY;
+ state = TelephonyManager.SIM_STATE_READY;
} else {
- state = IccCardConstants.State.UNKNOWN;
+ state = TelephonyManager.SIM_STATE_UNKNOWN;
}
return new SimData(state, slotId, subId);
}
@@ -1525,7 +1524,7 @@
handleBatteryUpdate((BatteryStatus) msg.obj);
break;
case MSG_SIM_STATE_CHANGE:
- handleSimStateChange(msg.arg1, msg.arg2, (State) msg.obj);
+ handleSimStateChange(msg.arg1, msg.arg2, (int) msg.obj);
break;
case MSG_RINGER_MODE_CHANGED:
handleRingerModeChange(msg.arg1);
@@ -2260,7 +2259,7 @@
* Handle {@link #MSG_SIM_STATE_CHANGE}
*/
@VisibleForTesting
- void handleSimStateChange(int subId, int slotId, State state) {
+ void handleSimStateChange(int subId, int slotId, int state) {
checkIsHandlerThread();
if (DEBUG_SIM_STATES) {
Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId="
@@ -2272,7 +2271,7 @@
Log.w(TAG, "invalid subId in handleSimStateChange()");
/* Only handle No SIM(ABSENT) and Card Error(CARD_IO_ERROR) due to
* handleServiceStateChange() handle other case */
- if (state == State.ABSENT) {
+ if (state == TelephonyManager.SIM_STATE_ABSENT) {
updateTelephonyCapable(true);
// Even though the subscription is not valid anymore, we need to notify that the
// SIM card was removed so we can update the UI.
@@ -2281,10 +2280,10 @@
// Set the SIM state of all SimData associated with that slot to ABSENT se we
// do not move back into PIN/PUK locked and not detect the change below.
if (data.slotId == slotId) {
- data.simState = State.ABSENT;
+ data.simState = TelephonyManager.SIM_STATE_ABSENT;
}
}
- } else if (state == State.CARD_IO_ERROR) {
+ } else if (state == TelephonyManager.SIM_STATE_CARD_IO_ERROR) {
updateTelephonyCapable(true);
} else {
return;
@@ -2303,7 +2302,7 @@
data.subId = subId;
data.slotId = slotId;
}
- if ((changed || becameAbsent) && state != State.UNKNOWN) {
+ if ((changed || becameAbsent) && state != TelephonyManager.SIM_STATE_UNKNOWN) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -2542,7 +2541,7 @@
@MainThread
public void reportSimUnlocked(int subId) {
if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")");
- handleSimStateChange(subId, getSlotId(subId), State.READY);
+ handleSimStateChange(subId, getSlotId(subId), TelephonyManager.SIM_STATE_READY);
}
/**
@@ -2607,11 +2606,11 @@
return false;
}
- public State getSimState(int subId) {
+ public int getSimState(int subId) {
if (mSimDatas.containsKey(subId)) {
return mSimDatas.get(subId).simState;
} else {
- return State.UNKNOWN;
+ return TelephonyManager.SIM_STATE_UNKNOWN;
}
}
@@ -2644,22 +2643,10 @@
* @return true if and only if the state has changed for the specified {@code slotId}
*/
private boolean refreshSimState(int subId, int slotId) {
-
- // This is awful. It exists because there are two APIs for getting the SIM status
- // that don't return the complete set of values and have different types. In Keyguard we
- // need IccCardConstants, but TelephonyManager would only give us
- // TelephonyManager.SIM_STATE*, so we retrieve it manually.
final TelephonyManager tele =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- int simState = (tele != null) ?
+ int state = (tele != null) ?
tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
- State state;
- try {
- state = State.intToState(simState);
- } catch (IllegalArgumentException ex) {
- Log.w(TAG, "Unknown sim state: " + simState);
- state = State.UNKNOWN;
- }
SimData data = mSimDatas.get(subId);
final boolean changed;
if (data == null) {
@@ -2676,10 +2663,10 @@
/**
* If the {@code state} is currently requiring a SIM PIN, PUK, or is disabled.
*/
- public static boolean isSimPinSecure(IccCardConstants.State state) {
- return (state == IccCardConstants.State.PIN_REQUIRED
- || state == IccCardConstants.State.PUK_REQUIRED
- || state == IccCardConstants.State.PERM_DISABLED);
+ public static boolean isSimPinSecure(int state) {
+ return (state == TelephonyManager.SIM_STATE_PIN_REQUIRED
+ || state == TelephonyManager.SIM_STATE_PUK_REQUIRED
+ || state == TelephonyManager.SIM_STATE_PERM_DISABLED);
}
public DisplayClientState getCachedDisplayClientState() {
@@ -2741,7 +2728,7 @@
*
* @return subid or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if none found
*/
- public int getNextSubIdForState(State state) {
+ public int getNextSubIdForState(int state) {
List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */);
int resultId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
int bestSlotId = Integer.MAX_VALUE; // Favor lowest slot first
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 0fef755..b4b83d6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -23,7 +23,6 @@
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicyConstants;
-import com.android.internal.telephony.IccCardConstants;
import com.android.systemui.statusbar.KeyguardIndicationController;
import java.util.TimeZone;
@@ -136,7 +135,7 @@
* @param slotId
* @param simState
*/
- public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { }
+ public void onSimStateChanged(int subId, int slotId, int simState) { }
/**
* Called when the user's info changed.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c876fa6..f026e68 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -18,9 +18,6 @@
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
-import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
-import static com.android.internal.telephony.IccCardConstants.State.PUK_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -61,7 +58,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManagerPolicyConstants;
@@ -72,7 +69,6 @@
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardStateCallback;
-import com.android.internal.telephony.IccCardConstants;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardConstants;
@@ -293,7 +289,7 @@
* Last SIM state reported by the telephony system.
* Index is the slotId - in case of multiple SIM cards.
*/
- private final SparseArray<IccCardConstants.State> mLastSimStates = new SparseArray<>();
+ private final SparseIntArray mLastSimStates = new SparseIntArray();
private boolean mDeviceInteractive;
private boolean mGoingToSleep;
@@ -433,7 +429,7 @@
}
@Override
- public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+ public void onSimStateChanged(int subId, int slotId, int simState) {
if (DEBUG_SIM_STATES) {
Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
@@ -455,14 +451,15 @@
boolean simWasLocked;
synchronized (KeyguardViewMediator.this) {
- IccCardConstants.State lastState = mLastSimStates.get(slotId);
- simWasLocked = (lastState == PIN_REQUIRED || lastState == PUK_REQUIRED);
+ int lastState = mLastSimStates.get(slotId);
+ simWasLocked = (lastState == TelephonyManager.SIM_STATE_PIN_REQUIRED
+ || lastState == TelephonyManager.SIM_STATE_PUK_REQUIRED);
mLastSimStates.append(slotId, simState);
}
switch (simState) {
- case NOT_READY:
- case ABSENT:
+ case TelephonyManager.SIM_STATE_NOT_READY:
+ case TelephonyManager.SIM_STATE_ABSENT:
// only force lock screen in case of missing sim if user hasn't
// gone through setup wizard
synchronized (KeyguardViewMediator.this) {
@@ -476,7 +473,7 @@
resetStateLocked();
}
}
- if (simState == ABSENT) {
+ if (simState == TelephonyManager.SIM_STATE_ABSENT) {
// MVNO SIMs can become transiently NOT_READY when switching networks,
// so we should only lock when they are ABSENT.
if (simWasLocked) {
@@ -487,8 +484,8 @@
}
}
break;
- case PIN_REQUIRED:
- case PUK_REQUIRED:
+ case TelephonyManager.SIM_STATE_PIN_REQUIRED:
+ case TelephonyManager.SIM_STATE_PUK_REQUIRED:
synchronized (KeyguardViewMediator.this) {
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG,
@@ -500,7 +497,7 @@
}
}
break;
- case PERM_DISABLED:
+ case TelephonyManager.SIM_STATE_PERM_DISABLED:
synchronized (KeyguardViewMediator.this) {
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
@@ -513,7 +510,7 @@
}
}
break;
- case READY:
+ case TelephonyManager.SIM_STATE_READY:
synchronized (KeyguardViewMediator.this) {
if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
if (mShowing && simWasLocked) {
@@ -1334,9 +1331,9 @@
// if the setup wizard hasn't run yet, don't show
final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
final boolean absent = SubscriptionManager.isValidSubscriptionId(
- mUpdateMonitor.getNextSubIdForState(ABSENT));
+ mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_ABSENT));
final boolean disabled = SubscriptionManager.isValidSubscriptionId(
- mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));
+ mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PERM_DISABLED));
final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
|| ((absent || disabled) && requireSim);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index 843c37f..0a7ee3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -20,11 +20,11 @@
import android.os.Bundle;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
-import com.android.internal.telephony.IccCardConstants.State;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.WirelessUtils;
@@ -138,9 +138,9 @@
final int N = subs.size();
for (int i = 0; i < N; i++) {
int subId = subs.get(i).getSubscriptionId();
- State simState = mKeyguardUpdateMonitor.getSimState(subId);
+ int simState = mKeyguardUpdateMonitor.getSimState(subId);
CharSequence carrierName = subs.get(i).getCarrierName();
- if (!TextUtils.isEmpty(carrierName) && simState == State.READY) {
+ if (!TextUtils.isEmpty(carrierName) && simState == TelephonyManager.SIM_STATE_READY) {
ServiceState ss = mKeyguardUpdateMonitor.getServiceState(subId);
if (ss != null && ss.getState() == ServiceState.STATE_IN_SERVICE) {
displayText = carrierName;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 4927ec8..60589843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -39,7 +39,6 @@
import androidx.annotation.Nullable;
import com.android.internal.graphics.ColorUtils;
-import com.android.internal.telephony.IccCardConstants;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dependency;
@@ -154,8 +153,7 @@
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
- public void onSimStateChanged(int subId, int slotId,
- IccCardConstants.State simState) {
+ public void onSimStateChanged(int subId, int slotId, int simState) {
mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
update();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 01cd2b4..bfecaaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
import android.util.Log;
@@ -127,7 +128,7 @@
// Assume it's all good unless we hear otherwise. We don't always seem
// to get broadcasts that it *is* there.
- IccCardConstants.State mSimState = IccCardConstants.State.READY;
+ int mSimState = TelephonyManager.SIM_STATE_READY;
private boolean mZenVisible;
private boolean mVolumeVisible;
@@ -307,25 +308,25 @@
private final void updateSimState(Intent intent) {
String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
- mSimState = IccCardConstants.State.ABSENT;
+ mSimState = TelephonyManager.SIM_STATE_READY;
} else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
- mSimState = IccCardConstants.State.CARD_IO_ERROR;
+ mSimState = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
} else if (IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED.equals(stateExtra)) {
- mSimState = IccCardConstants.State.CARD_RESTRICTED;
+ mSimState = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
} else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
- mSimState = IccCardConstants.State.READY;
+ mSimState = TelephonyManager.SIM_STATE_READY;
} else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
final String lockedReason =
intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PIN_REQUIRED;
+ mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED;
} else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PUK_REQUIRED;
+ mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED;
} else {
- mSimState = IccCardConstants.State.NETWORK_LOCKED;
+ mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
}
} else {
- mSimState = IccCardConstants.State.UNKNOWN;
+ mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index 353d6a4..e675a7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -24,11 +24,11 @@
import android.net.ConnectivityManager;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
-import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -83,6 +83,18 @@
getContext().unregisterReceiver(mReceiver);
}
+ private boolean iccCardExist(int simState) {
+ return ((simState == TelephonyManager.SIM_STATE_PIN_REQUIRED)
+ || (simState == TelephonyManager.SIM_STATE_PUK_REQUIRED)
+ || (simState == TelephonyManager.SIM_STATE_NETWORK_LOCKED)
+ || (simState == TelephonyManager.SIM_STATE_READY)
+ || (simState == TelephonyManager.SIM_STATE_NOT_READY)
+ || (simState == TelephonyManager.SIM_STATE_PERM_DISABLED)
+ || (simState == TelephonyManager.SIM_STATE_CARD_IO_ERROR)
+ || (simState == TelephonyManager.SIM_STATE_CARD_RESTRICTED)
+ || (simState == TelephonyManager.SIM_STATE_LOADED));
+ }
+
public void update() {
boolean hasMobile = ConnectivityManager.from(mContext)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -102,9 +114,9 @@
final int N = subs.size();
for (int i = 0; i < N; i++) {
int subId = subs.get(i).getSubscriptionId();
- IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
+ int simState = mKeyguardUpdateMonitor.getSimState(subId);
CharSequence carrierName = subs.get(i).getCarrierName();
- if (simState.iccCardExist() && !TextUtils.isEmpty(carrierName)) {
+ if (iccCardExist(simState) && !TextUtils.isEmpty(carrierName)) {
allSimsMissing = false;
displayText = carrierName;
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index d8eaaa1..1a1b679 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -54,7 +54,6 @@
import android.testing.TestableLooper;
import android.text.TextUtils;
-import com.android.internal.telephony.IccCardConstants;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -179,7 +178,7 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
- when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
mCarrierTextController.updateCarrierText();
@@ -199,13 +198,13 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
- when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
- IccCardConstants.State.CARD_IO_ERROR);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
mCarrierTextController.mCallback.onSimStateChanged(3, 1,
- IccCardConstants.State.CARD_IO_ERROR);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR);
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor.forClass(
@@ -234,11 +233,11 @@
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
new ArrayList<>());
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
- IccCardConstants.State.CARD_IO_ERROR);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR);
// This should not produce an out of bounds error, even though there are no subscriptions
mCarrierTextController.mCallback.onSimStateChanged(0, -3,
- IccCardConstants.State.CARD_IO_ERROR);
- mCarrierTextController.mCallback.onSimStateChanged(0, 3, IccCardConstants.State.READY);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+ mCarrierTextController.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY);
verify(mCarrierTextCallback, never()).updateCarrierInfo(any());
}
@@ -254,10 +253,10 @@
new ArrayList<>());
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
- IccCardConstants.State.CARD_IO_ERROR);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR);
// This should not produce an out of bounds error, even though there are no subscriptions
mCarrierTextController.mCallback.onSimStateChanged(0, 1,
- IccCardConstants.State.CARD_IO_ERROR);
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR);
mTestableLooper.processAllMessages();
verify(mCarrierTextCallback).updateCarrierInfo(
@@ -294,7 +293,8 @@
reset(mCarrierTextCallback);
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
- when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+ TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -318,7 +318,8 @@
reset(mCarrierTextCallback);
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION_ROAMING);
- when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+ TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -342,7 +343,8 @@
reset(mCarrierTextCallback);
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION_NULL);
- when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+ TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -366,7 +368,8 @@
reset(mCarrierTextCallback);
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION_NULL);
- when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+ TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mockWifi();
@@ -422,7 +425,8 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION);
- when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+ TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -446,8 +450,8 @@
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getSimState(anyInt()))
- .thenReturn(IccCardConstants.State.READY)
- .thenReturn(IccCardConstants.State.NOT_READY);
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ .thenReturn(TelephonyManager.SIM_STATE_NOT_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -471,8 +475,8 @@
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getSimState(anyInt()))
- .thenReturn(IccCardConstants.State.NOT_READY)
- .thenReturn(IccCardConstants.State.READY);
+ .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
+ .thenReturn(TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -497,9 +501,9 @@
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getSimState(anyInt()))
- .thenReturn(IccCardConstants.State.READY)
- .thenReturn(IccCardConstants.State.NOT_READY)
- .thenReturn(IccCardConstants.State.READY);
+ .thenReturn(TelephonyManager.SIM_STATE_READY)
+ .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
+ .thenReturn(TelephonyManager.SIM_STATE_READY);
when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index c1da53b..7be3e2b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -546,8 +546,7 @@
}
@Override
- protected void handleSimStateChange(int subId, int slotId,
- IccCardConstants.State state) {
+ protected void handleSimStateChange(int subId, int slotId, int state) {
mSimStateChanged.set(true);
super.handleSimStateChange(subId, slotId, state);
}
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index e90612e..f0bb192 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -16,8 +16,6 @@
package com.android.server.integrity.engine;
-import android.util.Slog;
-
import com.android.server.integrity.model.AppInstallMetadata;
import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.Rule;
@@ -53,23 +51,11 @@
*
* @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
* against.
- * @return A rule matching the metadata. If there are multiple matching rules, returns any. If
- * no rules are matching, returns {@link Rule#EMPTY}.
+ * @return result of the integrity check
*/
public IntegrityCheckResult evaluate(AppInstallMetadata appInstallMetadata) {
List<Rule> rules = loadRules(appInstallMetadata);
- Rule matchedRule = RuleEvaluator.evaluateRules(rules, appInstallMetadata);
- if (matchedRule == Rule.EMPTY) {
- return IntegrityCheckResult.allow();
- } else {
- switch (matchedRule.getEffect()) {
- case DENY:
- return IntegrityCheckResult.deny(matchedRule);
- default:
- Slog.e(TAG, "Matched a non-DENY rule: " + matchedRule);
- return IntegrityCheckResult.allow();
- }
- }
+ return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
}
private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
index 6416505..7deae46 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
@@ -16,14 +16,20 @@
package com.android.server.integrity.engine;
+import static com.android.server.integrity.model.Rule.DENY;
+import static com.android.server.integrity.model.Rule.FORCE_ALLOW;
+
+import android.annotation.NonNull;
import android.util.Slog;
import com.android.server.integrity.model.AppInstallMetadata;
import com.android.server.integrity.model.AtomicFormula;
import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -40,67 +46,40 @@
* <p>Rules must be in disjunctive normal form (DNF). A rule should contain AND'ed formulas
* only. All rules are OR'ed together by default.
*
- * @param rules The list of rules to evaluate.
+ * @param rules The list of rules to evaluate.
* @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
- * against.
- * @return A rule matching the metadata. If there are multiple matching rules, returns any. If
- * no rules are matching, returns {@link Rule#EMPTY}.
+ * against.
+ * @return result of the integrity check
*/
- static Rule evaluateRules(List<Rule> rules, AppInstallMetadata appInstallMetadata) {
+ @NonNull
+ static IntegrityCheckResult evaluateRules(
+ List<Rule> rules, AppInstallMetadata appInstallMetadata) {
+ List<Rule> matchedRules = new ArrayList<>();
for (Rule rule : rules) {
- if (isConjunctionOfFormulas(rule.getFormula()) && isMatch(rule, appInstallMetadata)) {
- return rule;
- }
- }
- return Rule.EMPTY;
- }
-
- /**
- * Match a rule against app install metadata.
- */
- private static boolean isMatch(Rule rule, AppInstallMetadata appInstallMetadata) {
- return isMatch(rule.getFormula(), appInstallMetadata);
- }
-
- private static boolean isMatch(Formula formula, AppInstallMetadata appInstallMetadata) {
- if (formula instanceof AtomicFormula) {
- AtomicFormula atomicFormula = (AtomicFormula) formula;
- switch (atomicFormula.getKey()) {
- case PACKAGE_NAME:
- return atomicFormula.isMatch(appInstallMetadata.getPackageName());
- case APP_CERTIFICATE:
- return atomicFormula.isMatch(appInstallMetadata.getAppCertificate());
- case INSTALLER_NAME:
- return atomicFormula.isMatch(appInstallMetadata.getInstallerName());
- case INSTALLER_CERTIFICATE:
- return atomicFormula.isMatch(appInstallMetadata.getInstallerCertificate());
- case VERSION_CODE:
- return atomicFormula.isMatch(appInstallMetadata.getVersionCode());
- case PRE_INSTALLED:
- return atomicFormula.isMatch(appInstallMetadata.isPreInstalled());
- default:
- Slog.i(TAG, String.format("Returned no match for unknown key %s",
- atomicFormula.getKey()));
- return false;
- }
- } else if (formula instanceof OpenFormula) {
- OpenFormula openFormula = (OpenFormula) formula;
- // A rule is in disjunctive normal form, so there are no OR connectors.
- switch (openFormula.getConnector()) {
- case NOT:
- // NOT connector has only 1 formula attached.
- return !isMatch(openFormula.getFormulas().get(0), appInstallMetadata);
- case AND:
- return openFormula.getFormulas().stream().allMatch(
- subFormula -> isMatch(subFormula, appInstallMetadata));
- default:
- Slog.i(TAG, String.format("Returned no match for unknown connector %s",
- openFormula.getConnector()));
- return false;
+ if (isConjunctionOfFormulas(rule.getFormula())
+ && rule.getFormula().isSatisfied(appInstallMetadata)) {
+ matchedRules.add(rule);
}
}
- return false;
+ boolean denied = false;
+ Rule denyRule = null;
+ for (Rule rule : matchedRules) {
+ switch (rule.getEffect()) {
+ case DENY:
+ if (!denied) {
+ denied = true;
+ denyRule = rule;
+ }
+ break;
+ case FORCE_ALLOW:
+ return IntegrityCheckResult.allow(rule);
+ default:
+ Slog.e(TAG, "Matched an unknown effect rule: " + rule);
+ return IntegrityCheckResult.allow();
+ }
+ }
+ return denied ? IntegrityCheckResult.deny(denyRule) : IntegrityCheckResult.allow();
}
private static boolean isConjunctionOfFormulas(Formula formula) {
@@ -111,7 +90,7 @@
return true;
}
OpenFormula openFormula = (OpenFormula) formula;
- return openFormula.getConnector() == OpenFormula.Connector.AND
+ return openFormula.getConnector() == OpenFormula.AND
&& openFormula.getFormulas().stream().allMatch(RuleEvaluator::isAtomicFormula);
}
@@ -120,7 +99,7 @@
return true;
}
OpenFormula openFormula = (OpenFormula) formula;
- return openFormula.getConnector() == OpenFormula.Connector.NOT
+ return openFormula.getConnector() == OpenFormula.NOT
&& openFormula.getFormulas().get(0) instanceof AtomicFormula;
}
}
diff --git a/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
index 660bd2e..dfc373b 100644
--- a/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
+++ b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
@@ -19,7 +19,11 @@
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.annotations.VisibleForTesting;
/**
* The app install metadata.
@@ -28,7 +32,11 @@
* to the rule evaluation engine to evaluate the metadata against the rules.
*
* <p>Instances of this class are immutable.
+ *
+ * @hide
*/
+@SystemApi
+@VisibleForTesting
public final class AppInstallMetadata {
private final String mPackageName;
// Raw string encoding for the SHA-256 hash of the certificate of the app.
@@ -48,10 +56,12 @@
this.mIsPreInstalled = builder.mIsPreInstalled;
}
+ @NonNull
public String getPackageName() {
return mPackageName;
}
+ @NonNull
public String getAppCertificate() {
return mAppCertificate;
}
@@ -66,23 +76,17 @@
return mInstallerCertificate;
}
- /**
- * @see AppInstallMetadata.Builder#setVersionCode(int)
- */
+ /** @see AppInstallMetadata.Builder#setVersionCode(int) */
public int getVersionCode() {
return mVersionCode;
}
- /**
- * @see AppInstallMetadata.Builder#setIsPreInstalled(boolean)
- */
+ /** @see AppInstallMetadata.Builder#setIsPreInstalled(boolean) */
public boolean isPreInstalled() {
return mIsPreInstalled;
}
- /**
- * Builder class for constructing {@link AppInstallMetadata} objects.
- */
+ /** Builder class for constructing {@link AppInstallMetadata} objects. */
public static final class Builder {
private String mPackageName;
private String mAppCertificate;
@@ -96,7 +100,8 @@
*
* @see AppInstallMetadata#getPackageName()
*/
- public Builder setPackageName(String packageName) {
+ @NonNull
+ public Builder setPackageName(@NonNull String packageName) {
this.mPackageName = checkNotNull(packageName);
return this;
}
@@ -109,7 +114,8 @@
*
* @see AppInstallMetadata#getAppCertificate()
*/
- public Builder setAppCertificate(String appCertificate) {
+ @NonNull
+ public Builder setAppCertificate(@NonNull String appCertificate) {
this.mAppCertificate = checkNotNull(appCertificate);
return this;
}
@@ -119,7 +125,8 @@
*
* @see AppInstallMetadata#getInstallerName()
*/
- public Builder setInstallerName(String installerName) {
+ @NonNull
+ public Builder setInstallerName(@NonNull String installerName) {
this.mInstallerName = checkNotNull(installerName);
return this;
}
@@ -132,7 +139,8 @@
*
* @see AppInstallMetadata#getInstallerCertificate()
*/
- public Builder setInstallerCertificate(String installerCertificate) {
+ @NonNull
+ public Builder setInstallerCertificate(@NonNull String installerCertificate) {
this.mInstallerCertificate = checkNotNull(installerCertificate);
return this;
}
@@ -142,6 +150,7 @@
*
* @see AppInstallMetadata#getVersionCode()
*/
+ @NonNull
public Builder setVersionCode(int versionCode) {
this.mVersionCode = versionCode;
return this;
@@ -152,6 +161,7 @@
*
* @see AppInstallMetadata#isPreInstalled()
*/
+ @NonNull
public Builder setIsPreInstalled(boolean isPreInstalled) {
this.mIsPreInstalled = isPreInstalled;
return this;
@@ -159,7 +169,10 @@
/**
* Build {@link AppInstallMetadata}.
+ *
+ * @throws IllegalArgumentException if package name or app certificate is null
*/
+ @NonNull
public AppInstallMetadata build() {
checkArgument(mPackageName != null);
checkArgument(mAppCertificate != null);
diff --git a/services/core/java/com/android/server/integrity/model/AtomicFormula.java b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
index b9b46e3..a757528 100644
--- a/services/core/java/com/android/server/integrity/model/AtomicFormula.java
+++ b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
@@ -17,220 +17,404 @@
package com.android.server.integrity.model;
import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import android.annotation.Nullable;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Represents a simple formula consisting of an app install metadata field and a value.
*
* <p>Instances of this class are immutable.
+ *
+ * @hide
*/
-public final class AtomicFormula extends Formula {
+@SystemApi
+@VisibleForTesting
+public abstract class AtomicFormula implements Formula {
private static final String TAG = "AtomicFormula";
- public enum Key {
- PACKAGE_NAME,
- APP_CERTIFICATE,
- INSTALLER_NAME,
- INSTALLER_CERTIFICATE,
- VERSION_CODE,
- PRE_INSTALLED
+ @IntDef(
+ value = {
+ PACKAGE_NAME,
+ APP_CERTIFICATE,
+ INSTALLER_NAME,
+ INSTALLER_CERTIFICATE,
+ VERSION_CODE,
+ PRE_INSTALLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Key {}
+
+ @IntDef(value = {EQ, LT, LE, GT, GE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Operator {}
+
+ public static final int PACKAGE_NAME = 0;
+ public static final int APP_CERTIFICATE = 1;
+ public static final int INSTALLER_NAME = 2;
+ public static final int INSTALLER_CERTIFICATE = 3;
+ public static final int VERSION_CODE = 4;
+ public static final int PRE_INSTALLED = 5;
+
+ public static final int EQ = 0;
+ public static final int LT = 1;
+ public static final int LE = 2;
+ public static final int GT = 3;
+ public static final int GE = 4;
+
+ private final @Key int mKey;
+
+ public AtomicFormula(@Key int key) {
+ mKey = key;
}
- public enum Operator {
- EQ,
- LT,
- LE,
- GT,
- GE
+ /** An {@link AtomicFormula} with an key and int value. */
+ public static final class IntAtomicFormula extends AtomicFormula implements Parcelable {
+ private final int mValue;
+ private final @Operator int mOperator;
+
+ /**
+ * Constructs a new {@link IntAtomicFormula}.
+ *
+ * <p>This formula will hold if and only if the corresponding information of an install
+ * specified by {@code key} is of the correct relationship to {@code value} as specified by
+ * {@code operator}.
+ *
+ * @throws IllegalArgumentException if {@code key} is not {@link #VERSION_CODE}
+ */
+ public IntAtomicFormula(@Key int key, @Operator int operator, int value) {
+ super(key);
+ checkArgument(
+ key == VERSION_CODE,
+ String.format("Key %s cannot be used with IntAtomicFormula", keyToString(key)));
+ mOperator = operator;
+ mValue = value;
+ }
+
+ IntAtomicFormula(Parcel in) {
+ super(in.readInt());
+ mValue = in.readInt();
+ mOperator = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<IntAtomicFormula> CREATOR =
+ new Creator<IntAtomicFormula>() {
+ @Override
+ public IntAtomicFormula createFromParcel(Parcel in) {
+ return new IntAtomicFormula(in);
+ }
+
+ @Override
+ public IntAtomicFormula[] newArray(int size) {
+ return new IntAtomicFormula[size];
+ }
+ };
+
+ @Override
+ public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+ int metadataValue = getMetadataValueByKey(appInstallMetadata);
+ switch (mOperator) {
+ case EQ:
+ return metadataValue == mValue;
+ case LE:
+ return metadataValue <= mValue;
+ case LT:
+ return metadataValue < mValue;
+ case GE:
+ return metadataValue >= mValue;
+ case GT:
+ return metadataValue > mValue;
+ default:
+ Slog.i(TAG, String.format("Unexpected operator %d", mOperator));
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "(%s %s %s)", keyToString(getKey()), operatorToString(mOperator), mValue);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ IntAtomicFormula that = (IntAtomicFormula) o;
+ return getKey() == that.getKey() && mValue == that.mValue;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getKey(), mOperator, mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(getKey());
+ dest.writeInt(mValue);
+ dest.writeInt(mOperator);
+ }
+
+ private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
+ switch (getKey()) {
+ case VERSION_CODE:
+ return appInstallMetadata.getVersionCode();
+ default:
+ throw new IllegalStateException(
+ "Unexpected key in IntAtomicFormula" + getKey());
+ }
+ }
}
- private final Key mKey;
- private final Operator mOperator;
+ /** An {@link AtomicFormula} with a key and string value. */
+ public static final class StringAtomicFormula extends AtomicFormula implements Parcelable {
+ private final String mValue;
- // The value of a key can take either 1 of 3 forms: String, Integer, or Boolean.
- // It cannot have multiple values.
- @Nullable
- private final String mStringValue;
- @Nullable
- private final Integer mIntValue;
- @Nullable
- private final Boolean mBoolValue;
+ /**
+ * Constructs a new {@link StringAtomicFormula}.
+ *
+ * <p>This formula will hold if and only if the corresponding information of an install
+ * specified by {@code key} equals {@code value}.
+ *
+ * @throws IllegalArgumentException if {@code key} is not one of {@link #PACKAGE_NAME},
+ * {@link #APP_CERTIFICATE}, {@link #INSTALLER_NAME} and {@link #INSTALLER_CERTIFICATE}
+ */
+ public StringAtomicFormula(@Key int key, @NonNull String value) {
+ super(key);
+ checkArgument(
+ key == PACKAGE_NAME
+ || key == APP_CERTIFICATE
+ || key == INSTALLER_CERTIFICATE
+ || key == INSTALLER_NAME,
+ String.format(
+ "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
+ mValue = value;
+ }
- public AtomicFormula(Key key, Operator operator, String stringValue) {
- validateOperator(key, operator);
- checkArgument(
- key == Key.PACKAGE_NAME || key == Key.APP_CERTIFICATE || key == Key.INSTALLER_NAME
- || key == Key.INSTALLER_CERTIFICATE,
- String.format("Key %s cannot have string value", key));
- this.mKey = checkNotNull(key);
- this.mOperator = checkNotNull(operator);
- this.mStringValue = checkNotNull(stringValue);
- this.mIntValue = null;
- this.mBoolValue = null;
+ StringAtomicFormula(Parcel in) {
+ super(in.readInt());
+ mValue = in.readStringNoHelper();
+ }
+
+ @NonNull
+ public static final Creator<StringAtomicFormula> CREATOR =
+ new Creator<StringAtomicFormula>() {
+ @Override
+ public StringAtomicFormula createFromParcel(Parcel in) {
+ return new StringAtomicFormula(in);
+ }
+
+ @Override
+ public StringAtomicFormula[] newArray(int size) {
+ return new StringAtomicFormula[size];
+ }
+ };
+
+ @Override
+ public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+ String metadataValue = getMetadataValueByKey(appInstallMetadata);
+ return metadataValue.equals(mValue);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ StringAtomicFormula that = (StringAtomicFormula) o;
+ return getKey() == that.getKey() && Objects.equals(mValue, that.mValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getKey(), mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(getKey());
+ dest.writeStringNoHelper(mValue);
+ }
+
+ private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
+ switch (getKey()) {
+ case PACKAGE_NAME:
+ return appInstallMetadata.getPackageName();
+ case APP_CERTIFICATE:
+ return appInstallMetadata.getAppCertificate();
+ case INSTALLER_CERTIFICATE:
+ return appInstallMetadata.getInstallerCertificate();
+ case INSTALLER_NAME:
+ return appInstallMetadata.getInstallerName();
+ default:
+ throw new IllegalStateException(
+ "Unexpected key in StringAtomicFormula: " + getKey());
+ }
+ }
}
- public AtomicFormula(Key key, Operator operator, Integer intValue) {
- validateOperator(key, operator);
- checkArgument(key == Key.VERSION_CODE,
- String.format("Key %s cannot have integer value", key));
- this.mKey = checkNotNull(key);
- this.mOperator = checkNotNull(operator);
- this.mStringValue = null;
- this.mIntValue = checkNotNull(intValue);
- this.mBoolValue = null;
+ /** An {@link AtomicFormula} with a key and boolean value. */
+ public static final class BooleanAtomicFormula extends AtomicFormula implements Parcelable {
+ private final boolean mValue;
+
+ /**
+ * Constructs a new {@link BooleanAtomicFormula}.
+ *
+ * <p>This formula will hold if and only if the corresponding information of an install
+ * specified by {@code key} equals {@code value}.
+ *
+ * @throws IllegalArgumentException if {@code key} is not {@link #PRE_INSTALLED}
+ */
+ public BooleanAtomicFormula(@Key int key, boolean value) {
+ super(key);
+ checkArgument(
+ key == PRE_INSTALLED,
+ String.format(
+ "Key %s cannot be used with BooleanAtomicFormula", keyToString(key)));
+ mValue = value;
+ }
+
+ BooleanAtomicFormula(Parcel in) {
+ super(in.readInt());
+ mValue = in.readByte() != 0;
+ }
+
+ @NonNull
+ public static final Creator<BooleanAtomicFormula> CREATOR =
+ new Creator<BooleanAtomicFormula>() {
+ @Override
+ public BooleanAtomicFormula createFromParcel(Parcel in) {
+ return new BooleanAtomicFormula(in);
+ }
+
+ @Override
+ public BooleanAtomicFormula[] newArray(int size) {
+ return new BooleanAtomicFormula[size];
+ }
+ };
+
+ @Override
+ public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+ boolean metadataValue = getMetadataValueByKey(appInstallMetadata);
+ return metadataValue == mValue;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ BooleanAtomicFormula that = (BooleanAtomicFormula) o;
+ return getKey() == that.getKey() && mValue == that.mValue;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getKey(), mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(getKey());
+ dest.writeByte((byte) (mValue ? 1 : 0));
+ }
+
+ private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
+ switch (getKey()) {
+ case PRE_INSTALLED:
+ return appInstallMetadata.isPreInstalled();
+ default:
+ throw new IllegalStateException(
+ "Unexpected key in BooleanAtomicFormula: " + getKey());
+ }
+ }
}
- public AtomicFormula(Key key, Operator operator, Boolean boolValue) {
- validateOperator(key, operator);
- checkArgument(key == Key.PRE_INSTALLED,
- String.format("Key %s cannot have boolean value", key));
- this.mKey = checkNotNull(key);
- this.mOperator = checkNotNull(operator);
- this.mStringValue = null;
- this.mIntValue = null;
- this.mBoolValue = checkNotNull(boolValue);
- }
-
- public Key getKey() {
+ public int getKey() {
return mKey;
}
- public Operator getOperator() {
- return mOperator;
- }
-
- public String getStringValue() {
- return mStringValue;
- }
-
- public Integer getIntValue() {
- return mIntValue;
- }
-
- public Boolean getBoolValue() {
- return mBoolValue;
- }
-
- /**
- * Get string representation of the value of the key in the formula.
- *
- * @return string representation of the value of the key.
- */
- public String getValue() {
- if (mStringValue != null) {
- return mStringValue;
- }
- if (mIntValue != null) {
- return mIntValue.toString();
- }
- return mBoolValue.toString();
- }
-
- /**
- * Check if the formula is true when substituting its {@link Key} with the string value.
- *
- * @param value String value to substitute the key with.
- * @return {@code true} if the formula is true, and {@code false} otherwise.
- */
- public boolean isMatch(String value) {
- switch (mOperator) {
- case EQ:
- return mStringValue.equals(value);
- }
- Slog.i(TAG, String.format("Found operator %s for value %s", mOperator, mStringValue));
- return false;
- }
-
- /**
- * Check if the formula is true when substituting its {@link Key} with the integer value.
- *
- * @param value Integer value to substitute the key with.
- * @return {@code true} if the formula is true, and {@code false} otherwise.
- */
- public boolean isMatch(int value) {
- switch (mOperator) {
- case EQ:
- return mIntValue == value;
- case LE:
- return mIntValue <= value;
- case LT:
- return mIntValue < value;
- case GE:
- return mIntValue >= value;
- case GT:
- return mIntValue > value;
- }
- Slog.i(TAG, String.format("Found operator %s for value %s", mOperator, mIntValue));
- return false;
- }
-
- /**
- * Check if the formula is true when substituting its {@link Key} with the boolean value.
- *
- * @param value Boolean value to substitute the key with.
- * @return {@code true} if the formula is true, and {@code false} otherwise.
- */
- public boolean isMatch(boolean value) {
- switch (mOperator) {
- case EQ:
- return mBoolValue == value;
- }
- Slog.i(TAG, String.format("Found operator %s for value %s", mOperator, mBoolValue));
- return false;
- }
-
- @Override
- public String toString() {
- return String.format("%s %s %s", mKey, mOperator, getValue());
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- AtomicFormula that = (AtomicFormula) o;
- return mKey == that.mKey
- && mOperator == that.mOperator
- && Objects.equals(mStringValue, that.mStringValue)
- && Objects.equals(mIntValue, that.mIntValue)
- && Objects.equals(mBoolValue, that.mBoolValue);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mKey, mOperator, mStringValue, mIntValue, mBoolValue);
- }
-
- private void validateOperator(Key key, Operator operator) {
- boolean validOperator;
+ String keyToString(int key) {
switch (key) {
case PACKAGE_NAME:
+ return "PACKAGE_NAME";
case APP_CERTIFICATE:
- case INSTALLER_NAME:
- case INSTALLER_CERTIFICATE:
- case PRE_INSTALLED:
- validOperator = (operator == Operator.EQ);
- break;
+ return "APP_CERTIFICATE";
case VERSION_CODE:
- validOperator = true;
- break;
+ return "VERSION_CODE";
+ case INSTALLER_NAME:
+ return "INSTALLER_NAME";
+ case INSTALLER_CERTIFICATE:
+ return "INSTALLER_CERTIFICATE";
+ case PRE_INSTALLED:
+ return "PRE_INSTALLED";
default:
- Slog.i(TAG, String.format("Found operator %s for key %s", operator, key));
- validOperator = false;
+ throw new IllegalArgumentException("Unknown key " + key);
}
- if (!validOperator) {
- throw new IllegalArgumentException(
- String.format("Invalid operator %s used for key %s", operator, key));
+ }
+
+ String operatorToString(int op) {
+ switch (op) {
+ case EQ:
+ return "EQ";
+ case LT:
+ return "LT";
+ case LE:
+ return "LE";
+ case GT:
+ return "GT";
+ case GE:
+ return "GE";
+ default:
+ throw new IllegalArgumentException("Unknown operator " + op);
}
}
}
diff --git a/services/core/java/com/android/server/integrity/model/Formula.java b/services/core/java/com/android/server/integrity/model/Formula.java
index 9db4453..852ece5 100644
--- a/services/core/java/com/android/server/integrity/model/Formula.java
+++ b/services/core/java/com/android/server/integrity/model/Formula.java
@@ -16,9 +16,84 @@
package com.android.server.integrity.model;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.integrity.model.AtomicFormula.BooleanAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.IntAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
+
/**
* Represents a rule logic/content.
+ *
+ * @hide
*/
-public abstract class Formula {
+@SystemApi
+@VisibleForTesting
+public interface Formula {
+ int OPEN_FORMULA_TAG = 0;
+ int STRING_ATOMIC_FORMULA_TAG = 1;
+ int INT_ATOMIC_FORMULA_TAG = 2;
+ int BOOLEAN_ATOMIC_FORMULA_TAG = 3;
+
+ /**
+ * Returns if this formula can be satisfied by substituting the corresponding information of
+ * {@code appInstallMetadata} into the formula.
+ */
+ boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata);
+
+ /**
+ * Write a {@link Formula} to {@link android.os.Parcel}.
+ *
+ * <p>This helper method is needed because non-final class/interface are not allowed to be
+ * {@link Parcelable}.
+ *
+ * @throws IllegalArgumentException if {@link Formula} is not a recognized subclass
+ */
+ static void writeToParcel(@NonNull Formula formula, @NonNull Parcel dest, int flags) {
+ if (formula instanceof OpenFormula) {
+ dest.writeInt(OPEN_FORMULA_TAG);
+ ((OpenFormula) formula).writeToParcel(dest, flags);
+ } else if (formula instanceof StringAtomicFormula) {
+ dest.writeInt(STRING_ATOMIC_FORMULA_TAG);
+ ((StringAtomicFormula) formula).writeToParcel(dest, flags);
+ } else if (formula instanceof IntAtomicFormula) {
+ dest.writeInt(INT_ATOMIC_FORMULA_TAG);
+ ((IntAtomicFormula) formula).writeToParcel(dest, flags);
+ } else if (formula instanceof BooleanAtomicFormula) {
+ dest.writeInt(BOOLEAN_ATOMIC_FORMULA_TAG);
+ ((BooleanAtomicFormula) formula).writeToParcel(dest, flags);
+ } else {
+ throw new IllegalArgumentException("Unrecognized class " + formula.getClass());
+ }
+ }
+
+ /**
+ * Read a {@link Formula} from a {@link android.os.Parcel}.
+ *
+ * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link
+ * Parcelable} (api lint error).
+ *
+ * @throws IllegalArgumentException if the parcel cannot be parsed
+ */
+ @NonNull
+ static Formula readFromParcel(@NonNull Parcel in) {
+ int tag = in.readInt();
+ switch (tag) {
+ case OPEN_FORMULA_TAG:
+ return OpenFormula.CREATOR.createFromParcel(in);
+ case STRING_ATOMIC_FORMULA_TAG:
+ return StringAtomicFormula.CREATOR.createFromParcel(in);
+ case INT_ATOMIC_FORMULA_TAG:
+ return IntAtomicFormula.CREATOR.createFromParcel(in);
+ case BOOLEAN_ATOMIC_FORMULA_TAG:
+ return BooleanAtomicFormula.CREATOR.createFromParcel(in);
+ default:
+ throw new IllegalArgumentException("Unknown formula tag " + tag);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
index 7aeb0c1..ef0751d 100644
--- a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
+++ b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
@@ -16,6 +16,8 @@
package com.android.server.integrity.model;
+import android.annotation.Nullable;
+
/**
* A class encapsulating the result from the evaluation engine after evaluating rules against app
* install metadata.
@@ -31,9 +33,9 @@
}
private final Effect mEffect;
- private final Rule mRule;
+ @Nullable private final Rule mRule;
- private IntegrityCheckResult(Effect effect, Rule rule) {
+ private IntegrityCheckResult(Effect effect, @Nullable Rule rule) {
this.mEffect = effect;
this.mRule = rule;
}
@@ -49,10 +51,19 @@
/**
* Create an ALLOW evaluation outcome.
*
- * @return An evaluation outcome with ALLOW effect and empty rule.
+ * @return An evaluation outcome with ALLOW effect and no rule.
*/
public static IntegrityCheckResult allow() {
- return new IntegrityCheckResult(Effect.ALLOW, Rule.EMPTY);
+ return new IntegrityCheckResult(Effect.ALLOW, null);
+ }
+
+ /**
+ * Create an ALLOW evaluation outcome.
+ *
+ * @return An evaluation outcome with ALLOW effect and rule causing that effect.
+ */
+ public static IntegrityCheckResult allow(Rule rule) {
+ return new IntegrityCheckResult(Effect.ALLOW, rule);
}
/**
diff --git a/services/core/java/com/android/server/integrity/model/OpenFormula.java b/services/core/java/com/android/server/integrity/model/OpenFormula.java
index 21da629..f29706a 100644
--- a/services/core/java/com/android/server/integrity/model/OpenFormula.java
+++ b/services/core/java/com/android/server/integrity/model/OpenFormula.java
@@ -17,8 +17,19 @@
package com.android.server.integrity.model;
import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -27,40 +38,108 @@
* Represents a complex formula consisting of other simple and complex formulas.
*
* <p>Instances of this class are immutable.
+ *
+ * @hide
*/
-public final class OpenFormula extends Formula {
+@SystemApi
+@VisibleForTesting
+public final class OpenFormula implements Formula, Parcelable {
+ private static final String TAG = "OpenFormula";
- public enum Connector {
- AND,
- OR,
- NOT
- }
+ @IntDef(
+ value = {
+ AND, OR, NOT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Connector {}
- private final Connector mConnector;
+ /** Boolean AND operator. */
+ public static final int AND = 0;
+
+ /** Boolean OR operator. */
+ public static final int OR = 1;
+
+ /** Boolean NOT operator. */
+ public static final int NOT = 2;
+
+ private final @Connector int mConnector;
private final List<Formula> mFormulas;
- public OpenFormula(Connector connector, List<Formula> formulas) {
+ @NonNull
+ public static final Creator<OpenFormula> CREATOR =
+ new Creator<OpenFormula>() {
+ @Override
+ public OpenFormula createFromParcel(Parcel in) {
+ return new OpenFormula(in);
+ }
+
+ @Override
+ public OpenFormula[] newArray(int size) {
+ return new OpenFormula[size];
+ }
+ };
+
+ /**
+ * Create a new formula from operator and operands.
+ *
+ * @throws IllegalArgumentException if the number of operands is not matching the requirements
+ * for that operator (at least 2 for {@link #AND} and {@link #OR}, 1 for {@link #NOT}).
+ */
+ public OpenFormula(@Connector int connector, @NonNull List<Formula> formulas) {
validateFormulas(connector, formulas);
- this.mConnector = checkNotNull(connector);
- this.mFormulas = Collections.unmodifiableList(checkNotNull(formulas));
+ this.mConnector = connector;
+ this.mFormulas = Collections.unmodifiableList(formulas);
}
- public Connector getConnector() {
+ OpenFormula(Parcel in) {
+ mConnector = in.readInt();
+ int length = in.readInt();
+ checkArgument(length >= 0, "Must have non-negative length. Got " + length);
+ mFormulas = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ mFormulas.add(Formula.readFromParcel(in));
+ }
+ }
+
+ public @Connector int getConnector() {
return mConnector;
}
+ @NonNull
public List<Formula> getFormulas() {
return mFormulas;
}
@Override
+ public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+ switch (mConnector) {
+ case NOT:
+ return !mFormulas.get(0).isSatisfied(appInstallMetadata);
+ case AND:
+ return mFormulas.stream()
+ .allMatch(formula -> formula.isSatisfied(appInstallMetadata));
+ case OR:
+ return mFormulas.stream()
+ .anyMatch(formula -> formula.isSatisfied(appInstallMetadata));
+ default:
+ Slog.i(TAG, "Unknown connector " + mConnector);
+ return false;
+ }
+ }
+
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder();
- for (int i = 0; i < mFormulas.size(); i++) {
- if (i > 0) {
- sb.append(String.format(" %s ", mConnector));
+ if (mFormulas.size() == 1) {
+ sb.append(String.format("%s ", connectorToString(mConnector)));
+ sb.append(mFormulas.get(0).toString());
+ } else {
+ for (int i = 0; i < mFormulas.size(); i++) {
+ if (i > 0) {
+ sb.append(String.format(" %s ", connectorToString(mConnector)));
+ }
+ sb.append(mFormulas.get(i).toString());
}
- sb.append(mFormulas.get(i).toString());
}
return sb.toString();
}
@@ -74,8 +153,7 @@
return false;
}
OpenFormula that = (OpenFormula) o;
- return mConnector == that.mConnector
- && mFormulas.equals(that.mFormulas);
+ return mConnector == that.mConnector && mFormulas.equals(that.mFormulas);
}
@Override
@@ -83,17 +161,50 @@
return Objects.hash(mConnector, mFormulas);
}
- private void validateFormulas(Connector connector, List<Formula> formulas) {
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mConnector);
+ dest.writeInt(mFormulas.size());
+ for (Formula formula : mFormulas) {
+ Formula.writeToParcel(formula, dest, flags);
+ }
+ }
+
+ private void validateFormulas(@Connector int connector, List<Formula> formulas) {
switch (connector) {
case AND:
case OR:
- checkArgument(formulas.size() >= 2,
- String.format("Connector %s must have at least 2 formulas", connector));
+ checkArgument(
+ formulas.size() >= 2,
+ String.format(
+ "Connector %s must have at least 2 formulas",
+ connectorToString(connector)));
break;
case NOT:
- checkArgument(formulas.size() == 1,
- String.format("Connector %s must have 1 formula only", connector));
+ checkArgument(
+ formulas.size() == 1,
+ String.format(
+ "Connector %s must have 1 formula only",
+ connectorToString(connector)));
break;
}
}
+
+ private String connectorToString(int connector) {
+ switch (connector) {
+ case AND:
+ return "AND";
+ case OR:
+ return "OR";
+ case NOT:
+ return "NOT";
+ default:
+ throw new IllegalArgumentException("Unknown connector " + connector);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java
index 63b9b91..14dcb26 100644
--- a/services/core/java/com/android/server/integrity/model/Rule.java
+++ b/services/core/java/com/android/server/integrity/model/Rule.java
@@ -18,55 +18,96 @@
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Represent rules to be used in the rule evaluation engine to match against app installs.
*
* <p>Instances of this class are immutable.
+ *
+ * @hide
*/
-public final class Rule {
+@SystemApi
+@VisibleForTesting
+public final class Rule implements Parcelable {
- public enum Effect {
- DENY
- }
+ @IntDef(
+ value = {
+ DENY,
+ FORCE_ALLOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Effect {}
- // Holds an empty rule instance.
- public static final Rule EMPTY = new Rule();
-
- private final Formula mFormula;
- private final Effect mEffect;
-
- private Rule() {
- this.mFormula = null;
- this.mEffect = null;
- }
-
- public Rule(Formula formula, Effect effect) {
- this.mFormula = checkNotNull(formula);
- this.mEffect = checkNotNull(effect);
- }
+ /** If this rule matches the install, the install should be denied. */
+ public static final int DENY = 0;
/**
- * Indicates whether the rule is empty or not.
- *
- * @return {@code true} if the rule is empty, and {@code false} otherwise.
+ * If this rule matches the install, the install will be allowed regardless of other matched
+ * rules.
*/
- public boolean isEmpty() {
- return mFormula == null && mEffect == null;
+ public static final int FORCE_ALLOW = 1;
+
+ private final Formula mFormula;
+ private final @Effect int mEffect;
+
+ public Rule(@NonNull Formula formula, @Effect int effect) {
+ this.mFormula = checkNotNull(formula);
+ this.mEffect = effect;
}
+ Rule(Parcel in) {
+ mFormula = Formula.readFromParcel(in);
+ mEffect = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<Rule> CREATOR =
+ new Creator<Rule>() {
+ @Override
+ public Rule createFromParcel(Parcel in) {
+ return new Rule(in);
+ }
+
+ @Override
+ public Rule[] newArray(int size) {
+ return new Rule[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ Formula.writeToParcel(mFormula, dest, flags);
+ dest.writeInt(mEffect);
+ }
+
+ @NonNull
public Formula getFormula() {
return mFormula;
}
- public Effect getEffect() {
+ public @Effect int getEffect() {
return mEffect;
}
@Override
public String toString() {
- return String.format("Rule: %s, %s", mFormula, mEffect);
+ return String.format("Rule: %s, %s", mFormula, effectToString(mEffect));
}
@Override
@@ -78,12 +119,22 @@
return false;
}
Rule that = (Rule) o;
- return Objects.equals(mFormula, that.mFormula)
- && Objects.equals(mEffect, that.mEffect);
+ return Objects.equals(mFormula, that.mFormula) && mEffect == that.mEffect;
}
@Override
public int hashCode() {
return Objects.hash(mFormula, mEffect);
}
+
+ private String effectToString(int effect) {
+ switch (effect) {
+ case DENY:
+ return "DENY";
+ case FORCE_ALLOW:
+ return "FORCE_ALLOW";
+ default:
+ throw new IllegalArgumentException("Unknown effect " + effect);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index c1567bc..5ed282c 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -19,18 +19,19 @@
import com.android.server.integrity.model.Rule;
import java.io.InputStream;
+import java.util.List;
/** A helper class to parse rules into the {@link Rule} model from Binary representation. */
public class RuleBinaryParser implements RuleParser {
@Override
- public Rule parse(String ruleText) {
+ public List<Rule> parse(String ruleText) {
// TODO: Implement binary text parser.
return null;
}
@Override
- public Rule parse(InputStream inputStream) {
+ public List<Rule> parse(InputStream inputStream) {
// TODO: Implement stream parser.
return null;
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
index 96ed5993..bfffc70 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -19,13 +19,14 @@
import com.android.server.integrity.model.Rule;
import java.io.InputStream;
+import java.util.List;
/** A helper class to parse rules into the {@link Rule} model. */
public interface RuleParser {
/** Parse rules from a string. */
- Rule parse(String ruleText);
+ List<Rule> parse(String ruleText);
/** Parse rules from an input stream. */
- Rule parse(InputStream inputStream);
+ List<Rule> parse(InputStream inputStream);
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
index 8b1bec9..bf31bb2 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -16,22 +16,90 @@
package com.android.server.integrity.parser;
+import android.util.Slog;
+import android.util.Xml;
+
import com.android.server.integrity.model.Rule;
-import java.io.InputStream;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
-/** A helper class to parse rules into the {@link Rule} model from Xml representation. */
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class to parse rules into the {@link Rule} model from Xml representation.
+ */
public final class RuleXmlParser implements RuleParser {
+ public static final String TAG = "RuleXmlParser";
+
+ private static final String RULE_LIST_TAG = "RuleList";
+ private static final String RULE_TAG = "Rule";
+
@Override
- public Rule parse(String ruleText) {
- // TODO: Implement text parser.
+ public List<Rule> parse(String ruleText) {
+ try {
+ XmlPullParser xmlPullParser = Xml.newPullParser();
+ xmlPullParser.setInput(new StringReader(ruleText));
+ return parseRules(xmlPullParser);
+ } catch (XmlPullParserException | IOException e) {
+ Slog.e(TAG, String.format("Unable to read rules from string: %s", ruleText), e);
+ }
return null;
}
@Override
- public Rule parse(InputStream inputStream) {
- // TODO: Implement stream parser.
+ public List<Rule> parse(InputStream inputStream) {
+ try {
+ XmlPullParser xmlPullParser = Xml.newPullParser();
+ xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
+ return parseRules(xmlPullParser);
+ } catch (XmlPullParserException | IOException e) {
+ Slog.e(TAG, "Unable to read rules from stream", e);
+ }
+ return null;
+ }
+
+ private List<Rule> parseRules(XmlPullParser parser) throws IOException, XmlPullParserException {
+ List<Rule> rules = new ArrayList<>();
+
+ // Skipping the first event type, which is always {@link XmlPullParser.START_DOCUMENT}
+ parser.next();
+
+ // Processing the first tag; which should always be a <RuleList> tag.
+ String nodeName = parser.getName();
+ // Validating that the XML is starting with a <RuleList> tag.
+ // Note: This is the only breaking validation to run against XML files in the platform.
+ // All rules inside are assumed to be validated at the server. If a rule is found to be
+ // corrupt in the XML, it will be skipped to the next rule.
+ if (!nodeName.equals(RULE_LIST_TAG)) {
+ throw new RuntimeException(
+ String.format("Rules must start with <RuleList> tag. Found: %s at %s", nodeName,
+ parser.getPositionDescription()));
+ }
+
+ int eventType;
+ while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ nodeName = parser.getName();
+ if (eventType != XmlPullParser.START_TAG || !nodeName.equals(RULE_TAG)) {
+ continue;
+ }
+ Rule parsedRule = parseRule(parser);
+ if (parsedRule != null) {
+ rules.add(parsedRule);
+ }
+ }
+
+ return rules;
+ }
+
+ private Rule parseRule(XmlPullParser parser) {
+ // TODO: Implement rule parser.
return null;
}
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 887dbb3..0a3c581 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,6 +22,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -125,7 +126,7 @@
// pkg|uid => PackagePreferences
private final ArrayMap<String, PackagePreferences> mPackagePreferences = new ArrayMap<>();
- // pkg => PackagePreferences
+ // pkg|userId => PackagePreferences
private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>();
private final Context mContext;
@@ -172,9 +173,6 @@
String tag = parser.getName();
if (!TAG_RANKING.equals(tag)) return;
synchronized (mPackagePreferences) {
- // Clobber groups and channels with the xml, but don't delete other data that wasn't
- // present at the time of serialization.
- mRestoredWithoutUids.clear();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
@@ -200,7 +198,8 @@
}
boolean skipWarningLogged = false;
- PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(
+ name, userId, uid,
XmlUtils.readIntAttribute(
parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
@@ -311,17 +310,27 @@
return mPackagePreferences.get(key);
}
- private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) {
- return getOrCreatePackagePreferencesLocked(pkg, uid,
+ private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+ int uid) {
+ return getOrCreatePackagePreferencesLocked(pkg, UserHandle.getUserId(uid), uid,
DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
DEFAULT_ALLOW_BUBBLE);
}
- private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid,
- int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) {
+ private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+ @UserIdInt int userId, int uid) {
+ return getOrCreatePackagePreferencesLocked(pkg, userId, uid,
+ DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
+ DEFAULT_ALLOW_BUBBLE);
+ }
+
+ private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+ @UserIdInt int userId, int uid, int importance, int priority, int visibility,
+ boolean showBadge, boolean allowBubble) {
final String key = packagePreferencesKey(pkg, uid);
PackagePreferences
- r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+ r = (uid == UNKNOWN_UID)
+ ? mRestoredWithoutUids.get(unrestoredPackageKey(pkg, userId))
: mPackagePreferences.get(key);
if (r == null) {
r = new PackagePreferences();
@@ -340,7 +349,7 @@
}
if (r.uid == UNKNOWN_UID) {
- mRestoredWithoutUids.put(pkg, r);
+ mRestoredWithoutUids.put(unrestoredPackageKey(pkg, userId), r);
} else {
mPackagePreferences.put(key, r);
}
@@ -382,6 +391,10 @@
private boolean createDefaultChannelIfNeededLocked(PackagePreferences r) throws
PackageManager.NameNotFoundException {
+ if (r.uid == UNKNOWN_UID) {
+ return false;
+ }
+
if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(mContext.getString(
com.android.internal.R.string.default_notification_channel_label));
@@ -1769,17 +1782,18 @@
synchronized (mPackagePreferences) {
mPackagePreferences.remove(packagePreferencesKey(pkg, uid));
}
- mRestoredWithoutUids.remove(pkg);
+ mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
updated = true;
}
} else {
for (String pkg : pkgList) {
// Package install
- final PackagePreferences r = mRestoredWithoutUids.get(pkg);
+ final PackagePreferences r =
+ mRestoredWithoutUids.get(unrestoredPackageKey(pkg, changeUserId));
if (r != null) {
try {
r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
- mRestoredWithoutUids.remove(pkg);
+ mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
synchronized (mPackagePreferences) {
mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
}
@@ -1910,6 +1924,10 @@
return pkg + "|" + uid;
}
+ private static String unrestoredPackageKey(String pkg, @UserIdInt int userId) {
+ return pkg + "|" + userId;
+ }
+
private static class PackagePreferences {
String pkg;
int uid = UNKNOWN_UID;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 157bd3b..c19c96f 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
@@ -558,8 +559,6 @@
private SurfaceAnimator mEnterBlackFrameAnimator;
private SurfaceAnimator mScreenshotRotationAnimator;
private SurfaceAnimator mRotateScreenAnimator;
- private final Runnable mNoopCallback = () -> { // b/141177184
- };
/**
* Start the rotation animation of the display and the screenshot on the
@@ -592,7 +591,7 @@
.setHeight(mDisplayContent.getSurfaceHeight())
.build(),
createWindowAnimationSpec(mRotateEnterAnimation),
- this::cancel);
+ this::onAnimationEnd);
}
private SurfaceAnimator startScreenshotAlphaAnimation() {
@@ -603,7 +602,7 @@
.setHeight(mHeight)
.build(),
createWindowAnimationSpec(mRotateAlphaAnimation),
- mNoopCallback);
+ this::onAnimationEnd);
}
private SurfaceAnimator startEnterBlackFrameAnimation() {
@@ -612,7 +611,7 @@
.setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.build(),
createWindowAnimationSpec(mRotateEnterAnimation),
- mNoopCallback);
+ this::onAnimationEnd);
}
private SurfaceAnimator startScreenshotRotationAnimation() {
@@ -654,18 +653,38 @@
}
private void onAnimationEnd() {
- mEnterBlackFrameAnimator = null;
- mScreenshotRotationAnimator = null;
- mRotateScreenAnimator = null;
- mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
- kill();
- mService.updateRotation(false, false);
- AccessibilityController accessibilityController = mService.mAccessibilityController;
+ synchronized (mService.mGlobalLock) {
+ if (isAnimating()) {
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "ScreenRotation sill animating: mDisplayAnimator: %s\n"
+ + "mEnterBlackFrameAnimator: "
+ + "%s\nmRotateScreenAnimator: %s\n"
+ + "mScreenshotRotationAnimator: %s",
+ mDisplayAnimator != null
+ ? mDisplayAnimator.isAnimating() : null,
+ mEnterBlackFrameAnimator != null
+ ? mEnterBlackFrameAnimator.isAnimating() : null,
+ mRotateScreenAnimator != null
+ ? mRotateScreenAnimator.isAnimating() : null,
+ mScreenshotRotationAnimator != null
+ ? mScreenshotRotationAnimator.isAnimating() : null
+ );
+ return;
+ }
+ ProtoLog.d(WM_DEBUG_ORIENTATION, "ScreenRotationAnimation onAnimationEnd");
+ mEnterBlackFrameAnimator = null;
+ mScreenshotRotationAnimator = null;
+ mRotateScreenAnimator = null;
+ mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
+ kill();
+ mService.updateRotation(false, false);
+ AccessibilityController accessibilityController = mService.mAccessibilityController;
- if (accessibilityController != null) {
- // We just finished rotation animation which means we did not
- // announce the rotation and waited for it to end, announce now.
- accessibilityController.onRotationChangedLocked(mDisplayContent);
+ if (accessibilityController != null) {
+ // We just finished rotation animation which means we did not
+ // announce the rotation and waited for it to end, announce now.
+ accessibilityController.onRotationChangedLocked(mDisplayContent);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationThread.java b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
index 0d3afc0..1259ee9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
@@ -21,6 +21,7 @@
import android.os.Handler;
import android.os.Trace;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.ServiceThread;
/**
@@ -56,4 +57,20 @@
return sHandler;
}
}
+
+ /**
+ * Disposes current surface animation thread if it's initialized. Should only be used in tests
+ * to set up a new environment.
+ */
+ @VisibleForTesting
+ public static void dispose() {
+ synchronized (SurfaceAnimationThread.class) {
+ if (sInstance == null) {
+ return;
+ }
+
+ getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
+ sInstance = null;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
index baf1ed0..e52aca3 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
@@ -16,11 +16,15 @@
package com.android.server.integrity.engine;
+import static com.android.server.integrity.model.IntegrityCheckResult.Effect.ALLOW;
+import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DENY;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import com.android.server.integrity.model.AppInstallMetadata;
import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
+import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
@@ -43,141 +47,176 @@
new AppInstallMetadata.Builder()
.setPackageName(PACKAGE_NAME_1)
.setAppCertificate(APP_CERTIFICATE)
+ .setVersionCode(2)
.build();
@Test
- public void testMatchRules_emptyRules() {
+ public void testEvaluateRules_noRules_allow() {
List<Rule> rules = new ArrayList<>();
- Rule matchedRule = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA);
+ IntegrityCheckResult result = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA);
- assertEquals(Rule.EMPTY, matchedRule);
+ assertEquals(ALLOW, result.getEffect());
}
@Test
- public void testMatchRules_emptyMatch() {
- Rule rule1 = new Rule(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_2), Rule.Effect.DENY);
+ public void testEvaluateRules_noMatchedRules_allow() {
+ Rule rule1 =
+ new Rule(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2),
+ Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule1),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Collections.singletonList(rule1), APP_INSTALL_METADATA);
- assertEquals(Rule.EMPTY, matchedRule);
- }
-
-
- @Test
- public void testMatchRules_oneMatch() {
- Rule rule1 = new Rule(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_1), Rule.Effect.DENY);
- Rule rule2 = new Rule(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_2), Rule.Effect.DENY);
-
- Rule matchedRule = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2),
- APP_INSTALL_METADATA);
-
- assertEquals(rule1, matchedRule);
+ assertEquals(ALLOW, result.getEffect());
}
@Test
- public void testMatchRules_multipleMatches() {
- Rule rule1 = new Rule(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_1), Rule.Effect.DENY);
- OpenFormula openFormula2 = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_1),
- new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
- AtomicFormula.Operator.EQ,
- APP_CERTIFICATE)));
- Rule rule2 = new Rule(
- openFormula2, Rule.Effect.DENY);
+ public void testEvaluateRules_oneMatch_deny() {
+ Rule rule1 =
+ new Rule(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ Rule.DENY);
+ Rule rule2 =
+ new Rule(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2),
+ Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
- assertNotEquals(Rule.EMPTY, matchedRule);
+ assertEquals(DENY, result.getEffect());
+ assertEquals(rule1, result.getRule());
}
@Test
- public void testMatchRules_ruleWithNot() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.NOT,
- Collections.singletonList(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_2)));
- Rule rule = new Rule(openFormula, Rule.Effect.DENY);
+ public void testEvaluateRules_multipleMatches_deny() {
+ Rule rule1 =
+ new Rule(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ Rule.DENY);
+ OpenFormula openFormula2 =
+ new OpenFormula(
+ OpenFormula.AND,
+ Arrays.asList(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+ Rule rule2 = new Rule(openFormula2, Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
- assertEquals(rule, matchedRule);
+ assertEquals(DENY, result.getEffect());
+ assertEquals(rule1, result.getRule());
}
@Test
- public void testMatchRules_ruleWithIntegerOperators() {
- Rule rule1 = new Rule(
- new AtomicFormula(AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.GT,
- 1), Rule.Effect.DENY);
+ public void testEvaluateRules_ruleWithNot_deny() {
+ OpenFormula openFormula =
+ new OpenFormula(
+ OpenFormula.NOT,
+ Collections.singletonList(
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2)));
+ Rule rule = new Rule(openFormula, Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule1),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
- assertEquals(rule1, matchedRule);
+ assertEquals(DENY, result.getEffect());
+ assertEquals(rule, result.getRule());
}
@Test
- public void testMatchRules_validForm() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_1),
- new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
- AtomicFormula.Operator.EQ,
- APP_CERTIFICATE)));
- Rule rule = new Rule(
- openFormula, Rule.Effect.DENY);
+ public void testEvaluateRules_ruleWithIntegerOperators_deny() {
+ Rule rule =
+ new Rule(
+ new AtomicFormula.IntAtomicFormula(
+ AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1),
+ Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
- assertEquals(rule, matchedRule);
+ assertEquals(DENY, result.getEffect());
+ assertEquals(rule, result.getRule());
}
@Test
- public void testMatchRules_ruleNotInDNF() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.OR, Arrays.asList(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_1),
- new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
- AtomicFormula.Operator.EQ,
- APP_CERTIFICATE)));
- Rule rule = new Rule(
- openFormula, Rule.Effect.DENY);
+ public void testEvaluateRules_validForm_deny() {
+ OpenFormula openFormula =
+ new OpenFormula(
+ OpenFormula.AND,
+ Arrays.asList(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+ Rule rule = new Rule(openFormula, Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
- assertEquals(Rule.EMPTY, matchedRule);
+ assertEquals(DENY, result.getEffect());
+ assertEquals(rule, result.getRule());
}
@Test
- public void testMatchRules_openFormulaWithNot() {
- OpenFormula openSubFormula = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME_2),
- new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
- AtomicFormula.Operator.EQ,
- APP_CERTIFICATE)));
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.NOT,
- Collections.singletonList(openSubFormula));
- Rule rule = new Rule(
- openFormula, Rule.Effect.DENY);
+ public void testEvaluateRules_ruleNotInDNF_ignoreAndAllow() {
+ OpenFormula openFormula =
+ new OpenFormula(
+ OpenFormula.OR,
+ Arrays.asList(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+ Rule rule = new Rule(openFormula, Rule.DENY);
- Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
- APP_INSTALL_METADATA);
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
- assertEquals(Rule.EMPTY, matchedRule);
+ assertEquals(ALLOW, result.getEffect());
+ }
+
+ @Test
+ public void testEvaluateRules_openFormulaWithNot_allow() {
+ OpenFormula openSubFormula =
+ new OpenFormula(
+ OpenFormula.AND,
+ Arrays.asList(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2),
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.NOT, Collections.singletonList(openSubFormula));
+ Rule rule = new Rule(openFormula, Rule.DENY);
+
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
+
+ assertEquals(ALLOW, result.getEffect());
+ }
+
+ @Test
+ public void testEvaluateRules_forceAllow() {
+ Rule rule1 =
+ new Rule(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ Rule.FORCE_ALLOW);
+ OpenFormula openFormula2 =
+ new OpenFormula(
+ OpenFormula.AND,
+ Arrays.asList(
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+ Rule rule2 = new Rule(openFormula2, Rule.DENY);
+
+ IntegrityCheckResult result =
+ RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
+
+ assertEquals(ALLOW, result.getEffect());
+ assertEquals(rule1, result.getRule());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
index 1cb2fb3..c8c5eca 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
@@ -19,6 +19,14 @@
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import com.android.server.integrity.model.AtomicFormula.BooleanAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.IntAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,32 +37,26 @@
@Test
public void testValidAtomicFormula_stringValue() {
- AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME,
- AtomicFormula.Operator.EQ, "com.test.app");
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.test.app");
- assertEquals(AtomicFormula.Key.PACKAGE_NAME, atomicFormula.getKey());
- assertEquals(AtomicFormula.Operator.EQ, atomicFormula.getOperator());
- assertEquals("com.test.app", atomicFormula.getStringValue());
+ assertEquals(AtomicFormula.PACKAGE_NAME, stringAtomicFormula.getKey());
}
@Test
public void testValidAtomicFormula_intValue() {
- AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.VERSION_CODE,
- AtomicFormula.Operator.LE, 1);
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1);
- assertEquals(AtomicFormula.Key.VERSION_CODE, atomicFormula.getKey());
- assertEquals(AtomicFormula.Operator.LE, atomicFormula.getOperator());
- assertEquals(1, atomicFormula.getIntValue().intValue());
+ assertEquals(AtomicFormula.VERSION_CODE, intAtomicFormula.getKey());
}
@Test
public void testValidAtomicFormula_boolValue() {
- AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.PRE_INSTALLED,
- AtomicFormula.Operator.EQ, true);
+ BooleanAtomicFormula atomicFormula =
+ new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
- assertEquals(AtomicFormula.Key.PRE_INSTALLED, atomicFormula.getKey());
- assertEquals(AtomicFormula.Operator.EQ, atomicFormula.getOperator());
- assertEquals(true, atomicFormula.getBoolValue());
+ assertEquals(AtomicFormula.PRE_INSTALLED, atomicFormula.getKey());
}
@Test
@@ -62,9 +64,9 @@
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Key %s cannot have string value", AtomicFormula.Key.VERSION_CODE),
- () -> new AtomicFormula(AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.EQ,
- "test-value"));
+ String.format(
+ "Key VERSION_CODE cannot be used with StringAtomicFormula"),
+ () -> new StringAtomicFormula(AtomicFormula.VERSION_CODE, "test-value"));
}
@Test
@@ -72,9 +74,9 @@
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Key %s cannot have integer value", AtomicFormula.Key.PACKAGE_NAME),
- () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- 1));
+ String.format(
+ "Key PACKAGE_NAME cannot be used with IntAtomicFormula"),
+ () -> new IntAtomicFormula(AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1));
}
@Test
@@ -82,19 +84,193 @@
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Key %s cannot have boolean value", AtomicFormula.Key.PACKAGE_NAME),
- () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- true));
+ String.format(
+ "Key PACKAGE_NAME cannot be used with BooleanAtomicFormula"),
+ () -> new BooleanAtomicFormula(AtomicFormula.PACKAGE_NAME, true));
}
@Test
- public void testValidateOperator_invalidKeyOperatorPair() {
- assertExpectException(
- IllegalArgumentException.class,
- /* expectedExceptionMessageRegex */
- String.format("Invalid operator %s used for key %s",
- AtomicFormula.Operator.LE, AtomicFormula.Key.PACKAGE_NAME),
- () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.LE,
- "test-value"));
+ public void testIsSatisfiable_string_true() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.test.app");
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("com.test.app").build();
+
+ assertTrue(stringAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_string_false() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.test.app");
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build();
+
+ assertFalse(stringAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_eq_true() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+ assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_eq_false() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(1).build();
+
+ assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_gt_true() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 0);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(1).build();
+
+ assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_gt_false() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+ assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_ge_true() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 0);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(1).build();
+
+ assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_ge_false() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 1);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+ assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_lt_true() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+ assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_lt_false() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(2).build();
+
+ assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_le_true() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+ assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_int_le_false() {
+ IntAtomicFormula intAtomicFormula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setVersionCode(2).build();
+
+ assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_bool_true() {
+ BooleanAtomicFormula boolFormula =
+ new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setIsPreInstalled(true).build();
+
+ assertTrue(boolFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_bool_false() {
+ BooleanAtomicFormula boolFormula =
+ new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setIsPreInstalled(false).build();
+
+ assertFalse(boolFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testParcelUnparcel_string() {
+ StringAtomicFormula formula = new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "abc");
+ Parcel p = Parcel.obtain();
+ formula.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ StringAtomicFormula newFormula = StringAtomicFormula.CREATOR.createFromParcel(p);
+
+ assertEquals(formula, newFormula);
+ }
+
+ @Test
+ public void testParcelUnparcel_int() {
+ IntAtomicFormula formula =
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1);
+ Parcel p = Parcel.obtain();
+ formula.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ IntAtomicFormula newFormula = IntAtomicFormula.CREATOR.createFromParcel(p);
+
+ assertEquals(formula, newFormula);
+ }
+
+ @Test
+ public void testParcelUnparcel_bool() {
+ BooleanAtomicFormula formula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+ Parcel p = Parcel.obtain();
+ formula.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ BooleanAtomicFormula newFormula = BooleanAtomicFormula.CREATOR.createFromParcel(p);
+
+ assertEquals(formula, newFormula);
+ }
+
+ /** Returns a builder with all fields filled with some dummy data. */
+ private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
+ return new AppInstallMetadata.Builder()
+ .setPackageName("abc")
+ .setAppCertificate("abc")
+ .setInstallerCertificate("abc")
+ .setInstallerName("abc")
+ .setVersionCode(-1)
+ .setIsPreInstalled(true);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
index 2133a7d..ecabb52 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
@@ -19,6 +19,10 @@
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,17 +34,17 @@
@RunWith(JUnit4.class)
public class OpenFormulaTest {
- private static final AtomicFormula ATOMIC_FORMULA_1 = new AtomicFormula(
- AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ, "test1");
- private static final AtomicFormula ATOMIC_FORMULA_2 = new AtomicFormula(
- AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.EQ, 1);
+ private static final AtomicFormula ATOMIC_FORMULA_1 =
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "test1");
+ private static final AtomicFormula ATOMIC_FORMULA_2 =
+ new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1);
@Test
public void testValidOpenFormula() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND,
- Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
- assertEquals(OpenFormula.Connector.AND, openFormula.getConnector());
+ assertEquals(OpenFormula.AND, openFormula.getConnector());
assertEquals(Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2), openFormula.getFormulas());
}
@@ -49,10 +53,10 @@
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Connector %s must have at least 2 formulas",
- OpenFormula.Connector.AND),
- () -> new OpenFormula(OpenFormula.Connector.AND,
- Collections.singletonList(ATOMIC_FORMULA_1)));
+ String.format("Connector AND must have at least 2 formulas"),
+ () ->
+ new OpenFormula(
+ OpenFormula.AND, Collections.singletonList(ATOMIC_FORMULA_1)));
}
@Test
@@ -60,8 +64,159 @@
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Connector %s must have 1 formula only", OpenFormula.Connector.NOT),
- () -> new OpenFormula(OpenFormula.Connector.NOT,
- Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
+ String.format("Connector NOT must have 1 formula only"),
+ () ->
+ new OpenFormula(
+ OpenFormula.NOT,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
+ }
+
+ @Test
+ public void testIsSatisfiable_notFalse_true() {
+ OpenFormula openFormula = new OpenFormula(OpenFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test2").build();
+ // validate assumptions about the metadata
+ assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+
+ assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_notTrue_false() {
+ OpenFormula openFormula = new OpenFormula(OpenFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test1").build();
+ // validate assumptions about the metadata
+ assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+
+ assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_trueAndTrue_true() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build();
+ // validate assumptions about the metadata
+ assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_trueAndFalse_false() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build();
+ // validate assumptions about the metadata
+ assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_falseAndTrue_false() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build();
+ // validate assumptions about the metadata
+ assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_falseAndFalse_false() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build();
+ // validate assumptions about the metadata
+ assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_trueOrTrue_true() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build();
+ // validate assumptions about the metadata
+ assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_trueOrFalse_true() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build();
+ // validate assumptions about the metadata
+ assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_falseOrTrue_true() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build();
+ // validate assumptions about the metadata
+ assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testIsSatisfiable_falseOrFalse_false() {
+ OpenFormula openFormula =
+ new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build();
+ // validate assumptions about the metadata
+ assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+ assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+ assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ OpenFormula formula =
+ new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1));
+ Parcel p = Parcel.obtain();
+ formula.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ OpenFormula newFormula = OpenFormula.CREATOR.createFromParcel(p);
+
+ assertEquals(formula, newFormula);
+ }
+
+ /** Returns a builder with all fields filled with some dummy data. */
+ private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
+ return new AppInstallMetadata.Builder()
+ .setPackageName("abc")
+ .setAppCertificate("abc")
+ .setInstallerCertificate("abc")
+ .setInstallerName("abc")
+ .setVersionCode(-1)
+ .setIsPreInstalled(true);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
index 048ee70..e0c36fd 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
@@ -20,7 +20,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
+
+import android.os.Parcel;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,23 +32,13 @@
@RunWith(JUnit4.class)
public class RuleTest {
- private static final Rule.Effect DENY_EFFECT = Rule.Effect.DENY;
+ private static final @Rule.Effect int DENY_EFFECT = Rule.DENY;
private static final String PACKAGE_NAME = "com.test.app";
private static final String APP_CERTIFICATE = "test_cert";
private static final Formula PACKAGE_NAME_ATOMIC_FORMULA =
- new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
- PACKAGE_NAME);
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME);
private static final Formula APP_CERTIFICATE_ATOMIC_FORMULA =
- new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE, AtomicFormula.Operator.EQ,
- APP_CERTIFICATE);
-
- @Test
- public void testEmptyRule() {
- Rule emptyRule = Rule.EMPTY;
-
- assertNull(emptyRule.getFormula());
- assertNull(emptyRule.getEffect());
- }
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE);
@Test
public void testValidRule() {
@@ -58,14 +49,6 @@
}
@Test
- public void testInvalidRule_invalidEffect() {
- assertExpectException(
- NullPointerException.class,
- /* expectedExceptionMessageRegex */ null,
- () -> new Rule(PACKAGE_NAME_ATOMIC_FORMULA, null));
- }
-
- @Test
public void testInvalidRule_invalidFormula() {
assertExpectException(
NullPointerException.class,
@@ -75,14 +58,17 @@
@Test
public void testToString() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND,
- Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA, APP_CERTIFICATE_ATOMIC_FORMULA));
- Rule rule = new Rule(openFormula, Rule.Effect.DENY);
+ OpenFormula openFormula =
+ new OpenFormula(
+ OpenFormula.AND,
+ Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA, APP_CERTIFICATE_ATOMIC_FORMULA));
+ Rule rule = new Rule(openFormula, Rule.DENY);
- String toString = rule.toString();
-
- assertEquals(String.format("Rule: PACKAGE_NAME EQ %s AND APP_CERTIFICATE EQ %s, DENY",
- PACKAGE_NAME, APP_CERTIFICATE), toString);
+ assertEquals(
+ String.format(
+ "Rule: (PACKAGE_NAME EQ %s) AND (APP_CERTIFICATE EQ %s), DENY",
+ PACKAGE_NAME, APP_CERTIFICATE),
+ rule.toString());
}
@Test
@@ -100,4 +86,24 @@
assertNotEquals(rule1, rule2);
}
+
+ @Test
+ public void testParcelUnparcel() {
+ Rule rule =
+ new Rule(
+ new OpenFormula(
+ OpenFormula.AND,
+ Arrays.asList(
+ APP_CERTIFICATE_ATOMIC_FORMULA,
+ new OpenFormula(
+ OpenFormula.NOT,
+ Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA)))),
+ Rule.DENY);
+ Parcel p = Parcel.obtain();
+ rule.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ Rule newRule = Rule.CREATOR.createFromParcel(p);
+
+ assertEquals(newRule, rule);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
new file mode 100644
index 0000000..86e544d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.parser;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.server.integrity.model.Rule;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class RuleXmlParserTest {
+
+ private static final String VALID_RULE_XML = "<RuleList>"
+ + "<Rule>"
+ + "<OpenFormula>"
+ + "<Connector>NOT</Connector>"
+ + "<AtomicFormula>"
+ + "<Key>PACKAGE_NAME</Key>"
+ + "<Operator>EQ</Operator>"
+ + "<Value>com.app.test</Value>"
+ + "</AtomicFormula>"
+ + "</OpenFormula>"
+ + "<Effect>DENY</Effect>"
+ + "</Rule>"
+ + "</RuleList>";
+
+ @Test
+ public void testXmlString_validRule() {
+ RuleParser xmlParser = new RuleXmlParser();
+
+ List<Rule> rules = xmlParser.parse(VALID_RULE_XML);
+
+ assertNotNull(rules);
+ assertTrue(rules.isEmpty());
+ }
+
+ @Test
+ public void testXmlStream_validRule() {
+ RuleParser xmlParser = new RuleXmlParser();
+ InputStream inputStream = new ByteArrayInputStream(VALID_RULE_XML.getBytes());
+
+ List<Rule> rules = xmlParser.parse(inputStream);
+
+ assertNotNull(rules);
+ assertTrue(rules.isEmpty());
+ }
+
+ @Test
+ public void testXmlString_withNoRuleList() {
+ String ruleXmlWithNoRuleList = "<Rule>"
+ + "<OpenFormula>"
+ + "<Connector>NOT</Connector>"
+ + "<AtomicFormula>"
+ + "<Key>PACKAGE_NAME</Key>"
+ + "<Operator>EQ</Operator>"
+ + "<Value>com.app.test</Value>"
+ + "</AtomicFormula>"
+ + "</OpenFormula>"
+ + "<Effect>DENY</Effect>"
+ + "</Rule>";
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuntimeException.class,
+ /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
+ () -> xmlParser.parse(ruleXmlWithNoRuleList));
+ }
+
+ @Test
+ public void testXmlStream_withNoRuleList() {
+ String ruleXmlWithNoRuleList = "<Rule>"
+ + "<OpenFormula>"
+ + "<Connector>NOT</Connector>"
+ + "<AtomicFormula>"
+ + "<Key>PACKAGE_NAME</Key>"
+ + "<Operator>EQ</Operator>"
+ + "<Value>com.app.test</Value>"
+ + "</AtomicFormula>"
+ + "</OpenFormula>"
+ + "<Effect>DENY</Effect>"
+ + "</Rule>";
+ InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuntimeException.class,
+ /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
+ () -> xmlParser.parse(inputStream));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index a1322b9..776c00e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2715,4 +2715,57 @@
assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true));
assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true));
}
+
+ @Test
+ public void testRestoreMultiUser() throws Exception {
+ String pkg = "restore_pkg";
+ String channelId = "channelId";
+ int user0Importance = 3;
+ int user10Importance = 4;
+ when(mPm.getPackageUidAsUser(eq(pkg), anyInt())).thenReturn(UserHandle.USER_NULL);
+
+ // both users have the same package, but different notification settings
+ final String xmlUser0 = "<ranking version=\"1\">\n"
+ + "<package name=\"" + pkg + "\" >\n"
+ + "<channel id=\"" + channelId + "\" name=\"hi\""
+ + " importance=\"" + user0Importance + "\"/>"
+ + "</package>"
+ + "</ranking>";
+ final String xmlUser10 = "<ranking version=\"1\">\n"
+ + "<package name=\"" + pkg + "\" >\n"
+ + "<channel id=\"" + channelId + "\" name=\"hi\""
+ + " importance=\"" + user10Importance + "\"/>"
+ + "</package>"
+ + "</ranking>";
+
+ // trigger a restore for both users
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, true, 0);
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, true, 10);
+
+ // "install" package on both users
+ String[] pkgList = new String[] {pkg};
+ int[] uidList0 = new int[] {UserHandle.PER_USER_RANGE};
+ int[] uidList10 = new int[] {UserHandle.PER_USER_RANGE + 1};
+ when(mPm.getPackageUidAsUser(pkg, 0)).thenReturn(uidList0[0]);
+ when(mPm.getPackageUidAsUser(pkg, 10)).thenReturn(uidList10[0]);
+ ApplicationInfo info = new ApplicationInfo();
+ info.targetSdkVersion = Build.VERSION_CODES.Q;
+ when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(info);
+
+ mHelper.onPackagesChanged(false, 0, pkgList, uidList0);
+ mHelper.onPackagesChanged(false, 10, pkgList, uidList10);
+
+ assertEquals(user0Importance,
+ mHelper.getNotificationChannel(pkg, uidList0[0], channelId, false).getImportance());
+ assertEquals(user10Importance, mHelper.getNotificationChannel(
+ pkg, uidList10[0], channelId, false).getImportance());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index df1135f..562775c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -310,6 +310,7 @@
DisplayThread.dispose();
AnimationThread.dispose();
UiThread.dispose();
+ SurfaceAnimationThread.dispose();
mInputChannel.dispose();
tearDownLocalServices();
diff --git a/tests/FlickerTests/TEST_MAPPING b/tests/FlickerTests/TEST_MAPPING
index f34c432..db251b9 100644
--- a/tests/FlickerTests/TEST_MAPPING
+++ b/tests/FlickerTests/TEST_MAPPING
@@ -1,8 +1,13 @@
{
"postsubmit": [
+ // Run tests on real device
{
"name": "FlickerTests",
"keywords": ["primary-device"]
+ },
+ // Also run the tests in the cloud
+ {
+ "name": "FlickerTests"
}
]
}
\ No newline at end of file