Improve snapshot performance

Bug: 185481065

Use caches to improve snapshot performance.  SnapshotCache.Auto is a
concrete SnapshotCache that can be applied to a Snappable.  All the
Watched* classes are Snappable.  The cache improves performance and
reduces memory churn.

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: Ia993613f566cb86b145ddf1d5280e8780252a951
This commit is contained in:
Lee Shombert
2021-05-12 08:25:50 -07:00
parent 84737b417b
commit 99173ce6b9
3 changed files with 137 additions and 20 deletions

View File

@@ -404,6 +404,7 @@ import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
import com.android.server.utils.Watched;
@@ -871,12 +872,17 @@ public class PackageManagerService extends IPackageManager.Stub
@Watched
@GuardedBy("mLock")
final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, AndroidPackage>> mPackagesSnapshot =
new SnapshotCache.Auto(mPackages, mPackages, "PackageManagerService.mPackages");
// Keys are isolated uids and values are the uid of the application
// that created the isolated process.
@Watched
@GuardedBy("mLock")
final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray();
private final SnapshotCache<WatchedSparseIntArray> mIsolatedOwnersSnapshot =
new SnapshotCache.Auto(mIsolatedOwners, mIsolatedOwners,
"PackageManagerService.mIsolatedOwners");
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -1398,14 +1404,27 @@ public class PackageManagerService extends IPackageManager.Stub
@Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mSharedLibraries = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mSharedLibrariesSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
@Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mStaticLibsByDeclaringPackageSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
// Mapping from instrumentation class names to info about them.
@Watched
final WatchedArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<ComponentName, ParsedInstrumentation>>
mInstrumentationSnapshot =
new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation,
"PackageManagerService.mInstrumentation");
// Packages whose data we have transfered into another package, thus
// should no longer exist.
@@ -1838,11 +1857,11 @@ public class PackageManagerService extends IPackageManager.Stub
Snapshot(int type) {
if (type == Snapshot.SNAPPED) {
settings = mSettings.snapshot();
isolatedOwners = mIsolatedOwners.snapshot();
packages = mPackages.snapshot();
sharedLibs = mSharedLibraries.snapshot();
staticLibs = mStaticLibsByDeclaringPackage.snapshot();
instrumentation = mInstrumentation.snapshot();
isolatedOwners = mIsolatedOwnersSnapshot.snapshot();
packages = mPackagesSnapshot.snapshot();
sharedLibs = mSharedLibrariesSnapshot.snapshot();
staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot();
instrumentation = mInstrumentationSnapshot.snapshot();
resolveComponentName = mResolveComponentName.clone();
resolveActivity = new ActivityInfo(mResolveActivity);
instantAppInstallerActivity =

View File

@@ -365,19 +365,21 @@ public final class Settings implements Watchable, Snappable {
/** Map from package name to settings */
@Watched
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
final WatchedArrayMap<String, PackageSetting> mPackages = new WatchedArrayMap<>();
final WatchedArrayMap<String, PackageSetting> mPackages;
private final SnapshotCache<WatchedArrayMap<String, PackageSetting>> mPackagesSnapshot;
/**
* List of packages that were involved in installing other packages, i.e. are listed
* in at least one app's InstallSource.
*/
@Watched
private final WatchedArraySet<String> mInstallerPackages = new WatchedArraySet<>();
private final WatchedArraySet<String> mInstallerPackages;
private final SnapshotCache<WatchedArraySet<String>> mInstallerPackagesSnapshot;
/** Map from package name to appId and excluded userids */
@Watched
private final WatchedArrayMap<String, KernelPackageState> mKernelMapping =
new WatchedArrayMap<>();
private final WatchedArrayMap<String, KernelPackageState> mKernelMapping;
private final SnapshotCache<WatchedArrayMap<String, KernelPackageState>> mKernelMappingSnapshot;
// List of replaced system applications
@Watched
@@ -398,7 +400,7 @@ public final class Settings implements Watchable, Snappable {
/** Map from volume UUID to {@link VersionInfo} */
@Watched
private WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
private final WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
/**
* Version details for a storage volume that may hold apps.
@@ -504,8 +506,7 @@ public final class Settings implements Watchable, Snappable {
private final File mSystemDir;
private final KeySetManagerService mKeySetManagerService =
new KeySetManagerService(mPackages);
private final KeySetManagerService mKeySetManagerService;
/** Settings and other information about permissions */
@Watched(manual = true)
@@ -561,8 +562,21 @@ public final class Settings implements Watchable, Snappable {
mKeySetRefs.registerObserver(mObserver);
}
// CONSTRUCTOR
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public Settings(Map<String, PackageSetting> pkgSettings) {
mPackages = new WatchedArrayMap<>();
mPackagesSnapshot =
new SnapshotCache.Auto<>(mPackages, mPackages, "Settings.mPackages");
mKernelMapping = new WatchedArrayMap<>();
mKernelMappingSnapshot =
new SnapshotCache.Auto<>(mKernelMapping, mKernelMapping, "Settings.mKernelMapping");
mInstallerPackages = new WatchedArraySet<>();
mInstallerPackagesSnapshot =
new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
"Settings.mInstallerPackages");
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
mAppIds = new WatchedArrayList<>();
@@ -589,6 +603,18 @@ public final class Settings implements Watchable, Snappable {
LegacyPermissionDataProvider permissionDataProvider,
@NonNull DomainVerificationManagerInternal domainVerificationManager,
@NonNull PackageManagerTracedLock lock) {
mPackages = new WatchedArrayMap<>();
mPackagesSnapshot =
new SnapshotCache.Auto<>(mPackages, mPackages, "Settings.mPackages");
mKernelMapping = new WatchedArrayMap<>();
mKernelMappingSnapshot =
new SnapshotCache.Auto<>(mKernelMapping, mKernelMapping, "Settings.mKernelMapping");
mInstallerPackages = new WatchedArraySet<>();
mInstallerPackagesSnapshot =
new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
"Settings.mInstallerPackages");
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = lock;
mAppIds = new WatchedArrayList<>();
mOtherAppIds = new WatchedSparseArray<>();
@@ -629,7 +655,13 @@ public final class Settings implements Watchable, Snappable {
* are changed by PackageManagerService APIs are deep-copied
*/
private Settings(Settings r) {
mPackages.putAll(r.mPackages);
mPackages = r.mPackagesSnapshot.snapshot();
mPackagesSnapshot = new SnapshotCache.Sealed<>();
mKernelMapping = r.mKernelMappingSnapshot.snapshot();
mKernelMappingSnapshot = new SnapshotCache.Sealed<>();
mInstallerPackages = r.mInstallerPackagesSnapshot.snapshot();
mInstallerPackagesSnapshot = new SnapshotCache.Sealed<>();
mKeySetManagerService = new KeySetManagerService(mPackages);
// The following assignments satisfy Java requirements but are not
// needed by the read-only methods. Note especially that the lock
@@ -646,9 +678,7 @@ public final class Settings implements Watchable, Snappable {
mDomainVerificationManager = r.mDomainVerificationManager;
mInstallerPackages.addAll(r.mInstallerPackages);
mKernelMapping.putAll(r.mKernelMapping);
mDisabledSysPackages.putAll(r.mDisabledSysPackages);
mDisabledSysPackages.snapshot(r.mDisabledSysPackages);
mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages);
mVersion.putAll(r.mVersion);
mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
@@ -658,7 +688,7 @@ public final class Settings implements Watchable, Snappable {
mPersistentPreferredActivities, r.mPersistentPreferredActivities);
WatchedSparseArray.snapshot(
mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
mSharedUsers.putAll(r.mSharedUsers);
mSharedUsers.snapshot(r.mSharedUsers);
mAppIds = r.mAppIds.snapshot();
mOtherAppIds = r.mOtherAppIds.snapshot();
WatchedArrayList.snapshot(

View File

@@ -19,6 +19,9 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A class that caches snapshots. Instances are instantiated on a {@link Watchable}; when the
* {@link Watchable} reports a change, the cache is cleared. The snapshot() method fetches the
@@ -35,6 +38,19 @@ public abstract class SnapshotCache<T> extends Watcher{
*/
private static final boolean ENABLED = true;
/**
* The statistics for a single cache. The object records the number of times a
* snapshot was reused and the number of times a snapshot was rebuilt.
*/
private static class Statistics {
final String mName;
private final AtomicInteger mReused = new AtomicInteger(0);
private final AtomicInteger mRebuilt = new AtomicInteger(0);
Statistics(@NonNull String n) {
mName = n;
}
}
// The source object from which snapshots are created. This may be null if createSnapshot()
// does not require it.
protected final T mSource;
@@ -45,15 +61,42 @@ public abstract class SnapshotCache<T> extends Watcher{
// True if the snapshot is sealed and may not be modified.
private volatile boolean mSealed = false;
// The statistics for this cache. This may be null.
private final Statistics mStatistics;
/**
* The global list of caches.
*/
private static final WeakHashMap<SnapshotCache, Void> sCaches = new WeakHashMap<>();
/**
* Create a cache with a source object for rebuilding snapshots and a
* {@link Watchable} that notifies when the cache is invalid.
* {@link Watchable} that notifies when the cache is invalid. If the name is null
* then statistics are not collected for this cache.
* @param source Source data for rebuilding snapshots.
* @param watchable The object that notifies when the cache is invalid.
* @param name The name of the cache, for statistics reporting.
*/
public SnapshotCache(@Nullable T source, @NonNull Watchable watchable, @Nullable String name) {
mSource = source;
watchable.registerObserver(this);
if (name != null) {
mStatistics = new Statistics(name);
sCaches.put(this, null);
} else {
mStatistics = null;
}
}
/**
* Create a cache with a source object for rebuilding snapshots and a
* {@link Watchable} that notifies when the cache is invalid. The name is null in
* this API.
* @param source Source data for rebuilding snapshots.
* @param watchable The object that notifies when the cache is invalid.
*/
public SnapshotCache(@Nullable T source, @NonNull Watchable watchable) {
mSource = source;
watchable.registerObserver(this);
this(source, watchable, null);
}
/**
@@ -63,6 +106,7 @@ public abstract class SnapshotCache<T> extends Watcher{
public SnapshotCache() {
mSource = null;
mSealed = true;
mStatistics = null;
}
/**
@@ -93,6 +137,9 @@ public abstract class SnapshotCache<T> extends Watcher{
if (s == null || !ENABLED) {
s = createSnapshot();
mSnapshot = s;
if (mStatistics != null) mStatistics.mRebuilt.incrementAndGet();
} else {
if (mStatistics != null) mStatistics.mReused.incrementAndGet();
}
return s;
}
@@ -123,4 +170,25 @@ public abstract class SnapshotCache<T> extends Watcher{
throw new UnsupportedOperationException("cannot snapshot a sealed snaphot");
}
}
/**
* A snapshot cache suitable for Snappable types. The key is that Snappable types
* have a known implementation of createSnapshot() so that this class is concrete.
* @param <T> The class whose snapshot is being cached.
*/
public static class Auto<T extends Snappable<T>> extends SnapshotCache<T> {
public Auto(@NonNull T source, @NonNull Watchable watchable, @Nullable String name) {
super(source, watchable, name);
}
public Auto(@NonNull T source, @NonNull Watchable watchable) {
this(source, watchable, null);
}
/**
* Concrete createSnapshot() using the snapshot() method of <T>.
*/
public T createSnapshot() {
return mSource.snapshot();
}
}
}