Add IntentFilter verification tests

In preparation for later changes, adds tests for the existing
domain verification flow for auto verified app links.

Implements a proxy verifier which saves incoming requests to
a file on disk which can be read back later by another call
from the host side test to send a success/failure code.

This tests some basic known success/failure cases, as well as
verifies the presence of bugs, which have been marked with TODOs
against the feature bug number, to be fixed with later work.

Also migrates manual test cases from
I200d85085ce79842a3ed39377d1f75ec381c8991.

Bug: 159952358
Bug: 162346237

Test: atest com.android.server.pm.test.intent.verify.IntentFilterVerificationTest

Change-Id: Ib646b7f6f155ae342195dd25f82bb2463a9ca2b7
This commit is contained in:
Winson
2020-08-10 16:30:42 -07:00
parent 8a783b2fdc
commit d3a10584c5
41 changed files with 1270 additions and 357 deletions

View File

@@ -22,6 +22,7 @@ java_test_host {
],
static_libs: [
"frameworks-base-hostutils",
"PackageManagerServiceHostTestsIntentVerifyUtils",
],
test_suites: ["general-tests"],
java_resources: [
@@ -33,7 +34,15 @@ java_test_host {
":PackageManagerTestAppVersion4",
":PackageManagerTestAppOriginalOverride",
":PackageManagerServiceDeviceSideTests",
],
":PackageManagerTestIntentVerifier",
":PackageManagerTestIntentVerifierTarget1",
":PackageManagerTestIntentVerifierTarget2",
":PackageManagerTestIntentVerifierTarget3",
":PackageManagerTestIntentVerifierTarget4Base",
":PackageManagerTestIntentVerifierTarget4NoAutoVerify",
":PackageManagerTestIntentVerifierTarget4Wildcard",
":PackageManagerTestIntentVerifierTarget4WildcardNoAutoVerify",
]
}
genrule {

View File

@@ -0,0 +1,19 @@
// 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 {
name: "PackageManagerServiceHostTestsIntentVerifyUtils",
srcs: ["src/**/*.kt"],
host_supported: true,
}

View File

@@ -13,3 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm.test.intent.verify
interface IntentVerifyTestParams {
val methodName: String
fun toArgsMap(): Map<String, String>
}

View File

@@ -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 com.android.server.pm.test.intent.verify
data class SetActivityAsAlwaysParams(
val uri: String,
val packageName: String,
val activityName: String,
override val methodName: String = "setActivityAsAlways"
) : IntentVerifyTestParams {
companion object {
private const val KEY_URI = "uri"
private const val KEY_PACKAGE_NAME = "packageName"
private const val KEY_ACTIVITY_NAME = "activityName"
fun fromArgs(args: Map<String, String>) = SetActivityAsAlwaysParams(
args.getValue(KEY_URI),
args.getValue(KEY_PACKAGE_NAME),
args.getValue(KEY_ACTIVITY_NAME)
)
}
override fun toArgsMap() = mapOf(
KEY_URI to uri,
KEY_PACKAGE_NAME to packageName,
KEY_ACTIVITY_NAME to activityName
)
}

View File

