Loading core/java/android/content/pm/PackageParser.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading services/core/java/com/android/server/pm/PackageManagerService.java +82 −56 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); Loading @@ -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); } Loading Loading @@ -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. Loading Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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); services/core/java/com/android/server/pm/ParallelPackageParser.java +18 −38 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading Loading @@ -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 { Loading @@ -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); } } services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java +7 −6 Original line number Diff line number Diff line Loading @@ -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} Loading @@ -43,7 +44,8 @@ public class ParallelPackageParserTest { @Before public void setUp() { mParser = new TestParallelPackageParser(); mParser = new TestParallelPackageParser(new PackageParser(), ParallelPackageParser.makeExecutorService()); } @Test(timeout = 1000) Loading @@ -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; } Loading Loading
core/java/android/content/pm/PackageParser.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading
services/core/java/com/android/server/pm/PackageManagerService.java +82 −56 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); Loading @@ -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); } Loading Loading @@ -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. Loading Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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);
services/core/java/com/android/server/pm/ParallelPackageParser.java +18 −38 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading Loading @@ -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 { Loading @@ -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); } }
services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java +7 −6 Original line number Diff line number Diff line Loading @@ -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} Loading @@ -43,7 +44,8 @@ public class ParallelPackageParserTest { @Before public void setUp() { mParser = new TestParallelPackageParser(); mParser = new TestParallelPackageParser(new PackageParser(), ParallelPackageParser.makeExecutorService()); } @Test(timeout = 1000) Loading @@ -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; } Loading