Add test for INSTALL_PACKAGES when adding installer package
Verifies that INSTALL_PACKAGES is required to add an installer
to an existing package and that an app cannot exploit a previous
vulnerability allowing it to grant itself whitelist restricted
permissions.
Bug: 150857253
Test: atest android.appsecurity.cts.PackageSetInstallerTest
Test: atest CtsMediaHostTestCases
Test: cts-tradefed run commandAndExit cts --abi armeabi-v7a
-m CtsMediaBitstreamsTestCases
Change-Id: Ib94bc437d6738821f58367216b711096459768c2
diff --git a/hostsidetests/appsecurity/Android.bp b/hostsidetests/appsecurity/Android.bp
index 3cc61fe..7a77cc9 100644
--- a/hostsidetests/appsecurity/Android.bp
+++ b/hostsidetests/appsecurity/Android.bp
@@ -17,7 +17,7 @@
defaults: ["cts_defaults"],
// Only compile source java files in this apk.
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
libs: [
"cts-tradefed",
@@ -27,7 +27,11 @@
"hamcrest-library",
],
- static_libs: ["CompatChangeGatingTestBase"],
+ static_libs: [
+ "CompatChangeGatingTestBase",
+ "CtsPkgInstallerConstants",
+ "cts-host-utils",
+ ],
java_resource_dirs: ["res"],
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
index 24cc5ae..283d3cb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
@@ -28,7 +28,7 @@
/**
* Base class.
*/
-abstract class BaseAppSecurityTest extends BaseHostJUnit4Test {
+public abstract class BaseAppSecurityTest extends BaseHostJUnit4Test {
/** Whether multi-user is supported. */
protected boolean mSupportsMultiUser;
@@ -92,7 +92,10 @@
this(false);
}
public InstallMultiple(boolean instant) {
- super(getDevice(), getBuild(), getAbi());
+ this(instant, true);
+ }
+ public InstallMultiple(boolean instant, boolean grantPermissions) {
+ super(getDevice(), getBuild(), getAbi(), grantPermissions);
addArg(instant ? "--instant" : "");
addArg("--force-queryable");
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseInstallMultiple.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseInstallMultiple.java
index cb170c9..00f4975 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseInstallMultiple.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseInstallMultiple.java
@@ -51,10 +51,17 @@
private boolean mUseNaturalAbi;
public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+ this(device, buildInfo, abi, true);
+ }
+
+ public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi,
+ boolean grantPermissions) {
mDevice = device;
mBuild = buildInfo;
mAbi = abi;
- addArg("-g");
+ if (grantPermissions) {
+ addArg("-g");
+ }
}
T addArg(String arg) {
@@ -114,6 +121,11 @@
return (T) this;
}
+ T restrictPermissions() {
+ addArg("--restrict-permissions");
+ return (T) this;
+ }
+
protected String deriveRemoteName(String originalName, int index) {
return index + "_" + originalName;
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt
new file mode 100644
index 0000000..f3c3420
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts
+
+import android.appsecurity.cts.PackageSetInstallerConstants.CHANGE_ID
+import android.appsecurity.cts.PackageSetInstallerConstants.PERMISSION_HARD_RESTRICTED
+import android.appsecurity.cts.PackageSetInstallerConstants.PERMISSION_IMMUTABLY_SOFT_RESTRICTED
+import android.appsecurity.cts.PackageSetInstallerConstants.PERMISSION_KEY
+import android.appsecurity.cts.PackageSetInstallerConstants.PERMISSION_NOT_RESTRICTED
+import android.appsecurity.cts.PackageSetInstallerConstants.SHOULD_SUCCEED_KEY
+import android.appsecurity.cts.PackageSetInstallerConstants.SHOULD_THROW_EXCEPTION_KEY
+import android.appsecurity.cts.PackageSetInstallerConstants.TARGET_APK
+import android.appsecurity.cts.PackageSetInstallerConstants.TARGET_PKG
+import android.appsecurity.cts.PackageSetInstallerConstants.WHITELIST_APK
+import android.appsecurity.cts.PackageSetInstallerConstants.WHITELIST_PKG
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters
+import android.cts.host.utils.DeviceJUnit4Parameterized
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * This test verifies protection for an exploit where any app could set the installer package
+ * name for another app if the installer was uninstalled or never set.
+ *
+ * It mimics both the set installer logic and checks for a permission bypass caused by this exploit,
+ * where an app could take installer for itself and whitelist itself to receive protected
+ * permissions.
+ */
+@RunWith(DeviceJUnit4Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(
+ DeviceJUnit4ClassRunnerWithParameters.RunnerFactory::class)
+class PackageSetInstallerTest : BaseAppSecurityTest() {
+
+ companion object {
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{1}")
+ fun parameters() = arrayOf(
+ arrayOf(true, "throwException"),
+ arrayOf(false, "failSilently")
+ )
+ }
+
+ @JvmField
+ @Parameterized.Parameter(0)
+ var failSilently = false
+
+ @Parameterized.Parameter(1)
+ lateinit var testName: String
+
+ @Before
+ @After
+ fun uninstallTestPackages() {
+ device.uninstallPackage(TARGET_PKG)
+ device.uninstallPackage(WHITELIST_PKG)
+ }
+
+ @After
+ fun resetChanges() {
+ device.executeShellCommand("am compat reset $CHANGE_ID $TARGET_PKG")
+ device.executeShellCommand("am compat reset $CHANGE_ID $WHITELIST_PKG")
+ }
+
+ @Before
+ fun initializeChangeState() {
+ if (failSilently) {
+ device.executeShellCommand("am compat disable $CHANGE_ID $TARGET_PKG")
+ device.executeShellCommand("am compat disable $CHANGE_ID $WHITELIST_PKG")
+ } else {
+ resetChanges()
+ }
+ }
+
+ @Test
+ fun notRestricted() {
+ runTest(removeWhitelistShouldSucceed = false,
+ permission = PERMISSION_NOT_RESTRICTED,
+ finalState = GrantState.TRUE)
+ }
+
+ @Test
+ fun hardRestricted() {
+ runTest(removeWhitelistShouldSucceed = true,
+ permission = PERMISSION_HARD_RESTRICTED,
+ finalState = GrantState.FALSE)
+ }
+
+ @Test
+ fun immutablySoftRestrictedGranted() {
+ runTest(removeWhitelistShouldSucceed = null,
+ permission = PERMISSION_IMMUTABLY_SOFT_RESTRICTED,
+ finalState = GrantState.TRUE_EXEMPT)
+ }
+
+ @Test
+ fun immutablySoftRestrictedRevoked() {
+ runTest(removeWhitelistShouldSucceed = null,
+ permission = PERMISSION_IMMUTABLY_SOFT_RESTRICTED,
+ restrictPermissions = true,
+ finalState = GrantState.TRUE_RESTRICTED)
+ }
+
+ private fun runTest(
+ removeWhitelistShouldSucceed: Boolean?,
+ permission: String,
+ restrictPermissions: Boolean = false,
+ finalState: GrantState
+ ) {
+ // Verifies throwing a SecurityException or failing silently for backwards compatibility
+ val testArgs: Map<String, String?> = mapOf(
+ PERMISSION_KEY to permission
+ )
+
+ // First, install both packages and ensure no installer is set
+ InstallMultiple(false, false)
+ .addFile(TARGET_APK)
+ .allowTest()
+ .forUser(mPrimaryUserId)
+ .apply {
+ if (restrictPermissions) {
+ restrictPermissions()
+ }
+ }
+ .run()
+
+ InstallMultiple(false, false)
+ .addFile(WHITELIST_APK)
+ .allowTest()
+ .forUser(mPrimaryUserId)
+ .run()
+
+ assertPermission(false, permission)
+ assertTargetInstaller(null)
+
+ // Install the installer whitelist app and take over the installer package. This methods
+ // adopts the INSTALL_PACKAGES permission and verifies that the new behavior of checking
+ // this permission is applied.
+ Utils.runDeviceTests(device, WHITELIST_PKG, ".PermissionWhitelistTest",
+ "setTargetInstallerPackage", mPrimaryUserId,
+ testArgs.plus(SHOULD_THROW_EXCEPTION_KEY to (!failSilently).toString()))
+ assertTargetInstaller(WHITELIST_PKG)
+
+ // Verify that without whitelist restriction, the target app can be granted the permission
+ grantPermission(permission)
+ assertPermission(true, permission)
+ revokePermission(permission)
+ assertPermission(false, permission)
+
+ val whitelistArgs = testArgs
+ .plus(SHOULD_SUCCEED_KEY to removeWhitelistShouldSucceed?.toString())
+ .filterValues { it != null }
+
+ // Now restrict the permission from the target app using the whitelist app
+ Utils.runDeviceTests(device, WHITELIST_PKG, ".PermissionWhitelistTest",
+ "removeWhitelistRestrictedPermission", mPrimaryUserId, whitelistArgs)
+
+ // Now remove the installer and verify the installer is wiped
+ device.uninstallPackage(WHITELIST_PKG)
+ assertTargetInstaller(null)
+
+ // Verify whitelist restriction retained by attempting and failing to grant permission
+ assertPermission(false, permission)
+ grantPermission(permission)
+ assertGrantState(finalState, permission)
+ revokePermission(permission)
+
+ // Attempt exploit to take over installer package and have target whitelist itself
+ Utils.runDeviceTests(device, TARGET_PKG, ".PermissionRequestTest",
+ "setSelfAsInstallerAndWhitelistPermission", mPrimaryUserId,
+ testArgs.plus(SHOULD_THROW_EXCEPTION_KEY to (!failSilently).toString()))
+
+ // Assert nothing changed about whitelist restriction
+ assertTargetInstaller(null)
+ grantPermission(permission)
+ assertGrantState(finalState, permission)
+ }
+
+ private fun assertTargetInstaller(installer: String?) {
+ assertThat(device.executeShellCommand("pm list packages -i | grep $TARGET_PKG").trim())
+ .isEqualTo("package:$TARGET_PKG installer=$installer")
+ }
+
+ private fun assertPermission(granted: Boolean, permission: String) {
+ assertThat(device.executeShellCommand("dumpsys package $TARGET_PKG | grep $permission"))
+ .contains("$permission: granted=$granted")
+ }
+
+ private fun grantPermission(permission: String) {
+ device.executeShellCommand("pm grant $TARGET_PKG $permission")
+ }
+
+ private fun revokePermission(permission: String) {
+ device.executeShellCommand("pm revoke $TARGET_PKG $permission")
+ }
+
+ private fun assertGrantState(state: GrantState, permission: String) {
+ val output = device.executeShellCommand(
+ "dumpsys package $TARGET_PKG | grep \"$permission: granted\"").trim()
+
+ // Make sure only the expected output line is returned
+ assertWithMessage(output).that(output.lines().size).isEqualTo(1)
+
+ when (state) {
+ GrantState.TRUE -> {
+ assertThat(output).contains("granted=true")
+ assertThat(output).doesNotContain("RESTRICTION")
+ assertThat(output).doesNotContain("EXEMPT")
+ }
+ GrantState.TRUE_EXEMPT -> {
+ assertThat(output).contains("granted=true")
+ assertThat(output).contains("RESTRICTION_INSTALLER_EXEMPT")
+ }
+ GrantState.TRUE_RESTRICTED -> {
+ assertThat(output).contains("granted=true")
+ assertThat(output).contains("APPLY_RESTRICTION")
+ assertThat(output).doesNotContain("EXEMPT")
+ }
+ GrantState.FALSE -> {
+ assertThat(output).contains("granted=false")
+ }
+ }
+ }
+
+ enum class GrantState {
+ // Granted in full, unrestricted
+ TRUE,
+
+ // Granted in full by exemption
+ TRUE_EXEMPT,
+
+ // Granted in part
+ TRUE_RESTRICTED,
+
+ // Not granted at all
+ FALSE
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp
new file mode 100644
index 0000000..990ef49
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "CtsPkgInstallerPermRequestApp",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "androidx.test.rules",
+ "truth-prebuilt",
+ "CtsPkgInstallerConstants",
+ ],
+ srcs: ["src/**/*.kt"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "30",
+ // sign this app with a different cert than CtsPkgInstallerPermWhitelistApp
+ certificate: ":cts-testkey2",
+}
+
+java_library {
+ name: "CtsPkgInstallerConstants",
+ srcs: ["utils/src/**/PackageSetInstallerConstants.kt"],
+ host_supported: true,
+}
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/AndroidManifest.xml
new file mode 100644
index 0000000..7d0ab56
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.packageinstallerpermissionrequestapp">
+
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.packageinstallerpermissionrequestapp"
+ android:label="Test for unset package installer permission exploit."/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/src/com/android/cts/packageinstallerpermissionrequestapp/PermissionRequestTest.kt b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/src/com/android/cts/packageinstallerpermissionrequestapp/PermissionRequestTest.kt
new file mode 100644
index 0000000..1ca6a7f
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/src/com/android/cts/packageinstallerpermissionrequestapp/PermissionRequestTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.packageinstallerpermissionrequestapp
+
+import android.Manifest
+import android.appsecurity.cts.PackageSetInstallerConstants
+import android.appsecurity.cts.PackageSetInstallerConstants.SHOULD_THROW_EXCEPTION_KEY
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Bundle
+import androidx.test.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+
+class PermissionRequestTest {
+
+ @get:Rule
+ val expectedException = ExpectedException.none()
+
+ private val arguments: Bundle = InstrumentationRegistry.getArguments()
+ private val permission = arguments.getString(PackageSetInstallerConstants.PERMISSION_KEY)!!
+ private val context: Context = InstrumentationRegistry.getContext()
+ private val packageName = context.packageName
+ private val packageManager = context.packageManager
+
+ @Before
+ @After
+ fun verifyPermissionsDeniedAndInstallerUnchanged() {
+ assertThat(context.checkSelfPermission(permission))
+ .isEqualTo(PackageManager.PERMISSION_DENIED)
+ assertThat(context.checkSelfPermission(Manifest.permission.INSTALL_PACKAGES))
+ .isEqualTo(PackageManager.PERMISSION_DENIED)
+ assertThat(packageManager.getInstallerPackageName(packageName))
+ .isEqualTo(null)
+ }
+
+ @Test
+ fun setSelfAsInstallerAndWhitelistPermission() {
+ val shouldThrowException = arguments.getString(SHOULD_THROW_EXCEPTION_KEY)!!.toBoolean()
+ if (shouldThrowException) {
+ expectedException.expect(SecurityException::class.java)
+ }
+
+ try {
+ // This set call should fail
+ packageManager.setInstallerPackageName(packageName, packageName)
+ } finally {
+ // But also call the whitelist method to attempt to take the permission regardless.
+ // If this fails, which it should, it should also be a SecurityException.
+ try {
+ packageManager.addWhitelistedRestrictedPermission(packageName,
+ permission, PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)
+ Assert.fail("addWhitelistedRestrictedPermission did not throw SecurityException")
+ } catch (ignored: SecurityException) {
+ // Ignore this to defer to shouldThrowException from above call
+ }
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/utils/src/android/appsecurity/cts/PackageSetInstallerConstants.kt b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/utils/src/android/appsecurity/cts/PackageSetInstallerConstants.kt
new file mode 100644
index 0000000..723cb94
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/utils/src/android/appsecurity/cts/PackageSetInstallerConstants.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts
+
+// Placed in CtsPkgInstallerPermRequestApp sources as its manifest declares what permissions to test
+object PackageSetInstallerConstants {
+
+ // The app that will be attempting to take over as installer and grant itself permissions
+ const val TARGET_APK = "CtsPkgInstallerPermRequestApp.apk"
+ const val TARGET_PKG = "com.android.cts.packageinstallerpermissionrequestapp"
+
+ // The app acting as the original installer who can restrict permissions
+ const val WHITELIST_APK = "CtsPkgInstallerPermWhitelistApp.apk"
+ const val WHITELIST_PKG = "com.android.cts.packageinstallerpermissionwhitelistapp"
+
+ const val PERMISSION_HARD_RESTRICTED = "android.permission.SEND_SMS"
+ const val PERMISSION_NOT_RESTRICTED = "android.permission.ACCESS_COARSE_LOCATION"
+ const val PERMISSION_IMMUTABLY_SOFT_RESTRICTED = "android.permission.READ_EXTERNAL_STORAGE"
+ const val PERMISSION_KEY = "permission"
+
+ // Whether setInstallerPackageName should throw
+ const val SHOULD_THROW_EXCEPTION_KEY = "shouldThrowException"
+
+ // Whether or not some boolean return method call should succeed
+ const val SHOULD_SUCCEED_KEY = "shouldSucceed"
+
+ // PackageManagerService.THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE
+ const val CHANGE_ID = 150857253
+}
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp b/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp
new file mode 100644
index 0000000..b731a05
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "CtsPkgInstallerPermWhitelistApp",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "CtsPkgInstallerConstants",
+ "testng",
+ ],
+ srcs: ["src/**/*.kt"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "30",
+ // sign this app with a different cert than CtsPkgInstallerPermRequestApp
+ certificate: ":cts-testkey1",
+}
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/AndroidManifest.xml
new file mode 100644
index 0000000..d54b9c5
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.packageinstallerpermissionwhitelistapp">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.packageinstallerpermissionwhitelistapp"
+ android:label="Test for unset package installer permission exploit."/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/src/com/android/cts/packageinstallerpermissionwhitelistapp/PermissionWhitelistTest.kt b/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/src/com/android/cts/packageinstallerpermissionwhitelistapp/PermissionWhitelistTest.kt
new file mode 100644
index 0000000..464047e
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/src/com/android/cts/packageinstallerpermissionwhitelistapp/PermissionWhitelistTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.packageinstallerpermissionwhitelistapp
+
+import android.Manifest
+import android.appsecurity.cts.PackageSetInstallerConstants
+import android.appsecurity.cts.PackageSetInstallerConstants.PERMISSION_KEY
+import android.appsecurity.cts.PackageSetInstallerConstants.SHOULD_THROW_EXCEPTION_KEY
+import android.appsecurity.cts.PackageSetInstallerConstants.TARGET_PKG
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Bundle
+import androidx.test.InstrumentationRegistry
+import com.android.compatibility.common.util.ShellIdentityUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.testng.Assert.assertThrows
+
+class PermissionWhitelistTest {
+
+ private val arguments: Bundle = InstrumentationRegistry.getArguments()
+ private val shouldThrowException = arguments.getString(SHOULD_THROW_EXCEPTION_KEY)
+ ?.toBoolean() ?: false
+ private val permission = arguments.getString(PERMISSION_KEY)!!
+ private val context: Context = InstrumentationRegistry.getContext()
+ private val packageName = context.packageName
+ private val packageManager = context.packageManager
+
+ @Before
+ fun verifyNoInstallPackagesPermissions() {
+ // This test adopts shell permissions to get INSTALL_PACKAGES. That ensures that the
+ // whitelist package having INSTALL_PACKAGES doesn't bypass any checks. In a realistic
+ // scenario, this whitelisting app would request install, not directly install the target
+ // package.
+ assertThat(context.checkSelfPermission(Manifest.permission.INSTALL_PACKAGES))
+ .isEqualTo(PackageManager.PERMISSION_DENIED)
+ }
+
+ @Test
+ fun setTargetInstallerPackage() {
+ assertTargetInstaller(null)
+
+ val block = {
+ packageManager.setInstallerPackageName(TARGET_PKG, packageName)
+ }
+
+ if (shouldThrowException) {
+ assertThrows(SecurityException::class.java) { block() }
+ } else {
+ block()
+ }
+
+ assertTargetInstaller(null)
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(packageManager,
+ ShellIdentityUtils.ShellPermissionMethodHelperNoReturn {
+ it.setInstallerPackageName(TARGET_PKG, packageName)
+ }, Manifest.permission.INSTALL_PACKAGES)
+ assertTargetInstaller(packageName)
+ }
+
+ @Test
+ fun removeWhitelistRestrictedPermission() {
+ val block = {
+ packageManager.removeWhitelistedRestrictedPermission(TARGET_PKG, permission,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)
+ }
+
+ val shouldSucceed = arguments.getString(
+ PackageSetInstallerConstants.SHOULD_SUCCEED_KEY)
+ if (shouldSucceed == null) {
+ assertThrows(SecurityException::class.java) { block() }
+ } else {
+ assertThat(block()).isEqualTo(shouldSucceed.toBoolean())
+ }
+
+ assertThat(packageManager.checkPermission(permission, TARGET_PKG))
+ .isEqualTo(PackageManager.PERMISSION_DENIED)
+ }
+
+ private fun assertTargetInstaller(installer: String?) {
+ assertThat(packageManager.getInstallerPackageName(TARGET_PKG))
+ .isEqualTo(installer)
+ }
+}
diff --git a/hostsidetests/media/Android.bp b/hostsidetests/media/Android.bp
index 3e85112..635c5c2 100644
--- a/hostsidetests/media/Android.bp
+++ b/hostsidetests/media/Android.bp
@@ -33,6 +33,10 @@
"tradefed",
"compatibility-host-util",
],
+
+ static_libs: [
+ "cts-host-utils",
+ ],
}
filegroup {
diff --git a/hostsidetests/media/bitstreams/Android.bp b/hostsidetests/media/bitstreams/Android.bp
index 9c17208..f13984e 100644
--- a/hostsidetests/media/bitstreams/Android.bp
+++ b/hostsidetests/media/bitstreams/Android.bp
@@ -22,6 +22,9 @@
"cts-tradefed",
"tradefed",
],
+ static_libs: [
+ "cts-host-utils",
+ ],
// Tag this module as a cts test artifact
test_suites: [
"cts",
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsFullTest.java
index 72bb15a..0c18703 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsTest.java
index 5bcfe7e..6ca00d8 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitBpBitstreamsTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsFullTest.java
index 7db0198f..3dd9b35 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsTest.java
index 6ba3822..7c06151 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitHpBitstreamsTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsFullTest.java
index 4811150..1634856 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsTest.java
index b7f2c67..90e9bdf 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/H264Yuv420_8bitMpBitstreamsTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv400BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv400BitstreamsFullTest.java
index e00283f..50e9924 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv400BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv400BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsFullTest.java
index eb0fda7..b7a752d 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsTest.java
index 1334c82..7d8b289 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv420BitstreamsTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv422BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv422BitstreamsFullTest.java
index 0efdad2..528eefb 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv422BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv422BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv444BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv444BitstreamsFullTest.java
index 0f564ea..94bad70 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv444BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/HevcYuv444BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsFullTest.java
index bbfc2eb..7146d94 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsTest.java
index 8587abd..679850a 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp8BitstreamsTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsFullTest.java
index d209011..656ea21 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsTest.java
index 9b048bb..b80ff7f 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv420BitstreamsTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv422BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv422BitstreamsFullTest.java
index a03f1c4..3dda21a 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv422BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv422BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv444BitstreamsFullTest.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv444BitstreamsFullTest.java
index 22786fc..bf6b095 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv444BitstreamsFullTest.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/Vp9Yuv444BitstreamsFullTest.java
@@ -15,6 +15,9 @@
*/
package android.media.cts.bitstreams;
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters;
+import android.cts.host.utils.DeviceJUnit4Parameterized;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
diff --git a/hostsidetests/utils/Android.bp b/hostsidetests/utils/Android.bp
new file mode 100644
index 0000000..0930f91
--- /dev/null
+++ b/hostsidetests/utils/Android.bp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+java_library_host {
+ name: "cts-host-utils",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ ],
+}
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4ClassRunnerWithParameters.java b/hostsidetests/utils/src/android/cts/host/utils/DeviceJUnit4ClassRunnerWithParameters.java
similarity index 97%
rename from hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4ClassRunnerWithParameters.java
rename to hostsidetests/utils/src/android/cts/host/utils/DeviceJUnit4ClassRunnerWithParameters.java
index 944e258..7f8e07e 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4ClassRunnerWithParameters.java
+++ b/hostsidetests/utils/src/android/cts/host/utils/DeviceJUnit4ClassRunnerWithParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.media.cts.bitstreams;
+package android.cts.host.utils;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4Parameterized.java b/hostsidetests/utils/src/android/cts/host/utils/DeviceJUnit4Parameterized.java
similarity index 97%
rename from hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4Parameterized.java
rename to hostsidetests/utils/src/android/cts/host/utils/DeviceJUnit4Parameterized.java
index ea7ce7f..114678d 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/DeviceJUnit4Parameterized.java
+++ b/hostsidetests/utils/src/android/cts/host/utils/DeviceJUnit4Parameterized.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.media.cts.bitstreams;
+package android.cts.host.utils;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationException;