From 20ad4b92a7528f24adf6e4f6d23d9d3a02a8792a Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Thu, 14 Sep 2017 19:22:39 -0700 Subject: [PATCH] Add preopt profile logic for compiling during first boot Allows pushing profiles on device that are used to optimize apps during first boot. Added logic to copy profiles to reference location for compressed APKs. Bug: 38032017 Bug: 64503246 Test: adb shell rm -rf /data/app/* Test: adb shell rm /data/system/package* Test: adb shell stop && adb shell start Test: look at apps in /data/app to make sure they are profile compiled Change-Id: I30452098a19a65a331d098107d37498e5b10c10f --- .../server/pm/PackageManagerService.java | 53 +++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ea1c029eebcb4..aae9170dcbe84 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3312,6 +3312,24 @@ public class PackageManagerService extends IPackageManager.Stub removeCodePathLI(dstCodePath); return null; } + + // If we have a profile for a compressed APK, copy it to the reference location. + // Since the package is the stub one, remove the stub suffix to get the normal package and + // APK name. + File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, "")); + if (profileFile.exists()) { + try { + // We could also do this lazily before calling dexopt in + // PackageDexOptimizer to prevent this happening on first boot. The issue + // is that we don't have a good way to say "do this only once". + if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), + pkg.applicationInfo.uid, pkg.packageName)) { + Log.e(TAG, "decompressPackage failed to copy system profile!"); + } + } catch (Exception e) { + Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); + } + } return dstCodePath; } @@ -9723,7 +9741,7 @@ public class PackageManagerService extends IPackageManager.Stub * and {@code numberOfPackagesFailed}. */ private int[] performDexOptUpgrade(List pkgs, boolean showDialog, - String compilerFilter, boolean bootComplete) { + final String compilerFilter, boolean bootComplete) { int numberOfPackagesVisited = 0; int numberOfPackagesOptimized = 0; @@ -9734,6 +9752,8 @@ public class PackageManagerService extends IPackageManager.Stub for (PackageParser.Package pkg : pkgs) { numberOfPackagesVisited++; + boolean useProfileForDexopt = false; + if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) { // Copy over initial preopt profiles since we won't get any JIT samples for methods // that are already compiled. @@ -9747,11 +9767,28 @@ public class PackageManagerService extends IPackageManager.Stub if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), pkg.applicationInfo.uid, pkg.packageName)) { Log.e(TAG, "Installer failed to copy system profile!"); + } else { + useProfileForDexopt = true; } } catch (Exception e) { Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); } + } else { + PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName); + // Handle compressed APKs in this path. Only do this for stubs with profiles to + // minimize the number off apps being speed-profile compiled during first boot. + // The other paths will not change the filter. + if (disabledPs != null && disabledPs.pkg.isStub) { + // The package is the stub one, remove the stub suffix to get the normal + // package and APK names. + String systemProfilePath = + getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, ""); + File systemProfile = new File(systemProfilePath); + // Use the profile for compilation if there exists one for the same package + // in the system partition. + useProfileForDexopt = systemProfile.exists(); + } } } @@ -9780,6 +9817,14 @@ public class PackageManagerService extends IPackageManager.Stub } } + String pkgCompilerFilter = compilerFilter; + if (useProfileForDexopt) { + // Use background dexopt mode to try and use the profile. Note that this does not + // guarantee usage of the profile. + pkgCompilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerService.REASON_BACKGROUND_DEXOPT); + } // If the OTA updates a system app which was previously preopted to a non-preopted state // the app might end up being verified at runtime. That's because by default the apps // are verify-profile but for preopted apps there's no profile. @@ -9788,9 +9833,9 @@ public class PackageManagerService extends IPackageManager.Stub // filter (by default 'quicken'). // Note that at this stage unused apps are already filtered. if (isSystemApp(pkg) && - DexFile.isProfileGuidedCompilerFilter(compilerFilter) && + DexFile.isProfileGuidedCompilerFilter(pkgCompilerFilter) && !Environment.getReferenceProfile(pkg.packageName).exists()) { - compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter); + pkgCompilerFilter = getNonProfileGuidedCompilerFilter(pkgCompilerFilter); } // checkProfiles is false to avoid merging profiles during boot which @@ -9801,7 +9846,7 @@ public class PackageManagerService extends IPackageManager.Stub int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0; int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( pkg.packageName, - compilerFilter, + pkgCompilerFilter, dexoptFlags)); switch (primaryDexOptStaus) {