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);