@@ -0,0 +1,48 @@
/*
* 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.server.pm.test.intent.verify
data class StartActivityParams(
val uri: String,
val expected: List<String>,
val withBrowsers: Boolean = false,
override val methodName: String = "verifyActivityStart"
) : IntentVerifyTestParams {
companion object {
private const val KEY_URI = "uri"
private const val KEY_EXPECTED = "expected"
private const val KEY_BROWSER = "browser"
fun fromArgs(args: Map<String, String>) = StartActivityParams(
args.getValue(KEY_URI),
args.getValue(KEY_EXPECTED).split(","),
args.getValue(KEY_BROWSER).toBoolean()
)
}
constructor(
uri: String,
expected: String,
withBrowsers: Boolean = false
) : this(uri, listOf(expected), withBrowsers)
override fun toArgsMap() = mapOf(
KEY_URI to uri,
KEY_EXPECTED to expected.joinToString(separator = ","),
KEY_BROWSER to withBrowsers.toString()
)
}

View File

@@ -0,0 +1,48 @@
/*
* 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.server.pm.test.intent.verify
data class VerifyRequest(
val id: Int = -1,
val scheme: String,
val hosts: List<String>,
val packageName: String
) {
companion object {
fun deserialize(value: String?): VerifyRequest {
val lines = value?.trim()?.lines()
?: return VerifyRequest(scheme = "", hosts = emptyList(), packageName = "")
return VerifyRequest(
lines[0].removePrefix("id=").toInt(),
lines[1].removePrefix("scheme="),
lines[2].removePrefix("hosts=").split(","),
lines[3].removePrefix("packageName=")
)
}
}
constructor(id: Int = -1, scheme: String, host: String, packageName: String) :
this(id, scheme, listOf(host), packageName)
fun serializeToString() = """
id=$id
scheme=$scheme
hosts=${hosts.joinToString(separator = ",")}
packageName=$packageName
""".trimIndent() + "\n"
}

View File

@@ -31,7 +31,8 @@ class FactoryPackageTest : BaseHostJUnit4Test() {
private val preparer: SystemPreparer = SystemPreparer(tempFolder,
SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
@get:Rule
@Rule
@JvmField
val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
private val filePath =
HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.SYSTEM)

View File

@@ -18,6 +18,7 @@ package com.android.server.pm.test
import com.android.internal.util.test.SystemPreparer
import com.android.tradefed.device.ITestDevice
import org.junit.rules.TemporaryFolder
import java.io.File
import java.io.FileOutputStream
@@ -34,6 +35,19 @@ internal fun SystemPreparer.deleteApkFolders(
}
}
internal fun ITestDevice.installJavaResourceApk(
tempFolder: TemporaryFolder,
javaResource: String,
reinstall: Boolean = true,
extraArgs: Array<String> = emptyArray()
): String? {
val file = HostUtils.copyResourceToHostFile(javaResource, tempFolder.newFile())
return installPackage(file, reinstall, *extraArgs)
}
internal fun ITestDevice.uninstallPackages(vararg pkgNames: String) =
pkgNames.forEach { uninstallPackage(it) }
internal object HostUtils {
fun getDataDir(device: ITestDevice, pkgName: String) =

View File

@@ -47,7 +47,8 @@ class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
private val preparer: SystemPreparer = SystemPreparer(tempFolder,
SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
@get:Rule
@Rule
@JvmField
val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
private val filePath = HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.PRODUCT)

View File

@@ -47,7 +47,8 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
private val preparer: SystemPreparer = SystemPreparer(tempFolder,
SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
@get:Rule
@Rule
@JvmField
val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
@Before

View File

@@ -22,6 +22,7 @@ import java.nio.file.Paths
// Unfortunately no easy way to access PMS SystemPartitions, so mock them here
internal enum class Partition(val baseAppFolder: Path) {
SYSTEM("/system/app"),
SYSTEM_PRIVILEGED("/system/priv-app"),
VENDOR("/vendor/app"),
PRODUCT("/product/app"),
SYSTEM_EXT("/system_ext/app")

View File

@@ -110,7 +110,8 @@ class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() {
private val preparer: SystemPreparer = SystemPreparer(tempFolder,
SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
@get:Rule
@Rule
@JvmField
val rules = RuleChain.outerRule(tempFolder).let {
if (DEBUG_NO_REBOOT) {
it!!

View File

@@ -0,0 +1,413 @@
/*
* 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.server.pm.test.intent.verify
import com.android.internal.util.test.SystemPreparer
import com.android.server.pm.test.Partition
import com.android.server.pm.test.deleteApkFolders
import com.android.server.pm.test.installJavaResourceApk
import com.android.server.pm.test.pushApk
import com.android.server.pm.test.uninstallPackages
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import java.io.File
import java.util.concurrent.TimeUnit
@RunWith(DeviceJUnit4ClassRunner::class)
class IntentFilterVerificationTest : BaseHostJUnit4Test() {
companion object {
private const val VERIFIER = "PackageManagerTestIntentVerifier.apk"
private const val VERIFIER_PKG_NAME = "com.android.server.pm.test.intent.verifier"
private const val TARGET_PKG_PREFIX = "$VERIFIER_PKG_NAME.target"
private const val TARGET_APK_PREFIX = "PackageManagerTestIntentVerifierTarget"
private const val TARGET_ONE = "${TARGET_APK_PREFIX}1.apk"
private const val TARGET_ONE_PKG_NAME = "$TARGET_PKG_PREFIX.one"
private const val TARGET_TWO = "${TARGET_APK_PREFIX}2.apk"
private const val TARGET_TWO_PKG_NAME = "$TARGET_PKG_PREFIX.two"
private const val TARGET_THREE = "${TARGET_APK_PREFIX}3.apk"
private const val TARGET_THREE_PKG_NAME = "$TARGET_PKG_PREFIX.three"
private const val TARGET_FOUR_BASE = "${TARGET_APK_PREFIX}4Base.apk"
private const val TARGET_FOUR_PKG_NAME = "$TARGET_PKG_PREFIX.four"
private const val TARGET_FOUR_NO_AUTO_VERIFY = "${TARGET_APK_PREFIX}4NoAutoVerify.apk"
private const val TARGET_FOUR_WILDCARD = "${TARGET_APK_PREFIX}4Wildcard.apk"
private const val TARGET_FOUR_WILDCARD_NO_AUTO_VERIFY =
"${TARGET_APK_PREFIX}4WildcardNoAutoVerify.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
}
private val tempFolder = TemporaryFolder()
private val preparer: SystemPreparer = SystemPreparer(tempFolder,
SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
@Rule
@JvmField
val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
private val permissionsFile = File("/system/etc/permissions" +
"/privapp-PackageManagerIntentFilterVerificationTest-permissions.xml")
@Before
fun cleanupAndPushPermissionsFile() {
// In order for the test app to be the verification agent, it needs a permission file
// which can be pushed onto the system and removed afterwards.
val file = tempFolder.newFile().apply {
"""
<permissions>
<privapp-permissions package="$VERIFIER_PKG_NAME">
<permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
</privapp-permissions>
</permissions>
"""
.trimIndent()
.let { writeText(it) }
}
device.uninstallPackages(TARGET_ONE_PKG_NAME, TARGET_TWO_PKG_NAME, TARGET_THREE_PKG_NAME,
TARGET_FOUR_PKG_NAME)
preparer.pushApk(VERIFIER, Partition.SYSTEM_PRIVILEGED)
.pushFile(file, permissionsFile.toString())
.reboot()
runTest("clearResponse")
}
@After
fun cleanupAndDeletePermissionsFile() {
device.uninstallPackages(TARGET_ONE_PKG_NAME, TARGET_TWO_PKG_NAME, TARGET_THREE_PKG_NAME,
TARGET_FOUR_PKG_NAME)
preparer.deleteApkFolders(Partition.SYSTEM_PRIVILEGED, VERIFIER)
.deleteFile(permissionsFile.toString())
device.reboot()
}
@Test
fun verifyOne() {
installPackage(TARGET_ONE)
assertReceivedRequests(true, VerifyRequest(
scheme = "https",
hosts = listOf(
"https_only.pm.server.android.com",
"other_activity.pm.server.android.com",
"http_only.pm.server.android.com",
"verify.pm.server.android.com",
"https_plus_non_web_scheme.pm.server.android.com",
"multiple.pm.server.android.com",
// TODO(b/159952358): the following domain should not be
// verified, this is because the verifier tries to verify all web domains,
// even in intent filters not marked for auto verify
"no_verify.pm.server.android.com"
),
packageName = TARGET_ONE_PKG_NAME
))
runTest(StartActivityParams(
uri = "https://https_only.pm.server.android.com",
expected = "$TARGET_ONE_PKG_NAME.TargetActivity"
))
}
@Test
fun nonWebScheme() {
installPackage(TARGET_TWO)
assertReceivedRequests(null)
}
@Test
fun verifyHttpNonSecureOnly() {
installPackage(TARGET_THREE)
assertReceivedRequests(true, VerifyRequest(
scheme = "https",
hosts = listOf(
"multiple.pm.server.android.com"
),
packageName = TARGET_THREE_PKG_NAME
))
runTest(StartActivityParams(
uri = "http://multiple.pm.server.android.com",
expected = "$TARGET_THREE_PKG_NAME.TargetActivity"
))
}
@Test
fun multipleResults() {
installPackage(TARGET_ONE)
installPackage(TARGET_THREE)
assertReceivedRequests(true, VerifyRequest(
scheme = "https",
hosts = listOf(
"https_only.pm.server.android.com",
"other_activity.pm.server.android.com",
"http_only.pm.server.android.com",
"verify.pm.server.android.com",
"https_plus_non_web_scheme.pm.server.android.com",
"multiple.pm.server.android.com",
// TODO(b/159952358): the following domain should not be
// verified, this is because the verifier tries to verify all web domains,
// even in intent filters not marked for auto verify
"no_verify.pm.server.android.com"
),
packageName = TARGET_ONE_PKG_NAME
), VerifyRequest(
scheme = "https",
hosts = listOf(
"multiple.pm.server.android.com"
),
packageName = TARGET_THREE_PKG_NAME
))
// Target3 declares http non-s, so it should be included in the set here
runTest(StartActivityParams(
uri = "http://multiple.pm.server.android.com",
expected = listOf(
"$TARGET_ONE_PKG_NAME.TargetActivity2",
"$TARGET_THREE_PKG_NAME.TargetActivity"
)
))
// But it excludes https, so it shouldn't resolve here
runTest(StartActivityParams(
uri = "https://multiple.pm.server.android.com",
expected = "$TARGET_ONE_PKG_NAME.TargetActivity2"
))
// Remove Target3 and return to single verified Target1 app for http non-s
device.uninstallPackage(TARGET_THREE_PKG_NAME)
runTest(StartActivityParams(
uri = "http://multiple.pm.server.android.com",
expected = "$TARGET_ONE_PKG_NAME.TargetActivity2"
))
}
@Test
fun demoteAlways() {
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(false, VerifyRequest(
scheme = "https",
host = "failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME
))
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
withBrowsers = true
))
runTest(SetActivityAsAlwaysParams(
uri = "https://failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME,
activityName = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
// Re-installing with same host/verify set will maintain always setting
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(null)
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
// Installing with new wildcard host will downgrade out of always, re-including browsers
installPackage(TARGET_FOUR_WILDCARD)
// TODO(b/159952358): The first request without the wildcard should not be sent. This is
// caused by the request being queued even if it should be dropped from the previous
// install case since the host set didn't change.
assertReceivedRequests(false, VerifyRequest(
scheme = "https",
hosts = listOf("failing.pm.server.android.com"),
packageName = TARGET_FOUR_PKG_NAME
), VerifyRequest(
scheme = "https",
hosts = listOf("failing.pm.server.android.com", "wildcard.tld"),
packageName = TARGET_FOUR_PKG_NAME
))
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
withBrowsers = true
))
}
@Test
fun unverifiedReinstallResendRequest() {
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(false, VerifyRequest(
scheme = "https",
host = "failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME
))
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(false, VerifyRequest(
scheme = "https",
host = "failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME
))
}
@Test
fun unverifiedUpdateRemovingDomainNoRequestDemoteAlways() {
installPackage(TARGET_FOUR_WILDCARD)
assertReceivedRequests(false, VerifyRequest(
scheme = "https",
hosts = listOf("failing.pm.server.android.com", "wildcard.tld"),
packageName = TARGET_FOUR_PKG_NAME
))
runTest(SetActivityAsAlwaysParams(
uri = "https://failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME,
activityName = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
// Re-installing with a smaller host/verify set will not request re-verification
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(null)
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
// Re-installing with a (now) larger host/verify set will re-request and demote
installPackage(TARGET_FOUR_WILDCARD)
// TODO(b/159952358): The first request should not be sent. This is caused by the request
// being queued even if it should be dropped from the previous install case.
assertReceivedRequests(false, VerifyRequest(
scheme = "https",
host = "failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME
), VerifyRequest(
scheme = "https",
hosts = listOf("failing.pm.server.android.com", "wildcard.tld"),
packageName = TARGET_FOUR_PKG_NAME
))
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
withBrowsers = true
))
}
// TODO(b/159952358): I would expect this to demote
// TODO(b/32810168)
@Test
fun verifiedUpdateRemovingAutoVerifyMaintainsAlways() {
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(true, VerifyRequest(
scheme = "https",
host = "failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME
))
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
installPackage(TARGET_FOUR_NO_AUTO_VERIFY)
assertReceivedRequests(null)
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
}
@Test
fun verifiedUpdateRemovingAutoVerifyAddingDomainDemotesAlways() {
installPackage(TARGET_FOUR_BASE)
assertReceivedRequests(true, VerifyRequest(
scheme = "https",
host = "failing.pm.server.android.com",
packageName = TARGET_FOUR_PKG_NAME
))
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
))
installPackage(TARGET_FOUR_WILDCARD_NO_AUTO_VERIFY)
assertReceivedRequests(null)
runTest(StartActivityParams(
uri = "https://failing.pm.server.android.com",
expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
withBrowsers = true
))
}
private fun installPackage(javaResourceName: String) {
// Need to pass --user as verification is not currently run for all user installs
assertThat(device.installJavaResourceApk(tempFolder, javaResourceName,
extraArgs = arrayOf("--user", device.currentUser.toString()))).isNull()
}
private fun assertReceivedRequests(success: Boolean?, vararg expected: VerifyRequest?) {
// TODO(b/159952358): This can probably be less than 10
// Because tests have to assert that multiple broadcasts aren't received, there's no real
// better way to await for a value than sleeping for a long enough time.
TimeUnit.SECONDS.sleep(10)
val params = mutableMapOf<String, String>()
if (expected.any { it != null }) {
params["expected"] = expected.filterNotNull()
.joinToString(separator = "") { it.serializeToString() }
}
runTest("compareLastReceived", params)
if (success != null) {
if (success) {
runTest("verifyPreviousReceivedSuccess")
} else {
runTest("verifyPreviousReceivedFailure")
}
runTest("clearResponse")
}
}
private fun runTest(params: IntentVerifyTestParams) =
runTest(params.methodName, params.toArgsMap())
private fun runTest(testName: String, args: Map<String, String> = emptyMap()) {
val escapedArgs = args.mapValues {
// Need to escape strings so that args are passed properly through the shell command
"\"${it.value.trim('"')}\""
}
runDeviceTests(device, null, VERIFIER_PKG_NAME, "$VERIFIER_PKG_NAME.VerifyReceiverTest",
testName, null, 10 * 60 * 1000L, 10 * 60 * 1000L, 0L, true, false, escapedArgs)
}
}

View File

@@ -0,0 +1,28 @@
// 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: "PackageManagerTestIntentVerifier",
srcs: [ "src/**/*.kt" ],
static_libs: [
"androidx.test.core",
"androidx.test.espresso.core",
"androidx.test.runner",
"compatibility-device-util-axt",
"junit",
"truth-prebuilt",
"PackageManagerServiceHostTestsIntentVerifyUtils",
],
platform_apis: true,
}

