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

Commit f61162a0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Combine package parsing thread pools"

parents 880983bc 2997442a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;

import android.annotation.AnyThread;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -1080,6 +1081,7 @@ public class PackageParser {
     *
     * @see #parsePackage(File, int, boolean)
     */
    @AnyThread
    public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches)
            throws PackageParserException {
        ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null;
+82 −56
Original line number Diff line number Diff line
@@ -387,6 +387,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -2868,23 +2869,34 @@ public class PackageManagerService extends IPackageManager.Stub
                scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
            }
            final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
            final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
            PackageParser packageParser = new PackageParser();
            packageParser.setSeparateProcesses(mSeparateProcesses);
            packageParser.setOnlyCoreApps(mOnlyCore);
            packageParser.setDisplayMetrics(mMetrics);
            packageParser.setCacheDir(mCacheDir);
            packageParser.setCallback(mPackageParserCallback);
            ExecutorService executorService = ParallelPackageParser.makeExecutorService();
            // Collect vendor/product/system_ext overlay packages. (Do this before scanning
            // any apps.)
            // For security and version matching reason, only consider overlay packages if they
            // reside in the right directory.
            final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
            final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
            for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
                final SystemPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.overlayFolder == null) {
                    continue;
                }
                scanDirTracedLI(partition.overlayFolder, systemParseFlags,
                        systemScanFlags | partition.scanFlag, 0);
                        systemScanFlags | partition.scanFlag, 0,
                        packageParser, executorService);
            }
            scanDirTracedLI(frameworkDir, systemParseFlags,
                    systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0);
                    systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                    packageParser, executorService);
            if (!mPackages.containsKey("android")) {
                throw new IllegalStateException(
                        "Failed to load frameworks package; check log for warnings");
@@ -2893,10 +2905,12 @@ public class PackageManagerService extends IPackageManager.Stub
                final SystemPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.privAppFolder != null) {
                    scanDirTracedLI(partition.privAppFolder, systemParseFlags,
                            systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0);
                            systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                            packageParser, executorService);
                }
                scanDirTracedLI(partition.appFolder, systemParseFlags,
                        systemScanFlags | partition.scanFlag, 0);
                        systemScanFlags | partition.scanFlag, 0,
                        packageParser, executorService);
            }
@@ -3000,8 +3014,18 @@ public class PackageManagerService extends IPackageManager.Stub
            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
                        packageParser, executorService);
            }
            List<Runnable> unfinishedTasks = executorService.shutdownNow();
            if (!unfinishedTasks.isEmpty()) {
                throw new IllegalStateException("Not all tasks finished before calling close: "
                        + unfinishedTasks);
            }
            if (!mOnlyCore) {
                // Remove disable package settings for updated system apps that were
                // removed via an OTA. If the update is no longer present, remove the
                // app completely. Otherwise, revoke their system privileges.
@@ -8578,16 +8602,18 @@ public class PackageManagerService extends IPackageManager.Stub
        return finalList;
    }
    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
            long currentTime, PackageParser packageParser, ExecutorService executorService) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
        try {
            scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
            scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
            PackageParser packageParser, ExecutorService executorService) {
        final File[] files = scanDir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + scanDir);
