Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99173ce6 authored by Lee Shombert's avatar Lee Shombert
Browse files

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
parent 84737b41
Loading
Loading
Loading
Loading
+24 −5
Original line number Diff line number Diff line
@@ -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 =
+42 −12
Original line number Diff line number Diff line
@@ -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(
+70 −2
Original line number Diff line number Diff line
@@ -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) {
    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) {
        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();
        }
    }

}