View File

@@ -0,0 +1,38 @@
<?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.server.pm.test.intent.verifier"
>
<uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.pm.test.intent.verifier"
/>
<application>
<receiver android:name=".VerifyReceiver" android:exported="true">
<intent-filter android:priority="999">
<action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"/>
<data android:mimeType="application/vnd.android.package-archive"/>
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -0,0 +1,62 @@
/*
* 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.server.pm.test.intent.verifier
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import com.android.server.pm.test.intent.verify.VerifyRequest
class VerifyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION) return
val params = intent.toVerifyParams()
// If the receiver is called for a normal request, proxy it to the real verifier on device
if (params.hosts.none { it.contains("pm.server.android.com") }) {
sendToRealVerifier(context, Intent(intent))
return
}
// When the receiver is invoked for a test install, there is no direct connection to host,
// so store the result in a file to read and assert on later. Append is intentional so that
// amount of invocations and clean up can be verified.
context.filesDir.resolve("test.txt")
.appendText(params.serializeToString())
}
private fun sendToRealVerifier(context: Context, intent: Intent) {
context.packageManager.queryBroadcastReceivers(intent, 0)
.first { it.activityInfo?.packageName != context.packageName }
.let { it.activityInfo!! }
.let { intent.setComponent(ComponentName(it.packageName, it.name)) }
.run { context.sendBroadcast(intent) }
}
private fun Intent.toVerifyParams() = VerifyRequest(
id = getIntExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID, -1),
scheme = getStringExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME)!!,
hosts = getStringExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS)!!
.split(' '),
packageName = getStringExtra(
PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME)!!
)
}

View File

@@ -0,0 +1,160 @@
/*
* 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.server.pm.test.intent.verifier
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.UserHandle
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import com.android.compatibility.common.util.ShellIdentityUtils
import com.android.server.pm.test.intent.verify.SetActivityAsAlwaysParams
import com.android.server.pm.test.intent.verify.StartActivityParams
import com.android.server.pm.test.intent.verify.VerifyRequest
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
@RunWith(AndroidJUnit4::class)
class VerifyReceiverTest {
val args: Bundle = InstrumentationRegistry.getArguments()
val context: Context = InstrumentationRegistry.getContext()
private val file = context.filesDir.resolve("test.txt")
@Test
fun clearResponse() {
file.delete()
}
@Test
fun compareLastReceived() {
val lastReceivedText = file.readTextIfExists()
val expectedText = args.getString("expected")
if (expectedText.isNullOrEmpty()) {
assertThat(lastReceivedText).isEmpty()
return
}
val expectedParams = expectedText.parseParams()
val lastReceivedParams = lastReceivedText.parseParams()
assertThat(lastReceivedParams).hasSize(expectedParams.size)
lastReceivedParams.zip(expectedParams).forEach { (actual, expected) ->
assertThat(actual.hosts).containsExactlyElementsIn(expected.hosts)
assertThat(actual.packageName).isEqualTo(expected.packageName)
assertThat(actual.scheme).isEqualTo(expected.scheme)
}
}
@Test
fun setActivityAsAlways() {
val params = SetActivityAsAlwaysParams.fromArgs(
args.keySet().associateWith { args.getString(it)!! })
val uri = Uri.parse(params.uri)
val filter = IntentFilter().apply {
addAction(Intent.ACTION_VIEW)
addCategory(Intent.CATEGORY_DEFAULT)
addDataScheme(uri.scheme)
addDataAuthority(uri.authority, null)
}
val intent = Intent(Intent.ACTION_VIEW, uri).apply {
addCategory(Intent.CATEGORY_DEFAULT)
}
val allResults = context.packageManager.queryIntentActivities(intent, 0)
val allComponents = allResults
.map { ComponentName(it.activityInfo.packageName, it.activityInfo.name) }
.toTypedArray()
val matchingInfo = allResults.first {
it.activityInfo.packageName == params.packageName &&
it.activityInfo.name == params.activityName
}
ShellIdentityUtils.invokeMethodWithShellPermissions(context.packageManager,
ShellIdentityUtils.ShellPermissionMethodHelper<Unit, PackageManager> {
it.addUniquePreferredActivity(filter, matchingInfo.match, allComponents,
ComponentName(matchingInfo.activityInfo.packageName,
matchingInfo.activityInfo.name))
it.updateIntentVerificationStatusAsUser(params.packageName,
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
UserHandle.myUserId())
}, "android.permission.SET_PREFERRED_APPLICATIONS")
}
@Test
fun verifyPreviousReceivedSuccess() {
file.readTextIfExists()
.parseParams()
.forEach {
context.packageManager.verifyIntentFilter(it.id,
PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS, emptyList())
}
}
@Test
fun verifyPreviousReceivedFailure() {
file.readTextIfExists()
.parseParams()
.forEach {
context.packageManager.verifyIntentFilter(it.id,
PackageManager.INTENT_FILTER_VERIFICATION_FAILURE, it.hosts)
}
}
@Test
fun verifyActivityStart() {
val params = StartActivityParams
.fromArgs(args.keySet().associateWith { args.getString(it)!! })
val uri = Uri.parse(params.uri)
val intent = Intent(Intent.ACTION_VIEW).apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val expectedActivities = params.expected.toMutableList()
if (params.withBrowsers) {
// Since the host doesn't know what browsers the device has, query here and add it to
// set if it's expected that browser are returned
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
expectedActivities += context.packageManager.queryIntentActivities(browserIntent, 0)
.map { it.activityInfo.name }
}
val infos = context.packageManager.queryIntentActivities(intent, 0)
.map { it.activityInfo.name }
assertThat(infos).containsExactlyElementsIn(expectedActivities)
}
private fun File.readTextIfExists() = if (exists()) readText() else ""
// Rudimentary list deserialization by splitting text block into 4 line sections
private fun String.parseParams() = trim()
.lines()
.windowed(4, 4)
.map { it.joinToString(separator = "\n") }
.map { VerifyRequest.deserialize(it) }
}

View File

@@ -0,0 +1,48 @@
// 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: "PackageManagerTestIntentVerifierTarget1",
manifest: "AndroidManifest1.xml",
}
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget2",
manifest: "AndroidManifest2.xml",
}
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget3",
manifest: "AndroidManifest3.xml",
}
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget4Base",
manifest: "AndroidManifest4Base.xml",
}
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget4NoAutoVerify",
manifest: "AndroidManifest4NoAutoVerify.xml",
}
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget4Wildcard",
manifest: "AndroidManifest4Wildcard.xml",
}
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget4WildcardNoAutoVerify",
manifest: "AndroidManifest4WildcardNoAutoVerify.xml",
}

View File

@@ -0,0 +1,94 @@
<?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.server.pm.test.intent.verifier.target.one" android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="verify.pm.server.android.com" />
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="no_verify.pm.server.android.com" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:host="http_only.pm.server.android.com" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https" />
<data android:host="https_only.pm.server.android.com" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="htttps" />
<data android:host="non_http.pm.server.android.com" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https" />
<data android:scheme="non_web_scheme" />
<data android:host="https_plus_non_web_scheme.pm.server.android.com" />
</intent-filter>
</activity>
<activity android:name=".TargetActivity2" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="other_activity.pm.server.android.com" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="multiple.pm.server.android.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,34 @@
<?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.server.pm.test.intent.verifier.target.two"
android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="non_web_scheme" />
<data android:host="only_https_plus_non_web_scheme.pm.server.android.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,32 @@
<?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.server.pm.test.intent.verifier.target.three"
android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:host="multiple.pm.server.android.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,33 @@
<?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.server.pm.test.intent.verifier.target.four"
android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="failing.pm.server.android.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,33 @@
<?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.server.pm.test.intent.verifier.target.four"
android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="failing.pm.server.android.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,34 @@
<?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.server.pm.test.intent.verifier.target.four"
android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="failing.pm.server.android.com" />
<data android:host="*.wildcard.tld" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,34 @@
<?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.server.pm.test.intent.verifier.target.four"
android:versionCode="1">
<application>
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="failing.pm.server.android.com" />
<data android:host="*.wildcard.tld" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,11 +0,0 @@
android_app {
name: "AutoVerifyTest",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
platform_apis: true,
min_sdk_version: "26",
target_sdk_version: "26",
optimize: {
enabled: false,
},
}

View File

@@ -1,43 +0,0 @@
<?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.test.autoverify" >
<uses-sdk android:targetSdkVersion="26" />
<application
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="explicit.example.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 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.
-->
<resources>
<!-- app icon label, do not translate -->
<string name="app_name" translatable="false">AutoVerify Test</string>
</resources>

View File

@@ -1,15 +0,0 @@
/*
* 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.
*/

