diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index f42a3404664a4..54091db797790 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -5096,6 +5096,19 @@ public class PackageParser { return latestUse; } + public long getLatestForegroundPackageUseTimeInMills() { + int[] foregroundReasons = { + PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, + PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE + }; + + long latestUse = 0L; + for (int reason : foregroundReasons) { + latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]); + } + return latestUse; + } + public String toString() { return "Package{" + Integer.toHexString(System.identityHashCode(this)) diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index b3ac05c2e91db..f6202742e735e 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -137,21 +137,14 @@ class PackageDexOptimizer { boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter); // If any part of the app is used by other apps, we cannot use profile-guided // compilation. - // Skip the check for forward locked packages since they don't share their code. - if (isProfileGuidedFilter && !pkg.isForwardLocked()) { - for (String path : paths) { - if (isUsedByOtherApps(path)) { - checkProfiles = false; + if (isProfileGuidedFilter && isUsedByOtherApps(pkg)) { + checkProfiles = false; - targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter); - if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) { - throw new IllegalStateException(targetCompilerFilter); - } - isProfileGuidedFilter = false; - - break; - } + targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter); + if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) { + throw new IllegalStateException(targetCompilerFilter); } + isProfileGuidedFilter = false; } // If we're asked to take profile updates into account, check now. @@ -281,20 +274,34 @@ class PackageDexOptimizer { mSystemReady = true; } - private boolean isUsedByOtherApps(String apkPath) { - try { - apkPath = new File(apkPath).getCanonicalPath(); - } catch (IOException e) { - // Log an error but continue without it. - Slog.w(TAG, "Failed to get canonical path", e); + /** + * Returns true if the profiling data collected for the given app indicate + * that the apps's APK has been loaded by another app. + * Note that this returns false for all forward-locked apps and apps without + * any collected profiling data. + */ + public static boolean isUsedByOtherApps(PackageParser.Package pkg) { + if (pkg.isForwardLocked()) { + // Skip the check for forward locked packages since they don't share their code. + return false; } - String useMarker = apkPath.replace('/', '@'); - final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); - for (int i = 0; i < currentUserIds.length; i++) { - File profileDir = Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]); - File foreignUseMark = new File(profileDir, useMarker); - if (foreignUseMark.exists()) { - return true; + + for (String apkPath : pkg.getAllCodePathsExcludingResourceOnly()) { + try { + apkPath = new File(apkPath).getCanonicalPath(); + } catch (IOException e) { + // Log an error but continue without it. + Slog.w(TAG, "Failed to get canonical path", e); + } + String useMarker = apkPath.replace('/', '@'); + final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); + for (int i = 0; i < currentUserIds.length; i++) { + File profileDir = + Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]); + File foreignUseMark = new File(profileDir, useMarker); + if (foreignUseMark.exists()) { + return true; + } } } return false; diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 3c065aea51ded..67cbcd88ead16 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -69,11 +69,12 @@ public class PackageManagerServiceUtils { long now = System.currentTimeMillis(); for (Iterator i = pkgs.iterator(); i.hasNext();) { PackageParser.Package pkg = i.next(); - long then = pkg.getLatestPackageUseTimeInMills(); + long then = pkg.getLatestForegroundPackageUseTimeInMills(); if (then + dexOptLRUThresholdInMills < now) { if (DEBUG_DEXOPT) { - Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " + - ((then == 0) ? "never" : new Date(then))); + Log.i(TAG, "Skipping dexopt of " + pkg.packageName + + " last used in foreground: " + + ((then == 0) ? "never" : new Date(then))); } i.remove(); skipped++; @@ -117,6 +118,18 @@ public class PackageManagerServiceUtils { } remainingPkgs.removeAll(result); + // Give priority to apps used by other apps. + for (PackageParser.Package pkg : remainingPkgs) { + if (PackageDexOptimizer.isUsedByOtherApps(pkg)) { + if (DEBUG_DEXOPT) { + Log.i(TAG, "Adding app used by other apps " + result.size() + ": " + + pkg.packageName); + } + result.add(pkg); + } + } + remainingPkgs.removeAll(result); + // Filter out packages that aren't recently used, add all remaining apps. // TODO: add a property to control this? if (packageManagerService.isHistoricalPackageUsageAvailable()) {