summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java206
-rw-r--r--services/core/java/com/android/server/pm/Settings.java10
2 files changed, 157 insertions, 59 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0b9d449fc648..9762e545a976 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -109,6 +109,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
@@ -1079,10 +1080,14 @@ public class PackageManagerService extends IPackageManager.Stub
verificationIntent.setComponent(mIntentFilterVerifierComponent);
verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ final long whitelistTimeout = getVerificationTimeout();
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setTemporaryAppWhitelistDuration(whitelistTimeout);
+
DeviceIdleController.LocalService idleController = getDeviceIdleController();
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
- mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(),
- userId, false, "intent filter verifier");
+ mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
+ userId, true, "intent filter verifier");
UserHandle user = new UserHandle(userId);
mContext.sendBroadcastAsUser(verificationIntent, user);
@@ -1123,9 +1128,6 @@ public class PackageManagerService extends IPackageManager.Stub
+ verificationId + " packageName:" + packageName);
return;
}
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "Updating IntentFilterVerificationInfo for package " + packageName
- +" verificationId:" + verificationId);
synchronized (mPackages) {
if (verified) {
@@ -1143,36 +1145,70 @@ public class PackageManagerService extends IPackageManager.Stub
int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
boolean needUpdate = false;
- // We cannot override the STATUS_ALWAYS / STATUS_NEVER states if they have
- // already been set by the User thru the Disambiguation dialog
- switch (userStatus) {
- case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
- if (verified) {
- updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
- } else {
- updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
- }
- needUpdate = true;
- break;
-
- case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
- if (verified) {
- updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
- needUpdate = true;
- }
- break;
-
- default:
- // Nothing to do
- }
+ // 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.
+ //
+ // If validation failed, the undefined state winds up in the basic ASK behavior,
+ // but apps that previously passed and became ALWAYS are *demoted* out of
+ // that state, since they would not deserve the ALWAYS behavior in case of a
+ // clean install.
+ switch (userStatus) {
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
+ if (!verified) {
+ // Don't demote if sysconfig says 'always'
+ SystemConfig systemConfig = SystemConfig.getInstance();
+ ArraySet<String> packages = systemConfig.getLinkedApps();
+ if (!packages.contains(packageName)) {
+ // updatedStatus is already UNDEFINED
+ needUpdate = true;
+
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Formerly validated but now failing; demoting");
+ }
+ } else {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Updating bundled package " + packageName
+ + " failed autoVerify, but sysconfig supersedes");
+ }
+ // leave needUpdate == false here intentionally
+ }
+ }
+ break;
+
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
+ // Stay in 'undefined' on verification failure
+ if (verified) {
+ updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+ }
+ needUpdate = true;
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Applying update; old=" + userStatus
+ + " new=" + updatedStatus);
+ }
+ break;
+
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
+ // Keep in 'ask' on failure
+ if (verified) {
+ updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+ needUpdate = true;
+ }
+ break;
+
+ default:
+ // Nothing to do
+ }
if (needUpdate) {
mSettings.updateIntentFilterVerificationStatusLPw(
packageName, updatedStatus, userId);
scheduleWritePackageRestrictionsLocked(userId);
}
+ } else {
+ Slog.i(TAG, "autoVerify ignored when installing for all users");
}
- }
+ }
}
@Override
@@ -18411,70 +18447,125 @@ 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);
}
}
- }
-
- 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) {
@@ -18483,6 +18574,7 @@ public class PackageManagerService extends IPackageManager.Stub
int status = ivi.getStatus();
switch (status) {
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
return true;
@@ -19177,7 +19269,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean installedStateChanged = false;
if (deletedPs != null) {
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
- clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
+ clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
clearDefaultBrowserIfNeeded(packageName);
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
removedAppId = mSettings.removePackageLPw(packageName);
@@ -20457,12 +20549,13 @@ 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. */
- 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())) {
@@ -20471,7 +20564,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 45d0c585627b..6a463a621878 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1368,7 +1368,8 @@ 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) {
@@ -1376,14 +1377,17 @@ 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;
}