View File

@@ -1,11 +0,0 @@
android_app {
name: "AutoVerifyTest2",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
platform_apis: true,
min_sdk_version: "26",
target_sdk_version: "26",
optimize: {
enabled: false,
},
}

View File

@@ -1,44 +0,0 @@
<?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.test.autoverify" >
<uses-sdk android:targetSdkVersion="26" />
<application
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="explicit.example.com" />
<data android:host="*.wildcard.tld" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 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.
-->
<resources>
<!-- app icon label, do not translate -->
<string name="app_name" translatable="false">AutoVerify Test</string>
</resources>

View File

@@ -1,15 +0,0 @@
/*
* 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.
*/

View File

@@ -1,11 +0,0 @@
android_app {
name: "AutoVerifyTest3",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
platform_apis: true,
min_sdk_version: "26",
target_sdk_version: "26",
optimize: {
enabled: false,
},
}

View File

@@ -1,44 +0,0 @@
<?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.test.autoverify" >
<uses-sdk android:targetSdkVersion="26" />
<application
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- does not request autoVerify -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="explicit.example.com" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 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.
-->
<resources>
<!-- app icon label, do not translate -->
<string name="app_name" translatable="false">AutoVerify Test</string>
</resources>

View File

@@ -1,11 +0,0 @@
android_app {
name: "AutoVerifyTest4",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
platform_apis: true,
min_sdk_version: "26",
target_sdk_version: "26",
optimize: {
enabled: false,
},
}

