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:
@@ -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 =
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user