diff options
28 files changed, 959 insertions, 1311 deletions
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 09ef03c38188..111bd340a3d1 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -67,7 +67,7 @@ import java.util.function.Consumer; * * @hide Only for use within the system server. */ -public abstract class PackageManagerInternal implements PackageSettingsSnapshotProvider { +public abstract class PackageManagerInternal { @IntDef(prefix = "PACKAGE_", value = { PACKAGE_SYSTEM, PACKAGE_SETUP_WIZARD, diff --git a/services/core/java/android/content/pm/PackageSettingsSnapshotProvider.java b/services/core/java/android/content/pm/PackageSettingsSnapshotProvider.java deleted file mode 100644 index 221f172c3463..000000000000 --- a/services/core/java/android/content/pm/PackageSettingsSnapshotProvider.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 android.content.pm; - -import android.annotation.NonNull; - -import com.android.internal.util.FunctionalUtils; -import com.android.server.pm.PackageManagerService; -import com.android.server.pm.PackageSetting; -import com.android.server.pm.pkg.PackageStateInternal; - -import java.util.function.Consumer; -import java.util.function.Function; - -/** @hide */ -public interface PackageSettingsSnapshotProvider { - - /** - * Run a function block that requires access to {@link PackageStateInternal} data. This will - * ensure the {@link PackageManagerService} lock is taken before any caller's internal lock - * to avoid deadlock. Note that this method may or may not lock. If a snapshot is available - * and valid, it will iterate the snapshot set of data. - */ - void withPackageSettingsSnapshot( - @NonNull Consumer<Function<String, PackageStateInternal>> block); - - /** - * Variant which returns a value to the caller. - * @see #withPackageSettingsSnapshot(Consumer) - */ - <Output> Output withPackageSettingsSnapshotReturning( - @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>, - Output> block); - - /** - * Variant which throws. - * @see #withPackageSettingsSnapshot(Consumer) - */ - <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing( - @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageStateInternal>, - ExceptionType> block) throws ExceptionType; - - /** - * Variant which throws 2 exceptions. - * @see #withPackageSettingsSnapshot(Consumer) - */ - <ExceptionOne extends Exception, ExceptionTwo extends Exception> void - withPackageSettingsSnapshotThrowing2( - @NonNull FunctionalUtils.ThrowingChecked2Consumer< - Function<String, PackageStateInternal>, - ExceptionOne, ExceptionTwo> block) - throws ExceptionOne, ExceptionTwo; - - /** - * Variant which returns a value to the caller and throws. - * @see #withPackageSettingsSnapshot(Consumer) - */ - <Output, ExceptionType extends Exception> Output - withPackageSettingsSnapshotReturningThrowing( - @NonNull FunctionalUtils.ThrowingCheckedFunction< - Function<String, PackageStateInternal>, Output, ExceptionType> block) - throws ExceptionType; -} diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 9e87898a7491..30ac1b85e7c3 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -3134,8 +3134,8 @@ public class ComputerEngine implements Computer { writer.println("Domain verification status:"); writer.increaseIndent(); try { - mDomainVerificationManager.printState(writer, packageName, - UserHandle.USER_ALL, mSettings::getPackage); + mDomainVerificationManager.printState(this, writer, packageName, + UserHandle.USER_ALL); } catch (Exception e) { pw.println("Failure printing domain verification information"); Slog.e(TAG, "Failure printing domain verification information", e); diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 3220b3171178..58f9bb2c1902 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -453,7 +453,8 @@ final class DeletePackageHelper { } for (final int affectedUserId : affectedUserIds) { if (hadSuspendAppsPermission.get(affectedUserId)) { - mPm.unsuspendForSuspendingPackage(packageName, affectedUserId); + mPm.unsuspendForSuspendingPackage(mPm.snapshotComputer(), packageName, + affectedUserId); mPm.removeAllDistractingPackageRestrictions(affectedUserId); } } diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java index d24435e12593..db8c6dc60b5e 100644 --- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java +++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java @@ -26,17 +26,12 @@ import android.os.Binder; import android.os.Message; import android.os.UserHandle; -import com.android.internal.util.FunctionalUtils; import com.android.server.DeviceIdleInternal; import com.android.server.pm.parsing.pkg.AndroidPackage; -import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.verify.domain.DomainVerificationService; import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1; import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2; -import java.util.function.Consumer; -import java.util.function.Function; - public final class DomainVerificationConnection implements DomainVerificationService.Connection, DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection { final PackageManagerService mPm; @@ -111,42 +106,8 @@ public final class DomainVerificationConnection implements DomainVerificationSer return mUmInternal.exists(userId); } - @Override - public void withPackageSettingsSnapshot( - @NonNull Consumer<Function<String, PackageStateInternal>> block) { - mPmInternal.withPackageSettingsSnapshot(block); - } - - @Override - public <Output> Output withPackageSettingsSnapshotReturning( - @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>, - Output> block) { - return mPmInternal.withPackageSettingsSnapshotReturning(block); - } - - @Override - public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing( - @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageStateInternal>, - ExceptionType> block) throws ExceptionType { - mPmInternal.withPackageSettingsSnapshotThrowing(block); - } - - @Override - public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void - withPackageSettingsSnapshotThrowing2( - @NonNull FunctionalUtils.ThrowingChecked2Consumer< - Function<String, PackageStateInternal>, ExceptionOne, - ExceptionTwo> block) - throws ExceptionOne, ExceptionTwo { - mPmInternal.withPackageSettingsSnapshotThrowing2(block); - } - - @Override - public <Output, ExceptionType extends Exception> Output - withPackageSettingsSnapshotReturningThrowing( - @NonNull FunctionalUtils.ThrowingCheckedFunction< - Function<String, PackageStateInternal>, Output, ExceptionType> block) - throws ExceptionType { - return mPmInternal.withPackageSettingsSnapshotReturningThrowing(block); + @NonNull + public Computer snapshot() { + return (Computer) mPmInternal.snapshot(); } } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 234a2309d76b..c09c904ff931 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -36,7 +36,6 @@ import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE; import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; -import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD; import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile; import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED; @@ -145,6 +144,7 @@ import com.android.internal.content.F2fsUtils; import com.android.internal.content.InstallLocationUtils; import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.pm.dex.ArtManagerService; @@ -2563,7 +2563,9 @@ final class InstallPackageHelper { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPm.mLock) { - size = mPm.mPendingBroadcasts.size(); + final SparseArray<ArrayMap<String, ArrayList<String>>> userIdToPackagesToComponents = + mPm.mPendingBroadcasts.copiedMap(); + size = userIdToPackagesToComponents.size(); if (size <= 0) { // Nothing to be done. Just return return; @@ -2573,11 +2575,11 @@ final class InstallPackageHelper { uids = new int[size]; int i = 0; // filling out the above arrays - for (int n = 0; n < mPm.mPendingBroadcasts.userIdCount(); n++) { - final int packageUserId = mPm.mPendingBroadcasts.userIdAt(n); + for (int n = 0; n < size; n++) { + final int packageUserId = userIdToPackagesToComponents.keyAt(n); final ArrayMap<String, ArrayList<String>> componentsToBroadcast = - mPm.mPendingBroadcasts.packagesForUserId(packageUserId); - final int numComponents = componentsToBroadcast.size(); + userIdToPackagesToComponents.valueAt(n); + final int numComponents = CollectionUtils.size(componentsToBroadcast); for (int index = 0; i < size && index < numComponents; index++) { packages[i] = componentsToBroadcast.keyAt(index); components[i] = componentsToBroadcast.valueAt(index); diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java index 46e2aa3ff841..b028a2cef2a5 100644 --- a/services/core/java/com/android/server/pm/PackageHandler.java +++ b/services/core/java/com/android/server/pm/PackageHandler.java @@ -382,6 +382,7 @@ final class PackageHandler extends Handler { case PRUNE_UNUSED_STATIC_SHARED_LIBRARIES: { try { mPm.mInjector.getSharedLibrariesImpl().pruneUnusedStaticSharedLibraries( + mPm.snapshotComputer(), Long.MAX_VALUE, Settings.Global.getLong(mPm.mContext.getContentResolver(), Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0b7a6a7cec45..c05faf14cae4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -293,7 +293,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import java.util.function.Function; /** * Keep track of all those APKs everywhere. @@ -1898,7 +1897,8 @@ public class PackageManagerService extends IPackageManager.Stub t.traceEnd(); t.traceBegin("read user settings"); - mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers( + mFirstBoot = !mSettings.readLPw(mLiveComputer, + mInjector.getUserManagerInternal().getUsers( /* excludePartial= */ true, /* excludeDying= */ false, /* excludePreCreated= */ false)); @@ -2841,8 +2841,9 @@ public class PackageManagerService extends IPackageManager.Stub } if (file.getUsableSpace() >= bytes) return; + Computer computer = snapshotComputer(); // 5. Consider shared libraries with refcount=0 and age>min cache period - if (internalVolume && mSharedLibraries.pruneUnusedStaticSharedLibraries(bytes, + if (internalVolume && mSharedLibraries.pruneUnusedStaticSharedLibraries(computer, bytes, android.provider.Settings.Global.getLong(mContext.getContentResolver(), Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD, FREE_STORAGE_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD))) { @@ -2854,14 +2855,12 @@ public class PackageManagerService extends IPackageManager.Stub // 7. Consider installed instant apps unused longer than min cache period if (internalVolume) { - if (executeWithConsistentComputerReturning(computer -> - mInstantAppRegistry.pruneInstalledInstantApps(computer, bytes, - android.provider.Settings.Global.getLong( - mContext.getContentResolver(), - Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD, - InstantAppRegistry - .DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) - ) { + if (mInstantAppRegistry.pruneInstalledInstantApps(computer, bytes, + android.provider.Settings.Global.getLong( + mContext.getContentResolver(), + Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD, + InstantAppRegistry + .DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { return; } } @@ -2881,14 +2880,12 @@ public class PackageManagerService extends IPackageManager.Stub // 10. Consider instant meta-data (uninstalled apps) older that min cache period if (internalVolume) { - if (executeWithConsistentComputerReturning(computer -> - mInstantAppRegistry.pruneUninstalledInstantApps(computer, bytes, - android.provider.Settings.Global.getLong( - mContext.getContentResolver(), - Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD, - InstantAppRegistry - .DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) - ) { + if (mInstantAppRegistry.pruneUninstalledInstantApps(computer, bytes, + android.provider.Settings.Global.getLong( + mContext.getContentResolver(), + Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD, + InstantAppRegistry + .DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { return; } } @@ -3493,8 +3490,8 @@ public class PackageManagerService extends IPackageManager.Stub enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "getEphemeralApplications"); - List<InstantAppInfo> instantApps = executeWithConsistentComputerReturning(computer -> - mInstantAppRegistry.getInstantApps(computer, userId)); + Computer computer = snapshotComputer(); + List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(computer, userId); if (instantApps != null) { return new ParceledListSlice<>(instantApps); } @@ -3710,13 +3707,13 @@ public class PackageManagerService extends IPackageManager.Stub public void notifyPackageUse(String packageName, int reason) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - boolean notify = executeWithConsistentComputerReturning(computer -> { - if (getInstantAppPackageName(callingUid) != null) { - return isCallerSameApp(packageName, callingUid); - } else { - return !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID); - } - }); + Computer computer = snapshotComputer(); + final boolean notify; + if (getInstantAppPackageName(callingUid) != null) { + notify = isCallerSameApp(packageName, callingUid); + } else { + notify = !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID); + } if (!notify) { return; } @@ -4255,34 +4252,33 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> unactionedPackages = new ArrayList<>(packageNames.length); ArraySet<String> changesToCommit = new ArraySet<>(); - executeWithConsistentComputer(computer -> { - final boolean[] canRestrict = (restrictionFlags != 0) - ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId, - callingUid) : null; - for (int i = 0; i < packageNames.length; i++) { - final String packageName = packageNames[i]; - final PackageStateInternal packageState = - computer.getPackageStateInternal(packageName); - if (packageState == null - || shouldFilterApplication(packageState, callingUid, userId)) { - Slog.w(TAG, "Could not find package setting for package: " + packageName - + ". Skipping..."); - unactionedPackages.add(packageName); - continue; - } - if (canRestrict != null && !canRestrict[i]) { - unactionedPackages.add(packageName); - continue; - } - final int oldDistractionFlags = packageState.getUserStateOrDefault(userId) - .getDistractionFlags(); - if (restrictionFlags != oldDistractionFlags) { - changedPackagesList.add(packageName); - changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); - changesToCommit.add(packageName); - } + Computer computer = snapshotComputer(); + final boolean[] canRestrict = (restrictionFlags != 0) + ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId, + callingUid) : null; + for (int i = 0; i < packageNames.length; i++) { + final String packageName = packageNames[i]; + final PackageStateInternal packageState = + computer.getPackageStateInternal(packageName); + if (packageState == null + || computer.shouldFilterApplication(packageState, callingUid, userId)) { + Slog.w(TAG, "Could not find package setting for package: " + packageName + + ". Skipping..."); + unactionedPackages.add(packageName); + continue; } - }); + if (canRestrict != null && !canRestrict[i]) { + unactionedPackages.add(packageName); + continue; + } + final int oldDistractionFlags = packageState.getUserStateOrDefault(userId) + .getDistractionFlags(); + if (restrictionFlags != oldDistractionFlags) { + changedPackagesList.add(packageName); + changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); + changesToCommit.add(packageName); + } + } commitPackageStateMutation(null, mutator -> { final int size = changesToCommit.size(); @@ -4341,8 +4337,9 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUid = Binder.getCallingUid(); enforceCanSetPackagesSuspendedAsUser(callingPackage, callingUid, userId, "setPackagesSuspendedAsUser"); - return mSuspendPackageHelper.setPackagesSuspended(packageNames, suspended, appExtras, - launcherExtras, dialogInfo, callingPackage, userId, callingUid); + return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames, + suspended, appExtras, launcherExtras, dialogInfo, callingPackage, userId, + callingUid); } @Override @@ -4361,11 +4358,12 @@ public class PackageManagerService extends IPackageManager.Stub return mComputer.isPackageSuspendedForUser(packageName, userId); } - void unsuspendForSuspendingPackage(String suspendingPackage, int userId) { + void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage, + @UserIdInt int userId) { // TODO: This can be replaced by a special parameter to iterate all packages, rather than // this weird pre-collect of all packages. - final String[] allPackages = getPackageStates().keySet().toArray(new String[0]); - mSuspendPackageHelper.removeSuspensionsBySuspendingPackage( + final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]); + mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages, suspendingPackage::equals, userId); } @@ -4424,7 +4422,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Calling uid " + callingUid + " cannot query getUnsuspendablePackagesForUser for user " + userId); } - return mSuspendPackageHelper.getUnsuspendablePackagesForUser( + return mSuspendPackageHelper.getUnsuspendablePackagesForUser(snapshotComputer(), packageNames, userId, callingUid); } @@ -4625,7 +4623,7 @@ public class PackageManagerService extends IPackageManager.Stub return true; }; PackageStateMutator.InitialState initialState = recordInitialState(); - boolean allowed = executeWithConsistentComputerReturningThrowing(implementation); + boolean allowed = implementation.apply(snapshotComputer()); if (allowed) { // TODO: Need to lock around here to handle mSettings.addInstallerPackageNames, // should find an alternative which avoids any race conditions @@ -4635,7 +4633,7 @@ public class PackageManagerService extends IPackageManager.Stub targetPackage, state -> state.setInstaller(installerPackageName)); if (result.isPackagesChanged() || result.isStateChanged()) { synchronized (mPackageStateWriteLock) { - allowed = executeWithConsistentComputerReturningThrowing(implementation); + allowed = implementation.apply(snapshotComputer()); if (allowed) { commitPackageStateMutation(null, targetPackage, state -> state.setInstaller(installerPackageName)); @@ -4685,12 +4683,12 @@ public class PackageManagerService extends IPackageManager.Stub } }; - PackageStateMutator.Result result = executeWithConsistentComputerReturning(implementation); + PackageStateMutator.Result result = implementation.apply(snapshotComputer()); if (result != null && result.isStateChanged() && !result.isSpecificPackageNull()) { // TODO: Specific return value of what state changed? // The installer on record might have changed, retry with lock synchronized (mPackageStateWriteLock) { - result = executeWithConsistentComputerReturning(implementation); + result = implementation.apply(snapshotComputer()); } } @@ -4988,7 +4986,7 @@ public class PackageManagerService extends IPackageManager.Stub } if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId) == PERMISSION_GRANTED) { - unsuspendForSuspendingPackage(packageName, userId); + unsuspendForSuspendingPackage(snapshotComputer(), packageName, userId); removeAllDistractingPackageRestrictions(userId); flushPackageRestrictionsAsUserInternalLocked(userId); } @@ -5080,17 +5078,7 @@ public class PackageManagerService extends IPackageManager.Stub updateInstantAppInstallerLocked(packageName); scheduleWritePackageRestrictions(userId); - final ArrayList<String> pendingComponents = mPendingBroadcasts.get(userId, packageName); - if (pendingComponents == null) { - mPendingBroadcasts.put(userId, packageName, updatedComponents); - } else { - for (int i = 0; i < updatedComponents.size(); i++) { - final String updatedComponent = updatedComponents.get(i); - if (!pendingComponents.contains(updatedComponent)) { - pendingComponents.add(updatedComponent); - } - } - } + mPendingBroadcasts.addComponents(userId, packageName, updatedComponents); if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); } @@ -5278,7 +5266,8 @@ public class PackageManagerService extends IPackageManager.Stub try { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { TypedXmlSerializer serializer = Xml.resolveSerializer(output); - mDomainVerificationManager.writeSettings(serializer, true, userId); + mDomainVerificationManager.writeSettings(snapshotComputer(), serializer, true, + userId); return output.toByteArray(); } } catch (Exception e) { @@ -5301,7 +5290,7 @@ public class PackageManagerService extends IPackageManager.Stub // User ID input isn't necessary here as it assumes the user integers match and that // the only states inside the backup XML are for the target user. - mDomainVerificationManager.restoreSettings(parser); + mDomainVerificationManager.restoreSettings(snapshotComputer(), parser); input.close(); } catch (Exception e) { if (DEBUG_BACKUP) { @@ -5689,48 +5678,48 @@ public class PackageManagerService extends IPackageManager.Stub int callingUid = Binder.getCallingUid(); String componentPkgName = componentName.getPackageName(); - boolean changed = executeWithConsistentComputerReturning(computer -> { - int componentUid = getPackageUid(componentPkgName, 0, userId); - if (!UserHandle.isSameApp(callingUid, componentUid)) { - throw new SecurityException("The calling UID (" + callingUid + ")" - + " does not match the target UID"); - } + Computer computer = snapshotComputer(); - String allowedCallerPkg = - mContext.getString(R.string.config_overrideComponentUiPackage); - if (TextUtils.isEmpty(allowedCallerPkg)) { - throw new SecurityException( "There is no package defined as allowed to change a " - + "component's label or icon"); - } + int componentUid = computer.getPackageUid(componentPkgName, 0, userId); + if (!UserHandle.isSameApp(callingUid, componentUid)) { + throw new SecurityException("The calling UID (" + callingUid + ")" + + " does not match the target UID"); + } - int allowedCallerUid = getPackageUid(allowedCallerPkg, PackageManager.MATCH_SYSTEM_ONLY, - userId); - if (allowedCallerUid == -1 || !UserHandle.isSameApp(callingUid, allowedCallerUid)) { - throw new SecurityException("The calling UID (" + callingUid + ")" - + " is not allowed to change a component's label or icon"); - } - PackageStateInternal packageState = computer.getPackageStateInternal(componentPkgName); - if (packageState == null || packageState.getPkg() == null - || (!packageState.isSystem() - && !packageState.getTransientState().isUpdatedSystemApp())) { - throw new SecurityException( - "Changing the label is not allowed for " + componentName); - } + String allowedCallerPkg = + mContext.getString(R.string.config_overrideComponentUiPackage); + if (TextUtils.isEmpty(allowedCallerPkg)) { + throw new SecurityException( "There is no package defined as allowed to change a " + + "component's label or icon"); + } - if (!mComponentResolver.componentExists(componentName)) { - throw new IllegalArgumentException("Component " + componentName + " not found"); - } + int allowedCallerUid = computer.getPackageUid(allowedCallerPkg, + PackageManager.MATCH_SYSTEM_ONLY, userId); + if (allowedCallerUid == -1 || !UserHandle.isSameApp(callingUid, allowedCallerUid)) { + throw new SecurityException("The calling UID (" + callingUid + ")" + + " is not allowed to change a component's label or icon"); + } + PackageStateInternal packageState = computer.getPackageStateInternal(componentPkgName); + if (packageState == null || packageState.getPkg() == null + || (!packageState.isSystem() + && !packageState.getTransientState().isUpdatedSystemApp())) { + throw new SecurityException( + "Changing the label is not allowed for " + componentName); + } + + if (!computer.getComponentResolver().componentExists(componentName)) { + throw new IllegalArgumentException("Component " + componentName + " not found"); + } - Pair<String, Integer> overrideLabelIcon = packageState.getUserStateOrDefault(userId) - .getOverrideLabelIconForComponent(componentName); + Pair<String, Integer> overrideLabelIcon = packageState.getUserStateOrDefault(userId) + .getOverrideLabelIconForComponent(componentName); - String existingLabel = overrideLabelIcon == null ? null : overrideLabelIcon.first; - Integer existingIcon = overrideLabelIcon == null ? null : overrideLabelIcon.second; + String existingLabel = overrideLabelIcon == null ? null : overrideLabelIcon.first; + Integer existingIcon = overrideLabelIcon == null ? null : overrideLabelIcon.second; - return !TextUtils.equals(existingLabel, nonLocalizedLabel) - || !Objects.equals(existingIcon, icon); - }); - if (!changed) { + if (TextUtils.equals(existingLabel, nonLocalizedLabel) + && Objects.equals(existingIcon, icon)) { + // Nothing changed return; } @@ -5738,16 +5727,7 @@ public class PackageManagerService extends IPackageManager.Stub state -> state.userState(userId) .setComponentLabelIcon(componentName, nonLocalizedLabel, icon)); - ArrayList<String> components = mPendingBroadcasts.get(userId, componentPkgName); - if (components == null) { - components = new ArrayList<>(); - mPendingBroadcasts.put(userId, componentPkgName, components); - } - - String className = componentName.getClassName(); - if (!components.contains(className)) { - components.add(className); - } + mPendingBroadcasts.addComponent(userId, componentPkgName, componentName.getClassName()); if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); @@ -5956,6 +5936,7 @@ public class PackageManagerService extends IPackageManager.Stub // packageName -> list of components to send broadcasts now final ArrayMap<String, ArrayList<String>> sendNowBroadcasts = new ArrayMap<>(targetSize); synchronized (mLock) { + Computer computer = snapshotComputer(); boolean scheduleBroadcastMessage = false; boolean isSynchronous = false; boolean anyChanged = false; @@ -5967,8 +5948,8 @@ public class PackageManagerService extends IPackageManager.Stub // update enabled settings final ComponentEnabledSetting setting = settings.get(i); final String packageName = setting.getPackageName(); - if (!setEnabledSettingInternalLocked(pkgSettings.get(packageName), setting, - userId, callingPackage)) { + if (!setEnabledSettingInternalLocked(computer, pkgSettings.get(packageName), + setting, userId, callingPackage)) { continue; } anyChanged = true; @@ -5979,26 +5960,18 @@ public class PackageManagerService extends IPackageManager.Stub // collect broadcast list for the package final String componentName = setting.isComponent() ? setting.getClassName() : packageName; - ArrayList<String> componentList = sendNowBroadcasts.get(packageName); - if (componentList == null) { - componentList = mPendingBroadcasts.get(userId, packageName); - } - final boolean newPackage = componentList == null; - if (newPackage) { - componentList = new ArrayList<>(); - } - if (!componentList.contains(componentName)) { - componentList.add(componentName); - } if ((setting.getEnabledFlags() & PackageManager.DONT_KILL_APP) == 0) { + ArrayList<String> componentList = sendNowBroadcasts.get(packageName); + componentList = componentList == null ? new ArrayList<>() : componentList; + if (!componentList.contains(componentName)) { + componentList.add(componentName); + } sendNowBroadcasts.put(packageName, componentList); // Purge entry from pending broadcast list if another one exists already // since we are sending one right away. mPendingBroadcasts.remove(userId, packageName); } else { - if (newPackage) { - mPendingBroadcasts.put(userId, packageName, componentList); - } + mPendingBroadcasts.addComponent(userId, packageName, componentName); scheduleBroadcastMessage = true; } } @@ -6041,8 +6014,9 @@ public class PackageManagerService extends IPackageManager.Stub } } - private boolean setEnabledSettingInternalLocked(PackageSetting pkgSetting, - ComponentEnabledSetting setting, int userId, String callingPackage) { + private boolean setEnabledSettingInternalLocked(@NonNull Computer computer, + PackageSetting pkgSetting, ComponentEnabledSetting setting, @UserIdInt int userId, + String callingPackage) { final int newState = setting.getEnabledState(); final String packageName = setting.getPackageName(); boolean success = false; @@ -6061,7 +6035,7 @@ public class PackageManagerService extends IPackageManager.Stub // This app should not generally be allowed to get disabled by the UI, but // if it ever does, we don't want to end up with some of the user's apps // permanently suspended. - unsuspendForSuspendingPackage(packageName, userId); + unsuspendForSuspendingPackage(computer, packageName, userId); removeAllDistractingPackageRestrictions(userId); } success = true; @@ -6152,11 +6126,8 @@ public class PackageManagerService extends IPackageManager.Stub public void setPackageStoppedState(String packageName, boolean stopped, int userId) { if (!mUserManager.exists(userId)) return; final int callingUid = Binder.getCallingUid(); - Pair<Boolean, String> wasNotLaunchedAndInstallerPackageName = - executeWithConsistentComputerReturningThrowing(computer -> { - if (computer.getInstantAppPackageName(callingUid) != null) { - return null; - } + final Computer computer = snapshotComputer(); + if (computer.getInstantAppPackageName(callingUid) == null) { final int permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); @@ -6171,36 +6142,30 @@ public class PackageManagerService extends IPackageManager.Stub true /* requireFullPermission */, true /* checkShell */, "stop package"); final PackageStateInternal packageState = computer.getPackageStateInternal(packageName); - final PackageUserState PackageUserState = packageState == null + final PackageUserState packageUserState = packageState == null ? null : packageState.getUserStateOrDefault(userId); - if (packageState == null - || computer.shouldFilterApplication(packageState, callingUid, userId) - || PackageUserState.isStopped() == stopped) { - return null; - } - - return Pair.create(PackageUserState.isNotLaunched(), - packageState.getInstallSource().installerPackageName); - }); - if (wasNotLaunchedAndInstallerPackageName != null) { - boolean wasNotLaunched = wasNotLaunchedAndInstallerPackageName.first; + if (packageState != null + && !computer.shouldFilterApplication(packageState, callingUid, userId) + && packageUserState.isStopped() != stopped) { + boolean wasNotLaunched = packageUserState.isNotLaunched(); + commitPackageStateMutation(null, packageName, state -> { + PackageUserStateWrite userState = state.userState(userId); + userState.setStopped(stopped); + if (wasNotLaunched) { + userState.setNotLaunched(false); + } + }); - commitPackageStateMutation(null, packageName, packageState -> { - PackageUserStateWrite userState = packageState.userState(userId); - userState.setStopped(stopped); if (wasNotLaunched) { - userState.setNotLaunched(false); + final String installerPackageName = + packageState.getInstallSource().installerPackageName; + if (installerPackageName != null) { + notifyFirstLaunch(packageName, installerPackageName, userId); + } } - }); - if (wasNotLaunched) { - final String installerPackageName = wasNotLaunchedAndInstallerPackageName.second; - if (installerPackageName != null) { - notifyFirstLaunch(packageName, installerPackageName, userId); - } + scheduleWritePackageRestrictions(userId); } - - scheduleWritePackageRestrictions(userId); } // If this would cause the app to leave force-stop, then also make sure to unhibernate the @@ -6687,7 +6652,7 @@ public class PackageManagerService extends IPackageManager.Stub "Only package verification agents can read the verifier device identity"); synchronized (mLock) { - return mSettings.getVerifierDeviceIdentityLPw(); + return mSettings.getVerifierDeviceIdentityLPw(mLiveComputer); } } @@ -7026,15 +6991,16 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void removeAllNonSystemPackageSuspensions(int userId) { - final String[] allPackages = mComputer.getAllAvailablePackageNames(); - mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(allPackages, + final Computer computer = snapshotComputer(); + final String[] allPackages = computer.getAllAvailablePackageNames(); + mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages, (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage), userId); } @Override public void removeNonSystemPackageSuspensions(String packageName, int userId) { - mSuspendPackageHelper.removeSuspensionsBySuspendingPackage( + mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(snapshotComputer(), new String[]{packageName}, (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage), userId); @@ -7233,29 +7199,29 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void grantImplicitAccess(int userId, Intent intent, int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) { - boolean accessGranted = executeWithConsistentComputerReturning(computer -> { - final AndroidPackage visiblePackage = computer.getPackage(visibleUid); - final int recipientUid = UserHandle.getUid(userId, recipientAppId); - if (visiblePackage == null || computer.getPackage(recipientUid) == null) { - return false; - } + Computer computer = snapshotComputer(); + final AndroidPackage visiblePackage = computer.getPackage(visibleUid); + final int recipientUid = UserHandle.getUid(userId, recipientAppId); + if (visiblePackage == null || computer.getPackage(recipientUid) == null) { + return; + } - final boolean instantApp = computer.isInstantAppInternal( - visiblePackage.getPackageName(), userId, visibleUid); - if (instantApp) { - if (!direct) { - // if the interaction that lead to this granting access to an instant app - // was indirect (i.e.: URI permission grant), do not actually execute the - // grant. - return false; - } - return mInstantAppRegistry.grantInstantAccess(userId, intent, - recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/); - } else { - return mAppsFilter.grantImplicitAccess(recipientUid, visibleUid, - retainOnUpdate); + final boolean instantApp = computer.isInstantAppInternal( + visiblePackage.getPackageName(), userId, visibleUid); + final boolean accessGranted; + if (instantApp) { + if (!direct) { + // if the interaction that lead to this granting access to an instant app + // was indirect (i.e.: URI permission grant), do not actually execute the + // grant. + return; } - }); + accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent, + recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/); + } else { + accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid, + retainOnUpdate); + } if (accessGranted) { ApplicationPackageManager.invalidateGetPackagesForUidCache(); @@ -7271,8 +7237,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void pruneInstantApps() { - executeWithConsistentComputer(computer -> - mInstantAppRegistry.pruneInstantApps(computer)); + mInstantAppRegistry.pruneInstantApps(snapshotComputer()); } @Override @@ -7680,7 +7645,8 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) { - PackageManagerService.this.unsuspendForSuspendingPackage(packageName, affectedUser); + PackageManagerService.this.unsuspendForSuspendingPackage(snapshotComputer(), + packageName, affectedUser); } @Override @@ -7744,52 +7710,6 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void withPackageSettingsSnapshot( - @NonNull Consumer<Function<String, PackageStateInternal>> block) { - executeWithConsistentComputer(computer -> - block.accept(computer::getPackageStateInternal)); - } - - @Override - public <Output> Output withPackageSettingsSnapshotReturning( - @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>, - Output> block) { - return executeWithConsistentComputerReturning(computer -> - block.apply(computer::getPackageStateInternal)); - } - - @Override - public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing( - @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, - PackageStateInternal>, ExceptionType> block) throws ExceptionType { - executeWithConsistentComputerThrowing(computer -> - block.accept(computer::getPackageStateInternal)); - } - - @Override - public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void - withPackageSettingsSnapshotThrowing2( - @NonNull FunctionalUtils.ThrowingChecked2Consumer< - Function<String, PackageStateInternal>, ExceptionOne, - ExceptionTwo> block) - throws ExceptionOne, ExceptionTwo { - executeWithConsistentComputerThrowing2( - (FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne, - ExceptionTwo>) computer -> block.accept(computer::getPackageStateInternal)); - } - - @Override - public <Output, ExceptionType extends Exception> Output - withPackageSettingsSnapshotReturningThrowing( - @NonNull FunctionalUtils.ThrowingCheckedFunction< - Function<String, PackageStateInternal>, Output, - ExceptionType> block) - throws ExceptionType { - return executeWithConsistentComputerReturningThrowing(computer -> - block.apply(computer::getPackageStateInternal)); - } - - @Override public void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags, boolean migrateAppsData) { PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags, @@ -7834,70 +7754,59 @@ public class PackageManagerService extends IPackageManager.Stub @NonNull Set<String> outUpdatedPackageNames) { synchronized (mOverlayPathsLock) { final ArrayMap<String, ArraySet<String>> libNameToModifiedDependents = new ArrayMap<>(); - Boolean targetModified = executeWithConsistentComputerReturning(computer -> { - final PackageStateInternal packageState = computer.getPackageStateInternal( - targetPackageName); - final AndroidPackage targetPkg = - packageState == null ? null : packageState.getPkg(); - if (targetPackageName == null || targetPkg == null) { - Slog.e(TAG, "failed to find package " + targetPackageName); - return null; - } + Computer computer = snapshotComputer(); + final PackageStateInternal packageState = computer.getPackageStateInternal( + targetPackageName); + final AndroidPackage targetPkg = packageState == null ? null : packageState.getPkg(); + if (targetPackageName == null || targetPkg == null) { + Slog.e(TAG, "failed to find package " + targetPackageName); + return false; + } - if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(), - newOverlayPaths)) { - return false; - } + if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(), + newOverlayPaths)) { + return true; + } - if (targetPkg.getLibraryNames() != null) { - // Set the overlay paths for dependencies of the shared library. - for (final String libName : targetPkg.getLibraryNames()) { - ArraySet<String> modifiedDependents = null; + if (targetPkg.getLibraryNames() != null) { + // Set the overlay paths for dependencies of the shared library. + for (final String libName : targetPkg.getLibraryNames()) { + ArraySet<String> modifiedDependents = null; - final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName, - SharedLibraryInfo.VERSION_UNDEFINED); - if (info == null) { - continue; - } - final List<VersionedPackage> dependents = computer - .getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID, userId); - if (dependents == null) { + final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName, + SharedLibraryInfo.VERSION_UNDEFINED); + if (info == null) { + continue; + } + final List<VersionedPackage> dependents = computer + .getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID, userId); + if (dependents == null) { + continue; + } + for (final VersionedPackage dependent : dependents) { + final PackageStateInternal dependentState = + computer.getPackageStateInternal(dependent.getPackageName()); + if (dependentState == null) { continue; } - for (final VersionedPackage dependent : dependents) { - final PackageStateInternal dependentState = - computer.getPackageStateInternal(dependent.getPackageName()); - if (dependentState == null) { - continue; - } - if (!Objects.equals(dependentState.getUserStateOrDefault(userId) - .getSharedLibraryOverlayPaths() - .get(libName), newOverlayPaths)) { - String dependentPackageName = dependent.getPackageName(); - modifiedDependents = ArrayUtils.add(modifiedDependents, - dependentPackageName); - outUpdatedPackageNames.add(dependentPackageName); - } + if (!Objects.equals(dependentState.getUserStateOrDefault(userId) + .getSharedLibraryOverlayPaths() + .get(libName), newOverlayPaths)) { + String dependentPackageName = dependent.getPackageName(); + modifiedDependents = ArrayUtils.add(modifiedDependents, + dependentPackageName); + outUpdatedPackageNames.add(dependentPackageName); } + } - if (modifiedDependents != null) { - libNameToModifiedDependents.put(libName, modifiedDependents); - } + if (modifiedDependents != null) { + libNameToModifiedDependents.put(libName, modifiedDependents); } } - - outUpdatedPackageNames.add(targetPackageName); - return true; - }); - - if (targetModified == null) { - // Null indicates error - return false; - } else if (!targetModified) { - // Treat non-modification as a successful commit - return true; } + outUpdatedPackageNames.add(targetPackageName); + commitPackageStateMutation(null, mutator -> { mutator.forPackage(targetPackageName) .userState(userId) @@ -8062,36 +7971,6 @@ public class PackageManagerService extends IPackageManager.Stub forEachPackageState(mComputer.getPackageStates(), actionWrapped); } - // TODO: Make private - void executeWithConsistentComputer( - @NonNull FunctionalUtils.ThrowingConsumer<Computer> consumer) { - consumer.accept(snapshotComputer()); - } - - private <T> T executeWithConsistentComputerReturning( - @NonNull FunctionalUtils.ThrowingFunction<Computer, T> function) { - return function.apply(snapshotComputer()); - } - - private <ExceptionType extends Exception> void executeWithConsistentComputerThrowing( - @NonNull FunctionalUtils.ThrowingCheckedConsumer<Computer, ExceptionType> consumer) - throws ExceptionType { - consumer.accept(snapshotComputer()); - } - - private <ExceptionOne extends Exception, ExceptionTwo extends Exception> void - executeWithConsistentComputerThrowing2( - @NonNull FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne, - ExceptionTwo> consumer) throws ExceptionOne, ExceptionTwo { - consumer.accept(snapshotComputer()); - } - - private <T, ExceptionType extends Exception> T executeWithConsistentComputerReturningThrowing( - @NonNull FunctionalUtils.ThrowingCheckedFunction<Computer, T, ExceptionType> function) - throws ExceptionType { - return function.apply(snapshotComputer()); - } - boolean isHistoricalPackageUsageAvailable() { return mPackageUsage.isHistoricalPackageUsageAvailable(); } @@ -8357,7 +8236,7 @@ public class PackageManagerService extends IPackageManager.Stub */ void writeSettingsLPrTEMP() { mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions); - mSettings.writeLPr(); + mSettings.writeLPr(mLiveComputer); } @Override @@ -8856,7 +8735,6 @@ public class PackageManagerService extends IPackageManager.Stub } void notifyInstantAppPackageInstalled(String packageName, int[] newUsers) { - executeWithConsistentComputer(computer -> - mInstantAppRegistry.onPackageInstalled(computer, packageName, newUsers)); + mInstantAppRegistry.onPackageInstalled(snapshotComputer(), packageName, newUsers); } } diff --git a/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java b/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java index 4e9a06a329a7..6e2f756cad27 100644 --- a/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java +++ b/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java @@ -16,12 +16,17 @@ package com.android.server.pm; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.util.ArrayMap; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.List; /** * Set of pending broadcasts for aggregating enable/disable of components. @@ -29,65 +34,111 @@ import java.util.ArrayList; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final class PendingPackageBroadcasts { + private final Object mLock = new PackageManagerTracedLock(); + // for each user id, a map of <package name -> components within that package> + @GuardedBy("mLock") final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap; public PendingPackageBroadcasts() { mUidMap = new SparseArray<>(2); } - public ArrayList<String> get(int userId, String packageName) { - ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId); - return packages.get(packageName); + public boolean hasPackage(@UserIdInt int userId, @NonNull String packageName) { + synchronized (mLock) { + final ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId); + return packages != null && packages.containsKey(packageName); + } } public void put(int userId, String packageName, ArrayList<String> components) { - ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId); - packages.put(packageName, components); - } - - public void remove(int userId, String packageName) { - ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId); - if (packages != null) { - packages.remove(packageName); + synchronized (mLock) { + ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId); + packages.put(packageName, components); } } - public void remove(int userId) { - mUidMap.remove(userId); + public void addComponent(@UserIdInt int userId, @NonNull String packageName, + @NonNull String componentClassName) { + synchronized (mLock) { + ArrayList<String> components = getOrAllocate(userId, packageName); + if (!components.contains(componentClassName)) { + components.add(componentClassName); + } + } } - public int userIdCount() { - return mUidMap.size(); + public void addComponents(@UserIdInt int userId, @NonNull String packageName, + @NonNull List<String> componentClassNames) { + synchronized (mLock) { + ArrayList<String> components = getOrAllocate(userId, packageName); + for (int index = 0; index < componentClassNames.size(); index++) { + String componentClassName = componentClassNames.get(index); + if (!components.contains(componentClassName)) { + components.add(componentClassName); + } + } + } } - public int userIdAt(int n) { - return mUidMap.keyAt(n); + public void remove(int userId, String packageName) { + synchronized (mLock) { + ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId); + if (packages != null) { + packages.remove(packageName); + } + } } - public ArrayMap<String, ArrayList<String>> packagesForUserId(int userId) { - return mUidMap.get(userId); + public void remove(int userId) { + synchronized (mLock) { + mUidMap.remove(userId); + } } - public int size() { - // total number of pending broadcast entries across all userIds - int num = 0; - for (int i = 0; i < mUidMap.size(); i++) { - num += mUidMap.valueAt(i).size(); + @Nullable + public SparseArray<ArrayMap<String, ArrayList<String>>> copiedMap() { + synchronized (mLock) { + SparseArray<ArrayMap<String, ArrayList<String>>> copy = new SparseArray<>(); + for (int userIdIndex = 0; userIdIndex < mUidMap.size(); userIdIndex++) { + final ArrayMap<String, ArrayList<String>> packages = mUidMap.valueAt(userIdIndex); + ArrayMap<String, ArrayList<String>> packagesCopy = new ArrayMap<>(); + for (int packagesIndex = 0; packagesIndex < packages.size(); packagesIndex++) { + packagesCopy.put(packages.keyAt(packagesIndex), + new ArrayList<>(packages.valueAt(packagesIndex))); + } + copy.put(mUidMap.keyAt(userIdIndex), packagesCopy); + } + return copy; } - return num; } public void clear() { - mUidMap.clear(); + synchronized (mLock) { + mUidMap.clear(); + } } private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) { - ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId); - if (map == null) { - map = new ArrayMap<>(); - mUidMap.put(userId, map); + synchronized (mLock) { + ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId); + if (map == null) { + map = new ArrayMap<>(); + mUidMap.put(userId, map); + } + return map; + } + } + + private ArrayList<String> getOrAllocate(int userId, @NonNull String packageName) { + synchronized (mLock) { + ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId); + if (map == null) { + map = new ArrayMap<>(); + mUidMap.put(userId, map); + } + + return map.computeIfAbsent(packageName, k -> new ArrayList<>()); } - return map; } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 2ad35b7acf50..394c8fb73156 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2432,7 +2432,7 @@ public final class Settings implements Watchable, Snappable { } } - void writeLPr() { + void writeLPr(@NonNull Computer computer) { //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024); final long startTime = SystemClock.uptimeMillis(); @@ -2524,8 +2524,8 @@ public final class Settings implements Watchable, Snappable { } } - mDomainVerificationManager.writeSettings(serializer, false /* includeSignatures */, - UserHandle.USER_ALL); + mDomainVerificationManager.writeSettings(computer, serializer, + false /* includeSignatures */, UserHandle.USER_ALL); mKeySetManagerService.writeKeySetManagerServiceLPr(serializer); @@ -2967,7 +2967,7 @@ public final class Settings implements Watchable, Snappable { } } - boolean readLPw(@NonNull List<UserInfo> users) { + boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) { FileInputStream str = null; if (mBackupSettingsFilename.exists()) { try { @@ -3111,7 +3111,7 @@ public final class Settings implements Watchable, Snappable { ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION); ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT); } else if (tagName.equals(DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) { - mDomainVerificationManager.readSettings(parser); + mDomainVerificationManager.readSettings(computer, parser); } else if (tagName.equals( DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) { mDomainVerificationManager.readLegacySettings(parser); @@ -4287,11 +4287,11 @@ public final class Settings implements Watchable, Snappable { return Process.FIRST_APPLICATION_UID + size; } - public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() { + public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) { if (mVerifierDeviceIdentity == null) { mVerifierDeviceIdentity = VerifierDeviceIdentity.generate(); - writeLPr(); + writeLPr(computer); } return mVerifierDeviceIdentity; diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java index 0638d5eee98b..3fe079034cf2 100644 --- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java +++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java @@ -321,7 +321,8 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable * on the device. * @return {@code true} if the available storage space is reached. */ - boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod) + boolean pruneUnusedStaticSharedLibraries(@NonNull Computer computer, long neededSpace, + long maxCachePeriod) throws IOException { final StorageManager storage = mInjector.getSystemService(StorageManager.class); final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL); @@ -332,38 +333,36 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable // Important: We skip shared libs used for some user since // in such a case we need to keep the APK on the device. The check for // a lib being used for any user is performed by the uninstall call. - mPm.executeWithConsistentComputer(computer -> { - final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> - sharedLibraries = computer.getSharedLibraries(); - final int libCount = sharedLibraries.size(); - for (int i = 0; i < libCount; i++) { - final WatchedLongSparseArray<SharedLibraryInfo> versionedLib = - sharedLibraries.valueAt(i); - if (versionedLib == null) { + final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> + sharedLibraries = computer.getSharedLibraries(); + final int libCount = sharedLibraries.size(); + for (int i = 0; i < libCount; i++) { + final WatchedLongSparseArray<SharedLibraryInfo> versionedLib = + sharedLibraries.valueAt(i); + if (versionedLib == null) { + continue; + } + final int versionCount = versionedLib.size(); + for (int j = 0; j < versionCount; j++) { + SharedLibraryInfo libInfo = versionedLib.valueAt(j); + final PackageStateInternal ps = getLibraryPackage(computer, libInfo); + if (ps == null) { + continue; + } + // Skip unused libs cached less than the min period to prevent pruning a lib + // needed by a subsequently installed package. + if (now - ps.getLastUpdateTime() < maxCachePeriod) { continue; } - final int versionCount = versionedLib.size(); - for (int j = 0; j < versionCount; j++) { - SharedLibraryInfo libInfo = versionedLib.valueAt(j); - final PackageStateInternal ps = getLibraryPackage(computer, libInfo); - if (ps == null) { - continue; - } - // Skip unused libs cached less than the min period to prevent pruning a lib - // needed by a subsequently installed package. - if (now - ps.getLastUpdateTime() < maxCachePeriod) { - continue; - } - - if (ps.getPkg().isSystem()) { - continue; - } - packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(), - libInfo.getDeclaringPackage().getLongVersionCode())); + if (ps.getPkg().isSystem()) { + continue; } + + packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(), + libInfo.getDeclaringPackage().getLongVersionCode())); } - }); + } final int packageCount = packagesToDelete.size(); for (int i = 0; i < packageCount; i++) { diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java index bd1c9c702bcb..3ef5599385ce 100644 --- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java +++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java @@ -27,6 +27,7 @@ import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Intent; @@ -99,10 +100,10 @@ public final class SuspendPackageHelper { * @return The names of failed packages. */ @Nullable - String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspended, - @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras, - @Nullable SuspendDialogInfo dialogInfo, @NonNull String callingPackage, - int userId, int callingUid) { + String[] setPackagesSuspended(@NonNull Computer computer, @Nullable String[] packageNames, + boolean suspended, @Nullable PersistableBundle appExtras, + @Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo, + @NonNull String callingPackage, @UserIdInt int userId, int callingUid) { if (ArrayUtils.isEmpty(packageNames)) { return packageNames; } @@ -121,62 +122,60 @@ public final class SuspendPackageHelper { ArraySet<String> modifiedPackages = new ArraySet<>(); - mPm.executeWithConsistentComputer(computer -> { - final boolean[] canSuspend = suspended - ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null; - for (int i = 0; i < packageNames.length; i++) { - final String packageName = packageNames[i]; - if (callingPackage.equals(packageName)) { - Slog.w(TAG, "Calling package: " + callingPackage + " trying to " - + (suspended ? "" : "un") + "suspend itself. Ignoring"); - unmodifiablePackages.add(packageName); - continue; - } - final PackageStateInternal packageState = - computer.getPackageStateInternal(packageName); - if (packageState == null - || computer.shouldFilterApplication(packageState, callingUid, userId)) { - Slog.w(TAG, "Could not find package setting for package: " + packageName - + ". Skipping suspending/un-suspending."); - unmodifiablePackages.add(packageName); - continue; - } - if (canSuspend != null && !canSuspend[i]) { - unmodifiablePackages.add(packageName); - continue; - } + final boolean[] canSuspend = suspended + ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null; + for (int i = 0; i < packageNames.length; i++) { + final String packageName = packageNames[i]; + if (callingPackage.equals(packageName)) { + Slog.w(TAG, "Calling package: " + callingPackage + " trying to " + + (suspended ? "" : "un") + "suspend itself. Ignoring"); + unmodifiablePackages.add(packageName); + continue; + } + final PackageStateInternal packageState = + computer.getPackageStateInternal(packageName); + if (packageState == null + || computer.shouldFilterApplication(packageState, callingUid, userId)) { + Slog.w(TAG, "Could not find package setting for package: " + packageName + + ". Skipping suspending/un-suspending."); + unmodifiablePackages.add(packageName); + continue; + } + if (canSuspend != null && !canSuspend[i]) { + unmodifiablePackages.add(packageName); + continue; + } - final WatchedArrayMap<String, SuspendParams> suspendParamsMap = - packageState.getUserStateOrDefault(userId).getSuspendParams(); - if (suspended) { - if (suspendParamsMap != null && suspendParamsMap.containsKey(packageName)) { - final SuspendParams suspendParams = suspendParamsMap.get(packageName); - // Skip if there's no changes - if (suspendParams != null - && Objects.equals(suspendParams.getDialogInfo(), dialogInfo) - && Objects.equals(suspendParams.getAppExtras(), appExtras) - && Objects.equals(suspendParams.getLauncherExtras(), - launcherExtras)) { - // Carried over API behavior, must notify change even if no change - changedPackagesList.add(packageName); - changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); - continue; - } + final WatchedArrayMap<String, SuspendParams> suspendParamsMap = + packageState.getUserStateOrDefault(userId).getSuspendParams(); + if (suspended) { + if (suspendParamsMap != null && suspendParamsMap.containsKey(packageName)) { + final SuspendParams suspendParams = suspendParamsMap.get(packageName); + // Skip if there's no changes + if (suspendParams != null + && Objects.equals(suspendParams.getDialogInfo(), dialogInfo) + && Objects.equals(suspendParams.getAppExtras(), appExtras) + && Objects.equals(suspendParams.getLauncherExtras(), + launcherExtras)) { + // Carried over API behavior, must notify change even if no change + changedPackagesList.add(packageName); + changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); + continue; } } + } - // If size one, the package will be unsuspended from this call - boolean packageUnsuspended = - !suspended && CollectionUtils.size(suspendParamsMap) <= 1; - if (suspended || packageUnsuspended) { - changedPackagesList.add(packageName); - changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); - } - - modifiedPackages.add(packageName); - modifiedUids.add(UserHandle.getUid(userId, packageState.getAppId())); + // If size one, the package will be unsuspended from this call + boolean packageUnsuspended = + !suspended && CollectionUtils.size(suspendParamsMap) <= 1; + if (suspended || packageUnsuspended) { + changedPackagesList.add(packageName); + changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); } - }); + + modifiedPackages.add(packageName); + modifiedUids.add(UserHandle.getUid(userId, packageState.getAppId())); + } mPm.commitPackageStateMutation(null, mutator -> { final int size = modifiedPackages.size(); @@ -218,29 +217,27 @@ public final class SuspendPackageHelper { * @return The names of packages which are Unsuspendable. */ @NonNull - String[] getUnsuspendablePackagesForUser(@NonNull String[] packageNames, int userId, - int callingUid) { + String[] getUnsuspendablePackagesForUser(@NonNull Computer computer, + @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) { if (!isSuspendAllowedForUser(userId, callingUid)) { Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId); return packageNames; } final ArraySet<String> unactionablePackages = new ArraySet<>(); - mPm.executeWithConsistentComputer(computer -> { - final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId, - callingUid); - for (int i = 0; i < packageNames.length; i++) { - if (!canSuspend[i]) { - unactionablePackages.add(packageNames[i]); - continue; - } - final PackageStateInternal packageState = - computer.getPackageStateFiltered(packageNames[i], callingUid, userId); - if (packageState == null) { - Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]); - unactionablePackages.add(packageNames[i]); - } + final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId, + callingUid); + for (int i = 0; i < packageNames.length; i++) { + if (!canSuspend[i]) { + unactionablePackages.add(packageNames[i]); + continue; } - }); + final PackageStateInternal packageState = + computer.getPackageStateFiltered(packageNames[i], callingUid, userId); + if (packageState == null) { + Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]); + unactionablePackages.add(packageNames[i]); + } + } return unactionablePackages.toArray(new String[unactionablePackages.size()]); } @@ -282,45 +279,44 @@ public final class SuspendPackageHelper { * suspensions will be removed. * @param userId The user for which the changes are taking place. */ - void removeSuspensionsBySuspendingPackage(@NonNull String[] packagesToChange, + void removeSuspensionsBySuspendingPackage(@NonNull Computer computer, + @NonNull String[] packagesToChange, @NonNull Predicate<String> suspendingPackagePredicate, int userId) { final List<String> unsuspendedPackages = new ArrayList<>(); final IntArray unsuspendedUids = new IntArray(); final ArrayMap<String, ArraySet<String>> pkgToSuspendingPkgsToCommit = new ArrayMap<>(); - mPm.executeWithConsistentComputer(computer -> { - for (String packageName : packagesToChange) { - final PackageStateInternal packageState = - computer.getPackageStateInternal(packageName); - final PackageUserStateInternal packageUserState = packageState == null - ? null : packageState.getUserStateOrDefault(userId); - if (packageUserState == null || !packageUserState.isSuspended()) { - continue; - } + for (String packageName : packagesToChange) { + final PackageStateInternal packageState = + computer.getPackageStateInternal(packageName); + final PackageUserStateInternal packageUserState = packageState == null + ? null : packageState.getUserStateOrDefault(userId); + if (packageUserState == null || !packageUserState.isSuspended()) { + continue; + } - WatchedArrayMap<String, SuspendParams> suspendParamsMap = - packageUserState.getSuspendParams(); - int countRemoved = 0; - for (int index = 0; index < suspendParamsMap.size(); index++) { - String suspendingPackage = suspendParamsMap.keyAt(index); - if (suspendingPackagePredicate.test(suspendingPackage)) { - ArraySet<String> suspendingPkgsToCommit = - pkgToSuspendingPkgsToCommit.get(packageName); - if (suspendingPkgsToCommit == null) { - suspendingPkgsToCommit = new ArraySet<>(); - pkgToSuspendingPkgsToCommit.put(packageName, suspendingPkgsToCommit); - } - suspendingPkgsToCommit.add(suspendingPackage); - countRemoved++; + WatchedArrayMap<String, SuspendParams> suspendParamsMap = + packageUserState.getSuspendParams(); + int countRemoved = 0; + for (int index = 0; index < suspendParamsMap.size(); index++) { + String suspendingPackage = suspendParamsMap.keyAt(index); + if (suspendingPackagePredicate.test(suspendingPackage)) { + ArraySet<String> suspendingPkgsToCommit = + pkgToSuspendingPkgsToCommit.get(packageName); + if (suspendingPkgsToCommit == null) { + suspendingPkgsToCommit = new ArraySet<>(); + pkgToSuspendingPkgsToCommit.put(packageName, suspendingPkgsToCommit); } + suspendingPkgsToCommit.add(suspendingPackage); + countRemoved++; } + } - // Everything would be removed and package unsuspended - if (countRemoved == suspendParamsMap.size()) { - unsuspendedPackages.add(packageState.getPackageName()); - unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId())); - } + // Everything would be removed and package unsuspended + if (countRemoved == suspendParamsMap.size()) { + unsuspendedPackages.add(packageState.getPackageName()); + unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId())); } - }); + } mPm.commitPackageStateMutation(null, mutator -> { for (int mapIndex = 0; mapIndex < pkgToSuspendingPkgsToCommit.size(); mapIndex++) { diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java index b730ab27c70f..e06b6081fd1b 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java @@ -30,6 +30,7 @@ import android.util.PackageUtils; import android.util.SparseArray; import com.android.internal.util.CollectionUtils; +import com.android.server.pm.Computer; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState; @@ -38,7 +39,6 @@ import com.android.server.pm.verify.domain.models.DomainVerificationStateMap; import java.util.Arrays; import java.util.List; -import java.util.function.Function; @SuppressWarnings("PointlessBooleanExpression") public class DomainVerificationDebug { @@ -62,8 +62,7 @@ public class DomainVerificationDebug { } public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName, - @Nullable @UserIdInt Integer userId, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction, + @Nullable @UserIdInt Integer userId, @NonNull Computer snapshot, @NonNull DomainVerificationStateMap<DomainVerificationPkgState> stateMap) throws NameNotFoundException { ArrayMap<String, Integer> reusedMap = new ArrayMap<>(); @@ -74,7 +73,7 @@ public class DomainVerificationDebug { for (int index = 0; index < size; index++) { DomainVerificationPkgState pkgState = stateMap.valueAt(index); String pkgName = pkgState.getPackageName(); - PackageStateInternal pkgSetting = pkgSettingFunction.apply(pkgName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName); if (pkgSetting == null || pkgSetting.getPkg() == null) { continue; } @@ -90,7 +89,7 @@ public class DomainVerificationDebug { throw DomainVerificationUtils.throwPackageUnavailable(packageName); } - PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); if (pkgSetting == null || pkgSetting.getPkg() == null) { throw DomainVerificationUtils.throwPackageUnavailable(packageName); } diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java index 25147d092066..17140865a9d5 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java @@ -25,7 +25,6 @@ import android.content.Intent; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageSettingsSnapshotProvider; import android.content.pm.ResolveInfo; import android.content.pm.verify.domain.DomainVerificationInfo; import android.content.pm.verify.domain.DomainVerificationManager; @@ -37,7 +36,7 @@ import android.util.Pair; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; -import com.android.server.pm.PackageManagerService; +import com.android.server.pm.Computer; import com.android.server.pm.PackageSetting; import com.android.server.pm.Settings; import com.android.server.pm.pkg.PackageStateInternal; @@ -227,14 +226,14 @@ public interface DomainVerificationManagerInternal { * assumed nothing has changed since the device rebooted. * <p> * If this is a new install, state will be restored from a previous call to {@link - * #restoreSettings(TypedXmlPullParser)}, or a new one will be generated. In either case, a + * #restoreSettings(Computer, TypedXmlPullParser)}, or a new one will be generated. In either case, a * broadcast will be sent to the domain verification agent so it may re-run any verification * logic for the newly associated domains. * <p> * This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal * lock. This should never be called from within the domain verification classes themselves. * <p> - * This will NOT call {@link #writeSettings(TypedXmlSerializer, boolean, int)}. That must be + * This will NOT call {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. That must be * handled by the caller. */ void addPackage(@NonNull PackageStateInternal newPkgSetting); @@ -249,7 +248,7 @@ public interface DomainVerificationManagerInternal { * This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal * lock. This should never be called from within the domain verification classes themselves. * <p> - * This will NOT call {@link #writeSettings(TypedXmlSerializer, boolean, int)}. That must be + * This will NOT call {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. That must be * handled by the caller. */ void migrateState(@NonNull PackageStateInternal oldPkgSetting, @@ -259,24 +258,24 @@ public interface DomainVerificationManagerInternal { * Serializes the entire internal state. This is equivalent to a full backup of the existing * verification state. This write includes legacy state, as a sibling tag the modern state. * + * @param snapshot * @param includeSignatures Whether to include the package signatures in the output, mainly * used for backing up the user settings and ensuring they're * re-attached to the same package. * @param userId The user to write out. Supports {@link UserHandle#USER_ALL} if all users - * should be written. */ - void writeSettings(@NonNull TypedXmlSerializer serializer, boolean includeSignatures, - @UserIdInt int userId) throws IOException; + void writeSettings(@NonNull Computer snapshot, @NonNull TypedXmlSerializer serializer, + boolean includeSignatures, @UserIdInt int userId) throws IOException; /** * Read back a list of {@link DomainVerificationPkgState}s previously written by {@link - * #writeSettings(TypedXmlSerializer, boolean, int)}. Assumes that the + * #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. Assumes that the * {@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)}. + * device. If restoring from a backup, use {@link #restoreSettings(Computer, TypedXmlPullParser)}. */ - void readSettings(@NonNull TypedXmlPullParser parser) + void readSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser) throws IOException, XmlPullParserException; /** @@ -306,7 +305,7 @@ public interface DomainVerificationManagerInternal { /** * Restore a list of {@link DomainVerificationPkgState}s previously written by {@link - * #writeSettings(TypedXmlSerializer, boolean, int)}. Assumes that the + * #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. Assumes that the * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS} * tag has already been entered. * <p> @@ -321,7 +320,7 @@ public interface DomainVerificationManagerInternal { * TODO(b/170746586): Figure out how to verify that package signatures match at snapshot time * and restore time. */ - void restoreSettings(@NonNull TypedXmlPullParser parser) + void restoreSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser) throws IOException, XmlPullParserException; /** @@ -349,17 +348,14 @@ public interface DomainVerificationManagerInternal { /** * Print the verification state and user selection state of a package. * + * @param snapshot * @param packageName the package whose state to change, or all packages if none is * specified * @param userId the specific user to print, or null to skip printing user selection - * states, supports {@link android.os.UserHandle#USER_ALL} - * @param pkgSettingFunction the method by which to retrieve package data; if this is called - * from {@link PackageManagerService}, it is expected to pass in the - * snapshot of {@link PackageStateInternal} objects + * states, supports {@link UserHandle#USER_ALL} */ - void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName, - @Nullable @UserIdInt Integer userId, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) + void printState(@NonNull Computer snapshot, @NonNull IndentingPrintWriter writer, + @Nullable String packageName, @Nullable @UserIdInt Integer userId) throws NameNotFoundException; @NonNull @@ -406,12 +402,11 @@ public interface DomainVerificationManagerInternal { @NonNull Set<String> domains, int state) throws NameNotFoundException; - interface Connection extends DomainVerificationEnforcer.Callback, - PackageSettingsSnapshotProvider { + interface Connection extends DomainVerificationEnforcer.Callback { /** * Notify that a settings change has been made and that eventually - * {@link #writeSettings(TypedXmlSerializer, boolean, int)} should be invoked by the parent. + * {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)} should be invoked by the parent. */ void scheduleWriteSettings(); @@ -433,5 +428,8 @@ public interface DomainVerificationManagerInternal { @UserIdInt int[] getAllUserIds(); + + @NonNull + Computer snapshot(); } } diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java index d6c89f7209e6..13218eaf2ded 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java @@ -37,7 +37,6 @@ import android.content.pm.verify.domain.DomainVerificationManager; import android.content.pm.verify.domain.DomainVerificationState; import android.content.pm.verify.domain.DomainVerificationUserState; import android.content.pm.verify.domain.IDomainVerificationManager; -import android.os.Build; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -52,11 +51,10 @@ import android.util.TypedXmlSerializer; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.CollectionUtils; -import com.android.internal.util.FunctionalUtils; import com.android.server.SystemConfig; import com.android.server.SystemService; import com.android.server.compat.PlatformCompat; -import com.android.server.pm.Settings; +import com.android.server.pm.Computer; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageStateUtils; @@ -80,7 +78,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; -import java.util.function.Consumer; import java.util.function.Function; @SuppressLint("MissingPermission") @@ -109,9 +106,9 @@ public class DomainVerificationService extends SystemService * immediately attached once its available. * <p> * Generally this should be not accessed directly. Prefer calling {@link - * #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Function)}. + * #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Computer)}. * - * @see #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Function) + * @see #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Computer) **/ @GuardedBy("mLock") @NonNull @@ -178,12 +175,7 @@ public class DomainVerificationService extends SystemService @Override public void setConnection(@NonNull Connection connection) { - if (Build.IS_USERDEBUG || Build.IS_ENG) { - mConnection = new LockSafeConnection(connection); - } else { - mConnection = connection; - } - + mConnection = connection; mEnforcer.setCallback(mConnection); } @@ -264,44 +256,43 @@ public class DomainVerificationService extends SystemService public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName) throws NameNotFoundException { mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy); - return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> { - synchronized (mLock) { - PackageStateInternal pkgSetting = pkgSettings.apply(packageName); - AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); - if (pkg == null) { - throw DomainVerificationUtils.throwPackageUnavailable(packageName); - } - - DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); - if (pkgState == null) { - return null; - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); + AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); + if (pkg == null) { + throw DomainVerificationUtils.throwPackageUnavailable(packageName); + } - ArrayMap<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap()); + DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); + if (pkgState == null) { + return null; + } - // TODO(b/159952358): Should the domain list be cached? - ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg); - if (domains.isEmpty()) { - return null; - } + ArrayMap<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap()); - int size = domains.size(); - for (int index = 0; index < size; index++) { - hostToStateMap.putIfAbsent(domains.valueAt(index), - DomainVerificationState.STATE_NO_RESPONSE); - } + // TODO(b/159952358): Should the domain list be cached? + ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg); + if (domains.isEmpty()) { + return null; + } - final int mapSize = hostToStateMap.size(); - for (int index = 0; index < mapSize; index++) { - int internalValue = hostToStateMap.valueAt(index); - int publicValue = DomainVerificationState.convertToInfoState(internalValue); - hostToStateMap.setValueAt(index, publicValue); - } + int size = domains.size(); + for (int index = 0; index < size; index++) { + hostToStateMap.putIfAbsent(domains.valueAt(index), + DomainVerificationState.STATE_NO_RESPONSE); + } - // TODO(b/159952358): Do not return if no values are editable (all ignored states)? - return new DomainVerificationInfo(pkgState.getId(), packageName, hostToStateMap); + final int mapSize = hostToStateMap.size(); + for (int index = 0; index < mapSize; index++) { + int internalValue = hostToStateMap.valueAt(index); + int publicValue = DomainVerificationState.convertToInfoState(internalValue); + hostToStateMap.setValueAt(index, publicValue); } - }); + + // TODO(b/159952358): Do not return if no values are editable (all ignored states)? + return new DomainVerificationInfo(pkgState.getId(), packageName, hostToStateMap); + } } @DomainVerificationManager.Error @@ -324,42 +315,40 @@ public class DomainVerificationService extends SystemService @NonNull Set<String> domains, int state) throws NameNotFoundException { mEnforcer.assertApprovedVerifier(callingUid, mProxy); - return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> { - synchronized (mLock) { - List<String> verifiedDomains = new ArrayList<>(); - - GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains, - true /* forAutoVerify */, callingUid, null /* userId */, - pkgSettings); - if (result.isError()) { - return result.getErrorCode(); - } - - DomainVerificationPkgState pkgState = result.getPkgState(); - ArrayMap<String, Integer> stateMap = pkgState.getStateMap(); - for (String domain : domains) { - Integer previousState = stateMap.get(domain); - if (previousState != null - && !DomainVerificationState.isModifiable(previousState)) { - continue; - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + List<String> verifiedDomains = new ArrayList<>(); - if (DomainVerificationState.isVerified(state)) { - verifiedDomains.add(domain); - } + GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains, + true /* forAutoVerify */, callingUid, null /* userId */, snapshot); + if (result.isError()) { + return result.getErrorCode(); + } - stateMap.put(domain, state); + DomainVerificationPkgState pkgState = result.getPkgState(); + ArrayMap<String, Integer> stateMap = pkgState.getStateMap(); + for (String domain : domains) { + Integer previousState = stateMap.get(domain); + if (previousState != null + && !DomainVerificationState.isModifiable(previousState)) { + continue; } - int size = verifiedDomains.size(); - for (int index = 0; index < size; index++) { - removeUserStatesForDomain(verifiedDomains.get(index)); + if (DomainVerificationState.isVerified(state)) { + verifiedDomains.add(domain); } + + stateMap.put(domain, state); + } + + int size = verifiedDomains.size(); + for (int index = 0; index < size; index++) { + removeUserStatesForDomain(verifiedDomains.get(index)); } + } - mConnection.scheduleWriteSettings(); - return DomainVerificationManager.STATUS_OK; - }); + mConnection.scheduleWriteSettings(); + return DomainVerificationManager.STATUS_OK; } @Override @@ -380,60 +369,30 @@ public class DomainVerificationService extends SystemService ArraySet<String> verifiedDomains = new ArraySet<>(); if (packageName == null) { - mConnection.withPackageSettingsSnapshot(pkgSettings -> { - synchronized (mLock) { - ArraySet<String> validDomains = new ArraySet<>(); - - int size = mAttachedPkgStates.size(); - for (int index = 0; index < size; index++) { - DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); - String pkgName = pkgState.getPackageName(); - PackageStateInternal pkgSetting = pkgSettings.apply(pkgName); - if (pkgSetting == null || pkgSetting.getPkg() == null) { - continue; - } - - AndroidPackage pkg = pkgSetting.getPkg(); - - validDomains.clear(); - - ArraySet<String> autoVerifyDomains = - mCollector.collectValidAutoVerifyDomains(pkg); - if (domains == null) { - validDomains.addAll(autoVerifyDomains); - } else { - validDomains.addAll(domains); - validDomains.retainAll(autoVerifyDomains); - } - - if (DomainVerificationState.isVerified(state)) { - verifiedDomains.addAll(validDomains); - } - - setDomainVerificationStatusInternal(pkgState, state, validDomains); - } - } - }); - } else { - mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> { - synchronized (mLock) { - DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); - if (pkgState == null) { - throw DomainVerificationUtils.throwPackageUnavailable(packageName); - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + ArraySet<String> validDomains = new ArraySet<>(); - PackageStateInternal pkgSetting = pkgSettings.apply(packageName); + int size = mAttachedPkgStates.size(); + for (int index = 0; index < size; index++) { + DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); + String pkgName = pkgState.getPackageName(); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName); if (pkgSetting == null || pkgSetting.getPkg() == null) { - throw DomainVerificationUtils.throwPackageUnavailable(packageName); + continue; } AndroidPackage pkg = pkgSetting.getPkg(); - final ArraySet<String> validDomains; + + validDomains.clear(); + + ArraySet<String> autoVerifyDomains = + mCollector.collectValidAutoVerifyDomains(pkg); if (domains == null) { - validDomains = mCollector.collectValidAutoVerifyDomains(pkg); + validDomains.addAll(autoVerifyDomains); } else { - validDomains = domains; - validDomains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg)); + validDomains.addAll(domains); + validDomains.retainAll(autoVerifyDomains); } if (DomainVerificationState.isVerified(state)) { @@ -442,7 +401,35 @@ public class DomainVerificationService extends SystemService setDomainVerificationStatusInternal(pkgState, state, validDomains); } - }); + } + } else { + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); + if (pkgState == null) { + throw DomainVerificationUtils.throwPackageUnavailable(packageName); + } + + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); + if (pkgSetting == null || pkgSetting.getPkg() == null) { + throw DomainVerificationUtils.throwPackageUnavailable(packageName); + } + + AndroidPackage pkg = pkgSetting.getPkg(); + final ArraySet<String> validDomains; + if (domains == null) { + validDomains = mCollector.collectValidAutoVerifyDomains(pkg); + } else { + validDomains = domains; + validDomains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg)); + } + + if (DomainVerificationState.isVerified(state)) { + verifiedDomains.addAll(validDomains); + } + + setDomainVerificationStatusInternal(pkgState, state, validDomains); + } } // Mirror SystemApi behavior of revoking user selection for approved domains. @@ -552,39 +539,38 @@ public class DomainVerificationService extends SystemService return DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID; } - return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> { - synchronized (mLock) { - GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains, - false /* forAutoVerify */, callingUid, userId, pkgSettings); - if (result.isError()) { - return result.getErrorCode(); - } - - DomainVerificationPkgState pkgState = result.getPkgState(); - DomainVerificationInternalUserState userState = pkgState.getOrCreateUserState( - userId); - - // Disable other packages if approving this one. Note that this check is only done - // for enabling. This allows an escape hatch in case multiple packages somehow get - // selected. They can be disabled without blocking in a circular dependency. - if (enabled) { - int statusCode = revokeOtherUserSelectionsLocked(userState, userId, domains, - pkgSettings); - if (statusCode != DomainVerificationManager.STATUS_OK) { - return statusCode; - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains, + false /* forAutoVerify */, callingUid, userId, snapshot); + if (result.isError()) { + return result.getErrorCode(); + } + + DomainVerificationPkgState pkgState = result.getPkgState(); + DomainVerificationInternalUserState userState = pkgState.getOrCreateUserState( + userId); + + // Disable other packages if approving this one. Note that this check is only done + // for enabling. This allows an escape hatch in case multiple packages somehow get + // selected. They can be disabled without blocking in a circular dependency. + if (enabled) { + int statusCode = revokeOtherUserSelectionsLocked(userState, userId, domains, + snapshot); + if (statusCode != DomainVerificationManager.STATUS_OK) { + return statusCode; } + } - if (enabled) { - userState.addHosts(domains); - } else { - userState.removeHosts(domains); - } + if (enabled) { + userState.addHosts(domains); + } else { + userState.removeHosts(domains); } + } - mConnection.scheduleWriteSettings(); - return DomainVerificationManager.STATUS_OK; - }); + mConnection.scheduleWriteSettings(); + return DomainVerificationManager.STATUS_OK; } @Override @@ -592,48 +578,47 @@ public class DomainVerificationService extends SystemService @NonNull String packageName, boolean enabled, @Nullable ArraySet<String> domains) throws NameNotFoundException { mEnforcer.assertInternal(mConnection.getCallingUid()); - mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> { - synchronized (mLock) { - DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); - if (pkgState == null) { - throw DomainVerificationUtils.throwPackageUnavailable(packageName); - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); + if (pkgState == null) { + throw DomainVerificationUtils.throwPackageUnavailable(packageName); + } - PackageStateInternal pkgSetting = pkgSettings.apply(packageName); - AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); - if (pkg == null) { - throw DomainVerificationUtils.throwPackageUnavailable(packageName); - } + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); + AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); + if (pkg == null) { + throw DomainVerificationUtils.throwPackageUnavailable(packageName); + } - Set<String> validDomains = - domains == null ? mCollector.collectAllWebDomains(pkg) : domains; + Set<String> validDomains = + domains == null ? mCollector.collectAllWebDomains(pkg) : domains; - validDomains.retainAll(mCollector.collectAllWebDomains(pkg)); + validDomains.retainAll(mCollector.collectAllWebDomains(pkg)); - if (userId == UserHandle.USER_ALL) { - for (int aUserId : mConnection.getAllUserIds()) { - DomainVerificationInternalUserState userState = - pkgState.getOrCreateUserState(aUserId); - revokeOtherUserSelectionsLocked(userState, aUserId, validDomains, - pkgSettings); - if (enabled) { - userState.addHosts(validDomains); - } else { - userState.removeHosts(validDomains); - } - } - } else { + if (userId == UserHandle.USER_ALL) { + for (int aUserId : mConnection.getAllUserIds()) { DomainVerificationInternalUserState userState = - pkgState.getOrCreateUserState(userId); - revokeOtherUserSelectionsLocked(userState, userId, validDomains, pkgSettings); + pkgState.getOrCreateUserState(aUserId); + revokeOtherUserSelectionsLocked(userState, aUserId, validDomains, + snapshot); if (enabled) { userState.addHosts(validDomains); } else { userState.removeHosts(validDomains); } } + } else { + DomainVerificationInternalUserState userState = + pkgState.getOrCreateUserState(userId); + revokeOtherUserSelectionsLocked(userState, userId, validDomains, snapshot); + if (enabled) { + userState.addHosts(validDomains); + } else { + userState.removeHosts(validDomains); + } } - }); + } mConnection.scheduleWriteSettings(); } @@ -641,8 +626,7 @@ public class DomainVerificationService extends SystemService @GuardedBy("mLock") private int revokeOtherUserSelectionsLocked( @NonNull DomainVerificationInternalUserState userState, @UserIdInt int userId, - @NonNull Set<String> domains, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) { + @NonNull Set<String> domains, @NonNull Computer snapshot) { // Cache the approved packages from the 1st pass because the search is expensive ArrayMap<String, List<String>> domainToApprovedPackages = new ArrayMap<>(); @@ -652,7 +636,7 @@ public class DomainVerificationService extends SystemService } Pair<List<String>, Integer> packagesToLevel = getApprovedPackagesLocked(domain, - userId, APPROVAL_LEVEL_NONE + 1, pkgSettingFunction); + userId, APPROVAL_LEVEL_NONE + 1, snapshot); int highestApproval = packagesToLevel.second; if (highestApproval > APPROVAL_LEVEL_SELECTION) { return DomainVerificationManager.ERROR_UNABLE_TO_APPROVE; @@ -698,51 +682,50 @@ public class DomainVerificationService extends SystemService throw DomainVerificationUtils.throwPackageUnavailable(packageName); } - return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> { - synchronized (mLock) { - PackageStateInternal pkgSetting = pkgSettings.apply(packageName); - AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); - if (pkg == null) { - throw DomainVerificationUtils.throwPackageUnavailable(packageName); - } - - DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); - if (pkgState == null) { - return null; - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); + AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); + if (pkg == null) { + throw DomainVerificationUtils.throwPackageUnavailable(packageName); + } - ArraySet<String> webDomains = mCollector.collectAllWebDomains(pkg); - int webDomainsSize = webDomains.size(); + DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName); + if (pkgState == null) { + return null; + } - Map<String, Integer> domains = new ArrayMap<>(webDomainsSize); - ArrayMap<String, Integer> stateMap = pkgState.getStateMap(); - DomainVerificationInternalUserState userState = pkgState.getUserState(userId); - Set<String> enabledHosts = - userState == null ? emptySet() : userState.getEnabledHosts(); - - for (int index = 0; index < webDomainsSize; index++) { - String host = webDomains.valueAt(index); - Integer state = stateMap.get(host); - - int domainState; - if (state != null && DomainVerificationState.isVerified(state)) { - domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED; - } else if (enabledHosts.contains(host)) { - domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED; - } else { - domainState = DomainVerificationUserState.DOMAIN_STATE_NONE; - } + ArraySet<String> webDomains = mCollector.collectAllWebDomains(pkg); + int webDomainsSize = webDomains.size(); - domains.put(host, domainState); + Map<String, Integer> domains = new ArrayMap<>(webDomainsSize); + ArrayMap<String, Integer> stateMap = pkgState.getStateMap(); + DomainVerificationInternalUserState userState = pkgState.getUserState(userId); + Set<String> enabledHosts = + userState == null ? emptySet() : userState.getEnabledHosts(); + + for (int index = 0; index < webDomainsSize; index++) { + String host = webDomains.valueAt(index); + Integer state = stateMap.get(host); + + int domainState; + if (state != null && DomainVerificationState.isVerified(state)) { + domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED; + } else if (enabledHosts.contains(host)) { + domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED; + } else { + domainState = DomainVerificationUserState.DOMAIN_STATE_NONE; } - boolean linkHandlingAllowed = - userState == null || userState.isLinkHandlingAllowed(); - - return new DomainVerificationUserState(pkgState.getId(), packageName, - UserHandle.of(userId), linkHandlingAllowed, domains); + domains.put(host, domainState); } - }); + + boolean linkHandlingAllowed = + userState == null || userState.isLinkHandlingAllowed(); + + return new DomainVerificationUserState(pkgState.getId(), packageName, + UserHandle.of(userId), linkHandlingAllowed, domains); + } } @NonNull @@ -751,27 +734,26 @@ public class DomainVerificationService extends SystemService mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(), userId); - return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> { - SparseArray<List<String>> levelToPackages = getOwnersForDomainInternal(domain, false, - userId, pkgSettings); - if (levelToPackages.size() == 0) { - return emptyList(); - } + final Computer snapshot = mConnection.snapshot(); + SparseArray<List<String>> levelToPackages = getOwnersForDomainInternal(domain, false, + userId, snapshot); + if (levelToPackages.size() == 0) { + return emptyList(); + } - List<DomainOwner> owners = new ArrayList<>(); - int size = levelToPackages.size(); - for (int index = 0; index < size; index++) { - int level = levelToPackages.keyAt(index); - boolean overrideable = level <= APPROVAL_LEVEL_SELECTION; - List<String> packages = levelToPackages.valueAt(index); - int packagesSize = packages.size(); - for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) { - owners.add(new DomainOwner(packages.get(packageIndex), overrideable)); - } + List<DomainOwner> owners = new ArrayList<>(); + int size = levelToPackages.size(); + for (int index = 0; index < size; index++) { + int level = levelToPackages.keyAt(index); + boolean overrideable = level <= APPROVAL_LEVEL_SELECTION; + List<String> packages = levelToPackages.valueAt(index); + int packagesSize = packages.size(); + for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) { + owners.add(new DomainOwner(packages.get(packageIndex), overrideable)); } + } - return owners; - }); + return owners; } /** @@ -782,8 +764,7 @@ public class DomainVerificationService extends SystemService */ @NonNull private SparseArray<List<String>> getOwnersForDomainInternal(@NonNull String domain, - boolean includeNegative, @UserIdInt int userId, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) { + boolean includeNegative, @UserIdInt int userId, @NonNull Computer snapshot) { SparseArray<List<String>> levelToPackages = new SparseArray<>(); // First, collect the raw approval level values synchronized (mLock) { @@ -791,7 +772,7 @@ public class DomainVerificationService extends SystemService for (int index = 0; index < size; index++) { DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); String packageName = pkgState.getPackageName(); - PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); if (pkgSetting == null) { continue; } @@ -818,8 +799,8 @@ public class DomainVerificationService extends SystemService // Then sort them ascending by first installed time, with package name as tie breaker for (int index = 0; index < size; index++) { levelToPackages.valueAt(index).sort((first, second) -> { - PackageStateInternal firstPkgSetting = pkgSettingFunction.apply(first); - PackageStateInternal secondPkgSetting = pkgSettingFunction.apply(second); + PackageStateInternal firstPkgSetting = snapshot.getPackageStateInternal(first); + PackageStateInternal secondPkgSetting = snapshot.getPackageStateInternal(second); long firstInstallTime = firstPkgSetting == null ? -1L : firstPkgSetting.getUserStateOrDefault(userId).getFirstInstallTime(); @@ -1060,44 +1041,38 @@ public class DomainVerificationService extends SystemService } @Override - public void writeSettings(@NonNull TypedXmlSerializer serializer, boolean includeSignatures, - @UserIdInt int userId) - throws IOException { - mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> { - synchronized (mLock) { - Function<String, String> pkgNameToSignature = null; - if (includeSignatures) { - pkgNameToSignature = pkgName -> { - PackageStateInternal pkgSetting = pkgSettings.apply(pkgName); - if (pkgSetting == null) { - // If querying for a user restored package that isn't installed on the - // device yet, there will be no signature to write out. In that case, - // it's expected that this returns null and it falls back to the - // restored state's stored signature if it exists. - return null; - } - - return PackageUtils.computeSignaturesSha256Digest( - pkgSetting.getSigningDetails().getSignatures()); - }; - } + public void writeSettings(Computer snapshot, @NonNull TypedXmlSerializer serializer, + boolean includeSignatures, @UserIdInt int userId) throws IOException { + synchronized (mLock) { + Function<String, String> pkgNameToSignature = null; + if (includeSignatures) { + pkgNameToSignature = pkgName -> { + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName); + if (pkgSetting == null) { + // If querying for a user restored package that isn't installed on the + // device yet, there will be no signature to write out. In that case, + // it's expected that this returns null and it falls back to the + // restored state's stored signature if it exists. + return null; + } - mSettings.writeSettings(serializer, mAttachedPkgStates, userId, pkgNameToSignature); + return PackageUtils.computeSignaturesSha256Digest( + pkgSetting.getSigningDetails().getSignatures()); + }; } - }); + + mSettings.writeSettings(serializer, mAttachedPkgStates, userId, pkgNameToSignature); + } mLegacySettings.writeSettings(serializer); } @Override - public void readSettings(@NonNull TypedXmlPullParser parser) throws IOException, - XmlPullParserException { - mConnection.<IOException, XmlPullParserException>withPackageSettingsSnapshotThrowing2( - pkgSettings -> { - synchronized (mLock) { - mSettings.readSettings(parser, mAttachedPkgStates, pkgSettings); - } - }); + public void readSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser) + throws IOException, XmlPullParserException { + synchronized (mLock) { + mSettings.readSettings(parser, mAttachedPkgStates, snapshot); + } } @Override @@ -1107,14 +1082,11 @@ public class DomainVerificationService extends SystemService } @Override - public void restoreSettings(@NonNull TypedXmlPullParser parser) + public void restoreSettings(Computer snapshot, @NonNull TypedXmlPullParser parser) throws IOException, XmlPullParserException { - mConnection.<IOException, XmlPullParserException>withPackageSettingsSnapshotThrowing2( - pkgSettings -> { - synchronized (mLock) { - mSettings.restoreSettings(parser, mAttachedPkgStates, pkgSettings); - } - }); + synchronized (mLock) { + mSettings.restoreSettings(parser, mAttachedPkgStates, snapshot); + } } @Override @@ -1190,18 +1162,16 @@ public class DomainVerificationService extends SystemService @Override public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName, @Nullable Integer userId) throws NameNotFoundException { - mConnection.withPackageSettingsSnapshotThrowing( - pkgSettings -> printState(writer, packageName, userId, pkgSettings)); + printState(mConnection.snapshot(), writer, packageName, userId); } @Override - public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName, - @Nullable @UserIdInt Integer userId, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) + public void printState(@NonNull Computer snapshot, @NonNull IndentingPrintWriter writer, + @Nullable String packageName, @Nullable @UserIdInt Integer userId) throws NameNotFoundException { mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy); synchronized (mLock) { - mDebug.printState(writer, packageName, userId, pkgSettingFunction, mAttachedPkgStates); + mDebug.printState(writer, packageName, userId, snapshot, mAttachedPkgStates); } } @@ -1209,31 +1179,30 @@ public class DomainVerificationService extends SystemService public void printOwnersForPackage(@NonNull IndentingPrintWriter writer, @Nullable String packageName, @Nullable @UserIdInt Integer userId) throws NameNotFoundException { - mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> { - synchronized (mLock) { - if (packageName == null) { - int size = mAttachedPkgStates.size(); - for (int index = 0; index < size; index++) { - try { - printOwnersForPackage(writer, - mAttachedPkgStates.valueAt(index).getPackageName(), userId, - pkgSettings); - } catch (NameNotFoundException ignored) { - // When iterating packages, if one doesn't exist somehow, ignore - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + if (packageName == null) { + int size = mAttachedPkgStates.size(); + for (int index = 0; index < size; index++) { + try { + printOwnersForPackage(writer, + mAttachedPkgStates.valueAt(index).getPackageName(), userId, + snapshot); + } catch (NameNotFoundException ignored) { + // When iterating packages, if one doesn't exist somehow, ignore } - } else { - printOwnersForPackage(writer, packageName, userId, pkgSettings); } + } else { + printOwnersForPackage(writer, packageName, userId, snapshot); } - }); + } } private void printOwnersForPackage(@NonNull IndentingPrintWriter writer, @NonNull String packageName, @Nullable @UserIdInt Integer userId, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) + @NonNull Computer snapshot) throws NameNotFoundException { - PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); if (pkg == null) { throw DomainVerificationUtils.throwPackageUnavailable(packageName); @@ -1249,7 +1218,7 @@ public class DomainVerificationService extends SystemService writer.increaseIndent(); for (int index = 0; index < size; index++) { - printOwnersForDomain(writer, domains.valueAt(index), userId, pkgSettingFunction); + printOwnersForDomain(writer, domains.valueAt(index), userId, snapshot); } writer.decreaseIndent(); @@ -1258,30 +1227,28 @@ public class DomainVerificationService extends SystemService @Override public void printOwnersForDomains(@NonNull IndentingPrintWriter writer, @NonNull List<String> domains, @Nullable @UserIdInt Integer userId) { - mConnection.withPackageSettingsSnapshot(pkgSettings -> { - synchronized (mLock) { - int size = domains.size(); - for (int index = 0; index < size; index++) { - printOwnersForDomain(writer, domains.get(index), userId, pkgSettings); - } + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + int size = domains.size(); + for (int index = 0; index < size; index++) { + printOwnersForDomain(writer, domains.get(index), userId, snapshot); } - }); + } } private void printOwnersForDomain(@NonNull IndentingPrintWriter writer, @NonNull String domain, - @Nullable @UserIdInt Integer userId, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) { + @Nullable @UserIdInt Integer userId, @NonNull Computer snapshot) { SparseArray<SparseArray<List<String>>> userIdToApprovalLevelToOwners = new SparseArray<>(); if (userId == null || userId == UserHandle.USER_ALL) { for (int aUserId : mConnection.getAllUserIds()) { userIdToApprovalLevelToOwners.put(aUserId, - getOwnersForDomainInternal(domain, true, aUserId, pkgSettingFunction)); + getOwnersForDomainInternal(domain, true, aUserId, snapshot)); } } else { userIdToApprovalLevelToOwners.put(userId, - getOwnersForDomainInternal(domain, true, userId, pkgSettingFunction)); + getOwnersForDomainInternal(domain, true, userId, snapshot)); } mDebug.printOwners(writer, domain, userIdToApprovalLevelToOwners); @@ -1330,8 +1297,7 @@ public class DomainVerificationService extends SystemService @GuardedBy("mLock") private GetAttachedResult getAndValidateAttachedLocked(@NonNull UUID domainSetId, @NonNull Set<String> domains, boolean forAutoVerify, int callingUid, - @Nullable Integer userIdForFilter, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) + @Nullable Integer userIdForFilter, @NonNull Computer snapshot) throws NameNotFoundException { if (domainSetId == null) { throw new IllegalArgumentException("domainSetId cannot be null"); @@ -1349,7 +1315,7 @@ public class DomainVerificationService extends SystemService return GetAttachedResult.error(DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID); } - PackageStateInternal pkgSetting = pkgSettingFunction.apply(pkgName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName); if (pkgSetting == null || pkgSetting.getPkg() == null) { throw DomainVerificationUtils.throwPackageUnavailable(pkgName); } @@ -1437,33 +1403,32 @@ public class DomainVerificationService extends SystemService @Override public void clearDomainVerificationState(@Nullable List<String> packageNames) { mEnforcer.assertInternal(mConnection.getCallingUid()); - mConnection.withPackageSettingsSnapshot(pkgSettings -> { - synchronized (mLock) { - if (packageNames == null) { - int size = mAttachedPkgStates.size(); - for (int index = 0; index < size; index++) { - DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); - String pkgName = pkgState.getPackageName(); - PackageStateInternal pkgSetting = pkgSettings.apply(pkgName); - if (pkgSetting == null || pkgSetting.getPkg() == null) { - continue; - } - resetDomainState(pkgState.getStateMap(), pkgSetting); + synchronized (mLock) { + final Computer snapshot = mConnection.snapshot(); + if (packageNames == null) { + int size = mAttachedPkgStates.size(); + for (int index = 0; index < size; index++) { + DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); + String pkgName = pkgState.getPackageName(); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName); + if (pkgSetting == null || pkgSetting.getPkg() == null) { + continue; } - } else { - int size = packageNames.size(); - for (int index = 0; index < size; index++) { - String pkgName = packageNames.get(index); - DomainVerificationPkgState pkgState = mAttachedPkgStates.get(pkgName); - PackageStateInternal pkgSetting = pkgSettings.apply(pkgName); - if (pkgSetting == null || pkgSetting.getPkg() == null) { - continue; - } - resetDomainState(pkgState.getStateMap(), pkgSetting); + resetDomainState(pkgState.getStateMap(), pkgSetting); + } + } else { + int size = packageNames.size(); + for (int index = 0; index < size; index++) { + String pkgName = packageNames.get(index); + DomainVerificationPkgState pkgState = mAttachedPkgStates.get(pkgName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName); + if (pkgSetting == null || pkgSetting.getPkg() == null) { + continue; } + resetDomainState(pkgState.getStateMap(), pkgSetting); } } - }); + } mConnection.scheduleWriteSettings(); } @@ -1935,35 +1900,32 @@ public class DomainVerificationService extends SystemService @GuardedBy("mLock") @NonNull private Pair<List<String>, Integer> getApprovedPackagesLocked(@NonNull String domain, - @UserIdInt int userId, int minimumApproval, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) { + @UserIdInt int userId, int minimumApproval, @NonNull Computer snapshot) { boolean includeNegative = minimumApproval < APPROVAL_LEVEL_NONE; int highestApproval = minimumApproval; List<String> approvedPackages = emptyList(); - synchronized (mLock) { - final int size = mAttachedPkgStates.size(); - for (int index = 0; index < size; index++) { - DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); - String packageName = pkgState.getPackageName(); - PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName); - if (pkgSetting == null) { - continue; - } + final int size = mAttachedPkgStates.size(); + for (int index = 0; index < size; index++) { + DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index); + String packageName = pkgState.getPackageName(); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); + if (pkgSetting == null) { + continue; + } - int level = approvalLevelForDomain(pkgSetting, domain, includeNegative, userId, - domain); - if (level < minimumApproval) { - continue; - } + int level = approvalLevelForDomain(pkgSetting, domain, includeNegative, userId, + domain); + if (level < minimumApproval) { + continue; + } - if (level > highestApproval) { - approvedPackages.clear(); - approvedPackages = CollectionUtils.add(approvedPackages, packageName); - highestApproval = level; - } else if (level == highestApproval) { - approvedPackages = CollectionUtils.add(approvedPackages, packageName); - } + if (level > highestApproval) { + approvedPackages.clear(); + approvedPackages = CollectionUtils.add(approvedPackages, packageName); + highestApproval = level; + } else if (level == highestApproval) { + approvedPackages = CollectionUtils.add(approvedPackages, packageName); } } @@ -1976,7 +1938,7 @@ public class DomainVerificationService extends SystemService final int approvedSize = approvedPackages.size(); for (int index = 0; index < approvedSize; index++) { String packageName = approvedPackages.get(index); - PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName); + PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName); if (pkgSetting == null) { continue; } @@ -2035,108 +1997,4 @@ public class DomainVerificationService extends SystemService return mErrorCode; } } - - /** - * Wraps a {@link Connection} to verify that the {@link PackageStateInternal} calls do not hold - * {@link #mLock}, as that can cause deadlock when {@link Settings} tries to serialize state to - * disk. Only enabled if {@link Build#IS_USERDEBUG} or {@link Build#IS_ENG} is true. - */ - private class LockSafeConnection implements Connection { - - @NonNull - private final Connection mConnection; - - private LockSafeConnection(@NonNull Connection connection) { - mConnection = connection; - } - - private void enforceLocking() { - if (Thread.holdsLock(mLock)) { - Slog.wtf(TAG, "Method should not hold DVS lock when accessing package data"); - } - } - - @Override - public void withPackageSettingsSnapshot( - @NonNull Consumer<Function<String, PackageStateInternal>> block) { - enforceLocking(); - mConnection.withPackageSettingsSnapshot(block); - } - - @Override - public <Output> Output withPackageSettingsSnapshotReturning( - @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>, - Output> block) { - enforceLocking(); - return mConnection.withPackageSettingsSnapshotReturning(block); - } - - @Override - public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing( - @NonNull FunctionalUtils.ThrowingCheckedConsumer< - Function<String, PackageStateInternal>, ExceptionType> block) - throws ExceptionType { - enforceLocking(); - mConnection.withPackageSettingsSnapshotThrowing(block); - } - - @Override - public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void - withPackageSettingsSnapshotThrowing2( - @NonNull FunctionalUtils.ThrowingChecked2Consumer< - Function<String, PackageStateInternal>, ExceptionOne, - ExceptionTwo> block) - throws ExceptionOne, ExceptionTwo { - enforceLocking(); - mConnection.withPackageSettingsSnapshotThrowing2(block); - } - - @Override - public <Output, ExceptionType extends Exception> Output - withPackageSettingsSnapshotReturningThrowing( - @NonNull FunctionalUtils.ThrowingCheckedFunction< - Function<String, PackageStateInternal>, Output, - ExceptionType> block) - throws ExceptionType { - enforceLocking(); - return mConnection.withPackageSettingsSnapshotReturningThrowing(block); - } - - @Override - public void scheduleWriteSettings() { - mConnection.scheduleWriteSettings(); - } - - @Override - public int getCallingUid() { - return mConnection.getCallingUid(); - } - - @Override - @UserIdInt - public int getCallingUserId() { - return mConnection.getCallingUserId(); - } - - @Override - public void schedule(int code, @Nullable Object object) { - mConnection.schedule(code, object); - } - - @Override - @UserIdInt - public int[] getAllUserIds() { - return mConnection.getAllUserIds(); - } - - @Override - public boolean filterAppAccess(@NonNull String packageName, int callingUid, int userId) { - return mConnection.filterAppAccess(packageName, callingUid, userId); - } - - @Override - public boolean doesUserExist(int userId) { - return mConnection.doesUserExist(userId); - } - } } diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java index 015d4e9e9f16..8d1ae0bc20b0 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java @@ -28,6 +28,7 @@ import android.util.TypedXmlSerializer; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.Computer; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState; @@ -101,8 +102,7 @@ class DomainVerificationSettings { */ public void readSettings(@NonNull TypedXmlPullParser parser, @NonNull DomainVerificationStateMap<DomainVerificationPkgState> liveState, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) - throws IOException, XmlPullParserException { + @NonNull Computer snapshot) throws IOException, XmlPullParserException { DomainVerificationPersistence.ReadResult result = DomainVerificationPersistence.readFromXml(parser); ArrayMap<String, DomainVerificationPkgState> active = result.active; @@ -118,7 +118,7 @@ class DomainVerificationSettings { // This branch should never be possible. Settings should be read from disk // before any states are attached. But just in case, handle it. if (!existingState.getId().equals(pkgState.getId())) { - mergePkgState(existingState, pkgState, pkgSettingFunction); + mergePkgState(existingState, pkgState, snapshot); } } else { mPendingPkgStates.put(pkgName, pkgState); @@ -139,8 +139,7 @@ class DomainVerificationSettings { */ public void restoreSettings(@NonNull TypedXmlPullParser parser, @NonNull DomainVerificationStateMap<DomainVerificationPkgState> liveState, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) - throws IOException, XmlPullParserException { + @NonNull Computer snapshot) throws IOException, XmlPullParserException { // TODO(b/170746586): Restoration assumes user IDs match, which is probably not the case on // a new device. @@ -166,7 +165,7 @@ class DomainVerificationSettings { } if (existingState != null) { - mergePkgState(existingState, newState, pkgSettingFunction); + mergePkgState(existingState, newState, snapshot); } else { // If there's no existing state, that means the new state has to be transformed // in preparation for attaching to brand new package that may eventually be @@ -216,9 +215,9 @@ class DomainVerificationSettings { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void mergePkgState(@NonNull DomainVerificationPkgState oldState, - @NonNull DomainVerificationPkgState newState, - @NonNull Function<String, PackageStateInternal> pkgSettingFunction) { - PackageStateInternal pkgSetting = pkgSettingFunction.apply(oldState.getPackageName()); + @NonNull DomainVerificationPkgState newState, @NonNull Computer snapshot) { + PackageStateInternal pkgSetting = + snapshot.getPackageStateInternal(oldState.getPackageName()); AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg(); Set<String> validDomains = pkg == null ? Collections.emptySet() : mCollector.collectValidAutoVerifyDomains(pkg); diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java index da2d162d46f9..4b0a8e2778c0 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java @@ -32,6 +32,7 @@ import android.util.ArraySet; import android.util.IndentingPrintWriter; import com.android.modules.utils.BasicShellCommandHandler; +import com.android.server.pm.Computer; import java.io.PrintWriter; import java.util.ArrayList; @@ -39,7 +40,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.function.Function; public class DomainVerificationShell { @@ -599,8 +599,8 @@ public class DomainVerificationShell { void verifyPackages(@Nullable List<String> packageNames, boolean reVerify); /** - * @see DomainVerificationManagerInternal#printState(IndentingPrintWriter, String, Integer, - * Function) + * @see DomainVerificationManagerInternal#printState(Computer, IndentingPrintWriter, String, + * Integer) */ void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName, @Nullable @UserIdInt Integer userId) throws NameNotFoundException; diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt index 43b2e1e4b21e..dcc461be0015 100644 --- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt +++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt @@ -265,12 +265,14 @@ class PackageManagerComponentLabelIconOverrideTest { assertServiceInitialized() ?: return when (params.result) { is Result.Changed, Result.ChangedWithoutNotify -> { - assertThat(mockPendingBroadcasts.get(userId, params.pkgName) ?: emptyList<String>()) + assertThat(mockPendingBroadcasts.copiedMap()?.get(userId)?.get(params.pkgName) + ?: emptyList<String>()) .containsExactly(params.componentName!!.className) .inOrder() } is Result.NotChanged, is Result.Exception -> { - assertThat(mockPendingBroadcasts.get(userId, params.pkgName)).isNull() + assertThat(mockPendingBroadcasts.copiedMap()?.get(userId)?.get(params.pkgName)) + .isNull() } }.run { /*exhaust*/ } } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt index 92cdb348e60d..c9601de6ff26 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt @@ -20,8 +20,6 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.content.pm.SigningDetails -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import android.content.pm.verify.domain.DomainVerificationManager import android.content.pm.verify.domain.DomainVerificationState import android.os.Build @@ -30,10 +28,12 @@ import android.util.ArraySet import android.util.IndentingPrintWriter import android.util.SparseArray import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.pm.Computer import com.android.server.pm.parsing.pkg.AndroidPackage import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates +import com.android.server.pm.pkg.component.ParsedActivityImpl +import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationEnforcer import com.android.server.pm.verify.domain.DomainVerificationManagerInternal import com.android.server.pm.verify.domain.DomainVerificationService @@ -100,11 +100,15 @@ class DomainVerificationEnforcerTest { mockThrowOnUnmocked { whenever(callingUid) { callingUidInt.get() } whenever(callingUserId) { callingUserIdInt.get() } - mockPackageStates { - when (it) { - VISIBLE_PKG -> visiblePkgState - INVISIBLE_PKG -> invisiblePkgState - else -> null + whenever(snapshot()) { + mockThrowOnUnmocked { + whenever(getPackageStateInternal(anyString())) { + when (getArgument<String>(0)) { + VISIBLE_PKG -> visiblePkgState + INVISIBLE_PKG -> invisiblePkgState + else -> null + } + } } } whenever(schedule(anyInt(), any())) @@ -211,9 +215,8 @@ class DomainVerificationEnforcerTest { printState(mock(IndentingPrintWriter::class.java), null, null) }, service(Type.QUERENT, "printStateInternal") { - printState(mock(IndentingPrintWriter::class.java), null, null) { - mockPkgState(it, UUID.randomUUID()) - } + printState(mock(Computer::class.java), mock(IndentingPrintWriter::class.java), + null, null) }, service(Type.VERIFIER, "setStatus") { setDomainVerificationStatus( diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt index 878bee012635..7273b0b54e1e 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt @@ -19,9 +19,6 @@ package com.android.server.pm.test.verify.domain import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl -import com.android.server.pm.pkg.PackageUserStateInternal import android.content.pm.verify.domain.DomainOwner import android.content.pm.verify.domain.DomainVerificationInfo import android.content.pm.verify.domain.DomainVerificationManager @@ -34,7 +31,9 @@ import android.util.ArraySet import android.util.SparseArray import com.android.server.pm.parsing.pkg.AndroidPackage import com.android.server.pm.pkg.PackageStateInternal -import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates +import com.android.server.pm.pkg.PackageUserStateInternal +import com.android.server.pm.pkg.component.ParsedActivityImpl +import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationManagerStub import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.testutils.mockThrowOnUnmocked @@ -502,8 +501,12 @@ class DomainVerificationManagerApiTest { whenever(callingUid) { Process.ROOT_UID } whenever(callingUserId) { 0 } - mockPackageStates { - pkgStateFunction(it) + whenever(snapshot()) { + mockThrowOnUnmocked { + whenever(getPackageStateInternal(anyString())) { + pkgStateFunction(getArgument(0)) + } + } } }) } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt index 0369bab61f0f..40f37a7ee1f7 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt @@ -20,9 +20,6 @@ import android.content.Intent import android.content.pm.PackageManager import android.content.pm.Signature import android.content.pm.SigningDetails -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl -import com.android.server.pm.pkg.PackageUserStateInternal import android.content.pm.verify.domain.DomainOwner import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED import android.content.pm.verify.domain.DomainVerificationInfo.STATE_NO_RESPONSE @@ -39,9 +36,12 @@ import android.os.Process import android.util.ArraySet import android.util.SparseArray import android.util.Xml +import com.android.server.pm.Computer import com.android.server.pm.parsing.pkg.AndroidPackage import com.android.server.pm.pkg.PackageStateInternal -import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates +import com.android.server.pm.pkg.PackageUserStateInternal +import com.android.server.pm.pkg.component.ParsedActivityImpl +import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.testutils.mock import com.android.server.testutils.mockThrowOnUnmocked @@ -194,7 +194,8 @@ class DomainVerificationPackageTest { """ val service = makeService(pkg1, pkg2) - service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream())) + val computer = mockComputer(pkg1, pkg2) + service.restoreSettings(computer, Xml.resolvePullParser(xml.byteInputStream())) service.addPackage(pkg1) val info = service.getInfo(pkg1.packageName) assertThat(info.packageName).isEqualTo(pkg1.packageName) @@ -243,7 +244,8 @@ class DomainVerificationPackageTest { """ val service = makeService(pkg1, pkg2) - service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream())) + val computer = mockComputer(pkg1, pkg2) + service.restoreSettings(computer, Xml.resolvePullParser(xml.byteInputStream())) service.addPackage(pkg1) val info = service.getInfo(pkg1.packageName) assertThat(info.packageName).isEqualTo(pkg1.packageName) @@ -298,8 +300,9 @@ class DomainVerificationPackageTest { """.trimIndent() val service = makeService(pkg1, pkg2) + val computer = mockComputer(pkg1, pkg2) xml.byteInputStream().use { - service.readSettings(Xml.resolvePullParser(it)) + service.readSettings(computer, Xml.resolvePullParser(it)) } service.addPackage(pkg1) @@ -311,8 +314,9 @@ class DomainVerificationPackageTest { fun addPackagePendingStripInvalidDomains() { val xml = addPackagePendingOrRestoredWithInvalidDomains() val service = makeService(pkg1, pkg2) + val computer = mockComputer(pkg1, pkg2) xml.byteInputStream().use { - service.readSettings(Xml.resolvePullParser(it)) + service.readSettings(computer, Xml.resolvePullParser(it)) } service.addPackage(pkg1) @@ -334,8 +338,9 @@ class DomainVerificationPackageTest { fun addPackageRestoredStripInvalidDomains() { val xml = addPackagePendingOrRestoredWithInvalidDomains() val service = makeService(pkg1, pkg2) + val computer = mockComputer(pkg1, pkg2) xml.byteInputStream().use { - service.restoreSettings(Xml.resolvePullParser(it)) + service.restoreSettings(computer, Xml.resolvePullParser(it)) } service.addPackage(pkg1) @@ -686,6 +691,7 @@ class DomainVerificationPackageTest { val pkg2 = mockPkgState(PKG_TWO, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3)) val serviceBefore = makeService(pkg1, pkg2) + val computerBefore = mockComputer(pkg1, pkg2) serviceBefore.addPackage(pkg1) serviceBefore.addPackage(pkg2) @@ -729,16 +735,17 @@ class DomainVerificationPackageTest { assertExpectedState(serviceBefore) val backupUser0 = ByteArrayOutputStream().use { - serviceBefore.writeSettings(Xml.resolveSerializer(it), true, 0) + serviceBefore.writeSettings(computerBefore, Xml.resolveSerializer(it), true, 0) it.toByteArray() } val backupUser1 = ByteArrayOutputStream().use { - serviceBefore.writeSettings(Xml.resolveSerializer(it), true, 10) + serviceBefore.writeSettings(computerBefore, Xml.resolveSerializer(it), true, 10) it.toByteArray() } val serviceAfter = makeService(pkg1, pkg2) + val computerAfter = mockComputer(pkg1, pkg2) serviceAfter.addPackage(pkg1) serviceAfter.addPackage(pkg2) @@ -763,7 +770,7 @@ class DomainVerificationPackageTest { } ByteArrayInputStream(backupUser1).use { - serviceAfter.restoreSettings(Xml.resolvePullParser(it)) + serviceAfter.restoreSettings(computerAfter, Xml.resolvePullParser(it)) } // Assert user 1 was restored @@ -800,7 +807,7 @@ class DomainVerificationPackageTest { ) ByteArrayInputStream(backupUser0).use { - serviceAfter.restoreSettings(Xml.resolvePullParser(it)) + serviceAfter.restoreSettings(computerAfter, Xml.resolvePullParser(it)) } assertExpectedState(serviceAfter) @@ -848,12 +855,20 @@ class DomainVerificationPackageTest { whenever(callingUid) { Process.ROOT_UID } whenever(callingUserId) { 0 } - mockPackageStates { - pkgStateFunction(it) - } + whenever(snapshot()) { mockComputer(pkgStateFunction) } }) } + private fun mockComputer(vararg pkgStates: PackageStateInternal) = + mockComputer { pkgName -> pkgStates.find { pkgName == it.packageName } } + + private fun mockComputer(pkgStateFunction: (String) -> PackageStateInternal? = { null }) = + mockThrowOnUnmocked<Computer> { + whenever(getPackageStateInternal(anyString())) { + pkgStateFunction(getArgument(0)) + } + } + private fun mockPkgState( pkgName: String, domainSetId: UUID, diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt index 3a602a8b3c46..fc20c2657b97 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt @@ -29,7 +29,6 @@ import android.util.ArraySet import android.util.SparseArray import com.android.server.pm.parsing.pkg.AndroidPackage import com.android.server.pm.pkg.PackageStateInternal -import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates import com.android.server.pm.verify.domain.DomainVerificationManagerInternal import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy @@ -245,10 +244,14 @@ class DomainVerificationSettingsMutationTest { mockThrowOnUnmocked { whenever(callingUid) { TEST_UID } whenever(callingUserId) { TEST_USER_ID } - mockPackageStates { - when (it) { - TEST_PKG -> mockPkgState() - else -> null + whenever(snapshot()) { + mockThrowOnUnmocked { + whenever(getPackageStateInternal(anyString())) { + when (getArgument<String>(0)) { + TEST_PKG -> mockPkgState() + else -> null + } + } } } whenever(schedule(anyInt(), any())) diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationTestUtils.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationTestUtils.kt deleted file mode 100644 index c5f0eb184386..000000000000 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationTestUtils.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.test.verify.domain - -import com.android.internal.util.FunctionalUtils -import com.android.server.pm.pkg.PackageStateInternal -import com.android.server.pm.verify.domain.DomainVerificationManagerInternal -import com.android.server.testutils.whenever -import org.mockito.ArgumentMatchers.any -import java.util.function.Consumer -import java.util.function.Function - -internal object DomainVerificationTestUtils { - - @Suppress("UNCHECKED_CAST") - fun DomainVerificationManagerInternal.Connection.mockPackageStates( - block: (String) -> PackageStateInternal? - ) { - whenever(withPackageSettingsSnapshot(any())) { - (arguments[0] as Consumer<Function<String, PackageStateInternal?>>).accept { block(it) } - } - whenever(withPackageSettingsSnapshotReturning(any())) { - (arguments[0] as FunctionalUtils.ThrowingFunction< - Function<String, PackageStateInternal?>, *>) - .apply { block(it) } - } - whenever(withPackageSettingsSnapshotThrowing<Exception>(any())) { - (arguments[0] as FunctionalUtils.ThrowingCheckedConsumer< - Function<String, PackageStateInternal?>, *>) - .accept { block(it) } - } - whenever(withPackageSettingsSnapshotThrowing2<Exception, Exception>(any())) { - (arguments[0] as FunctionalUtils.ThrowingChecked2Consumer< - Function<String, PackageStateInternal?>, *, *>) - .accept { block(it) } - } - whenever(withPackageSettingsSnapshotReturningThrowing<Any, Exception>(any())) { - (arguments[0] as FunctionalUtils.ThrowingCheckedFunction< - Function<String, PackageStateInternal?>, *, *>) - .apply { block(it) } - } - } -} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt index ffc287736066..589633ccb900 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt @@ -31,7 +31,6 @@ import android.util.SparseArray import com.android.server.pm.parsing.pkg.AndroidPackage import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever @@ -85,11 +84,15 @@ class DomainVerificationUserStateOverrideTest { // Need to provide an internal UID so some permission checks are ignored whenever(callingUid) { Process.ROOT_UID } whenever(callingUserId) { 0 } - mockPackageStates { - when (it) { - PKG_ONE -> pkg1 - PKG_TWO -> pkg2 - else -> null + whenever(snapshot()) { + mockThrowOnUnmocked { + whenever(getPackageStateInternal(anyString())) { + when (getArgument<String>(0)) { + PKG_ONE -> pkg1 + PKG_TWO -> pkg2 + else -> null + } + } } } }) diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index ca5bf2085d71..6510cd19e5fb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -167,7 +167,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { } whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap) whenever(mocks.settings.getPackageLPr(anyString())) { mSettingsMap[getArgument<Any>(0)] } - whenever(mocks.settings.readLPw(nullable())) { + whenever(mocks.settings.readLPw(any(), nullable())) { mSettingsMap.putAll(mPreExistingSettings) !mPreExistingSettings.isEmpty() } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt index f35986b178d8..b063d22de2bb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt @@ -120,17 +120,16 @@ class SharedLibrariesImplTest { whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile) doAnswer { it.arguments[0] }.`when`(mPms).resolveInternalPackageName(any(), any()) doAnswer { - it.getArgument<FunctionalUtils.ThrowingConsumer<Computer>>(0).acceptOrThrow( - mockThrowOnUnmocked { - whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries } - whenever(resolveInternalPackageName(anyString(), anyLong())) { - mPms.resolveInternalPackageName(getArgument(0), getArgument(1)) - } - whenever(getPackageStateInternal(anyString())) { - mPms.getPackageStateInternal(getArgument(0)) - } - }) - }.`when`(mPms).executeWithConsistentComputer(any()) + mockThrowOnUnmocked<Computer> { + whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries } + whenever(resolveInternalPackageName(anyString(), anyLong())) { + mPms.resolveInternalPackageName(getArgument(0), getArgument(1)) + } + whenever(getPackageStateInternal(anyString())) { + mPms.getPackageStateInternal(getArgument(0)) + } + } + }.`when`(mPms).snapshotComputer() whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any())) .thenReturn(PackageManager.DELETE_SUCCEEDED) whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat) @@ -206,7 +205,8 @@ class SharedLibrariesImplTest { @Test fun pruneUnusedStaticSharedLibraries() { - mSharedLibrariesImpl.pruneUnusedStaticSharedLibraries(Long.MAX_VALUE, 0) + mSharedLibrariesImpl.pruneUnusedStaticSharedLibraries(mPms.snapshotComputer(), + Long.MAX_VALUE, 0) verify(mDeletePackageHelper) .deletePackageX(eq(STATIC_LIB_PACKAGE_NAME), any(), any(), any(), any()) diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt index ac406b588d38..5230ea7304c8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt @@ -123,8 +123,8 @@ class SuspendPackageHelperTest { @Test fun setPackagesSuspended() { val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2) - val failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages, - true /* suspended */, null /* appExtras */, null /* launcherExtras */, + val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + targetPackages, true /* suspended */, null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() @@ -144,14 +144,15 @@ class SuspendPackageHelperTest { @Test fun setPackagesSuspended_emptyPackageName() { - var failedNames = suspendPackageHelper.setPackagesSuspended(null /* packageNames */, - true /* suspended */, null /* appExtras */, null /* launcherExtras */, - null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + null /* packageNames */, true /* suspended */, null /* appExtras */, + null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, + deviceOwnerUid) assertThat(failedNames).isNull() - failedNames = suspendPackageHelper.setPackagesSuspended(arrayOfNulls(0), - true /* suspended */, null /* appExtras */, null /* launcherExtras */, + failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOfNulls(0), true /* suspended */, null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) assertThat(failedNames).isEmpty() @@ -159,9 +160,10 @@ class SuspendPackageHelperTest { @Test fun setPackagesSuspended_callerIsNotAllowed() { - val failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_2), - true /* suspended */, null /* appExtras */, null /* launcherExtras */, - null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, Binder.getCallingUid()) + val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, + null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, + Binder.getCallingUid()) assertThat(failedNames).asList().hasSize(1) assertThat(failedNames).asList().contains(TEST_PACKAGE_2) @@ -169,9 +171,10 @@ class SuspendPackageHelperTest { @Test fun setPackagesSuspended_callerSuspendItself() { - val failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(DEVICE_OWNER_PACKAGE), - true /* suspended */, null /* appExtras */, null /* launcherExtras */, - null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) + val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */, + null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, + deviceOwnerUid) assertThat(failedNames).asList().hasSize(1) assertThat(failedNames).asList().contains(DEVICE_OWNER_PACKAGE) @@ -179,9 +182,10 @@ class SuspendPackageHelperTest { @Test fun setPackagesSuspended_nonexistentPackage() { - val failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(NONEXISTENT_PACKAGE), - true /* suspended */, null /* appExtras */, null /* launcherExtras */, - null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) + val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */, + null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, + deviceOwnerUid) assertThat(failedNames).asList().hasSize(1) assertThat(failedNames).asList().contains(NONEXISTENT_PACKAGE) @@ -191,8 +195,8 @@ class SuspendPackageHelperTest { fun setPackagesSuspended_knownPackages() { val knownPackages = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE, INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE) - val failedNames = suspendPackageHelper.setPackagesSuspended(knownPackages, - true /* suspended */, null /* appExtras */, null /* launcherExtras */, + val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + knownPackages, true /* suspended */, null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!! assertThat(failedNames.size).isEqualTo(knownPackages.size) @@ -204,13 +208,13 @@ class SuspendPackageHelperTest { @Test fun setPackagesUnsuspended() { val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2) - var failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages, - true /* suspended */, null /* appExtras */, null /* launcherExtras */, + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + targetPackages, true /* suspended */, null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() - failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages, - false /* suspended */, null /* appExtras */, null /* launcherExtras */, + failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + targetPackages, false /* suspended */, null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() @@ -235,7 +239,7 @@ class SuspendPackageHelperTest { val suspendables = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2) val unsuspendables = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE, INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE) - val results = suspendPackageHelper.getUnsuspendablePackagesForUser( + val results = suspendPackageHelper.getUnsuspendablePackagesForUser(pms.snapshotComputer(), suspendables + unsuspendables, TEST_USER_ID, deviceOwnerUid) assertThat(results.size).isEqualTo(unsuspendables.size) @@ -247,7 +251,7 @@ class SuspendPackageHelperTest { @Test fun getUnsuspendablePackagesForUser_callerIsNotAllowed() { val suspendables = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2) - val results = suspendPackageHelper.getUnsuspendablePackagesForUser( + val results = suspendPackageHelper.getUnsuspendablePackagesForUser(pms.snapshotComputer(), suspendables, TEST_USER_ID, Binder.getCallingUid()) assertThat(results.size).isEqualTo(suspendables.size) @@ -260,8 +264,8 @@ class SuspendPackageHelperTest { fun getSuspendedPackageAppExtras() { val appExtras = PersistableBundle() appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1) - var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_1), - true /* suspended */, appExtras, null /* launcherExtras */, + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() @@ -277,8 +281,8 @@ class SuspendPackageHelperTest { val appExtras = PersistableBundle() appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_2) val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2) - var failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages, - true /* suspended */, appExtras, null /* launcherExtras */, + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + targetPackages, true /* suspended */, appExtras, null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() @@ -291,8 +295,9 @@ class SuspendPackageHelperTest { assertThat(suspendPackageHelper.getSuspendedPackageAppExtras( TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull() - suspendPackageHelper.removeSuspensionsBySuspendingPackage(targetPackages, - { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE }, TEST_USER_ID) + suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(), + targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE }, + TEST_USER_ID) testHandler.flush() verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) @@ -320,8 +325,8 @@ class SuspendPackageHelperTest { fun getSuspendedPackageLauncherExtras() { val launcherExtras = PersistableBundle() launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2) - var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_2), - true /* suspended */, null /* appExtras */, launcherExtras, + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() @@ -334,9 +339,10 @@ class SuspendPackageHelperTest { @Test fun isPackageSuspended() { - var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_1), - true /* suspended */, null /* appExtras */, null /* launcherExtras */, - null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */, + null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, + deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() @@ -348,8 +354,8 @@ class SuspendPackageHelperTest { fun getSuspendingPackage() { val launcherExtras = PersistableBundle() launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2) - var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_2), - true /* suspended */, null /* appExtras */, launcherExtras, + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() @@ -362,9 +368,10 @@ class SuspendPackageHelperTest { fun getSuspendedDialogInfo() { val dialogInfo = SuspendDialogInfo.Builder() .setTitle(TEST_PACKAGE_1).build() - var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_1), - true /* suspended */, null /* appExtras */, null /* launcherExtras */, - dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid) + var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(), + arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */, + null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID, + deviceOwnerUid) testHandler.flush() assertThat(failedNames).isEmpty() 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 6789af4a13d8..2b34bc2ef28d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -35,6 +35,7 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.annotation.NonNull; @@ -109,6 +110,8 @@ public class PackageManagerSettingsTests { LegacyPermissionDataProvider mPermissionDataProvider; @Mock DomainVerificationManagerInternal mDomainVerificationManager; + @Mock + Computer computer; final ArrayMap<String, Long> mOrigFirstInstallTimes = new ArrayMap<>(); @@ -132,7 +135,7 @@ public class PackageManagerSettingsTests { /* write out files and read */ writeOldFiles(); Settings settings = makeSettings(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } @@ -143,11 +146,11 @@ public class PackageManagerSettingsTests { // write out files and read writeOldFiles(); Settings settings = makeSettings(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); // write out, read back in and verify the same - settings.writeLPr(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); + settings.writeLPr(computer); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } @@ -156,7 +159,7 @@ public class PackageManagerSettingsTests { // Write delegateshellthe package files and make sure they're parsed properly the first time writeOldFiles(); Settings settings = makeSettings(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue())); assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue())); @@ -175,12 +178,12 @@ public class PackageManagerSettingsTests { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); Settings settings = makeSettings(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); - settings.writeLPr(); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); + settings.writeLPr(computer); // Create Settings again to make it read from the new files settings = makeSettings(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2); assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER)); @@ -469,12 +472,12 @@ public class PackageManagerSettingsTests { ps2.setUsesStaticLibrariesVersions(new long[] { 34 }); settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2); - settingsUnderTest.writeLPr(); + settingsUnderTest.writeLPr(computer); settingsUnderTest.mPackages.clear(); settingsUnderTest.mDisabledSysPackages.clear(); - assertThat(settingsUnderTest.readLPw(createFakeUsers()), is(true)); + assertThat(settingsUnderTest.readLPw(computer, createFakeUsers()), is(true)); PackageSetting readPs1 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_1); PackageSetting readPs2 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_2); @@ -534,12 +537,12 @@ public class PackageManagerSettingsTests { ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 }); settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2); - settingsUnderTest.writeLPr(); + settingsUnderTest.writeLPr(computer); settingsUnderTest.mPackages.clear(); settingsUnderTest.mDisabledSysPackages.clear(); - assertThat(settingsUnderTest.readLPw(createFakeUsers()), is(true)); + assertThat(settingsUnderTest.readLPw(computer, createFakeUsers()), is(true)); PackageSetting readPs1 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_1); PackageSetting readPs2 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_2); @@ -587,7 +590,7 @@ public class PackageManagerSettingsTests { Settings settings = makeSettings(); final WatchableTester watcher = new WatchableTester(settings, "testEnableDisable"); watcher.register(); - assertThat(settings.readLPw(createFakeUsers()), is(true)); + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); watcher.verifyChangeReported("readLPw"); // Enable/Disable a package |