View File

@@ -1,45 +0,0 @@
<?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.test.autoverify" >
<uses-sdk android:targetSdkVersion="26" />
<application
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- intentionally does not autoVerify -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="explicit.example.com" />
<data android:host="*.wildcard.tld" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 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.
-->
<resources>
<!-- app icon label, do not translate -->
<string name="app_name" translatable="false">AutoVerify Test</string>
</resources>

View File

@@ -1,15 +0,0 @@
/*
* 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.
*/

View File

@@ -62,12 +62,22 @@ public class SystemPreparer extends ExternalResource {
private final RebootStrategy mRebootStrategy;
private final TearDownRule mTearDownRule;
// When debugging, it may be useful to run a test case without rebooting the device afterwards,
// to manually verify the device state.
private boolean mDebugSkipAfterReboot;
public SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
this(hostTempFolder, RebootStrategy.FULL, null, deviceProvider);
}
public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
@Nullable TestRuleDelegate testRuleDelegate, DeviceProvider deviceProvider) {
this(hostTempFolder, rebootStrategy, testRuleDelegate, false, deviceProvider);
}
public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
@Nullable TestRuleDelegate testRuleDelegate, boolean debugSkipAfterReboot,
DeviceProvider deviceProvider) {
mHostTempFolder = hostTempFolder;
mDeviceProvider = deviceProvider;
mRebootStrategy = rebootStrategy;
@@ -75,6 +85,7 @@ public class SystemPreparer extends ExternalResource {
if (testRuleDelegate != null) {
testRuleDelegate.setDelegate(mTearDownRule);
}
mDebugSkipAfterReboot = debugSkipAfterReboot;
}
/** Copies a file within the host test jar to a path on device. */
@@ -172,7 +183,9 @@ public class SystemPreparer extends ExternalResource {
case USERSPACE_UNTIL_ONLINE:
device.rebootUserspaceUntilOnline();
break;
case START_STOP:
// TODO(b/159540015): Make this START_STOP instead of default once it's fixed. Can't
// currently be done because START_STOP is commented out.
default:
device.executeShellCommand("stop");
device.executeShellCommand("start");
ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
@@ -228,7 +241,9 @@ public class SystemPreparer extends ExternalResource {
for (final String packageName : mInstalledPackages) {
device.uninstallPackage(packageName);
}
reboot();
if (!mDebugSkipAfterReboot) {
reboot();
}
} catch (DeviceNotAvailableException e) {
Assert.fail(e.toString());
}
@@ -355,6 +370,7 @@ public class SystemPreparer extends ExternalResource {
/**
* How to reboot the device. Ordered from slowest to fastest.
*/
@SuppressWarnings("DanglingJavadoc")
public enum RebootStrategy {
/** @see ITestDevice#reboot() */
FULL,
@@ -374,7 +390,15 @@ public class SystemPreparer extends ExternalResource {
*
* TODO(b/159540015): There's a bug with this causing unnecessary disk space usage, which
* can eventually lead to an insufficient storage space error.
*
* This can be uncommented for local development, but should be left out when merging.
* It is done this way to hopefully be caught by code review, since merging this will
* break all of postsubmit. But the nearly 50% reduction in test runtime is worth having
* this option exist.
*
* @deprecated do not use this in merged code until bug is resolved
*/
START_STOP
// @Deprecated
// START_STOP
}
}