Give StrictMode more bits to work with.
We're almost out of bits, and we don't really need to smash both
thread and VM policy into the same 32-bit value, so use the lower
16-bits for each policy type and the upper 16-bits for penalty.
ActivityManager is only consulting the penalty bits, so we can
remove getViolationBit() and switch CTS over to doing instanceof
checks.
Bug: 110413274
Test: atest cts/tests/tests/os/src/android/os/cts/StrictModeTest.java
Change-Id: I760e6a28f56da66dc75b7df9daf2167ff5bdff50
diff --git a/api/test-current.txt b/api/test-current.txt
index 5d1f3e2..b08ae0e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -683,23 +683,6 @@
public final class StrictMode {
method public static void setViolationLogger(android.os.StrictMode.ViolationLogger);
- field public static final int DETECT_CUSTOM = 8; // 0x8
- field public static final int DETECT_DISK_READ = 2; // 0x2
- field public static final int DETECT_DISK_WRITE = 1; // 0x1
- field public static final int DETECT_NETWORK = 4; // 0x4
- field public static final int DETECT_RESOURCE_MISMATCH = 16; // 0x10
- field public static final int DETECT_UNBUFFERED_IO = 32; // 0x20
- field public static final int DETECT_VM_ACTIVITY_LEAKS = 1024; // 0x400
- field public static final int DETECT_VM_CLEARTEXT_NETWORK = 16384; // 0x4000
- field public static final int DETECT_VM_CLOSABLE_LEAKS = 512; // 0x200
- field public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 32768; // 0x8000
- field public static final int DETECT_VM_CURSOR_LEAKS = 256; // 0x100
- field public static final int DETECT_VM_FILE_URI_EXPOSURE = 8192; // 0x2000
- field public static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 536870912; // 0x20000000
- field public static final int DETECT_VM_INSTANCE_LEAKS = 2048; // 0x800
- field public static final int DETECT_VM_NON_SDK_API_USAGE = 1073741824; // 0x40000000
- field public static final int DETECT_VM_REGISTRATION_LEAKS = 4096; // 0x1000
- field public static final int DETECT_VM_UNTAGGED_SOCKET = -2147483648; // 0x80000000
}
public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
@@ -707,9 +690,8 @@
ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
- method public int getPolicyMask();
method public java.lang.String getStackTrace();
- method public int getViolationBit();
+ method public java.lang.Class<? extends android.os.strictmode.Violation> getViolationClass();
method public java.lang.String getViolationDetails();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b39eb9b..49d3fff 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -237,11 +237,8 @@
// running.
List<ApplicationInfo> getRunningExternalApplications();
void finishHeavyWeightApp();
- // A StrictMode violation to be handled. The violationMask is a
- // subset of the original StrictMode policy bitmask, with only the
- // bit violated and penalty bits to be executed by the
- // ActivityManagerService remaining set.
- void handleApplicationStrictModeViolation(in IBinder app, int violationMask,
+ // A StrictMode violation to be handled.
+ void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask,
in StrictMode.ViolationInfo crashInfo);
boolean isTopActivityImmersive();
void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3ce7150..ea76c9a3 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -16,6 +16,7 @@
package android.os;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -70,6 +71,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayDeque;
@@ -189,120 +192,103 @@
// of the Looper.
private static final int MAX_OFFENSES_PER_LOOP = 10;
- // Byte 1: Thread-policy
+ /** @hide */
+ @IntDef(flag = true, prefix = { "DETECT_THREAD_", "PENALTY_" }, value = {
+ DETECT_THREAD_DISK_WRITE,
+ DETECT_THREAD_DISK_READ,
+ DETECT_THREAD_NETWORK,
+ DETECT_THREAD_CUSTOM,
+ DETECT_THREAD_RESOURCE_MISMATCH,
+ DETECT_THREAD_UNBUFFERED_IO,
+ DETECT_THREAD_EXPLICIT_GC,
+ PENALTY_GATHER,
+ PENALTY_LOG,
+ PENALTY_DIALOG,
+ PENALTY_DEATH,
+ PENALTY_FLASH,
+ PENALTY_DROPBOX,
+ PENALTY_DEATH_ON_NETWORK,
+ PENALTY_DEATH_ON_CLEARTEXT_NETWORK,
+ PENALTY_DEATH_ON_FILE_URI_EXPOSURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ThreadPolicyMask {}
+
+ // Thread policy: bits 0-15
/** @hide */
- @TestApi public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_DISK_WRITE = 1 << 0;
/** @hide */
- @TestApi public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_DISK_READ = 1 << 1;
/** @hide */
- @TestApi public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
-
- /**
- * For StrictMode.noteSlowCall()
- *
- * @hide
- */
- @TestApi public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
-
- /**
- * For StrictMode.noteResourceMismatch()
- *
- * @hide
- */
- @TestApi public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_NETWORK = 1 << 2;
/** @hide */
- @TestApi public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_CUSTOM = 1 << 3;
+ /** @hide */
+ private static final int DETECT_THREAD_RESOURCE_MISMATCH = 1 << 4;
+ /** @hide */
+ private static final int DETECT_THREAD_UNBUFFERED_IO = 1 << 5;
/** @hide */
- public static final int DETECT_EXPLICIT_GC = 0x40; // for ThreadPolicy
-
- private static final int ALL_THREAD_DETECT_BITS =
- DETECT_DISK_WRITE
- | DETECT_DISK_READ
- | DETECT_NETWORK
- | DETECT_CUSTOM
- | DETECT_RESOURCE_MISMATCH
- | DETECT_UNBUFFERED_IO
- | DETECT_EXPLICIT_GC;
-
- // Byte 2: Process-policy
-
- /**
- * Note, a "VM_" bit, not thread.
- *
- * @hide
- */
- @TestApi public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
-
- /**
- * Note, a "VM_" bit, not thread.
- *
- * @hide
- */
- @TestApi public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
-
- /**
- * Note, a "VM_" bit, not thread.
- *
- * @hide
- */
- @TestApi public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
+ private static final int DETECT_THREAD_EXPLICIT_GC = 1 << 6;
/** @hide */
- @TestApi public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
+ private static final int DETECT_THREAD_ALL = 0x0000ffff;
/** @hide */
- @TestApi public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
+ @IntDef(flag = true, prefix = { "DETECT_THREAD_", "PENALTY_" }, value = {
+ DETECT_VM_CURSOR_LEAKS,
+ DETECT_VM_CLOSABLE_LEAKS,
+ DETECT_VM_ACTIVITY_LEAKS,
+ DETECT_VM_INSTANCE_LEAKS,
+ DETECT_VM_REGISTRATION_LEAKS,
+ DETECT_VM_FILE_URI_EXPOSURE,
+ DETECT_VM_CLEARTEXT_NETWORK,
+ DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION,
+ DETECT_VM_UNTAGGED_SOCKET,
+ DETECT_VM_NON_SDK_API_USAGE,
+ DETECT_VM_IMPLICIT_DIRECT_BOOT,
+ PENALTY_GATHER,
+ PENALTY_LOG,
+ PENALTY_DIALOG,
+ PENALTY_DEATH,
+ PENALTY_FLASH,
+ PENALTY_DROPBOX,
+ PENALTY_DEATH_ON_NETWORK,
+ PENALTY_DEATH_ON_CLEARTEXT_NETWORK,
+ PENALTY_DEATH_ON_FILE_URI_EXPOSURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VmPolicyMask {}
+
+ // VM policy: bits 0-15
/** @hide */
- @TestApi public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
+ private static final int DETECT_VM_CURSOR_LEAKS = 1 << 0;
+ /** @hide */
+ private static final int DETECT_VM_CLOSABLE_LEAKS = 1 << 1;
+ /** @hide */
+ private static final int DETECT_VM_ACTIVITY_LEAKS = 1 << 2;
+ /** @hide */
+ private static final int DETECT_VM_INSTANCE_LEAKS = 1 << 3;
+ /** @hide */
+ private static final int DETECT_VM_REGISTRATION_LEAKS = 1 << 4;
+ /** @hide */
+ private static final int DETECT_VM_FILE_URI_EXPOSURE = 1 << 5;
+ /** @hide */
+ private static final int DETECT_VM_CLEARTEXT_NETWORK = 1 << 6;
+ /** @hide */
+ private static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 1 << 7;
+ /** @hide */
+ private static final int DETECT_VM_UNTAGGED_SOCKET = 1 << 8;
+ /** @hide */
+ private static final int DETECT_VM_NON_SDK_API_USAGE = 1 << 9;
+ /** @hide */
+ private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10;
/** @hide */
- @TestApi public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
+ private static final int DETECT_VM_ALL = 0x0000ffff;
- /** @hide */
- @TestApi
- public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
-
- /** @hide */
- @TestApi public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
-
- /** @hide */
- @TestApi public static final int DETECT_VM_NON_SDK_API_USAGE = 0x40 << 24; // for VmPolicy
-
- /** @hide */
- @TestApi public static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 0x20 << 24; // for VmPolicy
-
- private static final int ALL_VM_DETECT_BITS =
- DETECT_VM_CURSOR_LEAKS
- | DETECT_VM_CLOSABLE_LEAKS
- | DETECT_VM_ACTIVITY_LEAKS
- | DETECT_VM_INSTANCE_LEAKS
- | DETECT_VM_REGISTRATION_LEAKS
- | DETECT_VM_FILE_URI_EXPOSURE
- | DETECT_VM_CLEARTEXT_NETWORK
- | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION
- | DETECT_VM_UNTAGGED_SOCKET
- | DETECT_VM_NON_SDK_API_USAGE
- | DETECT_VM_IMPLICIT_DIRECT_BOOT;
-
-
- // Byte 3: Penalty
-
- /** {@hide} */
- public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
- /** {@hide} */
- public static final int PENALTY_DIALOG = 0x02 << 16;
- /** {@hide} */
- public static final int PENALTY_DEATH = 0x04 << 16;
- /** {@hide} */
- public static final int PENALTY_FLASH = 0x10 << 16;
- /** {@hide} */
- public static final int PENALTY_DROPBOX = 0x20 << 16;
+ // Penalty policy: bits 16-31
/**
* Non-public penalty mode which overrides all the other penalty bits and signals that we're in
@@ -313,50 +299,27 @@
*
* @hide
*/
- public static final int PENALTY_GATHER = 0x40 << 16;
+ public static final int PENALTY_GATHER = 1 << 31;
- // Byte 4: Special cases
+ /** {@hide} */
+ public static final int PENALTY_LOG = 1 << 30;
+ /** {@hide} */
+ public static final int PENALTY_DIALOG = 1 << 29;
+ /** {@hide} */
+ public static final int PENALTY_DEATH = 1 << 28;
+ /** {@hide} */
+ public static final int PENALTY_FLASH = 1 << 27;
+ /** {@hide} */
+ public static final int PENALTY_DROPBOX = 1 << 26;
+ /** {@hide} */
+ public static final int PENALTY_DEATH_ON_NETWORK = 1 << 25;
+ /** {@hide} */
+ public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 1 << 24;
+ /** {@hide} */
+ public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 1 << 23;
- /**
- * Death when network traffic is detected on main thread.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_NETWORK = 0x01 << 24;
-
- /**
- * Death when cleartext network traffic is detected.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x02 << 24;
-
- /**
- * Death when file exposure is detected.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
-
- // CAUTION: we started stealing the top bits of Byte 4 for VM above
-
- /** Mask of all the penalty bits valid for thread policies. */
- private static final int THREAD_PENALTY_MASK =
- PENALTY_LOG
- | PENALTY_DIALOG
- | PENALTY_DEATH
- | PENALTY_DROPBOX
- | PENALTY_GATHER
- | PENALTY_DEATH_ON_NETWORK
- | PENALTY_FLASH;
-
- /** Mask of all the penalty bits valid for VM policies. */
- private static final int VM_PENALTY_MASK =
- PENALTY_LOG
- | PENALTY_DEATH
- | PENALTY_DROPBOX
- | PENALTY_DEATH_ON_CLEARTEXT_NETWORK
- | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
+ /** @hide */
+ public static final int PENALTY_ALL = 0xffff0000;
/** {@hide} */
public static final int NETWORK_POLICY_ACCEPT = 0;
@@ -454,11 +417,12 @@
/** The default, lax policy which doesn't catch anything. */
public static final ThreadPolicy LAX = new ThreadPolicy(0, null, null);
- final int mask;
+ final @ThreadPolicyMask int mask;
final OnThreadViolationListener mListener;
final Executor mCallbackExecutor;
- private ThreadPolicy(int mask, OnThreadViolationListener listener, Executor executor) {
+ private ThreadPolicy(@ThreadPolicyMask int mask, OnThreadViolationListener listener,
+ Executor executor) {
this.mask = mask;
mListener = listener;
mCallbackExecutor = executor;
@@ -488,7 +452,7 @@
* </pre>
*/
public static final class Builder {
- private int mMask = 0;
+ private @ThreadPolicyMask int mMask = 0;
private OnThreadViolationListener mListener;
private Executor mExecutor;
@@ -534,52 +498,52 @@
/** Disable the detection of everything. */
public Builder permitAll() {
- return disable(ALL_THREAD_DETECT_BITS);
+ return disable(DETECT_THREAD_ALL);
}
/** Enable detection of network operations. */
public Builder detectNetwork() {
- return enable(DETECT_NETWORK);
+ return enable(DETECT_THREAD_NETWORK);
}
/** Disable detection of network operations. */
public Builder permitNetwork() {
- return disable(DETECT_NETWORK);
+ return disable(DETECT_THREAD_NETWORK);
}
/** Enable detection of disk reads. */
public Builder detectDiskReads() {
- return enable(DETECT_DISK_READ);
+ return enable(DETECT_THREAD_DISK_READ);
}
/** Disable detection of disk reads. */
public Builder permitDiskReads() {
- return disable(DETECT_DISK_READ);
+ return disable(DETECT_THREAD_DISK_READ);
}
/** Enable detection of slow calls. */
public Builder detectCustomSlowCalls() {
- return enable(DETECT_CUSTOM);
+ return enable(DETECT_THREAD_CUSTOM);
}
/** Disable detection of slow calls. */
public Builder permitCustomSlowCalls() {
- return disable(DETECT_CUSTOM);
+ return disable(DETECT_THREAD_CUSTOM);
}
/** Disable detection of mismatches between defined resource types and getter calls. */
public Builder permitResourceMismatches() {
- return disable(DETECT_RESOURCE_MISMATCH);
+ return disable(DETECT_THREAD_RESOURCE_MISMATCH);
}
/** Detect unbuffered input/output operations. */
public Builder detectUnbufferedIo() {
- return enable(DETECT_UNBUFFERED_IO);
+ return enable(DETECT_THREAD_UNBUFFERED_IO);
}
/** Disable detection of unbuffered input/output operations. */
public Builder permitUnbufferedIo() {
- return disable(DETECT_UNBUFFERED_IO);
+ return disable(DETECT_THREAD_UNBUFFERED_IO);
}
/**
@@ -595,17 +559,17 @@
* resource as an integer to avoid unnecessary type conversion.
*/
public Builder detectResourceMismatches() {
- return enable(DETECT_RESOURCE_MISMATCH);
+ return enable(DETECT_THREAD_RESOURCE_MISMATCH);
}
/** Enable detection of disk writes. */
public Builder detectDiskWrites() {
- return enable(DETECT_DISK_WRITE);
+ return enable(DETECT_THREAD_DISK_WRITE);
}
/** Disable detection of disk writes. */
public Builder permitDiskWrites() {
- return disable(DETECT_DISK_WRITE);
+ return disable(DETECT_THREAD_DISK_WRITE);
}
/**
@@ -618,7 +582,7 @@
// TODO(b/3400644): Un-hide ExplicitGcViolation for next API update
// TODO(b/3400644): Make DETECT_EXPLICIT_GC a @TestApi for next API update
// TODO(b/3400644): Call this from detectAll in next API update
- return enable(DETECT_EXPLICIT_GC);
+ return enable(DETECT_THREAD_EXPLICIT_GC);
}
/**
@@ -628,7 +592,7 @@
*/
public Builder permitExplicitGc() {
// TODO(b/3400644): Un-hide this for next API update
- return disable(DETECT_EXPLICIT_GC);
+ return disable(DETECT_THREAD_EXPLICIT_GC);
}
/**
@@ -701,13 +665,13 @@
return penaltyListener(executor, listener);
}
- private Builder enable(int bit) {
- mMask |= bit;
+ private Builder enable(@ThreadPolicyMask int mask) {
+ mMask |= mask;
return this;
}
- private Builder disable(int bit) {
- mMask &= ~bit;
+ private Builder disable(@ThreadPolicyMask int mask) {
+ mMask &= ~mask;
return this;
}
@@ -744,7 +708,7 @@
/** The default, lax policy which doesn't catch anything. */
public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP, null, null);
- final int mask;
+ final @VmPolicyMask int mask;
final OnVmViolationListener mListener;
final Executor mCallbackExecutor;
@@ -752,7 +716,7 @@
final HashMap<Class, Integer> classInstanceLimit;
private VmPolicy(
- int mask,
+ @VmPolicyMask int mask,
HashMap<Class, Integer> classInstanceLimit,
OnVmViolationListener listener,
Executor executor) {
@@ -789,7 +753,7 @@
* </pre>
*/
public static final class Builder {
- private int mMask;
+ private @VmPolicyMask int mMask;
private OnVmViolationListener mListener;
private Executor mExecutor;
@@ -1090,13 +1054,13 @@
return penaltyListener(executor, listener);
}
- private Builder enable(int bit) {
- mMask |= bit;
+ private Builder enable(@VmPolicyMask int mask) {
+ mMask |= mask;
return this;
}
- Builder disable(int bit) {
- mMask &= ~bit;
+ Builder disable(@VmPolicyMask int mask) {
+ mMask &= ~mask;
return this;
}
@@ -1161,21 +1125,21 @@
}
/** @hide */
- public static void setThreadPolicyMask(final int policyMask) {
+ public static void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) {
// In addition to the Java-level thread-local in Dalvik's
// BlockGuard, we also need to keep a native thread-local in
// Binder in order to propagate the value across Binder calls,
// even across native-only processes. The two are kept in
// sync via the callback to onStrictModePolicyChange, below.
- setBlockGuardPolicy(policyMask);
+ setBlockGuardPolicy(threadPolicyMask);
// And set the Android native version...
- Binder.setThreadStrictModePolicy(policyMask);
+ Binder.setThreadStrictModePolicy(threadPolicyMask);
}
// Sets the policy in Dalvik/libcore (BlockGuard)
- private static void setBlockGuardPolicy(final int policyMask) {
- if (policyMask == 0) {
+ private static void setBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) {
+ if (threadPolicyMask == 0) {
BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
return;
}
@@ -1187,7 +1151,7 @@
androidPolicy = THREAD_ANDROID_POLICY.get();
BlockGuard.setThreadPolicy(androidPolicy);
}
- androidPolicy.setPolicyMask(policyMask);
+ androidPolicy.setThreadPolicyMask(threadPolicyMask);
}
// Sets up CloseGuard in Dalvik/libcore
@@ -1204,8 +1168,13 @@
* @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
* @hide
*/
- public static int getThreadPolicyMask() {
- return BlockGuard.getThreadPolicy().getPolicyMask();
+ public static @ThreadPolicyMask int getThreadPolicyMask() {
+ final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+ if (policy instanceof AndroidBlockGuardPolicy) {
+ return ((AndroidBlockGuardPolicy) policy).getThreadPolicyMask();
+ } else {
+ return 0;
+ }
}
/** Returns the current thread's policy. */
@@ -1237,9 +1206,9 @@
}
/** @hide */
- public static int allowThreadDiskWritesMask() {
+ public static @ThreadPolicyMask int allowThreadDiskWritesMask() {
int oldPolicyMask = getThreadPolicyMask();
- int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
+ int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_WRITE | DETECT_THREAD_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
@@ -1261,9 +1230,9 @@
}
/** @hide */
- public static int allowThreadDiskReadsMask() {
+ public static @ThreadPolicyMask int allowThreadDiskReadsMask() {
int oldPolicyMask = getThreadPolicyMask();
- int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
+ int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
@@ -1431,32 +1400,6 @@
sVmPolicy.mCallbackExecutor);
}
- /**
- * Parses the BlockGuard policy mask out from the Exception's getMessage() String value. Kinda
- * gross, but least invasive. :/
- *
- * <p>Input is of the following forms: "policy=137 violation=64" "policy=137 violation=64
- * msg=Arbitrary text"
- *
- * <p>Returns 0 on failure, which is a valid policy, but not a valid policy during a violation
- * (else there must've been some policy in effect to violate).
- */
- private static int parsePolicyFromMessage(String message) {
- if (message == null || !message.startsWith("policy=")) {
- return 0;
- }
- int spaceIndex = message.indexOf(' ');
- if (spaceIndex == -1) {
- return 0;
- }
- String policyString = message.substring(7, spaceIndex);
- try {
- return Integer.parseInt(policyString);
- } catch (NumberFormatException e) {
- return 0;
- }
- }
-
private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
new ThreadLocal<ArrayList<ViolationInfo>>() {
@Override
@@ -1487,30 +1430,30 @@
}
private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
- private int mPolicyMask;
+ private @ThreadPolicyMask int mThreadPolicyMask;
// Map from violation stacktrace hashcode -> uptimeMillis of
// last violation. No locking needed, as this is only
// accessed by the same thread.
private ArrayMap<Integer, Long> mLastViolationTime;
- public AndroidBlockGuardPolicy(final int policyMask) {
- mPolicyMask = policyMask;
+ public AndroidBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) {
+ mThreadPolicyMask = threadPolicyMask;
}
@Override
public String toString() {
- return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask;
+ return "AndroidBlockGuardPolicy; mPolicyMask=" + mThreadPolicyMask;
}
// Part of BlockGuard.Policy interface:
public int getPolicyMask() {
- return mPolicyMask;
+ return mThreadPolicyMask;
}
// Part of BlockGuard.Policy interface:
public void onWriteToDisk() {
- if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_DISK_WRITE) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1521,7 +1464,7 @@
// Not part of BlockGuard.Policy; just part of StrictMode:
void onCustomSlowCall(String name) {
- if ((mPolicyMask & DETECT_CUSTOM) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_CUSTOM) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1532,7 +1475,7 @@
// Not part of BlockGuard.Policy; just part of StrictMode:
void onResourceMismatch(Object tag) {
- if ((mPolicyMask & DETECT_RESOURCE_MISMATCH) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_RESOURCE_MISMATCH) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1543,7 +1486,7 @@
// Not part of BlockGuard.Policy; just part of StrictMode:
public void onUnbufferedIO() {
- if ((mPolicyMask & DETECT_UNBUFFERED_IO) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_UNBUFFERED_IO) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1554,7 +1497,7 @@
// Part of BlockGuard.Policy interface:
public void onReadFromDisk() {
- if ((mPolicyMask & DETECT_DISK_READ) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_DISK_READ) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1565,10 +1508,10 @@
// Part of BlockGuard.Policy interface:
public void onNetwork() {
- if ((mPolicyMask & DETECT_NETWORK) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_NETWORK) == 0) {
return;
}
- if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) {
+ if ((mThreadPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) {
throw new NetworkOnMainThreadException();
}
if (tooManyViolationsThisLoop()) {
@@ -1579,7 +1522,7 @@
// Part of BlockGuard.Policy interface:
public void onExplicitGc() {
- if ((mPolicyMask & DETECT_EXPLICIT_GC) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_EXPLICIT_GC) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1588,8 +1531,12 @@
startHandlingViolationException(new ExplicitGcViolation());
}
- public void setPolicyMask(int policyMask) {
- mPolicyMask = policyMask;
+ public @ThreadPolicyMask int getThreadPolicyMask() {
+ return mThreadPolicyMask;
+ }
+
+ public void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) {
+ mThreadPolicyMask = threadPolicyMask;
}
// Start handling a violation that just started and hasn't
@@ -1598,7 +1545,8 @@
// thread and, if so, uses it to roughly measure how long the
// violation took.
void startHandlingViolationException(Violation e) {
- final ViolationInfo info = new ViolationInfo(e, mPolicyMask);
+ final int penaltyMask = (mThreadPolicyMask & PENALTY_ALL);
+ final ViolationInfo info = new ViolationInfo(e, penaltyMask);
info.violationUptimeMillis = SystemClock.uptimeMillis();
handleViolationWithTimingAttempt(info);
}
@@ -1627,7 +1575,7 @@
//
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
- if (looper == null || (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
+ if (looper == null || (info.mPenaltyMask == PENALTY_DEATH)) {
info.durationMillis = -1; // unknown (redundant, already set)
onThreadPolicyViolation(info);
return;
@@ -1698,7 +1646,7 @@
// to people who push/pop temporary policy in regions of code,
// hence the policy being passed around.
void onThreadPolicyViolation(final ViolationInfo info) {
- if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; policy=" + info.mPolicy);
+ if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; penalty=" + info.mPenaltyMask);
if (info.penaltyEnabled(PENALTY_GATHER)) {
ArrayList<ViolationInfo> violations = gatheredViolations.get();
@@ -1739,25 +1687,20 @@
final Violation violation = info.mViolation;
- // The violationMaskSubset, passed to ActivityManager, is a
- // subset of the original StrictMode policy bitmask, with
- // only the bit violated and penalty bits to be executed
- // by the ActivityManagerService remaining set.
- int violationMaskSubset = 0;
+ // Penalties that ActivityManager should execute on our behalf.
+ int penaltyMask = 0;
if (info.penaltyEnabled(PENALTY_DIALOG)
&& timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
- violationMaskSubset |= PENALTY_DIALOG;
+ penaltyMask |= PENALTY_DIALOG;
}
if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) {
- violationMaskSubset |= PENALTY_DROPBOX;
+ penaltyMask |= PENALTY_DROPBOX;
}
- if (violationMaskSubset != 0) {
- violationMaskSubset |= info.getViolationBit();
-
- final boolean justDropBox = (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
+ if (penaltyMask != 0) {
+ final boolean justDropBox = (info.mPenaltyMask == PENALTY_DROPBOX);
if (justDropBox) {
// If all we're going to ask the activity manager
// to do is dropbox it (the common case during
@@ -1765,13 +1708,13 @@
// call synchronously which Binder data suggests
// isn't always super fast, despite the implementation
// in the ActivityManager trying to be mostly async.
- dropboxViolationAsync(violationMaskSubset, info);
+ dropboxViolationAsync(penaltyMask, info);
} else {
- handleApplicationStrictModeViolation(violationMaskSubset, info);
+ handleApplicationStrictModeViolation(penaltyMask, info);
}
}
- if ((info.getPolicyMask() & PENALTY_DEATH) != 0) {
+ if (info.penaltyEnabled(PENALTY_DEATH)) {
throw new RuntimeException("StrictMode ThreadPolicy violation", violation);
}
@@ -1784,11 +1727,11 @@
executor.execute(
() -> {
// Lift violated policy to prevent infinite recursion.
- ThreadPolicy oldPolicy = allowThreadViolations();
+ ThreadPolicy oldPolicy = StrictMode.allowThreadViolations();
try {
listener.onThreadViolation(violation);
} finally {
- setThreadPolicy(oldPolicy);
+ StrictMode.setThreadPolicy(oldPolicy);
}
});
} catch (RejectedExecutionException e) {
@@ -1805,7 +1748,7 @@
* per-thread and vm-wide violations when applicable.
*/
private static void dropboxViolationAsync(
- final int violationMaskSubset, final ViolationInfo info) {
+ final int penaltyMask, final ViolationInfo info) {
int outstanding = sDropboxCallsInFlight.incrementAndGet();
if (outstanding > 20) {
// What's going on? Let's not make make the situation
@@ -1817,13 +1760,13 @@
if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding);
BackgroundThread.getHandler().post(() -> {
- handleApplicationStrictModeViolation(violationMaskSubset, info);
+ handleApplicationStrictModeViolation(penaltyMask, info);
int outstandingInner = sDropboxCallsInFlight.decrementAndGet();
if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstandingInner);
});
}
- private static void handleApplicationStrictModeViolation(int violationMaskSubset,
+ private static void handleApplicationStrictModeViolation(int penaltyMask,
ViolationInfo info) {
final int oldMask = getThreadPolicyMask();
try {
@@ -1838,7 +1781,7 @@
Log.w(TAG, "No activity manager; failed to Dropbox violation.");
} else {
am.handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
+ RuntimeInit.getApplicationObject(), penaltyMask, info);
}
} catch (RemoteException e) {
if (e instanceof DeadObjectException) {
@@ -1925,7 +1868,7 @@
if (looper != null) {
MessageQueue mq = looper.mQueue;
if (policy.classInstanceLimit.size() == 0
- || (sVmPolicy.mask & VM_PENALTY_MASK) == 0) {
+ || (sVmPolicy.mask & PENALTY_ALL) == 0) {
mq.removeIdleHandler(sProcessIdleHandler);
sIsIdlerRegistered = false;
} else if (!sIsIdlerRegistered) {
@@ -2116,7 +2059,9 @@
final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0;
final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath;
final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0;
- final ViolationInfo info = new ViolationInfo(violation, sVmPolicy.mask);
+
+ final int penaltyMask = (sVmPolicy.mask & PENALTY_ALL);
+ final ViolationInfo info = new ViolationInfo(violation, penaltyMask);
// Erase stuff not relevant for process-wide violations
info.numAnimationsRunning = 0;
@@ -2145,16 +2090,14 @@
sLogger.log(info);
}
- int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicy.mask);
-
if (penaltyDropbox) {
if (penaltyDeath) {
- handleApplicationStrictModeViolation(violationMaskSubset, info);
+ handleApplicationStrictModeViolation(PENALTY_DROPBOX, info);
} else {
// Common case for userdebug/eng builds. If no death and
// just dropboxing, we can do the ActivityManager call
// asynchronously.
- dropboxViolationAsync(violationMaskSubset, info);
+ dropboxViolationAsync(PENALTY_DROPBOX, info);
}
}
@@ -2229,7 +2172,7 @@
* Binder for its current (native) thread-local policy value and synchronize it to libcore's
* (Java) thread-local policy value.
*/
- private static void onBinderStrictModePolicyChange(int newPolicy) {
+ private static void onBinderStrictModePolicyChange(@ThreadPolicyMask int newPolicy) {
setBlockGuardPolicy(newPolicy);
}
@@ -2547,8 +2490,8 @@
/** Memoized stack trace of full violation. */
@Nullable private String mStackTrace;
- /** The strict mode policy mask at the time of violation. */
- private final int mPolicy;
+ /** The strict mode penalty mask at the time of violation. */
+ private final int mPenaltyMask;
/** The wall time duration of the violation, when known. -1 when not known. */
public int durationMillis = -1;
@@ -2579,9 +2522,9 @@
public long numInstances = -1;
/** Create an instance of ViolationInfo initialized from an exception. */
- ViolationInfo(Violation tr, int policy) {
+ ViolationInfo(Violation tr, int penaltyMask) {
this.mViolation = tr;
- this.mPolicy = policy;
+ this.mPenaltyMask = penaltyMask;
violationUptimeMillis = SystemClock.uptimeMillis();
this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
@@ -2610,7 +2553,10 @@
}
}
- /** Equivalent output to {@link ApplicationErrorReport.CrashInfo#stackTrace}. */
+ /**
+ * Equivalent output to
+ * {@link android.app.ApplicationErrorReport.CrashInfo#stackTrace}.
+ */
public String getStackTrace() {
if (mStackTrace == null) {
StringWriter sw = new StringWriter();
@@ -2631,6 +2577,10 @@
return mStackTrace;
}
+ public Class<? extends Violation> getViolationClass() {
+ return mViolation.getClass();
+ }
+
/**
* Optional message describing this violation.
*
@@ -2641,18 +2591,8 @@
return mViolation.getMessage();
}
- /**
- * Policy mask at time of violation.
- *
- * @hide
- */
- @TestApi
- public int getPolicyMask() {
- return mPolicy;
- }
-
boolean penaltyEnabled(int p) {
- return (mPolicy & p) != 0;
+ return (mPenaltyMask & p) != 0;
}
/**
@@ -2665,53 +2605,6 @@
mBinderStack.addFirst(t.getStackTrace());
}
- /**
- * Retrieve the type of StrictMode violation.
- *
- * @hide
- */
- @TestApi
- public int getViolationBit() {
- if (mViolation instanceof DiskWriteViolation) {
- return DETECT_DISK_WRITE;
- } else if (mViolation instanceof DiskReadViolation) {
- return DETECT_DISK_READ;
- } else if (mViolation instanceof NetworkViolation) {
- return DETECT_NETWORK;
- } else if (mViolation instanceof CustomViolation) {
- return DETECT_CUSTOM;
- } else if (mViolation instanceof ResourceMismatchViolation) {
- return DETECT_RESOURCE_MISMATCH;
- } else if (mViolation instanceof UnbufferedIoViolation) {
- return DETECT_UNBUFFERED_IO;
- } else if (mViolation instanceof SqliteObjectLeakedViolation) {
- return DETECT_VM_CURSOR_LEAKS;
- } else if (mViolation instanceof LeakedClosableViolation) {
- return DETECT_VM_CLOSABLE_LEAKS;
- } else if (mViolation instanceof InstanceCountViolation) {
- return DETECT_VM_INSTANCE_LEAKS;
- } else if (mViolation instanceof IntentReceiverLeakedViolation) {
- return DETECT_VM_REGISTRATION_LEAKS;
- } else if (mViolation instanceof ServiceConnectionLeakedViolation) {
- return DETECT_VM_REGISTRATION_LEAKS;
- } else if (mViolation instanceof FileUriExposedViolation) {
- return DETECT_VM_FILE_URI_EXPOSURE;
- } else if (mViolation instanceof CleartextNetworkViolation) {
- return DETECT_VM_CLEARTEXT_NETWORK;
- } else if (mViolation instanceof ContentUriWithoutPermissionViolation) {
- return DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
- } else if (mViolation instanceof UntaggedSocketViolation) {
- return DETECT_VM_UNTAGGED_SOCKET;
- } else if (mViolation instanceof ExplicitGcViolation) {
- return DETECT_EXPLICIT_GC;
- } else if (mViolation instanceof NonSdkApiUsedViolation) {
- return DETECT_VM_NON_SDK_API_USAGE;
- } else if (mViolation instanceof ImplicitDirectBootViolation) {
- return DETECT_VM_IMPLICIT_DIRECT_BOOT;
- }
- throw new IllegalStateException("missing violation bit");
- }
-
@Override
public int hashCode() {
int result = 17;
@@ -2759,11 +2652,11 @@
}
mBinderStack.add(traceElements);
}
- int rawPolicy = in.readInt();
+ int rawPenaltyMask = in.readInt();
if (unsetGatheringBit) {
- mPolicy = rawPolicy & ~PENALTY_GATHER;
+ mPenaltyMask = rawPenaltyMask & ~PENALTY_GATHER;
} else {
- mPolicy = rawPolicy;
+ mPenaltyMask = rawPenaltyMask;
}
durationMillis = in.readInt();
violationNumThisLoop = in.readInt();
@@ -2789,7 +2682,7 @@
}
}
int start = dest.dataPosition();
- dest.writeInt(mPolicy);
+ dest.writeInt(mPenaltyMask);
dest.writeInt(durationMillis);
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
@@ -2801,8 +2694,8 @@
if (Binder.CHECK_PARCEL_SIZE && total > 10 * 1024) {
Slog.d(
TAG,
- "VIO: policy="
- + mPolicy
+ "VIO: penalty="
+ + mPenaltyMask
+ " dur="
+ durationMillis
+ " numLoop="
@@ -2822,7 +2715,7 @@
/** Dump a ViolationInfo instance to a Printer. */
public void dump(Printer pw, String prefix) {
pw.println(prefix + "stackTrace: " + getStackTrace());
- pw.println(prefix + "policy: " + mPolicy);
+ pw.println(prefix + "penalty: " + mPenaltyMask);
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70901d0..50310a3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12042,13 +12042,13 @@
public void handleApplicationStrictModeViolation(
IBinder app,
- int violationMask,
+ int penaltyMask,
StrictMode.ViolationInfo info) {
// We're okay if the ProcessRecord is missing; it probably means that
// we're reporting a violation from the system process itself.
final ProcessRecord r = findAppProcess(app, "StrictMode");
- if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
+ if ((penaltyMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
boolean logIt = true;
synchronized (mAlreadyLoggedViolatedStacks) {
@@ -12072,7 +12072,7 @@
}
}
- if ((violationMask & StrictMode.PENALTY_DIALOG) != 0) {
+ if ((penaltyMask & StrictMode.PENALTY_DIALOG) != 0) {
AppErrorResult result = new AppErrorResult();
synchronized (this) {
final long origId = Binder.clearCallingIdentity();
@@ -12082,7 +12082,6 @@
HashMap<String, Object> data = new HashMap<String, Object>();
data.put("result", result);
data.put("app", r);
- data.put("violationMask", violationMask);
data.put("info", info);
msg.obj = data;
mUiHandler.sendMessage(msg);