diff options
| author | 2021-01-19 11:35:33 -0800 | |
|---|---|---|
| committer | 2021-02-04 10:27:00 -0800 | |
| commit | 0af8c46c2fa7653e15c21c29b4a0f9dfb986f086 (patch) | |
| tree | b59839b0d926a18bcad94656e38c4f3f0a5eeec8 | |
| parent | c89bd75a18c53e7205eb0bbfbb4179edcec465c1 (diff) | |
Migrate legacy intent filter verification settings
These legacy settings need to be migrated once to the new domain
verification API, so this pulls the parsing out of the legacy classes
into a DomainVerificationLegacySettings.
This does NOT handle serializing the legacy settings. It's assumed
that migration is a one-time best effort attempt, and that dropping
the legacy settings is an acceptable fallback.
The old setting was a result of an unexplained and unintuitive user
path, set through ResolverActivity, and so it's not clear whether we
should migrate at all.
Worst case, the user can always re-do their preferences.
NOTE: This change should only be merged if merged together with the
change that removes the legacy code. It's invalid to run these
separately, as this change breaks the legacy manager class. These are
only separate to make review easier, to separate their concerns.
Exempt-From-Owner-Approval: Already approved by owners on main branch
Bug: 171251883
Test: TODO
Change-Id: Iefde9f2cd8ab73cb5f592abc7d2163dd7d244789
17 files changed, 573 insertions, 213 deletions
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 99258712030c..5cc74c0a1c8e 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -77,8 +77,6 @@ public class PackageUserState { public boolean virtualPreload; public int enabled; public String lastDisableAppCaller; - public int domainVerificationStatus; - public int appLinkGeneration; public int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED; public int installReason; public @PackageManager.UninstallReason int uninstallReason; @@ -100,8 +98,6 @@ public class PackageUserState { hidden = false; suspended = false; enabled = COMPONENT_ENABLED_STATE_DEFAULT; - domainVerificationStatus = - PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; installReason = PackageManager.INSTALL_REASON_UNKNOWN; uninstallReason = PackageManager.UNINSTALL_REASON_UNKNOWN; } @@ -120,8 +116,6 @@ public class PackageUserState { virtualPreload = o.virtualPreload; enabled = o.enabled; lastDisableAppCaller = o.lastDisableAppCaller; - domainVerificationStatus = o.domainVerificationStatus; - appLinkGeneration = o.appLinkGeneration; categoryHint = o.categoryHint; installReason = o.installReason; uninstallReason = o.uninstallReason; @@ -416,12 +410,6 @@ public class PackageUserState { && !lastDisableAppCaller.equals(oldState.lastDisableAppCaller))) { return false; } - if (domainVerificationStatus != oldState.domainVerificationStatus) { - return false; - } - if (appLinkGeneration != oldState.appLinkGeneration) { - return false; - } if (categoryHint != oldState.categoryHint) { return false; } @@ -481,8 +469,6 @@ public class PackageUserState { hashCode = 31 * hashCode + Boolean.hashCode(virtualPreload); hashCode = 31 * hashCode + enabled; hashCode = 31 * hashCode + Objects.hashCode(lastDisableAppCaller); - hashCode = 31 * hashCode + domainVerificationStatus; - hashCode = 31 * hashCode + appLinkGeneration; hashCode = 31 * hashCode + categoryHint; hashCode = 31 * hashCode + installReason; hashCode = 31 * hashCode + uninstallReason; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 42d900f04060..cbc66ac64436 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -238,7 +238,6 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; -import android.content.pm.domain.verify.DomainVerificationManager; import android.content.pm.parsing.ApkLiteParseUtils; import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.ParsingPackageUtils; @@ -386,7 +385,6 @@ import com.android.server.pm.domain.verify.proxy.DomainVerificationProxyV2; import com.android.server.pm.intent.verify.legacy.IntentFilterVerificationManager; import com.android.server.pm.intent.verify.legacy.IntentFilterVerificationParams; import com.android.server.pm.intent.verify.legacy.IntentVerifierProxy; -import com.android.server.pm.intent.verify.legacy.IntentVerifyUtils; import com.android.server.pm.parsing.PackageCacher; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.PackageParser2; @@ -1814,7 +1812,7 @@ public class PackageManagerService extends IPackageManager.Stub @NonNull @Override public WatchedSparseIntArray getNextAppLinkGeneration() { - return mSettings.mNextAppLinkGeneration; + return null; } @NonNull @@ -2753,7 +2751,8 @@ public class PackageManagerService extends IPackageManager.Stub } // Try to get the status from User settings first - long packedStatus = IntentVerifyUtils.getDomainVerificationStatus(ps, userId); + long packedStatus = 0; + //IntentVerifyUtils.getDomainVerificationStatus(ps, userId); int status = (int)(packedStatus >> 32); int linkGeneration = (int)(packedStatus & 0xFFFFFFFF); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { @@ -2980,8 +2979,8 @@ public class PackageManagerService extends IPackageManager.Stub result.wereAnyDomainsVerificationApproved |= mDomainVerificationManager .isApprovedForDomain(ps, intent, riTargetUser.targetUserId); } else { - long verificationState = - IntentVerifyUtils.getDomainVerificationStatus(ps, parentUserId); + long verificationState = 0; + //IntentVerifyUtils.getDomainVerificationStatus(ps, parentUserId); int status = (int) (verificationState >> 32); result.bestDomainVerificationStatus = bestDomainVerificationStatus(status, result.bestDomainVerificationStatus); @@ -3257,8 +3256,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - final long packedStatus = - IntentVerifyUtils.getDomainVerificationStatus(ps, userId); + final long packedStatus = 0; + //IntentVerifyUtils.getDomainVerificationStatus(ps, userId); final int status = (int)(packedStatus >> 32); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { // there's a local instant application installed, but, the user has @@ -4202,8 +4201,8 @@ public class PackageManagerService extends IPackageManager.Stub } } else { // Try to get the status from User settings first - final long packedStatus = - IntentVerifyUtils.getDomainVerificationStatus(ps, userId); + final long packedStatus = 0; + //IntentVerifyUtils.getDomainVerificationStatus(ps, userId); final int status = (int) (packedStatus >> 32); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS || status @@ -9655,8 +9654,8 @@ public class PackageManagerService extends IPackageManager.Stub return ri; } } else { - final long packedStatus = - IntentVerifyUtils.getDomainVerificationStatus(ps, userId); + final long packedStatus = 0; + //IntentVerifyUtils.getDomainVerificationStatus(ps, userId); final int status = (int) (packedStatus >> 32); if (status != INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) { return ri; @@ -16447,13 +16446,13 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int getIntentVerificationStatus(String packageName, int userId) { - return mIntentFilterVerificationManager.getIntentVerificationStatus(packageName, userId); + return mDomainVerificationManager.getLegacyState(packageName, userId); } @Override public boolean updateIntentVerificationStatus(String packageName, int status, int userId) { - return mIntentFilterVerificationManager.updateIntentVerificationStatus(packageName, status, - userId); + mDomainVerificationManager.setLegacyUserState(packageName, userId, status); + return true; } @Override @@ -21681,8 +21680,6 @@ public class PackageManagerService extends IPackageManager.Stub null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, - ps.readUserState(nextUserId).domainVerificationStatus, - 0 /*linkGeneration*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, null /*harmfulAppWarning*/); diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index b69d2b015d6c..d3005184e087 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -133,8 +133,6 @@ public abstract class PackageSettingBase extends SettingBase { /** Whether or not an update is available. Ostensibly only for instant apps. */ boolean updateAvailable; - IntentFilterVerificationInfo verificationInfo; - boolean forceQueryableOverride; @NonNull @@ -260,7 +258,6 @@ public abstract class PackageSettingBase extends SettingBase { for (int i = 0; i < orig.mUserState.size(); i++) { mUserState.put(orig.mUserState.keyAt(i), orig.mUserState.valueAt(i)); } - verificationInfo = orig.verificationInfo; versionCode = orig.versionCode; volumeUuid = orig.volumeUuid; categoryHint = orig.categoryHint; @@ -354,12 +351,6 @@ public abstract class PackageSettingBase extends SettingBase { /** * Only use for testing. Do NOT use in production code. - * - * Unless you're {@link DomainVerificationService} and you need to migrate legacy state. - * This is done rather than passing in the user IDs to - * {@link DomainVerificationManagerInternal#addPackage(PackageSetting)} to make the v2 APIs - * completely correct, without legacy details, since that method inherently does not care about - * the users on the device. */ @VisibleForTesting @Deprecated @@ -507,8 +498,7 @@ public abstract class PackageSettingBase extends SettingBase { ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp, boolean virtualPreload, String lastDisableAppCaller, ArraySet<String> enabledComponents, ArraySet<String> disabledComponents, - int domainVerifState, int linkGeneration, int installReason, int uninstallReason, - String harmfulAppWarning) { + int installReason, int uninstallReason, String harmfulAppWarning) { PackageUserState state = modifyUserState(userId); state.ceDataInode = ceDataInode; state.enabled = enabled; @@ -522,8 +512,6 @@ public abstract class PackageSettingBase extends SettingBase { state.lastDisableAppCaller = lastDisableAppCaller; state.enabledComponents = enabledComponents; state.disabledComponents = disabledComponents; - state.domainVerificationStatus = domainVerifState; - state.appLinkGeneration = linkGeneration; state.installReason = installReason; state.uninstallReason = uninstallReason; state.instantApp = instantApp; @@ -539,7 +527,6 @@ public abstract class PackageSettingBase extends SettingBase { otherState.instantApp, otherState.virtualPreload, otherState.lastDisableAppCaller, otherState.enabledComponents, otherState.disabledComponents, - otherState.domainVerificationStatus, otherState.appLinkGeneration, otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning); } @@ -655,40 +642,6 @@ public abstract class PackageSettingBase extends SettingBase { return excludedUserIds; } - public IntentFilterVerificationInfo getIntentFilterVerificationInfo() { - return verificationInfo; - } - - public void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) { - verificationInfo = info; - onChanged(); - } - - // Returns a packed value as a long: - // - // high 'int'-sized word: link status: undefined/ask/never/always. - // low 'int'-sized word: relative priority among 'always' results. - public long getDomainVerificationStatusForUser(int userId) { - PackageUserState state = readUserState(userId); - long result = (long) state.appLinkGeneration; - result |= ((long) state.domainVerificationStatus) << 32; - return result; - } - - public void setDomainVerificationStatusForUser(final int status, int generation, int userId) { - PackageUserState state = modifyUserState(userId); - state.domainVerificationStatus = status; - if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { - state.appLinkGeneration = generation; - onChanged(); - } - } - - public void clearDomainVerificationStatusForUser(int userId) { - modifyUserState(userId).domainVerificationStatus = - PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; - } - protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) { int count = mUserState.size(); for (int i = 0; i < count; i++) { @@ -856,7 +809,6 @@ public abstract class PackageSettingBase extends SettingBase { this.volumeUuid = other.volumeUuid; this.categoryHint = other.categoryHint; this.updateAvailable = other.updateAvailable; - this.verificationInfo = other.verificationInfo; this.forceQueryableOverride = other.forceQueryableOverride; this.incrementalStates = other.incrementalStates; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 689830bd6b98..43617cf9a0c9 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -21,7 +21,6 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; import static android.content.pm.PackageManager.UNINSTALL_REASON_USER_TYPE; @@ -106,6 +105,7 @@ import com.android.permission.persistence.RuntimePermissionsState; import com.android.server.LocalServices; import com.android.server.backup.PreferredActivityBackupHelper; import com.android.server.pm.Installer.InstallerException; +import com.android.server.pm.domain.verify.DomainVerificationLegacySettings; import com.android.server.pm.domain.verify.DomainVerificationManagerInternal; import com.android.server.pm.domain.verify.DomainVerificationPersistence; import com.android.server.pm.intent.verify.legacy.IntentFilterVerificationManager; @@ -557,7 +557,6 @@ public final class Settings implements Watchable, Snappable { mOtherAppIds.registerObserver(mObserver); mRenamedPackages.registerObserver(mObserver); mDefaultBrowserApp.registerObserver(mObserver); - mNextAppLinkGeneration.registerObserver(mObserver); Watchable.verifyWatchedAttributes(this, mObserver); } @@ -610,7 +609,6 @@ public final class Settings implements Watchable, Snappable { mOtherAppIds.registerObserver(mObserver); mRenamedPackages.registerObserver(mObserver); mDefaultBrowserApp.registerObserver(mObserver); - mNextAppLinkGeneration.registerObserver(mObserver); Watchable.verifyWatchedAttributes(this, mObserver); } @@ -659,7 +657,6 @@ public final class Settings implements Watchable, Snappable { mKeySetRefs.putAll(r.mKeySetRefs); mRenamedPackages.snapshot(r.mRenamedPackages); mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp); - mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration); // mReadMessages mPendingPackages.addAll(r.mPendingPackages); mSystemDir = null; @@ -938,8 +935,6 @@ public final class Settings implements Watchable, Snappable { null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, - 0 /*linkGeneration*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, null /*harmfulAppWarning*/); @@ -1182,12 +1177,6 @@ public final class Settings implements Watchable, Snappable { replaceAppIdLPw(p.appId, sharedUser); } } - - IntentFilterVerificationInfo info = - mIntentFilterVerificationManager.getRestoredIntentFilterVerificationInfo(p.name); - if (info != null) { - p.setIntentFilterVerificationInfo(info); - } } int removePackageLPw(String name) { @@ -1582,8 +1571,6 @@ public final class Settings implements Watchable, Snappable { null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, - 0 /*linkGeneration*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, null /*harmfulAppWarning*/); @@ -1608,8 +1595,6 @@ public final class Settings implements Watchable, Snappable { return; } - int maxAppLinkGeneration = 0; - int outerDepth = parser.getDepth(); PackageSetting ps = null; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -1672,11 +1657,6 @@ public final class Settings implements Watchable, Snappable { final int verifState = parser.getAttributeInt(null, ATTR_DOMAIN_VERIFICATON_STATE, PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); - final int linkGeneration = - parser.getAttributeInt(null, ATTR_APP_LINK_GENERATION, 0); - if (linkGeneration > maxAppLinkGeneration) { - maxAppLinkGeneration = linkGeneration; - } final int installReason = parser.getAttributeInt(null, ATTR_INSTALL_REASON, PackageManager.INSTALL_REASON_UNKNOWN); final int uninstallReason = parser.getAttributeInt(null, ATTR_UNINSTALL_REASON, @@ -1752,9 +1732,10 @@ public final class Settings implements Watchable, Snappable { } ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched, hidden, distractionFlags, suspended, suspendParamsMap, - instantApp, virtualPreload, - enabledCaller, enabledComponents, disabledComponents, verifState, - linkGeneration, installReason, uninstallReason, harmfulAppWarning); + instantApp, virtualPreload, enabledCaller, enabledComponents, + disabledComponents, installReason, uninstallReason, harmfulAppWarning); + + mDomainVerificationManager.setLegacyUserState(name, userId, verifState); } else if (tagName.equals("preferred-activities")) { readPreferredActivitiesLPw(parser, userId); } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { @@ -1773,9 +1754,6 @@ public final class Settings implements Watchable, Snappable { } str.close(); - - mNextAppLinkGeneration.put(userId, maxAppLinkGeneration + 1); - } catch (XmlPullParserException e) { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, @@ -2002,15 +1980,6 @@ public final class Settings implements Watchable, Snappable { ustate.lastDisableAppCaller); } } - if (ustate.domainVerificationStatus != - PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { - serializer.attributeInt(null, ATTR_DOMAIN_VERIFICATON_STATE, - ustate.domainVerificationStatus); - } - if (ustate.appLinkGeneration != 0) { - serializer.attributeInt(null, ATTR_APP_LINK_GENERATION, - ustate.appLinkGeneration); - } if (ustate.installReason != PackageManager.INSTALL_REASON_UNKNOWN) { serializer.attributeInt(null, ATTR_INSTALL_REASON, ustate.installReason); } @@ -2747,8 +2716,7 @@ public final class Settings implements Watchable, Snappable { writeSigningKeySetLPr(serializer, pkg.keySetData); writeUpgradeKeySetsLPr(serializer, pkg.keySetData); writeKeySetAliasesLPr(serializer, pkg.keySetData); - mIntentFilterVerificationManager.writeDomainVerificationsLPr(serializer, - pkg.verificationInfo); + mDomainVerificationManager.writeLegacySettings(serializer, pkg.name); writeMimeGroupLPr(serializer, pkg.mimeGroups); serializer.endTag(null, "package"); @@ -2924,7 +2892,10 @@ public final class Settings implements Watchable, Snappable { ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT); } else if (tagName.equals(DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) { mDomainVerificationManager.readSettings(parser); - }else { + } else if (tagName.equals( + DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) { + mDomainVerificationManager.readLegacySettings(parser); + } else { Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: " + parser.getName()); XmlUtils.skipCurrentTag(parser); @@ -3739,9 +3710,8 @@ public final class Settings implements Watchable, Snappable { packageSetting.installSource = packageSetting.installSource.setInitiatingPackageSignatures(signatures); } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) { - IntentFilterVerificationInfo ivi = - mIntentFilterVerificationManager.readDomainVerificationLPw(parser); - packageSetting.setIntentFilterVerificationInfo(ivi); + IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser); + mDomainVerificationManager.addLegacySetting(packageSetting.name, ivi); if (DEBUG_PARSER) { Log.d(TAG, "Read domain verification for package: " + ivi.getPackageName()); } diff --git a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationCollector.java index 5aaa37e9dadd..832714f2bfe6 100644 --- a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationCollector.java +++ b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationCollector.java @@ -88,9 +88,8 @@ public class DomainVerificationCollector { @NonNull private ArraySet<String> collectDomains(@NonNull AndroidPackage pkg, boolean checkAutoVerify) { - @SuppressWarnings("ConstantConditions") - boolean restrictDomains = Binder.withCleanCallingIdentity( - () -> mPlatformCompat.isChangeEnabled(RESTRICT_DOMAINS, buildMockAppInfo(pkg))); + boolean restrictDomains = + DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, RESTRICT_DOMAINS); ArraySet<String> domains = new ArraySet<>(); @@ -198,19 +197,4 @@ public class DomainVerificationCollector { } } } - - /** - * Passed to {@link PlatformCompat} because this can be invoked mid-install process, and - * {@link PlatformCompat} will not be able to query the pending {@link ApplicationInfo} from - * {@link PackageManager}. - * - * TODO(b/177613575): Can a different API be used? - */ - @NonNull - private ApplicationInfo buildMockAppInfo(@NonNull AndroidPackage pkg) { - ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.packageName = pkg.getPackageName(); - appInfo.targetSdkVersion = pkg.getTargetSdkVersion(); - return appInfo; - } } diff --git a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationEnforcer.java b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationEnforcer.java index 05b1c47f8b27..cdcc5fcba7b5 100644 --- a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationEnforcer.java +++ b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationEnforcer.java @@ -118,4 +118,11 @@ public class DomainVerificationEnforcer { Binder.getCallingPid(), callingUid, "Caller is not allowed to edit user selections"); } + + public void callerIsLegacyUserSelector(int callingUid) { + mContext.enforcePermission( + android.Manifest.permission.SET_PREFERRED_APPLICATIONS, + Binder.getCallingPid(), callingUid, + "Caller is not allowed to edit user state"); + } } diff --git a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationLegacySettings.java b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationLegacySettings.java new file mode 100644 index 000000000000..09307d2a2db1 --- /dev/null +++ b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationLegacySettings.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.domain.verify; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.content.pm.IntentFilterVerificationInfo; +import android.content.pm.PackageManager; +import android.util.ArrayMap; +import android.util.SparseIntArray; +import android.util.TypedXmlPullParser; +import android.util.TypedXmlSerializer; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.pm.SettingsXml; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Map; + +/** + * Reads and writes the old {@link android.content.pm.IntentFilterVerificationInfo} so that it can + * be migrated in to the new API. Will throw away the state once it's successfully applied so that + * eventually there will be no legacy state on the device. + * + * This attempt is best effort, and if the legacy state is lost that's acceptable. The user setting + * in the legacy API may have been set incorrectly because it was never made obvious to the user + * what it actually toggled, so there's a strong argument to prevent migration anyways. The user + * can just set their preferences again, this time with finer grained control, if the legacy state + * gets dropped. + */ +public class DomainVerificationLegacySettings { + + public static final String TAG_DOMAIN_VERIFICATIONS_LEGACY = "domain-verifications-legacy"; + public static final String TAG_USER_STATES = "user-states"; + public static final String ATTR_PACKAGE_NAME = "packageName"; + public static final String TAG_USER_STATE = "user-state"; + public static final String ATTR_USER_ID = "userId"; + public static final String ATTR_STATE = "state"; + + @NonNull + private final Object mLock = new Object(); + + @NonNull + private final ArrayMap<String, LegacyState> mStates = new ArrayMap<>(); + + public void add(@NonNull String packageName, @NonNull IntentFilterVerificationInfo info) { + synchronized (mLock) { + getOrCreateStateLocked(packageName).setInfo(info); + } + } + + public void add(@NonNull String packageName, @UserIdInt int userId, int state) { + synchronized (mLock) { + getOrCreateStateLocked(packageName).addUserState(userId, state); + } + } + + public int getUserState(@NonNull String packageName, @UserIdInt int userId) { + synchronized (mLock) { + LegacyState state = mStates.get(packageName); + if (state != null) { + return state.getUserState(userId); + } + } + return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; + } + + @Nullable + public SparseIntArray getUserStates(@NonNull String packageName) { + synchronized (mLock) { + LegacyState state = mStates.get(packageName); + if (state != null) { + // Yes, this returns outside of the lock, but we assume that retrieval generally + // only happens after all adding has concluded from reading settings. + return state.getUserStates(); + } + } + return null; + } + + @Nullable + public IntentFilterVerificationInfo remove(@NonNull String packageName) { + synchronized (mLock) { + LegacyState state = mStates.get(packageName); + if (state != null && !state.isAttached()) { + state.markAttached(); + return state.getInfo(); + } + } + return null; + } + + @GuardedBy("mLock") + @NonNull + private LegacyState getOrCreateStateLocked(@NonNull String packageName) { + LegacyState state = mStates.get(packageName); + if (state == null) { + state = new LegacyState(); + mStates.put(packageName, state); + } + + return state; + } + + public void writeSettings(TypedXmlSerializer xmlSerializer) throws IOException { + try (SettingsXml.Serializer serializer = SettingsXml.serializer(xmlSerializer)) { + try (SettingsXml.WriteSection ignored = + serializer.startSection(TAG_DOMAIN_VERIFICATIONS_LEGACY)) { + synchronized (mLock) { + final int statesSize = mStates.size(); + for (int stateIndex = 0; stateIndex < statesSize; stateIndex++) { + final LegacyState state = mStates.valueAt(stateIndex); + final SparseIntArray userStates = state.getUserStates(); + if (userStates == null) { + continue; + } + + final String packageName = mStates.keyAt(stateIndex); + try (SettingsXml.WriteSection userStatesSection = + serializer.startSection(TAG_USER_STATES) + .attribute(ATTR_PACKAGE_NAME, packageName)) { + final int userStatesSize = userStates.size(); + for (int userStateIndex = 0; userStateIndex < userStatesSize; + userStateIndex++) { + final int userId = userStates.keyAt(userStateIndex); + final int userState = userStates.valueAt(userStateIndex); + userStatesSection.startSection(TAG_USER_STATE) + .attribute(ATTR_USER_ID, userId) + .attribute(ATTR_STATE, userState) + .finish(); + } + } + } + } + } + } + } + + public void readSettings(TypedXmlPullParser xmlParser) + throws IOException, XmlPullParserException { + final SettingsXml.ChildSection child = SettingsXml.parser(xmlParser).children(); + while (child.moveToNext()) { + if (TAG_USER_STATES.equals(child.getName())) { + readUserStates(child); + } + } + } + + private void readUserStates(SettingsXml.ReadSection section) { + String packageName = section.getString(ATTR_PACKAGE_NAME); + synchronized (mLock) { + final LegacyState legacyState = getOrCreateStateLocked(packageName); + final SettingsXml.ChildSection child = section.children(); + while (child.moveToNext()) { + if (TAG_USER_STATE.equals(child.getName())) { + readUserState(child, legacyState); + } + } + } + } + + private void readUserState(SettingsXml.ReadSection section, LegacyState legacyState) { + int userId = section.getInt(ATTR_USER_ID); + int state = section.getInt(ATTR_STATE); + legacyState.addUserState(userId, state); + } + + static class LegacyState { + @Nullable + private IntentFilterVerificationInfo mInfo; + + @Nullable + private SparseIntArray mUserStates; + + private boolean attached; + + @Nullable + public IntentFilterVerificationInfo getInfo() { + return mInfo; + } + + public int getUserState(int userId) { + return mUserStates.get(userId, + PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); + } + + @Nullable + public SparseIntArray getUserStates() { + return mUserStates; + } + + public void setInfo(@NonNull IntentFilterVerificationInfo info) { + mInfo = info; + } + + public void addUserState(@UserIdInt int userId, int state) { + if (mUserStates == null) { + mUserStates = new SparseIntArray(1); + } + mUserStates.put(userId, state); + } + + public boolean isAttached() { + return attached; + } + + public void markAttached() { + attached = true; + } + } +} diff --git a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationManagerInternal.java index 9ef498780393..56994c864870 100644 --- a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationManagerInternal.java +++ b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationManagerInternal.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.content.Intent; +import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.domain.verify.DomainVerificationManager; import android.content.pm.domain.verify.DomainVerificationSet; @@ -31,6 +32,7 @@ import android.util.TypedXmlSerializer; import com.android.server.pm.PackageSetting; import com.android.server.pm.domain.verify.models.DomainVerificationPkgState; import com.android.server.pm.domain.verify.proxy.DomainVerificationProxy; +import com.android.server.pm.parsing.pkg.AndroidPackage; import org.xmlpull.v1.XmlPullParserException; @@ -103,15 +105,14 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan /** * Serializes the entire internal state. This is equivalent to a full backup of the existing - * verification state. + * verification state. This write includes legacy state, as a sibling tag the modern state. */ void writeSettings(@NonNull TypedXmlSerializer serializer) throws IOException; /** * Read back a list of {@link DomainVerificationPkgState}s previously written by {@link * #writeSettings(TypedXmlSerializer)}. Assumes that the - * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS} - * tag has already been entered. + * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS} tag has already been entered. * <p> * This is expected to only be used to re-attach states for packages already known to be on the * device. If restoring from a backup, use {@link #restoreSettings(TypedXmlPullParser)}. @@ -120,6 +121,15 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan throws IOException, XmlPullParserException; /** + * Read back data from + * {@link DomainVerificationLegacySettings#writeSettings(TypedXmlSerializer)}. Assumes that the + * {@link DomainVerificationLegacySettings#TAG_DOMAIN_VERIFICATIONS_LEGACY} tag has already + * been entered. + */ + void readLegacySettings(@NonNull TypedXmlPullParser parser) + throws IOException, XmlPullParserException; + + /** * Remove all state for the given package. */ void clearPackage(@NonNull String packageName); @@ -149,6 +159,32 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan throws IOException, XmlPullParserException; /** + * Set aside a legacy {@link IntentFilterVerificationInfo} that will be restored to a pending + * {@link DomainVerificationPkgState} once it's added through + * {@link #addPackage(PackageSetting)}. + */ + void addLegacySetting(@NonNull String packageName, @NonNull IntentFilterVerificationInfo info); + + /** + * Set aside a legacy user selection that will be restored to a pending + * {@link DomainVerificationPkgState} once it's added through + * {@link #addPackage(PackageSetting)}. + */ + void setLegacyUserState(@NonNull String packageName, @UserIdInt int userId, int state); + + /** + * Until the legacy APIs are entirely removed, returns the legacy state from the previously + * written info stored in {@link com.android.server.pm.Settings}. + */ + int getLegacyState(@NonNull String packageName, @UserIdInt int userId); + + /** + * Serialize a legacy setting that wasn't attached yet. + * TODO: Does this even matter? Should consider for removal. + */ + void writeLegacySettings(TypedXmlSerializer serializer, String name); + + /** * Print the verification state and user selection state of a package. * * @param packageName the package whose state to change, or all packages if none is specified diff --git a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationService.java b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationService.java index 0a28069017d4..ace72090193a 100644 --- a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationService.java +++ b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationService.java @@ -19,6 +19,8 @@ package com.android.server.pm.domain.verify; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.content.Context; import android.content.Intent; import android.content.pm.IntentFilterVerificationInfo; @@ -38,6 +40,7 @@ import android.util.IndentingPrintWriter; import android.util.Singleton; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; @@ -74,6 +77,19 @@ public class DomainVerificationService extends SystemService public static final boolean DEBUG_APPROVAL = true; /** + * The new user preference API for verifying domains marked autoVerify=true in + * AndroidManifest.xml intent filters is not yet implemented in the current platform preview. + * This is anticipated to ship before S releases. + * + * For now, it is possible to preview the new user preference changes by enabling this + * ChangeId and using the <code>adb shell pm set-app-links-user-selection</code> and similar + * commands. + */ + @ChangeId + @Disabled + private static final long SETTINGS_API_V2 = 178111421; + + /** * States that are currently alive and attached to a package. Entries are exclusive with the * state stored in {@link DomainVerificationSettings}, as any pending/restored state should be * immediately attached once its available. @@ -100,6 +116,9 @@ public class DomainVerificationService extends SystemService private final SystemConfig mSystemConfig; @NonNull + private final PlatformCompat mPlatformCompat; + + @NonNull private final DomainVerificationSettings mSettings; @NonNull @@ -115,6 +134,9 @@ public class DomainVerificationService extends SystemService private final DomainVerificationShell mShell; @NonNull + private final DomainVerificationLegacySettings mLegacySettings; + + @NonNull private final IDomainVerificationManager.Stub mStub = new DomainVerificationManagerStub(this); @NonNull @@ -125,11 +147,13 @@ public class DomainVerificationService extends SystemService super(context); mConnection = connection; mSystemConfig = systemConfig; + mPlatformCompat = platformCompat; mSettings = new DomainVerificationSettings(); mCollector = new DomainVerificationCollector(platformCompat, systemConfig); mEnforcer = new DomainVerificationEnforcer(context); mDebug = new DomainVerificationDebug(mCollector); mShell = new DomainVerificationShell(this); + mLegacySettings = new DomainVerificationLegacySettings(); } @Override @@ -401,6 +425,8 @@ public class DomainVerificationService extends SystemService .setDisallowLinkHandling(!allowed); } } + + mConnection.get().scheduleWriteSettings(); } @Override @@ -473,6 +499,8 @@ public class DomainVerificationService extends SystemService enabled, domains); } } + + mConnection.get().scheduleWriteSettings(); } private void setDomainVerificationUserSelectionInternal(int userId, @@ -500,6 +528,8 @@ public class DomainVerificationService extends SystemService userState.removeHosts(domains); } } + + mConnection.get().scheduleWriteSettings(); } @Nullable @@ -693,12 +723,11 @@ public class DomainVerificationService extends SystemService // and disable them if appropriate. ArraySet<String> webDomains = null; - @SuppressWarnings("deprecation") - SparseArray<PackageUserState> userState = newPkgSetting.getUserState(); - int userStateSize = userState.size(); + SparseIntArray legacyUserStates = mLegacySettings.getUserStates(pkgName); + int userStateSize = legacyUserStates == null ? 0 : legacyUserStates.size(); for (int index = 0; index < userStateSize; index++) { - int userId = userState.keyAt(index); - int legacyStatus = userState.valueAt(index).domainVerificationStatus; + int userId = legacyUserStates.keyAt(index); + int legacyStatus = legacyUserStates.valueAt(index); if (legacyStatus == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { if (webDomains == null) { @@ -709,8 +738,7 @@ public class DomainVerificationService extends SystemService } } - IntentFilterVerificationInfo legacyInfo = - newPkgSetting.getIntentFilterVerificationInfo(); + IntentFilterVerificationInfo legacyInfo = mLegacySettings.remove(pkgName); if (legacyInfo != null && legacyInfo.getStatus() == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { @@ -772,6 +800,8 @@ public class DomainVerificationService extends SystemService synchronized (mLock) { mSettings.writeSettings(serializer, mAttachedPkgStates); } + + mLegacySettings.writeSettings(serializer); } @Override @@ -783,6 +813,12 @@ public class DomainVerificationService extends SystemService } @Override + public void readLegacySettings(@NonNull TypedXmlPullParser parser) + throws IOException, XmlPullParserException { + mLegacySettings.readSettings(parser); + } + + @Override public void restoreSettings(@NonNull TypedXmlPullParser parser) throws IOException, XmlPullParserException { synchronized (mLock) { @@ -791,6 +827,28 @@ public class DomainVerificationService extends SystemService } @Override + public void addLegacySetting(@NonNull String packageName, + @NonNull IntentFilterVerificationInfo info) { + mLegacySettings.add(packageName, info); + } + + @Override + public void setLegacyUserState(@NonNull String packageName, @UserIdInt int userId, int state) { + mEnforcer.callerIsLegacyUserSelector(mConnection.get().getCallingUid()); + mLegacySettings.add(packageName, userId, state); + } + + @Override + public int getLegacyState(@NonNull String packageName, @UserIdInt int userId) { + return mLegacySettings.getUserState(packageName, userId); + } + + @Override + public void writeLegacySettings(TypedXmlSerializer serializer, String name) { + + } + + @Override public void clearPackage(@NonNull String packageName) { synchronized (mLock) { mAttachedPkgStates.remove(packageName); @@ -1051,13 +1109,36 @@ public class DomainVerificationService extends SystemService return false; } - // To allow an instant app to immediately open domains after being installed by the user, - // auto approve them for any declared autoVerify domains. String host = intent.getData().getHost(); final AndroidPackage pkg = pkgSetting.getPkg(); - if (pkgSetting.getInstantApp(userId) && pkg != null - && mCollector.collectAutoVerifyDomains(pkg).contains(host)) { - return true; + + // Should never be null, but if it is, skip this and assume that v2 is enabled + if (pkg != null) { + // To allow an instant app to immediately open domains after being installed by the + // user, auto approve them for any declared autoVerify domains. + if (pkgSetting.getInstantApp(userId) + && mCollector.collectAutoVerifyDomains(pkg).contains(host)) { + return true; + } + + if (!DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, SETTINGS_API_V2)) { + int legacyState = mLegacySettings.getUserState(packageName, userId); + switch (legacyState) { + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: + // If nothing specifically set, assume v2 rules + break; + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK: + // With v2 split into 2 lists, always and undefined, the concept of whether + // or not to ask is irrelevant. Assume the user wants this application to + // open the domain. + return true; + case PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: + // Never has the same semantics are before + return false; + } + } } synchronized (mLock) { diff --git a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationUtils.java index ff030710274e..f704478b92a5 100644 --- a/services/core/java/com/android/server/pm/domain/verify/DomainVerificationUtils.java +++ b/services/core/java/com/android/server/pm/domain/verify/DomainVerificationUtils.java @@ -19,13 +19,20 @@ package com.android.server.pm.domain.verify; import android.annotation.CheckResult; import android.annotation.NonNull; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Binder; + +import com.android.server.compat.PlatformCompat; +import com.android.server.pm.PackageManagerService; +import com.android.server.pm.parsing.pkg.AndroidPackage; final class DomainVerificationUtils { /** - * Consolidates package exception messages. A generic unavailable message is included since - * the caller doesn't bother to check why the package isn't available. + * Consolidates package exception messages. A generic unavailable message is included since the + * caller doesn't bother to check why the package isn't available. */ @CheckResult static NameNotFoundException throwPackageUnavailable(@NonNull String packageName) @@ -38,4 +45,26 @@ final class DomainVerificationUtils { && intent.hasCategory(Intent.CATEGORY_BROWSABLE) && intent.hasCategory(Intent.CATEGORY_DEFAULT); } + + static boolean isChangeEnabled(PlatformCompat platformCompat, AndroidPackage pkg, + long changeId) { + //noinspection ConstantConditions + return Binder.withCleanCallingIdentity( + () -> platformCompat.isChangeEnabled(changeId, buildMockAppInfo(pkg))); + } + + /** + * Passed to {@link PlatformCompat} because this can be invoked mid-install process or when + * {@link PackageManagerService#mLock} is being held, and {@link PlatformCompat} will not be + * able to query the pending {@link ApplicationInfo} from {@link PackageManager}. + * <p> + * TODO(b/177613575): Can a different API be used? + */ + @NonNull + private static ApplicationInfo buildMockAppInfo(@NonNull AndroidPackage pkg) { + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.packageName = pkg.getPackageName(); + appInfo.targetSdkVersion = pkg.getTargetSdkVersion(); + return appInfo; + } } diff --git a/services/core/java/com/android/server/pm/intent/verify/legacy/IntentFilterVerificationSettings.java b/services/core/java/com/android/server/pm/intent/verify/legacy/IntentFilterVerificationSettings.java index 2aac51402d10..3ff770d5fb3a 100644 --- a/services/core/java/com/android/server/pm/intent/verify/legacy/IntentFilterVerificationSettings.java +++ b/services/core/java/com/android/server/pm/intent/verify/legacy/IntentFilterVerificationSettings.java @@ -176,10 +176,10 @@ public class IntentFilterVerificationSettings { public IntentFilterVerificationInfo updatePackageSetting(@NonNull PackageSetting pkgSetting, ArraySet<String> domains) { String pkgName = pkgSetting.name; - IntentFilterVerificationInfo ivi = pkgSetting.getIntentFilterVerificationInfo(); + IntentFilterVerificationInfo ivi = null;//pkgSetting.getIntentFilterVerificationInfo(); if (ivi == null) { ivi = new IntentFilterVerificationInfo(pkgName, domains); - pkgSetting.setIntentFilterVerificationInfo(ivi); + // pkgSetting.setIntentFilterVerificationInfo(ivi); mConnection.debugLog("Creating new IntentFilterVerificationInfo for pkg: " + pkgName); } else { ivi.setDomains(domains); @@ -197,7 +197,7 @@ public class IntentFilterVerificationSettings { mConnection.warnLog("No package known: " + packageName); return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; } - return (int) (pkgSetting.getDomainVerificationStatusForUser(userId) >> 32); + return 0;//(int) (pkgSetting.getDomainVerificationStatusForUser(userId) >> 32); } @Nullable @@ -208,7 +208,7 @@ public class IntentFilterVerificationSettings { mConnection.warnLog("No package known: " + packageName); return null; } - return ps.getIntentFilterVerificationInfo(); + return null;//ps.getIntentFilterVerificationInfo(); } boolean updateIntentFilterVerificationStatusLPw(String packageName, final int status, @@ -222,14 +222,14 @@ public class IntentFilterVerificationSettings { final int alwaysGeneration; if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { - WatchedSparseIntArray nextAppLinkGeneration = mConnection.getNextAppLinkGeneration(); - alwaysGeneration = nextAppLinkGeneration.get(userId) + 1; - nextAppLinkGeneration.put(userId, alwaysGeneration); +// WatchedSparseIntArray nextAppLinkGeneration = mConnection.getNextAppLinkGeneration(); +// alwaysGeneration = nextAppLinkGeneration.get(userId) + 1; +// nextAppLinkGeneration.put(userId, alwaysGeneration); } else { alwaysGeneration = 0; } - current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId); +// current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId); return true; } @@ -241,9 +241,8 @@ public class IntentFilterVerificationSettings { return false; } if (alsoResetStatus) { - ps.clearDomainVerificationStatusForUser(userId); +// ps.clearDomainVerificationStatusForUser(userId); } - ps.setIntentFilterVerificationInfo(null); return true; } @@ -262,7 +261,7 @@ public class IntentFilterVerificationSettings { } ArrayList<IntentFilterVerificationInfo> result = new ArrayList<>(); for (PackageSetting ps : mConnection.getPackageSettingsLPr().values()) { - IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo(); + IntentFilterVerificationInfo ivi = null;//ps.getIntentFilterVerificationInfo(); if (ivi == null || TextUtils.isEmpty(ivi.getPackageName()) || !ivi.getPackageName().equalsIgnoreCase(packageName)) { continue; @@ -278,7 +277,7 @@ public class IntentFilterVerificationSettings { throws IllegalArgumentException, IllegalStateException, IOException { serializer.startTag(null, Settings.TAG_ALL_INTENT_FILTER_VERIFICATION); for (PackageSetting value : pkgSettings.values()) { - IntentFilterVerificationInfo ivi = value.getIntentFilterVerificationInfo(); + IntentFilterVerificationInfo ivi = null;//value.getIntentFilterVerificationInfo(); if (ivi != null) { writeDomainVerificationsLPr(serializer, ivi); } @@ -318,7 +317,9 @@ public class IntentFilterVerificationSettings { final PackageSetting ps = mConnection.getPackageSettingLPr(pkgName); if (ps != null) { // known/existing package; update in place - ps.setIntentFilterVerificationInfo(ivi); + // TODO: Removed, commented out to allow compile, awaiting removal of entire + // class + // ps.setIntentFilterVerificationInfo(ivi); mConnection.debugLog("Restored IVI for existing app " + pkgName + " status=" + ivi.getStatusString()); } else { diff --git a/services/core/java/com/android/server/pm/intent/verify/legacy/IntentVerifyUtils.java b/services/core/java/com/android/server/pm/intent/verify/legacy/IntentVerifyUtils.java index 389aa20e9ff0..b64ac94ba07f 100644 --- a/services/core/java/com/android/server/pm/intent/verify/legacy/IntentVerifyUtils.java +++ b/services/core/java/com/android/server/pm/intent/verify/legacy/IntentVerifyUtils.java @@ -31,19 +31,4 @@ public class IntentVerifyUtils { && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)); } - - // Returns a packed value as a long: - // - // high 'int'-sized word: link status: undefined/ask/never/always. - // low 'int'-sized word: relative priority among 'always' results. - public static long getDomainVerificationStatus(PackageSetting ps, int userId) { - long result = ps.getDomainVerificationStatusForUser(userId); - // if none available, get the status - if (result >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { - if (ps.getIntentFilterVerificationInfo() != null) { - result = ((long) ps.getIntentFilterVerificationInfo().getStatus()) << 32; - } - } - return result; - } } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationEnforcerTest.kt index 13a37ffe77d6..c944cff8c04f 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationEnforcerTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationEnforcerTest.kt @@ -149,6 +149,7 @@ class DomainVerificationEnforcerTest { whenever(getPackageSettingLocked(TEST_PKG)) { mockPkgSetting } whenever(getPackageLocked(TEST_PKG)) { mockPkg } whenever(schedule(anyInt(), any())) + whenever(scheduleWriteSettings()) } }) ) diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationLegacySettingsTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationLegacySettingsTest.kt new file mode 100644 index 000000000000..47601a499d62 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationLegacySettingsTest.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.domain.verify + +import android.content.pm.IntentFilterVerificationInfo +import android.content.pm.PackageManager +import android.util.ArraySet +import com.android.server.pm.domain.verify.DomainVerificationLegacySettings +import com.android.server.pm.test.domain.verify.DomainVerificationPersistenceTest.Companion.readXml +import com.android.server.pm.test.domain.verify.DomainVerificationPersistenceTest.Companion.writeXml +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class DomainVerificationLegacySettingsTest { + + @Rule + @JvmField + val tempFolder = TemporaryFolder() + + @Test + fun writeAndReadBackNormal() { + val settings = DomainVerificationLegacySettings().apply { + add( + "com.test.one", + IntentFilterVerificationInfo( + "com.test.one", + ArraySet(setOf("example1.com", "example2.com")) + ).apply { + status = PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK + } + ) + add( + "com.test.one", + 0, PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS + ) + add( + "com.test.one", + 10, PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER + ) + + add( + "com.test.two", + IntentFilterVerificationInfo( + "com.test.two", + ArraySet(setOf("example3.com")) + ) + ) + + add( + "com.test.three", + 11, PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS + ) + } + + + val file = tempFolder.newFile().writeXml(settings::writeSettings) + val newSettings = file.readXml { + DomainVerificationLegacySettings().apply { + readSettings(it) + } + } + + val xml = file.readText() + + // Legacy migrated settings doesn't bother writing the legacy verification info + assertWithMessage(xml).that(newSettings.remove("com.test.one")).isNull() + assertWithMessage(xml).that(newSettings.getUserState("com.test.one", 0)) + .isEqualTo(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) + assertWithMessage(xml).that(newSettings.getUserState("com.test.one", 10)) + .isEqualTo(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) + + val firstUserStates = newSettings.getUserStates("com.test.one") + assertWithMessage(xml).that(firstUserStates).isNotNull() + assertWithMessage(xml).that(firstUserStates!!.size()).isEqualTo(2) + assertWithMessage(xml).that(firstUserStates[0]) + .isEqualTo(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) + assertWithMessage(xml).that(firstUserStates[10]) + .isEqualTo(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) + + assertWithMessage(xml).that(newSettings.remove("com.test.two")).isNull() + assertWithMessage(xml).that(newSettings.getUserStates("com.test.two")).isNull() + + assertWithMessage(xml).that(newSettings.remove("com.test.three")).isNull() + assertWithMessage(xml).that(newSettings.getUserState("com.test.three", 11)) + .isEqualTo(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationPersistenceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationPersistenceTest.kt index cf331d5ce775..ada5c1b063fa 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationPersistenceTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/domain/verify/DomainVerificationPersistenceTest.kt @@ -18,6 +18,7 @@ package com.android.server.pm.test.domain.verify import android.content.pm.domain.verify.DomainVerificationManager import android.util.ArrayMap +import android.util.TypedXmlPullParser import android.util.TypedXmlSerializer import android.util.Xml import com.android.server.pm.domain.verify.DomainVerificationPersistence @@ -29,12 +30,33 @@ import com.google.common.truth.Truth.assertWithMessage import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import java.io.File +import java.nio.charset.StandardCharsets import java.util.UUID class DomainVerificationPersistenceTest { companion object { private val PKG_PREFIX = DomainVerificationPersistenceTest::class.java.`package`!!.name + + internal fun File.writeXml(block: (serializer: TypedXmlSerializer) -> Unit) = apply { + outputStream().use { + // Explicitly use string based XML so it can printed in the test failure output + Xml.newFastSerializer() + .apply { + setOutput(it, StandardCharsets.UTF_8.name()) + startDocument(null, true) + setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true) + } + .apply(block) + .endDocument() + } + } + + internal fun <T> File.readXml(block: (parser: TypedXmlPullParser) -> T) = + inputStream().use { + block(Xml.resolvePullParser(it)) + } } @Rule @@ -56,17 +78,18 @@ class DomainVerificationPersistenceTest { mockPkgState(5).let { put(it.packageName, it) } } - val file = writeXml { + val file = tempFolder.newFile().writeXml { DomainVerificationPersistence.writeToXml(it, attached, pending, restored) } val xml = file.readText() - val (readActive, readRestored) = file.inputStream() - .use { DomainVerificationPersistence.readFromXml(Xml.resolvePullParser(it)) } + val (readActive, readRestored) = file.readXml { + DomainVerificationPersistence.readFromXml(it) + } assertWithMessage(xml).that(readActive.values) - .containsExactlyElementsIn(attached.values() + pending.values) + .containsExactlyElementsIn(attached.values() + pending.values) assertWithMessage(xml).that(readRestored.values).containsExactlyElementsIn(restored.values) } @@ -172,25 +195,12 @@ class DomainVerificationPersistenceTest { """.trimIndent() val (active, restored) = DomainVerificationPersistence - .readFromXml(Xml.resolvePullParser(xml.byteInputStream())) + .readFromXml(Xml.resolvePullParser(xml.byteInputStream())) assertThat(active.values).containsExactly(stateZero) assertThat(restored.values).containsExactly(stateOne, stateTwo) } - private fun writeXml(block: (TypedXmlSerializer) -> Unit) = tempFolder.newFile() - .apply { - outputStream().use { - Xml.resolveSerializer(it) - .apply { - startDocument(null, true) - setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true) - } - .apply(block) - .endDocument() - } - } - private fun mockEmptyPkgState( id: Int, hasAutoVerifyDomains: Boolean = true diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 850a031d7ad6..beeae7df6956 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -961,8 +961,6 @@ public class PackageManagerSettingsTests { assertNotSame(origPkgSetting.getUserState(), is(testPkgSetting.getUserState())); // No equals() method for SparseArray object // assertThat(origPkgSetting.getUserState(), is(testPkgSetting.getUserState())); - assertSame(origPkgSetting.verificationInfo, testPkgSetting.verificationInfo); - assertThat(origPkgSetting.verificationInfo, is(testPkgSetting.verificationInfo)); assertThat(origPkgSetting.versionCode, is(testPkgSetting.versionCode)); assertSame(origPkgSetting.volumeUuid, testPkgSetting.volumeUuid); assertThat(origPkgSetting.volumeUuid, is(testPkgSetting.volumeUuid)); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java index 1cfbad93c2e5..938e4cc84e62 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java @@ -53,18 +53,10 @@ public class PackageUserStateTest { assertThat(testUserState.equals(oldUserState), is(true)); oldUserState = new PackageUserState(); - oldUserState.appLinkGeneration = 6; - assertThat(testUserState.equals(oldUserState), is(false)); - - oldUserState = new PackageUserState(); oldUserState.ceDataInode = 4000L; assertThat(testUserState.equals(oldUserState), is(false)); oldUserState = new PackageUserState(); - oldUserState.domainVerificationStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; - assertThat(testUserState.equals(oldUserState), is(false)); - - oldUserState = new PackageUserState(); oldUserState.enabled = COMPONENT_ENABLED_STATE_ENABLED; assertThat(testUserState.equals(oldUserState), is(false)); |