diff options
6 files changed, 142 insertions, 33 deletions
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 590d791b8195..044e3e3c303f 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -517,6 +517,38 @@ public class IntentFilter implements Parcelable { } /** + * Return if this filter handle all HTTP or HTTPS data URI or not. + * + * @return True if the filter handle all HTTP or HTTPS data URI. False otherwise. + * + * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and + * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent + * data scheme is "http" or "https" and that there is no specific host defined. + * + * @hide + */ + public final boolean handleAllWebDataURI() { + return hasWebDataURI() && (countDataAuthorities() == 0); + } + + /** + * Return if this filter has any HTTP or HTTPS data URI or not. + * + * @return True if the filter has any HTTP or HTTPS data URI. False otherwise. + * + * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and + * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent + * data scheme is "http" or "https". + * + * @hide + */ + public final boolean hasWebDataURI() { + return hasAction(Intent.ACTION_VIEW) && + hasCategory(Intent.CATEGORY_BROWSABLE) && + (hasDataScheme(SCHEME_HTTP) || hasDataScheme(SCHEME_HTTPS)); + } + + /** * Return if this filter needs to be automatically verified again its data URIs or not. * * @return True if the filter needs to be automatically verified. False otherwise. @@ -530,10 +562,7 @@ public class IntentFilter implements Parcelable { * @hide */ public final boolean needsVerification() { - return hasAction(Intent.ACTION_VIEW) && - hasCategory(Intent.CATEGORY_BROWSABLE) && - (hasDataScheme(SCHEME_HTTP) || hasDataScheme(SCHEME_HTTPS)) && - getAutoVerify(); + return hasWebDataURI() && getAutoVerify(); } /** diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java index 28cbaa8852b7..e50b0ff17a0a 100644 --- a/core/java/android/content/pm/IntentFilterVerificationInfo.java +++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java @@ -36,7 +36,7 @@ import java.util.ArrayList; /** * The {@link com.android.server.pm.PackageManagerService} maintains some - * {@link IntentFilterVerificationInfo}s for each domain / package / class name per user. + * {@link IntentFilterVerificationInfo}s for each domain / package name. * * @hide */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index bdbed7551cae..6b9d3f8a79d2 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2794,6 +2794,7 @@ public class PackageParser { if (!aii.hasAction(Intent.ACTION_VIEW)) continue; if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { + Slog.d(TAG, "hasDomainURLs:true for package:" + pkg.packageName); return true; } } diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index 7b141f050e67..05f5e90e56d7 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -144,9 +144,9 @@ public class ResolveInfo implements Parcelable { public boolean system; /** - * @hide Does the associated IntentFilter needs verification ? + * @hide Does the associated IntentFilter comes from a Browser ? */ - public boolean filterNeedsVerification; + public boolean handleAllWebDataURI; private ComponentInfo getComponentInfo() { if (activityInfo != null) return activityInfo; @@ -288,7 +288,7 @@ public class ResolveInfo implements Parcelable { resolvePackageName = orig.resolvePackageName; system = orig.system; targetUserId = orig.targetUserId; - filterNeedsVerification = orig.filterNeedsVerification; + handleAllWebDataURI = orig.handleAllWebDataURI; } public String toString() { @@ -350,7 +350,7 @@ public class ResolveInfo implements Parcelable { dest.writeInt(targetUserId); dest.writeInt(system ? 1 : 0); dest.writeInt(noResourceId ? 1 : 0); - dest.writeInt(filterNeedsVerification ? 1 : 0); + dest.writeInt(handleAllWebDataURI ? 1 : 0); } public static final Creator<ResolveInfo> CREATOR @@ -396,7 +396,7 @@ public class ResolveInfo implements Parcelable { targetUserId = source.readInt(); system = source.readInt() != 0; noResourceId = source.readInt() != 0; - filterNeedsVerification = source.readInt() != 0; + handleAllWebDataURI = source.readInt() != 0; } public static class DisplayNameComparator diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 80a4351d08dc..42b4aaf0d906 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -560,7 +560,6 @@ public class PackageManagerService extends IPackageManager.Stub { mIntentFilterVerificationStates.get(verificationId); String packageName = ivs.getPackageName(); - boolean modified = false; ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters(); final int filterCount = filters.size(); @@ -571,9 +570,8 @@ public class PackageManagerService extends IPackageManager.Stub { } ArrayList<String> domainsList = new ArrayList<>(domainsSet); synchronized (mPackages) { - modified = mSettings.createIntentFilterVerificationIfNeededLPw( - packageName, domainsList); - if (modified) { + if (mSettings.createIntentFilterVerificationIfNeededLPw( + packageName, domainsList) != null) { scheduleWriteSettingsLocked(); } } @@ -698,8 +696,7 @@ public class PackageManagerService extends IPackageManager.Stub { ivs = createDomainVerificationState(verifierId, userId, verificationId, packageName); } - ArrayList<String> hosts = filter.getHostsList(); - if (!hasValidHosts(hosts)) { + if (!hasValidDomains(filter)) { return false; } ivs.addFilter(filter); @@ -719,17 +716,35 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private static boolean hasValidHosts(ArrayList<String> hosts) { - if (hosts.size() == 0) { - Slog.d(TAG, "IntentFilter does not contain any data hosts"); + private static boolean hasValidDomains(ActivityIntentInfo filter) { + return hasValidDomains(filter, true); + } + + private static boolean hasValidDomains(ActivityIntentInfo filter, boolean logging) { + boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || + filter.hasDataScheme(IntentFilter.SCHEME_HTTPS); + if (!hasHTTPorHTTPS) { + if (logging) { + Slog.d(TAG, "IntentFilter does not contain any HTTP or HTTPS data scheme"); + } return false; } + ArrayList<String> hosts = filter.getHostsList(); + if (hosts.size() == 0) { + if (logging) { + Slog.d(TAG, "IntentFilter does not contain any data hosts"); + } + // We still return true as this is the case of any Browser + return true; + } String hostEndBase = null; for (String host : hosts) { String[] hostParts = host.split("\\."); // Should be at minimum a host like "example.com" if (hostParts.length < 2) { - Slog.d(TAG, "IntentFilter does not contain a valid data host name: " + host); + if (logging) { + Slog.d(TAG, "IntentFilter does not contain a valid data host name: " + host); + } return false; } // Verify that we have the same ending domain @@ -739,7 +754,9 @@ public class PackageManagerService extends IPackageManager.Stub { hostEndBase = hostEnd; } if (!hostEnd.equalsIgnoreCase(hostEndBase)) { - Slog.d(TAG, "IntentFilter does not contain the same data domains"); + if (logging) { + Slog.d(TAG, "IntentFilter does not contain the same data domains"); + } return false; } } @@ -2176,6 +2193,8 @@ public class PackageManagerService extends IPackageManager.Stub { mIntentFilterVerifier = new IntentVerifierProxy(mContext, mIntentFilterVerifierComponent); + primeDomainVerificationsLPw(false); + } // synchronized (mPackages) } // synchronized (mInstallLock) @@ -2272,6 +2291,50 @@ public class PackageManagerService extends IPackageManager.Stub { return verifierComponentName; } + private void primeDomainVerificationsLPw(boolean logging) { + Slog.d(TAG, "Start priming domain verification"); + boolean updated = false; + ArrayList<String> allHosts = new ArrayList<>(); + for (PackageParser.Package pkg : mPackages.values()) { + final String packageName = pkg.packageName; + if (!hasDomainURLs(pkg)) { + if (logging) { + Slog.d(TAG, "No priming domain verifications for " + + "package with no domain URLs: " + packageName); + } + continue; + } + for (PackageParser.Activity a : pkg.activities) { + for (ActivityIntentInfo filter : a.intents) { + if (hasValidDomains(filter, false)) { + allHosts.addAll(filter.getHostsList()); + } + } + } + if (allHosts.size() > 0) { + allHosts.add("*"); + } + IntentFilterVerificationInfo ivi = + mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHosts); + if (ivi != null) { + // We will always log this + Slog.d(TAG, "Priming domain verifications for package: " + packageName); + ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS); + updated = true; + } + else { + if (logging) { + Slog.d(TAG, "No priming domain verifications for package: " + packageName); + } + } + allHosts.clear(); + } + if (updated) { + scheduleWriteSettingsLocked(); + } + Slog.d(TAG, "End priming domain verification"); + } + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -3947,6 +4010,8 @@ public class PackageManagerService extends IPackageManager.Stub { } final int userId = UserHandle.getCallingUserId(); ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>(); + ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>(); + ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>(); synchronized (mPackages) { final int count = candidates.size(); // First, try to use the domain prefered App @@ -3959,13 +4024,28 @@ public class PackageManagerService extends IPackageManager.Stub { int status = getDomainVerificationStatusLPr(ps, userId); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { result.add(info); + } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { + neverList.add(info); + } + // Add to the special match all list (Browser use case) + if (info.handleAllWebDataURI) { + matchAllList.add(info); } } } - // There is not much we can do, add all candidates + // If there is nothing selected, add all candidates and remove the ones that the User + // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state and + // also remove any . + // If there is still none after this pass, add all Browser Apps and let the User decide + // with the Disambiguation dialog if there are several ones. if (result.size() == 0) { result.addAll(candidates); } + result.removeAll(neverList); + result.removeAll(matchAllList); + if (result.size() == 0) { + result.addAll(matchAllList); + } } if (DEBUG_PREFERRED) { Slog.v("TAG", "Filtered results with prefered activities. New candidates count: " + @@ -7843,7 +7923,7 @@ public class PackageManagerService extends IPackageManager.Stub { res.filter = info; } if (info != null) { - res.filterNeedsVerification = info.needsVerification(); + res.handleAllWebDataURI = info.handleAllWebDataURI(); } res.priority = info.getPriority(); res.preferredOrder = activity.owner.mPreferredOrder; @@ -11234,9 +11314,8 @@ public class PackageManagerService extends IPackageManager.Stub { count++; } else { Slog.d(TAG, "No verification needed for IntentFilter:" + filter.toString()); - ArrayList<String> list = filter.getHostsList(); - if (hasValidHosts(list)) { - allHosts.addAll(list); + if (hasValidDomains(filter)) { + allHosts.addAll(filter.getHostsList()); } } } @@ -11251,7 +11330,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.d(TAG, "No need to start any IntentFilter verification!"); if (allHosts.size() > 0 && hasDomainURLs(pkg) && mSettings.createIntentFilterVerificationIfNeededLPw( - packageName, allHosts)) { + packageName, allHosts) != null) { scheduleWriteSettingsLocked(); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 2e2053d54ce8..bfcc3db66370 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -966,19 +966,19 @@ final class Settings { } /* package protected */ - boolean createIntentFilterVerificationIfNeededLPw(String packageName, + IntentFilterVerificationInfo createIntentFilterVerificationIfNeededLPw(String packageName, ArrayList<String> domains) { PackageSetting ps = mPackages.get(packageName); if (ps == null) { Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName); - return false; + return null; } - if (ps.getIntentFilterVerificationInfo() == null) { - IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(packageName, domains); + IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo(); + if (ivi == null) { + ivi = new IntentFilterVerificationInfo(packageName, domains); ps.setIntentFilterVerificationInfo(ivi); - return true; } - return false; + return ivi; } int getIntentFilterVerificationStatusLPr(String packageName, int userId) { |