summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java6
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java15
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt44
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt126
4 files changed, 187 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index bf2b3c7f491f..a8a6a723ce74 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.os.Build;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Patterns;
@@ -32,7 +33,6 @@ import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.List;
-import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -251,6 +251,10 @@ public class DomainVerificationCollector {
* improve the reliability of any legacy verifiers.
*/
private boolean isValidHost(String host) {
+ if (TextUtils.isEmpty(host)) {
+ return false;
+ }
+
mDomainMatcher.reset(host);
return mDomainMatcher.matches();
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 44ff3eb4b942..246810f4d796 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -22,6 +22,8 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.text.TextUtils;
+import android.util.Patterns;
import com.android.internal.util.CollectionUtils;
import com.android.server.compat.PlatformCompat;
@@ -29,9 +31,13 @@ import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.Set;
+import java.util.regex.Matcher;
public final class DomainVerificationUtils {
+ private static final ThreadLocal<Matcher> sCachedMatcher = ThreadLocal.withInitial(
+ () -> Patterns.DOMAIN_NAME.matcher(""));
+
/**
* Consolidates package exception messages. A generic unavailable message is included since the
* caller doesn't bother to check why the package isn't available.
@@ -48,6 +54,15 @@ public final class DomainVerificationUtils {
return false;
}
+ String host = intent.getData().getHost();
+ if (TextUtils.isEmpty(host)) {
+ return false;
+ }
+
+ if (!sCachedMatcher.get().reset(host).matches()) {
+ return false;
+ }
+
Set<String> categories = intent.getCategories();
int categoriesSize = CollectionUtils.size(categories);
if (categoriesSize > 2) {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index dce853afc763..4de8d52a8c2e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -235,9 +235,23 @@ class DomainVerificationCollectorTest {
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https"/>
- <data android:path="/sub5"/>
- <data android:host="example5.com"/>
- <data android:host="invalid5"/>
+ <data android:path="/sub6"/>
+ <data android:host="example6.com"/>
+ <data android:host="invalid6"/>
+ </intent-filter>
+ <intent-filter android:autoVerify="$autoVerify">
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="example7.com"/>
+ <intent-filter android:autoVerify="$autoVerify">
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="https"/>
+ </intent-filter>
+ <intent-filter android:autoVerify="$autoVerify">
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:path="/sub7"/>
</intent-filter>
</xml>
""".trimIndent()
@@ -324,6 +338,30 @@ class DomainVerificationCollectorTest {
addDataAuthority("invalid6", null)
}
)
+ addIntent(
+ ParsedIntentInfo().apply {
+ setAutoVerify(autoVerify)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataAuthority("example7.com", null)
+ }
+ )
+ addIntent(
+ ParsedIntentInfo().apply {
+ setAutoVerify(autoVerify)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("https")
+ }
+ )
+ addIntent(
+ ParsedIntentInfo().apply {
+ setAutoVerify(autoVerify)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataPath("/sub7", PatternMatcher.PATTERN_LITERAL)
+ }
+ )
},
)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
new file mode 100644
index 000000000000..98634b28ea9d
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.verify.domain
+
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import com.android.server.pm.verify.domain.DomainVerificationUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class DomainVerificationValidIntentTest {
+
+ companion object {
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun parameters(): Array<Params> {
+ val succeeding = mutableListOf<Params>()
+ val failing = mutableListOf<Params>()
+
+ // Start with the base intent
+ val base = Params(categorySet = emptySet()).also { succeeding += it }
+
+ // Add all explicit supported categorySet
+ succeeding += base.copy(
+ categorySet = setOf(Intent.CATEGORY_BROWSABLE),
+ matchDefaultOnly = true
+ )
+
+ failing += base.copy(
+ categorySet = setOf(Intent.CATEGORY_BROWSABLE),
+ matchDefaultOnly = false
+ )
+
+ succeeding += listOf(true, false).map {
+ base.copy(
+ categorySet = setOf(Intent.CATEGORY_DEFAULT),
+ matchDefaultOnly = it
+ )
+ }
+
+ succeeding += listOf(true, false).map {
+ base.copy(
+ categorySet = setOf(Intent.CATEGORY_BROWSABLE, Intent.CATEGORY_DEFAULT),
+ matchDefaultOnly = it
+ )
+ }
+
+ // Fail on unsupported category
+ failing += listOf(
+ emptySet(),
+ setOf(Intent.CATEGORY_BROWSABLE),
+ setOf(Intent.CATEGORY_DEFAULT),
+ setOf(Intent.CATEGORY_BROWSABLE, Intent.CATEGORY_DEFAULT)
+ ).map { base.copy(categorySet = it + "invalid.CATEGORY") }
+
+ // Fail on unsupported action
+ failing += base.copy(action = Intent.ACTION_SEND)
+
+ // Fail on unsupported domain
+ failing += base.copy(domain = "invalid")
+
+ // Fail on empty domains
+ failing += base.copy(domain = "")
+
+ // Fail on missing scheme
+ failing += base.copy(
+ uriFunction = { Uri.Builder().authority("test.com").build() }
+ )
+
+ // Fail on missing host
+ failing += base.copy(
+ domain = "",
+ uriFunction = { Uri.Builder().scheme("https").build() }
+ )
+
+ succeeding.forEach { it.expected = true }
+ failing.forEach { it.expected = false }
+ return (succeeding + failing).toTypedArray()
+ }
+
+ data class Params(
+ val action: String = Intent.ACTION_VIEW,
+ val categorySet: Set<String> = mutableSetOf(),
+ val domain: String = "test.com",
+ val matchDefaultOnly: Boolean = true,
+ var expected: Boolean? = null,
+ val uriFunction: (domain: String) -> Uri = { Uri.parse("https://$it") }
+ ) {
+ val intent = Intent(action, uriFunction(domain)).apply {
+ categorySet.forEach(::addCategory)
+ }
+
+ override fun toString() = intent.toShortString(false, false, false, false) +
+ ", matchDefaultOnly = $matchDefaultOnly, expected = $expected"
+ }
+ }
+
+ @Parameterized.Parameter(0)
+ lateinit var params: Params
+
+ @Test
+ fun verify() {
+ val flags = if (params.matchDefaultOnly) PackageManager.MATCH_DEFAULT_ONLY else 0
+ assertThat(DomainVerificationUtils.isDomainVerificationIntent(params.intent, flags))
+ .isEqualTo(params.expected)
+ }
+}