Commit 6d48958d authored by huangxueqing's avatar huangxueqing Committed by Commit Bot

Ignore Intent filters with wildcard hosts when handling links.

If the Android device has a package installed that declares
an Intent filter with `android:host="*"`, Chrome will launch
the Intent picker UX whenever a person taps a link.
This is a poor user experience. (Using `android:host="*"`
arguably doesn't make much sense; normally, Intent filters
would use `*` to match subdomains such as *.google.com.) Thus,
skip Intent filters with such wildcard hosts when handling
acceptable scheme links.

R=dtrainor@chromium.org

Bug: 841133
Change-Id: I3cb14309ed53e0bd623ed0da59af6635391a8718
Reviewed-on: https://chromium-review.googlesource.com/1053847Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarMaria Khomenko <mariakhomenko@chromium.org>
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Cr-Commit-Position: refs/heads/master@{#564487}
parent 6a5e8ee9
......@@ -42,7 +42,7 @@ interface ExternalNavigationDelegate {
* Returns the number of specialized intent handlers in {@params infos}. Specialized intent
* handlers are intent handlers which handle only a few URLs (e.g. google maps or youtube).
*/
int countSpecializedHandlers(List<ResolveInfo> infos);
int countSpecializedHandlers(List<ResolveInfo> infos, Intent intent);
/**
* Returns the package name of the first valid WebAPK in {@link infos}.
......
......@@ -59,6 +59,7 @@ import org.chromium.ui.base.WindowAndroid;
import org.chromium.webapk.lib.client.WebApkValidator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
......@@ -266,32 +267,20 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
}
@Override
public int countSpecializedHandlers(List<ResolveInfo> infos) {
return getSpecializedHandlersWithFilter(infos, null).size();
public int countSpecializedHandlers(List<ResolveInfo> infos, Intent intent) {
return getSpecializedHandlersWithFilter(infos, null, intent).size();
}
@VisibleForTesting
public static ArrayList<String> getSpecializedHandlersWithFilter(
List<ResolveInfo> infos, String filterPackageName) {
List<ResolveInfo> infos, String filterPackageName, Intent intent) {
ArrayList<String> result = new ArrayList<>();
if (infos == null) {
return result;
}
for (ResolveInfo info : infos) {
IntentFilter filter = info.filter;
if (filter == null) {
// Error on the side of classifying ResolveInfo as generic.
continue;
}
if (filter.countDataAuthorities() == 0 && filter.countDataPaths() == 0) {
// Don't count generic handlers.
continue;
}
if (!TextUtils.isEmpty(filterPackageName)
&& (info.activityInfo == null
|| !info.activityInfo.packageName.equals(filterPackageName))) {
if (!matchResolveInfoExceptWildCardHost(info, filterPackageName, intent)) {
continue;
}
......@@ -309,6 +298,39 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
return result;
}
private static boolean matchResolveInfoExceptWildCardHost(
ResolveInfo info, String filterPackageName, Intent intent) {
IntentFilter intentFilter = info.filter;
if (intentFilter == null) {
// Error on the side of classifying ResolveInfo as generic.
return false;
}
if (intentFilter.countDataAuthorities() == 0 && intentFilter.countDataPaths() == 0) {
// Don't count generic handlers.
return false;
}
if (intent != null && UrlUtilities.isAcceptedScheme(intent.toUri(0))) {
boolean isWildCardHost = false;
Iterator<IntentFilter.AuthorityEntry> it = intentFilter.authoritiesIterator();
while (it != null && it.hasNext()) {
IntentFilter.AuthorityEntry entry = it.next();
if ("*".equals(entry.getHost())) {
isWildCardHost = true;
break;
}
}
if (isWildCardHost) {
return false;
}
}
if (!TextUtils.isEmpty(filterPackageName)
&& (info.activityInfo == null
|| !info.activityInfo.packageName.equals(filterPackageName))) {
return false;
}
return true;
}
/**
* Check whether the given package is a specialized handler for the given intent
*
......@@ -322,7 +344,7 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
try {
List<ResolveInfo> handlers = context.getPackageManager().queryIntentActivities(
intent, PackageManager.GET_RESOLVED_FILTER);
return getSpecializedHandlersWithFilter(handlers, packageName).size() > 0;
return getSpecializedHandlersWithFilter(handlers, packageName, intent).size() > 0;
} catch (RuntimeException e) {
IntentUtils.logTransactionTooLargeOrRethrow(e, intent);
}
......@@ -596,7 +618,7 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
@Override
public void maybeRecordAppHandlersInIntent(Intent intent, List<ResolveInfo> infos) {
intent.putExtra(IntentHandler.EXTRA_EXTERNAL_NAV_PACKAGES,
getSpecializedHandlersWithFilter(infos, null));
getSpecializedHandlersWithFilter(infos, null, intent));
}
@Override
......
......@@ -441,7 +441,7 @@ public class ExternalNavigationHandler {
// handlers. If webkit can't handle it internally, we need to call
// startActivityIfNeeded or startActivity.
if (!isExternalProtocol) {
if (mDelegate.countSpecializedHandlers(resolvingInfos) == 0) {
if (mDelegate.countSpecializedHandlers(resolvingInfos, intent) == 0) {
if (incomingIntentRedirect
&& mDelegate.maybeLaunchInstantApp(
params.getUrl(), params.getReferrerUrl(), true)) {
......@@ -566,7 +566,7 @@ public class ExternalNavigationHandler {
}
if (targetWebApkPackageName != null
&& mDelegate.countSpecializedHandlers(resolvingInfos) == 1) {
&& mDelegate.countSpecializedHandlers(resolvingInfos, null) == 1) {
intent.setPackage(targetWebApkPackageName);
}
......@@ -746,7 +746,8 @@ public class ExternalNavigationHandler {
} catch (URISyntaxException ex) {
return false;
}
return ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter(handlers, appId)
return ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(handlers, appId, null)
.size()
> 0;
}
......
......@@ -84,7 +84,7 @@ public class WebappTabDelegate extends TabDelegate {
boolean foundSpecializedHandler = false;
for (String result : ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter(
handlers, null)) {
handlers, null, null)) {
if (result.equals(mApkPackageName)) {
// Current webapk matches, don't intercept so that we can launch a cct. See
// http://crbug.com/831806 for more context.
......
......@@ -4,9 +4,11 @@
package org.chromium.chrome.browser.externalnav;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
......@@ -47,7 +49,7 @@ public class ExternalNavigationDelegateImplTest {
List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
......@@ -60,7 +62,7 @@ public class ExternalNavigationDelegateImplTest {
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
......@@ -74,7 +76,7 @@ public class ExternalNavigationDelegateImplTest {
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
......@@ -88,7 +90,49 @@ public class ExternalNavigationDelegateImplTest {
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithAuthority_Wildcard_Host() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("*", null);
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName, intent)
.size());
Intent intentWildcardHost =
new Intent(Intent.ACTION_VIEW, Uri.parse("https://*.google.com"));
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, intentWildcardHost)
.size());
ResolveInfo infoWildcardSubDomain = new ResolveInfo();
infoWildcardSubDomain.filter = new IntentFilter();
infoWildcardSubDomain.filter.addDataAuthority("http://*.google.com", "80");
List<ResolveInfo> resolveInfosWildcardSubDomain = makeResolveInfos(infoWildcardSubDomain);
Intent intentSubDomain1 = new Intent(Intent.ACTION_VIEW, Uri.parse("https://google.com"));
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(
resolveInfosWildcardSubDomain, packageName, intentSubDomain1)
.size());
Intent intentSubDomain2 =
new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com"));
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(
resolveInfosWildcardSubDomain, packageName, intentSubDomain2)
.size());
}
......@@ -104,7 +148,7 @@ public class ExternalNavigationDelegateImplTest {
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
......@@ -120,7 +164,7 @@ public class ExternalNavigationDelegateImplTest {
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
......@@ -138,7 +182,7 @@ public class ExternalNavigationDelegateImplTest {
// Ephemeral resolver is not counted as a specialized handler.
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.getSpecializedHandlersWithFilter(resolveInfos, packageName, null)
.size());
}
......
......@@ -1502,7 +1502,7 @@ public class ExternalNavigationHandlerTest {
}
@Override
public int countSpecializedHandlers(List<ResolveInfo> infos) {
public int countSpecializedHandlers(List<ResolveInfo> infos, Intent intent) {
int count = 0;
List<IntentActivity> matchingIntentActivities = findMatchingIntentActivities(infos);
for (IntentActivity intentActivity : matchingIntentActivities) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment