diff options
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 119 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/Settings.java | 10 |
2 files changed, 91 insertions, 38 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6bed7f381a6c..b983e34fb87b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1142,13 +1142,6 @@ public class PackageManagerService extends IPackageManager.Stub int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; boolean needUpdate = false; - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, - "Updating IntentFilterVerificationInfo for package " + packageName - + " verificationId:" + verificationId - + " verified=" + verified); - } - // In a success case, we promote from undefined or ASK to ALWAYS. This // supports a flow where the app fails validation but then ships an updated // APK that passes, and therefore deserves to be in ALWAYS. @@ -18121,72 +18114,126 @@ public class PackageManagerService extends IPackageManager.Stub int count = 0; final String packageName = pkg.packageName; - + boolean handlesWebUris = false; + ArraySet<String> domains = new ArraySet<>(); + final boolean previouslyVerified; + boolean hostSetExpanded = false; + boolean needToRunVerify = false; synchronized (mPackages) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - if (!replacing) { - IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - if (ivi != null) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName+ " already verified: status=" - + ivi.getStatusString()); - } - return; + IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + previouslyVerified = (ivi != null); + if (!replacing && previouslyVerified) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName + " already verified: status=" + + ivi.getStatusString()); } + return; } - // If any filters need to be verified, then all need to be. - boolean needToVerify = false; + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, " Previous verified hosts: " + + (ivi == null ? "[none]" : ivi.getDomainsString())); + } + + // If any filters need to be verified, then all need to be. In addition, we need to + // know whether an updating app has any web navigation intent filters, to re- + // examine handling policy even if not re-verifying. + final boolean needsVerification = needsNetworkVerificationLPr(packageName); for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { - if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { + if (filter.handlesWebUris(true)) { + handlesWebUris = true; + } + if (needsVerification && filter.needsVerification()) { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, - "Intent filter needs verification, so processing all filters"); + Slog.d(TAG, "autoVerify requested, processing all filters"); } - needToVerify = true; + needToRunVerify = true; + // It's safe to break out here because filter.needsVerification() + // can only be true if filter.handlesWebUris(true) returned true, so + // we've already noted that. break; } } } - if (needToVerify) { + // Compare the new set of recognized hosts if the app is either requesting + // autoVerify or has previously used autoVerify but no longer does. + if (needToRunVerify || previouslyVerified) { final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { // Run verification against hosts mentioned in any web-nav intent filter, // even if the filter matches non-web schemes as well - if (filter.handlesWebUris(false) && needsNetworkVerificationLPr(filter)) { + if (filter.handlesWebUris(false /*onlyWebSchemes*/)) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString()); mIntentFilterVerifier.addOneIntentFilterVerification( verifierUid, userId, verificationId, filter, packageName); + domains.addAll(filter.getHostsList()); count++; } } } } + + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, " Update published hosts: " + domains.toString()); + } + + // If we've previously verified this same host set (or a subset), we can trust that + // a current ALWAYS policy is still applicable. If this is the case, we're done. + // (If we aren't in ALWAYS, we want to reverify to allow for apps that had failing + // hosts in their intent filters, then pushed a new apk that removed them and now + // passes.) + // + // Cases: + // + still autoVerify (needToRunVerify): + // - preserve current state if all of: unexpanded, in always + // - otherwise rerun as usual (fall through) + // + no longer autoVerify (alreadyVerified && !needToRunVerify) + // - wipe verification history always + // - preserve current state if all of: unexpanded, in always + hostSetExpanded = !previouslyVerified + || (ivi != null && !ivi.getDomains().containsAll(domains)); + final int currentPolicy = + mSettings.getIntentFilterVerificationStatusLPr(packageName, userId); + final boolean keepCurState = !hostSetExpanded + && currentPolicy == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; + + if (needToRunVerify && keepCurState) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Host set not expanding + ALWAYS -> no need to reverify"); + } + ivi.setDomains(domains); + scheduleWriteSettingsLocked(); + return; + } else if (previouslyVerified && !needToRunVerify) { + // Prior autoVerify state but not requesting it now. Clear autoVerify history, + // and preserve the always policy iff the host set is not expanding. + clearIntentFilterVerificationsLPw(packageName, userId, !keepCurState); + return; + } } - if (count > 0) { + if (needToRunVerify && count > 0) { + // app requested autoVerify and has at least one matching intent filter if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No filters or not all autoVerify for " + packageName); + Slog.d(TAG, "No web filters or no new host policy for " + packageName); } } } @GuardedBy("mPackages") - private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) { - final ComponentName cn = filter.activity.getComponentName(); - final String packageName = cn.getPackageName(); - + private boolean needsNetworkVerificationLPr(String packageName) { IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr( packageName); if (ivi == null) { @@ -18932,7 +18979,7 @@ public class PackageManagerService extends IPackageManager.Stub if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { final SparseBooleanArray changedUsers = new SparseBooleanArray(); synchronized (mPackages) { - clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL); + clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true); clearDefaultBrowserIfNeeded(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); removedAppId = mSettings.removePackageLPw(packageName); @@ -20437,13 +20484,14 @@ public class PackageManagerService extends IPackageManager.Stub final int packageCount = mPackages.size(); for (int i = 0; i < packageCount; i++) { PackageParser.Package pkg = mPackages.valueAt(i); - clearIntentFilterVerificationsLPw(pkg.packageName, userId); + clearIntentFilterVerificationsLPw(pkg.packageName, userId, true); } } /** This method takes a specific user id as well as UserHandle.USER_ALL. */ @GuardedBy("mPackages") - void clearIntentFilterVerificationsLPw(String packageName, int userId) { + void clearIntentFilterVerificationsLPw(String packageName, int userId, + boolean alsoResetStatus) { if (userId == UserHandle.USER_ALL) { if (mSettings.removeIntentFilterVerificationLPw(packageName, sUserManager.getUserIds())) { @@ -20452,7 +20500,8 @@ public class PackageManagerService extends IPackageManager.Stub } } } else { - if (mSettings.removeIntentFilterVerificationLPw(packageName, userId)) { + if (mSettings.removeIntentFilterVerificationLPw(packageName, userId, + alsoResetStatus)) { scheduleWritePackageRestrictionsLocked(userId); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index d9e4db29de07..c69af6c3a284 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1243,7 +1243,8 @@ public final class Settings { return result; } - boolean removeIntentFilterVerificationLPw(String packageName, int userId) { + boolean removeIntentFilterVerificationLPw(String packageName, int userId, + boolean alsoResetStatus) { PackageSetting ps = mPackages.get(packageName); if (ps == null) { if (DEBUG_DOMAIN_VERIFICATION) { @@ -1251,14 +1252,17 @@ public final class Settings { } return false; } - ps.clearDomainVerificationStatusForUser(userId); + if (alsoResetStatus) { + ps.clearDomainVerificationStatusForUser(userId); + } + ps.setIntentFilterVerificationInfo(null); return true; } boolean removeIntentFilterVerificationLPw(String packageName, int[] userIds) { boolean result = false; for (int userId : userIds) { - result |= removeIntentFilterVerificationLPw(packageName, userId); + result |= removeIntentFilterVerificationLPw(packageName, userId, true); } return result; } |