DO NOT MERGE - Only autoVerify at install for new hosts
Re-run app link verification at update time only when the set of hosts has expanded. Intentionally revoke verify history when an app stops using autoVerify, as a one-time measure to place it back into the non-autoverify model for tracking the user's launch preferences. If the app starts using autoVerify again later, it behaves identically to an app that has never done so before. Bug: 151475497 Bug: 146204120 Test: described on master CL Merged-In: I200d85085ce79842a3ed39377d1f75ec381c8991 Merged-In: Ibaf087946966ad82d60c7b255e3ee75990716b63 Change-Id: Ibaf087946966ad82d60c7b255e3ee75990716b63
This commit is contained in:
committed by
Chris Tate
parent
6255311d39
commit
90b716a442
@@ -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;
|
||||
// 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;
|
||||
|
||||
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
|
||||
if (verified) {
|
||||
updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
|
||||
needUpdate = true;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
|
||||
default:
|
||||
// Nothing to do
|
||||
}
|
||||
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
|
||||
@@ -18436,70 +18472,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) {
|
||||
@@ -18508,6 +18599,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;
|
||||
|
||||
@@ -19202,7 +19294,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);
|
||||
@@ -20482,12 +20574,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())) {
|
||||
@@ -20496,7 +20589,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mSettings.removeIntentFilterVerificationLPw(packageName, userId)) {
|
||||
if (mSettings.removeIntentFilterVerificationLPw(packageName, userId,
|
||||
alsoResetStatus)) {
|
||||
scheduleWritePackageRestrictionsLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user