Merge "Only autoVerify at install for new hosts" into pi-dev

This commit is contained in:
Chris Tate
2020-06-25 23:41:25 +00:00
committed by Android (Google) Code Review
2 changed files with 154 additions and 57 deletions

View File

@@ -121,6 +121,7 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.IActivityManager; import android.app.IActivityManager;
import android.app.ResourcesManager; import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager; import android.app.admin.IDevicePolicyManager;
@@ -1105,9 +1106,13 @@ public class PackageManagerService extends IPackageManager.Stub
verificationIntent.setComponent(mIntentFilterVerifierComponent); verificationIntent.setComponent(mIntentFilterVerifierComponent);
verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long whitelistTimeout = getVerificationTimeout();
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppWhitelistDuration(whitelistTimeout);
DeviceIdleController.LocalService idleController = getDeviceIdleController(); DeviceIdleController.LocalService idleController = getDeviceIdleController();
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(), mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
UserHandle.USER_SYSTEM, true, "intent filter verifier"); UserHandle.USER_SYSTEM, true, "intent filter verifier");
mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM); mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM);
@@ -1148,9 +1153,6 @@ public class PackageManagerService extends IPackageManager.Stub
+ verificationId + " packageName:" + packageName); + verificationId + " packageName:" + packageName);
return; return;
} }
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Updating IntentFilterVerificationInfo for package " + packageName
+" verificationId:" + verificationId);
synchronized (mPackages) { synchronized (mPackages) {
if (verified) { if (verified) {
@@ -1168,36 +1170,70 @@ public class PackageManagerService extends IPackageManager.Stub
int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
boolean needUpdate = false; boolean needUpdate = false;
// We cannot override the STATUS_ALWAYS / STATUS_NEVER states if they have // In a success case, we promote from undefined or ASK to ALWAYS. This
// already been set by the User thru the Disambiguation dialog // supports a flow where the app fails validation but then ships an updated
switch (userStatus) { // APK that passes, and therefore deserves to be in ALWAYS.
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: //
if (verified) { // If validation failed, the undefined state winds up in the basic ASK behavior,
updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; // but apps that previously passed and became ALWAYS are *demoted* out of
} else { // that state, since they would not deserve the ALWAYS behavior in case of a
updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; // clean install.
} switch (userStatus) {
needUpdate = true; case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
break; 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;
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: if (DEBUG_DOMAIN_VERIFICATION) {
if (verified) { Slog.d(TAG, "Formerly validated but now failing; demoting");
updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; }
needUpdate = true; } else {
} if (DEBUG_DOMAIN_VERIFICATION) {
break; Slog.d(TAG, "Updating bundled package " + packageName
+ " failed autoVerify, but sysconfig supersedes");
}
// leave needUpdate == false here intentionally
}
}
break;
default: case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
// Nothing to do // 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) { if (needUpdate) {
mSettings.updateIntentFilterVerificationStatusLPw( mSettings.updateIntentFilterVerificationStatusLPw(
packageName, updatedStatus, userId); packageName, updatedStatus, userId);
scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageRestrictionsLocked(userId);
} }
} else {
Slog.i(TAG, "autoVerify ignored when installing for all users");
} }
} }
} }
@Override @Override
@@ -17738,71 +17774,125 @@ public class PackageManagerService extends IPackageManager.Stub
int count = 0; int count = 0;
final String packageName = pkg.packageName; final String packageName = pkg.packageName;
boolean handlesWebUris = false;
ArraySet<String> domains = new ArraySet<>();
final boolean previouslyVerified;
boolean hostSetExpanded = false;
boolean needToRunVerify = false;
synchronized (mPackages) { synchronized (mPackages) {
// If this is a new install and we see that we've already run verification for this // 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. // package, we have nothing to do: it means the state was restored from backup.
if (!replacing) { IntentFilterVerificationInfo ivi =
IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(packageName);
mSettings.getIntentFilterVerificationLPr(packageName); previouslyVerified = (ivi != null);
if (ivi != null) { if (!replacing && previouslyVerified) {
if (DEBUG_DOMAIN_VERIFICATION) { if (DEBUG_DOMAIN_VERIFICATION) {
Slog.i(TAG, "Package " + packageName+ " already verified: status=" Slog.i(TAG, "Package " + packageName + " already verified: status="
+ ivi.getStatusString()); + ivi.getStatusString());
}
return;
} }
return;
} }
// If any filters need to be verified, then all need to be. if (DEBUG_DOMAIN_VERIFICATION) {
boolean needToVerify = false; 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 (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) { for (ActivityIntentInfo filter : a.intents) {
if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (filter.handlesWebUris(true)) {
handlesWebUris = true;
}
if (needsVerification && filter.needsVerification()) {
if (DEBUG_DOMAIN_VERIFICATION) { if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, Slog.d(TAG, "autoVerify requested, processing all filters");
"Intent filter needs verification, so 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; 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++; final int verificationId = mIntentFilterVerificationToken++;
for (PackageParser.Activity a : pkg.activities) { for (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) { for (ActivityIntentInfo filter : a.intents) {
// Run verification against hosts mentioned in any web-nav intent filter, // Run verification against hosts mentioned in any web-nav intent filter,
// even if the filter matches non-web schemes as well // 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, if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Verification needed for IntentFilter:" + filter.toString()); "Verification needed for IntentFilter:" + filter.toString());
mIntentFilterVerifier.addOneIntentFilterVerification( mIntentFilterVerifier.addOneIntentFilterVerification(
verifierUid, userId, verificationId, filter, packageName); verifierUid, userId, verificationId, filter, packageName);
domains.addAll(filter.getHostsList());
count++; 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 if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
+ " IntentFilter verification" + (count > 1 ? "s" : "") + " IntentFilter verification" + (count > 1 ? "s" : "")
+ " for userId:" + userId); + " for userId:" + userId);
mIntentFilterVerifier.startVerifications(userId); mIntentFilterVerifier.startVerifications(userId);
} else { } else {
if (DEBUG_DOMAIN_VERIFICATION) { 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( IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
packageName); packageName);
if (ivi == null) { if (ivi == null) {
@@ -17811,6 +17901,7 @@ public class PackageManagerService extends IPackageManager.Stub
int status = ivi.getStatus(); int status = ivi.getStatus();
switch (status) { switch (status) {
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
return true; return true;
@@ -18524,7 +18615,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean installedStateChanged = false; boolean installedStateChanged = false;
if (deletedPs != null) { if (deletedPs != null) {
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) { if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL); clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
clearDefaultBrowserIfNeeded(packageName); clearDefaultBrowserIfNeeded(packageName);
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
removedAppId = mSettings.removePackageLPw(packageName); removedAppId = mSettings.removePackageLPw(packageName);
@@ -19912,12 +20003,13 @@ public class PackageManagerService extends IPackageManager.Stub
final int packageCount = mPackages.size(); final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) { for (int i = 0; i < packageCount; i++) {
PackageParser.Package pkg = mPackages.valueAt(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. */ /** 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 (userId == UserHandle.USER_ALL) {
if (mSettings.removeIntentFilterVerificationLPw(packageName, if (mSettings.removeIntentFilterVerificationLPw(packageName,
sUserManager.getUserIds())) { sUserManager.getUserIds())) {
@@ -19926,7 +20018,8 @@ public class PackageManagerService extends IPackageManager.Stub
} }
} }
} else { } else {
if (mSettings.removeIntentFilterVerificationLPw(packageName, userId)) { if (mSettings.removeIntentFilterVerificationLPw(packageName, userId,
alsoResetStatus)) {
scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageRestrictionsLocked(userId);
} }
} }

View File

@@ -1310,7 +1310,8 @@ public final class Settings {
return result; return result;
} }
boolean removeIntentFilterVerificationLPw(String packageName, int userId) { boolean removeIntentFilterVerificationLPw(String packageName, int userId,
boolean alsoResetStatus) {
PackageSetting ps = mPackages.get(packageName); PackageSetting ps = mPackages.get(packageName);
if (ps == null) { if (ps == null) {
if (DEBUG_DOMAIN_VERIFICATION) { if (DEBUG_DOMAIN_VERIFICATION) {
@@ -1318,14 +1319,17 @@ public final class Settings {
} }
return false; return false;
} }
ps.clearDomainVerificationStatusForUser(userId); if (alsoResetStatus) {
ps.clearDomainVerificationStatusForUser(userId);
}
ps.setIntentFilterVerificationInfo(null);
return true; return true;
} }
boolean removeIntentFilterVerificationLPw(String packageName, int[] userIds) { boolean removeIntentFilterVerificationLPw(String packageName, int[] userIds) {
boolean result = false; boolean result = false;
for (int userId : userIds) { for (int userId : userIds) {
result |= removeIntentFilterVerificationLPw(packageName, userId); result |= removeIntentFilterVerificationLPw(packageName, userId, true);
} }
return result; return result;
} }