@@ -8598,9 +8624,10 @@ public class PackageManagerService extends IPackageManager.Stub
            Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }
        try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
                mPackageParserCallback)) {
        ParallelPackageParser parallelPackageParser =
                new ParallelPackageParser(packageParser, executorService);
        // Submit files for parsing in parallel
        int fileCount = 0;
        for (File file : files) {
@@ -8644,15 +8671,14 @@ public class PackageManagerService extends IPackageManager.Stub
            }
            // Delete invalid userdata apps
                if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
                        errorCode != PackageManager.INSTALL_SUCCEEDED) {
            if ((scanFlags & SCAN_AS_SYSTEM) == 0
                    && errorCode != PackageManager.INSTALL_SUCCEEDED) {
                logCriticalInfo(Log.WARN,
                        "Deleting invalid package at " + parseResult.scanFile);
                removeCodePathLI(parseResult.scanFile);
            }
        }
    }
    }
    public static void reportSettingsProblem(int priority, String msg) {
        logCriticalInfo(priority, msg);
+18 −38
Original line number Diff line number Diff line
@@ -22,13 +22,11 @@ import android.content.pm.PackageParser;
import android.content.pm.parsing.ParsedPackage;
import android.os.Process;
import android.os.Trace;
import android.util.DisplayMetrics;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ConcurrentUtils;

import java.io.File;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
@@ -38,30 +36,27 @@ import java.util.concurrent.ExecutorService;
 * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
 * At any time, at most {@link #QUEUE_CAPACITY} results are kept in RAM</p>
 */
class ParallelPackageParser implements AutoCloseable {
class ParallelPackageParser {

    private static final int QUEUE_CAPACITY = 10;
    private static final int QUEUE_CAPACITY = 30;
    private static final int MAX_THREADS = 4;

    private final String[] mSeparateProcesses;
    private final boolean mOnlyCore;
    private final DisplayMetrics mMetrics;
    private final File mCacheDir;
    private final PackageParser.Callback mPackageParserCallback;
    private volatile String mInterruptedInThread;

    private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);

    private final ExecutorService mService = ConcurrentUtils.newFixedThreadPool(MAX_THREADS,
            "package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
    static ExecutorService makeExecutorService() {
        return ConcurrentUtils.newFixedThreadPool(MAX_THREADS, "package-parsing-thread",
                Process.THREAD_PRIORITY_FOREGROUND);
    }

    private final PackageParser mPackageParser;

    ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
            DisplayMetrics metrics, File cacheDir, PackageParser.Callback callback) {
        mSeparateProcesses = separateProcesses;
        mOnlyCore = onlyCoreApps;
        mMetrics = metrics;
        mCacheDir = cacheDir;
        mPackageParserCallback = callback;
    private final ExecutorService mExecutorService;

    ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
        mPackageParser = packageParser;
        mExecutorService = executorService;
    }

    static class ParseResult {
@@ -104,18 +99,12 @@ class ParallelPackageParser implements AutoCloseable {
     * @param parseFlags parse flags
     */
    public void submit(File scanFile, int parseFlags) {
        mService.submit(() -> {
        mExecutorService.submit(() -> {
            ParseResult pr = new ParseResult();
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
            try {
                PackageParser pp = new PackageParser();
                pp.setSeparateProcesses(mSeparateProcesses);
                pp.setOnlyCoreApps(mOnlyCore);
                pp.setDisplayMetrics(mMetrics);
                pp.setCacheDir(mCacheDir);
                pp.setCallback(mPackageParserCallback);
                pr.scanFile = scanFile;
                pr.parsedPackage = parsePackage(pp, scanFile, parseFlags);
                pr.parsedPackage = parsePackage(scanFile, parseFlags);
            } catch (Throwable e) {
                pr.throwable = e;
            } finally {
@@ -134,17 +123,8 @@ class ParallelPackageParser implements AutoCloseable {
    }

    @VisibleForTesting
    protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
            int parseFlags) throws PackageParser.PackageParserException {
        return packageParser.parseParsedPackage(scanFile, parseFlags, true);
    }

    @Override
    public void close() {
        List<Runnable> unfinishedTasks = mService.shutdownNow();
        if (!unfinishedTasks.isEmpty()) {
            throw new IllegalStateException("Not all tasks finished before calling close: "
                    + unfinishedTasks);
        }
    protected ParsedPackage parsePackage(File scanFile, int parseFlags)
            throws PackageParser.PackageParserException {
        return mPackageParser.parseParsedPackage(scanFile, parseFlags, true);
    }
}
+7 −6
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;

/**
 * Tests for {@link ParallelPackageParser}
@@ -43,7 +44,8 @@ public class ParallelPackageParserTest {

    @Before
    public void setUp() {
        mParser = new TestParallelPackageParser();
        mParser = new TestParallelPackageParser(new PackageParser(),
                ParallelPackageParser.makeExecutorService());
    }

    @Test(timeout = 1000)
@@ -68,15 +70,14 @@ public class ParallelPackageParserTest {
        }
    }

    class TestParallelPackageParser extends ParallelPackageParser {
    private class TestParallelPackageParser extends ParallelPackageParser {

        TestParallelPackageParser() {
            super(null, false, null, null, null);
        TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
            super(packageParser, executorService);
        }

        @Override
        protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
                int parseFlags) throws PackageParser.PackageParserException {
        protected ParsedPackage parsePackage(File scanFile, int parseFlags) {
            // Do not actually parse the package for testing
            return null;
        }