From fcde814628f62b46e6be3c33efa89ee8ce5ec9c4 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Tue, 13 Jul 2021 08:40:03 -0700 Subject: [PATCH] Take snapshots of SettingBase subclasses Bug: 192478088 Snapshot SharedUserSetting and PackageSetting. Test: atest * CtsContentTestCases:IntentFilterTest * CtsDynamicMimeHostTestCases * CtsRoleTestCases * FrameworksServicesTests:UserSystemPackageInstallerTest * FrameworksServicesTests:PackageManagerSettingsTests * FrameworksServicesTests:PackageManagerServiceTest * FrameworksServicesTests:AppsFilterTest * FrameworksServicesTests:PackageInstallerSessionTest * FrameworksServicesTests:ScanTests * UserLifecycleTests#startUser * UserLifecycleTests#stopUser * UserLifecycleTests#switchUser * FrameworksServicesTests:WatcherTest * android.appsecurity.cts.EphemeralTest * android.appsecurity.cts.InstantAppUserTest Change-Id: I5ccd77bd8a07aa833219c6bab797cdc153c1136f --- .../com/android/server/pm/PackageSetting.java | 44 +++++++++++++++ .../android/server/pm/PackageSettingBase.java | 9 ++++ .../com/android/server/pm/SettingBase.java | 3 +- .../android/server/pm/SharedUserSetting.java | 53 ++++++++++++++++--- .../pm/PackageManagerSettingsTests.java | 1 + 5 files changed, 101 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 81ea46514d3db..376326264d9c3 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -31,6 +31,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.LegacyPermissionState; import com.android.server.pm.pkg.PackageStateUnserialized; +import com.android.server.utils.SnapshotCache; import java.io.File; import java.util.ArrayList; @@ -81,6 +82,7 @@ public class PackageSetting extends PackageSettingBase { * object equality to check whether shared user settings are the same. */ SharedUserSetting sharedUser; + /** * Temporary holding space for the shared user ID. While parsing package settings, the * shared users tag may come after the packages. In this case, we must delay linking the @@ -103,6 +105,19 @@ public class PackageSetting extends PackageSettingBase { @NonNull private UUID mDomainSetId; + /** + * Snapshot support. + */ + private final SnapshotCache mSnapshot; + + private SnapshotCache makeCache() { + return new SnapshotCache(this, this) { + @Override + public PackageSetting createSnapshot() { + return new PackageSetting(mSource, true); + }}; + } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public PackageSetting(String name, String realName, @NonNull File codePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, @@ -118,6 +133,7 @@ public class PackageSetting extends PackageSettingBase { this.sharedUserId = sharedUserId; mDomainSetId = domainSetId; copyMimeGroups(mimeGroups); + mSnapshot = makeCache(); } /** @@ -127,6 +143,7 @@ public class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig) { super(orig, orig.realName); doCopy(orig); + mSnapshot = makeCache(); } /** @@ -137,6 +154,33 @@ public class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig, String realPkgName) { super(orig, realPkgName); doCopy(orig); + mSnapshot = makeCache(); + } + + /** + * Create a snapshot. The copy constructor is already in use and cannot be modified + * for this purpose. + */ + PackageSetting(PackageSetting orig, boolean snapshot) { + super(orig, snapshot); + // The existing doCopy() method cannot be used in here because sharedUser must be + // a snapshot, and not a reference. Also, the pkgState must be copied. However, + // this code should otherwise be kept in sync with doCopy(). + appId = orig.appId; + pkg = orig.pkg; + sharedUser = orig.sharedUser == null ? null : orig.sharedUser.snapshot(); + sharedUserId = orig.sharedUserId; + copyMimeGroups(orig.mimeGroups); + pkgState = orig.pkgState; + mDomainSetId = orig.getDomainSetId(); + mSnapshot = new SnapshotCache.Sealed(); + } + + /** + * Return the package snapshot. + */ + public PackageSetting snapshot() { + return mSnapshot.snapshot(); } /** @see #pkg **/ diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 731d41c38f797..bf82bd8b09d54 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -169,6 +169,15 @@ public abstract class PackageSettingBase extends SettingBase { doCopy(base); } + // A copy constructor used to create snapshots. The boolean is present only to + // match up with the constructor in PackageSetting. + PackageSettingBase(PackageSettingBase orig, boolean snapshot) { + super(orig); + name = orig.name; + realName = orig.realName; + doCopy(orig); + } + public void setInstallerPackageName(String packageName) { installSource = installSource.setInstallerPackage(packageName); onChanged(); diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 0e8a278f3b6b0..7b5c7e3a0c849 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -22,12 +22,13 @@ import android.content.pm.ApplicationInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.permission.LegacyPermissionState; +import com.android.server.utils.Snappable; import com.android.server.utils.Watchable; import com.android.server.utils.WatchableImpl; import com.android.server.utils.Watcher; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public abstract class SettingBase implements Watchable { +public abstract class SettingBase implements Watchable, Snappable { // TODO: make this variable protected, or even private with a getter and setter. // Simply making it protected or private requires that the name be changed to conformm // to the Android naming convention, and that touches quite a few files. diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index 9b1c08d9c3219..8ddbe08e25720 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -26,6 +26,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.utils.SnapshotCache; import libcore.util.EmptyArray; @@ -49,12 +50,25 @@ public final class SharedUserSetting extends SettingBase { // that all apps within the sharedUser run in the same selinux context. int seInfoTargetSdkVersion; - final ArraySet packages = new ArraySet<>(); + final ArraySet packages; final PackageSignatures signatures = new PackageSignatures(); Boolean signaturesChanged; - ArrayMap processes; + final ArrayMap processes; + + /** + * Snapshot support. + */ + private final SnapshotCache mSnapshot; + + private SnapshotCache makeCache() { + return new SnapshotCache(this, this) { + @Override + public SharedUserSetting createSnapshot() { + return new SharedUserSetting(mSource); + }}; + } SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) { super(_pkgFlags, _pkgPrivateFlags); @@ -62,6 +76,31 @@ public final class SharedUserSetting extends SettingBase { uidPrivateFlags = _pkgPrivateFlags; name = _name; seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; + packages = new ArraySet<>(); + processes = new ArrayMap<>(); + mSnapshot = makeCache(); + } + + // The copy constructor is used to create a snapshot + private SharedUserSetting(SharedUserSetting orig) { + super(orig); + name = orig.name; + uidFlags = orig.uidFlags; + uidPrivateFlags = orig.uidPrivateFlags; + packages = new ArraySet(orig.packages); + // A PackageParser.SigningDetails seems to consist solely of final attributes, so + // it is safe to copy the reference. + signatures.mSigningDetails = orig.signatures.mSigningDetails; + signaturesChanged = orig.signaturesChanged; + processes = new ArrayMap(orig.processes); + mSnapshot = new SnapshotCache.Sealed(); + } + + /** + * Return a read-only snapshot of this object. + */ + public SharedUserSetting snapshot() { + return mSnapshot.snapshot(); } @Override @@ -80,9 +119,6 @@ public final class SharedUserSetting extends SettingBase { void addProcesses(Map newProcs) { if (newProcs != null) { final int numProcs = newProcs.size(); - if (processes == null) { - processes = new ArrayMap<>(numProcs); - } for (String key : newProcs.keySet()) { ParsedProcess newProc = newProcs.get(key); ParsedProcess proc = processes.get(newProc.getName()); @@ -191,7 +227,7 @@ public final class SharedUserSetting extends SettingBase { * Update tracked data about processes based on all known packages in the shared user ID. */ public void updateProcesses() { - processes = null; + processes.clear(); for (int i = packages.size() - 1; i >= 0; i--) { final AndroidPackage pkg = packages.valueAt(i).pkg; if (pkg != null) { @@ -230,14 +266,15 @@ public final class SharedUserSetting extends SettingBase { this.signaturesChanged = sharedUser.signaturesChanged; if (sharedUser.processes != null) { final int numProcs = sharedUser.processes.size(); - this.processes = new ArrayMap<>(numProcs); + this.processes.clear(); + this.processes.ensureCapacity(numProcs); for (int i = 0; i < numProcs; i++) { ParsedProcess proc = new ParsedProcess(sharedUser.processes.valueAt(i)); this.processes.put(proc.getName(), proc); } } else { - this.processes = null; + this.processes.clear(); } onChanged(); return this; 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 29f4aa976ef61..22fb76b1fbe53 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -198,6 +198,7 @@ public class PackageManagerSettingsTests { new WatchableTester(settingsUnderTest, "noSuspendingPackage"); watcher.register(); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1)); + settingsUnderTest.readPackageRestrictionsLPr(0); watcher.verifyChangeReported("put package 1"); // Collect a snapshot at the midway point (package 2 has not been added) final Settings snapshot = settingsUnderTest.snapshot();