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

Commit 5c50e863 authored by Narayan Kamath's avatar Narayan Kamath
Browse files

PackageManagerService: Implement packageParser cache in ParallelPackageParser.

We save about 2800ms of cold startup time over baseline on a marlin,
and ~1200 ms over the parallel parsing case.

                   warm     cold
		   ---------------
Baseline         : 1700ms   4300ms
Parallel         : 1400ms   2700ms
Cache            : 1000ms   1600ms
Cache & parallel : 900ms    1500ms

Note that further changes will improve the speed of cache processing.

This change also includes support for :
- a flag that been flipped in code (currently set to false).
- disabling the cache via a system property.
- wiping the cache on system upgrades.
- cache versioning.

Bug: 30792387

Test: FrameworksServicesTests
Test: manual timing

Change-Id: I281710c110af5307901dd62ce93b515287c91918
parent 874d4559
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -762,4 +762,19 @@ public class FileUtils {
    public static @Nullable File newFileOrNull(@Nullable String path) {
    public static @Nullable File newFileOrNull(@Nullable String path) {
        return (path != null) ? new File(path) : null;
        return (path != null) ? new File(path) : null;
    }
    }

    /**
     * Creates a directory with name {@code name} under an existing directory {@code baseDir}.
     * Returns a {@code File} object representing the directory on success, {@code null} on
     * failure.
     */
    public static @Nullable File createDir(File baseDir, String name) {
        final File dir = new File(baseDir, name);

        if (dir.exists()) {
            return dir.isDirectory() ? dir : null;
        }

        return dir.mkdir() ? dir : null;
    }
}
}
+46 −2
Original line number Original line Diff line number Diff line
@@ -102,7 +102,6 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCES
import android.Manifest;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IActivityManager;
@@ -566,6 +565,18 @@ public class PackageManagerService extends IPackageManager.Stub {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_NUMBER);
            Manifest.permission.READ_PHONE_NUMBER);
    /**
     * Version number for the package parser cache. Increment this whenever the format or
     * extent of cached data changes. See {@code PackageParser#setCacheDir}.
     */
    private static final String PACKAGE_PARSER_CACHE_VERSION = "1";
    /**
     * Whether the package parser cache is enabled.
     */
    private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = false;
    final ServiceThread mHandlerThread;
    final ServiceThread mHandlerThread;
    final PackageHandler mHandler;
    final PackageHandler mHandler;
@@ -804,6 +815,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    private UserManagerInternal mUserManagerInternal;
    private UserManagerInternal mUserManagerInternal;
    private File mCacheDir;
    private static class IFVerificationParams {
    private static class IFVerificationParams {
        PackageParser.Package pkg;
        PackageParser.Package pkg;
        boolean replacing;
        boolean replacing;
@@ -2353,6 +2366,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                }
                }
            }
            }
            mCacheDir = preparePackageParserCache(mIsUpgrade);
            // Set flag to monitor and not change apk file paths when
            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            // scanning install directories.
            int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
            int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
@@ -2815,6 +2830,35 @@ public class PackageManagerService extends IPackageManager.Stub {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    }
    private static File preparePackageParserCache(boolean isUpgrade) {
        if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
            return null;
        }
        if (SystemProperties.getBoolean("ro.boot.disable_package_cache", false)) {
            Slog.i(TAG, "Disabling package parser cache due to system property.");
            return null;
        }
        // The base directory for the package parser cache lives under /data/system/.
        final File cacheBaseDir = FileUtils.createDir(Environment.getDataSystemDirectory(),
                "package_cache");
        if (cacheBaseDir == null) {
            return null;
        }
        // If this is a system upgrade scenario, delete the contents of the package cache dir.
        // This also serves to "GC" unused entries when the package cache version changes (which
        // can only happen during upgrades).
        if (isUpgrade) {
            FileUtils.deleteContents(cacheBaseDir);
        }
        // Return the versioned package cache directory. This is something like
        // "/data/system/package_cache/1"
        return FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
    }
    @Override
    @Override
    public boolean isFirstBoot() {
    public boolean isFirstBoot() {
        return mFirstBoot;
        return mFirstBoot;
@@ -6938,7 +6982,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    + " flags=0x" + Integer.toHexString(parseFlags));
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }
        }
        ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
        ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
                mSeparateProcesses, mOnlyCore, mMetrics);
                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir);
        // Submit files for parsing in parallel
        // Submit files for parsing in parallel
        int fileCount = 0;
        int fileCount = 0;
+5 −2
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ class ParallelPackageParser implements AutoCloseable {
    private final String[] mSeparateProcesses;
    private final String[] mSeparateProcesses;
    private final boolean mOnlyCore;
    private final boolean mOnlyCore;
    private final DisplayMetrics mMetrics;
    private final DisplayMetrics mMetrics;
    private final File mCacheDir;
    private volatile String mInterruptedInThread;
    private volatile String mInterruptedInThread;


    private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
    private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
@@ -68,10 +69,11 @@ class ParallelPackageParser implements AutoCloseable {
            });
            });


    ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
    ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
            DisplayMetrics metrics) {
            DisplayMetrics metrics, File cacheDir) {
        mSeparateProcesses = separateProcesses;
        mSeparateProcesses = separateProcesses;
        mOnlyCore = onlyCoreApps;
        mOnlyCore = onlyCoreApps;
        mMetrics = metrics;
        mMetrics = metrics;
        mCacheDir = cacheDir;
    }
    }


    static class ParseResult {
    static class ParseResult {
@@ -122,6 +124,7 @@ class ParallelPackageParser implements AutoCloseable {
                pp.setSeparateProcesses(mSeparateProcesses);
                pp.setSeparateProcesses(mSeparateProcesses);
                pp.setOnlyCoreApps(mOnlyCore);
                pp.setOnlyCoreApps(mOnlyCore);
                pp.setDisplayMetrics(mMetrics);
                pp.setDisplayMetrics(mMetrics);
                pp.setCacheDir(mCacheDir);
                pr.scanFile = scanFile;
                pr.scanFile = scanFile;
                pr.pkg = parsePackage(pp, scanFile, parseFlags);
                pr.pkg = parsePackage(pp, scanFile, parseFlags);
            } catch (Throwable e) {
            } catch (Throwable e) {
@@ -144,7 +147,7 @@ class ParallelPackageParser implements AutoCloseable {
    @VisibleForTesting
    @VisibleForTesting
    protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
    protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
            int parseFlags) throws PackageParser.PackageParserException {
            int parseFlags) throws PackageParser.PackageParserException {
        return packageParser.parsePackage(scanFile, parseFlags);
        return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
    }
    }


    @Override
    @Override
+1 −1
Original line number Original line Diff line number Diff line
@@ -69,7 +69,7 @@ public class ParallelPackageParserTest {
    class TestParallelPackageParser extends ParallelPackageParser {
    class TestParallelPackageParser extends ParallelPackageParser {


        TestParallelPackageParser() {
        TestParallelPackageParser() {
            super(null, false, null);
            super(null, false, null, null);
        }
        }


        @Override
        @Override