diff options
5 files changed, 97 insertions, 12 deletions
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index f30b3fee7f46..755232c6a6b6 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -628,4 +628,9 @@ public abstract class PackageManagerInternal { */ public abstract boolean hasSignatureCapability(int serverUid, int clientUid, @PackageParser.SigningDetails.CertCapabilities int capability); + + /** + * Ask the package manager to compile layouts in the given package. + */ + public abstract boolean compileLayouts(String packageName); } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index f0807b9b36d3..a48104a16a9f 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -589,6 +589,14 @@ public class Installer extends SystemService { throw new InstallerException("Invalid instruction set: " + instructionSet); } + public boolean compileLayouts(String apkPath, String packageName, String outDexFile, int uid) { + try { + return mInstalld.compileLayouts(apkPath, packageName, outDexFile, uid); + } catch (RemoteException e) { + return false; + } + } + public static class InstallerException extends Exception { public InstallerException(String detailMessage) { super(detailMessage); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f4673a8fa7ba..bf872b7c48f6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -450,6 +450,9 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean ENABLE_FREE_CACHE_V2 = SystemProperties.getBoolean("fw.free_cache_v2", true); + private static final boolean PRECOMPILED_LAYOUT_ENABLED = + SystemProperties.getBoolean("view.precompiled_layout_enabled", false); + private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; @@ -9177,6 +9180,10 @@ public class PackageManagerService extends IPackageManager.Stub pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT; } + if (PRECOMPILED_LAYOUT_ENABLED) { + mArtManagerService.compileLayouts(pkg); + } + // checkProfiles is false to avoid merging profiles during boot which // might interfere with background compilation (b/28612421). // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will @@ -17739,6 +17746,13 @@ public class PackageManagerService extends IPackageManager.Stub && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0); if (performDexopt) { + // Compile the layout resources. + if (PRECOMPILED_LAYOUT_ENABLED) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts"); + mArtManagerService.compileLayouts(pkg); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` may not be in `mPackages` yet. @@ -24483,6 +24497,21 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); PackageManagerService.this.notifyPackageUseLocked(packageName, reason); } } + + /** + * Ask the package manager to compile layouts in the given package. + */ + @Override + public boolean compileLayouts(String packageName) { + PackageParser.Package pkg; + synchronized (mPackages) { + pkg = mPackages.get(packageName); + if (pkg == null) { + return false; + } + } + return mArtManagerService.compileLayouts(pkg); + } } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index e5b903024795..e1c13026507f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -41,6 +41,7 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionParams; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -1146,6 +1147,7 @@ class PackageManagerShellCommand extends ShellCommand { String checkProfilesRaw = null; boolean secondaryDex = false; String split = null; + boolean compileLayouts = false; String opt; while ((opt = getNextOption()) != null) { @@ -1165,6 +1167,9 @@ class PackageManagerShellCommand extends ShellCommand { case "-r": compilationReason = getNextArgRequired(); break; + case "--compile-layouts": + compileLayouts = true; + break; case "--check-prof": checkProfilesRaw = getNextArgRequired(); break; @@ -1196,14 +1201,16 @@ class PackageManagerShellCommand extends ShellCommand { } } - if (compilerFilter != null && compilationReason != null) { - pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " + - "at the same time"); - return 1; - } - if (compilerFilter == null && compilationReason == null) { - pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " + - "reason (\"-r\") at the same time"); + final boolean compilerFilterGiven = compilerFilter != null; + final boolean compilationReasonGiven = compilationReason != null; + // Make sure exactly one of -m, -r, or --compile-layouts is given. + if ((!compilerFilterGiven && !compilationReasonGiven && !compileLayouts) + || (!compilerFilterGiven && compilationReasonGiven && compileLayouts) + || (compilerFilterGiven && !compilationReasonGiven && compileLayouts) + || (compilerFilterGiven && compilationReasonGiven && !compileLayouts) + || (compilerFilterGiven && compilationReasonGiven && compileLayouts)) { + pw.println("Must specify exactly one of compilation filter (\"-m\"), compilation " + + "reason (\"-r\"), or compile layouts (\"--compile-layouts\")"); return 1; } @@ -1217,15 +1224,16 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - String targetCompilerFilter; - if (compilerFilter != null) { + String targetCompilerFilter = null; + if (compilerFilterGiven) { if (!DexFile.isValidCompilerFilter(compilerFilter)) { pw.println("Error: \"" + compilerFilter + "\" is not a valid compilation filter."); return 1; } targetCompilerFilter = compilerFilter; - } else { + } + if (compilationReasonGiven) { int reason = -1; for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals( @@ -1267,12 +1275,19 @@ class PackageManagerShellCommand extends ShellCommand { pw.flush(); } - boolean result = secondaryDex + boolean result = true; + if (compileLayouts) { + PackageManagerInternal internal = LocalServices.getService( + PackageManagerInternal.class); + result = internal.compileLayouts(packageName); + } else { + result = secondaryDex ? mInterface.performDexOptSecondary(packageName, targetCompilerFilter, forceCompilation) : mInterface.performDexOptMode(packageName, checkProfiles, targetCompilerFilter, forceCompilation, true /* bootComplete */, split); + } if (!result) { failedPackages.add(packageName); } @@ -2908,6 +2923,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" --check-prof (true | false): look at profiles when doing dexopt?"); pw.println(" --secondary-dex: compile app secondary dex files"); pw.println(" --split SPLIT: compile only the given split name"); + pw.println(" --compile-layouts: compile layout resources for faster inflation"); pw.println(""); pw.println(" force-dex-opt PACKAGE"); pw.println(" Force immediate execution of dex opt for the given PACKAGE."); diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 1f05dc966555..863bfd5ea391 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -472,6 +472,33 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } /** + * Compile layout resources in a given package. + */ + public boolean compileLayouts(PackageParser.Package pkg) { + try { + final String packageName = pkg.packageName; + final String apkPath = pkg.baseCodePath; + final ApplicationInfo appInfo = pkg.applicationInfo; + final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; + Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + + ") to " + outDexFile); + long callingId = Binder.clearCallingIdentity(); + try { + synchronized (mInstallLock) { + return mInstaller.compileLayouts(apkPath, packageName, outDexFile, + appInfo.uid); + } + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + catch (Throwable e) { + Log.e("PackageManager", "Failed to compile layouts", e); + return false; + } + } + + /** * Build the profiles names for all the package code paths (excluding resource only paths). * Return the map [code path -> profile name]. */ |