Merge "Enable profile guided compilation on the framework side"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2f2fbbe..a7d3669 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4723,6 +4723,9 @@
}
private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
+ if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
+ return;
+ }
final ApplicationInfo appInfo = loadedApk.getApplicationInfo();
if (isSharingRuntime(appInfo)) {
// If sharing is enabled we do not have a unique application
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index b3222f0..ed4722d 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -21,6 +21,7 @@
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;
+import android.text.TextUtils;
import com.android.internal.util.Preconditions;
@@ -139,14 +140,24 @@
}
public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
- int dexFlags) throws InstallerException {
- dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /* outputPath */, dexFlags);
+ int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+ dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
+ null /*outputPath*/, dexFlags, volumeUuid, useProfiles);
}
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
- int dexoptNeeded, String outputPath, int dexFlags) throws InstallerException {
- execute("dexopt", apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
- dexFlags);
+ int dexoptNeeded, String outputPath, int dexFlags, String volumeUuid,
+ boolean useProfiles) throws InstallerException {
+ execute("dexopt",
+ apkPath,
+ uid,
+ pkgName,
+ instructionSet,
+ dexoptNeeded,
+ outputPath,
+ dexFlags,
+ volumeUuid,
+ useProfiles ? '1' : '0');
}
private boolean connect() {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index eecc0ee..6ad9e20 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -500,8 +500,11 @@
final int dexoptNeeded = DexFile.getDexOptNeeded(
classPathElement, "*", instructionSet, false /* defer */);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ // System server is fully AOTed and never profiled
+ // for profile guided compilation.
installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
- dexoptNeeded, 0 /*dexFlags*/);
+ dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
+ false /*useProfiles*/);
}
}
} catch (IOException | InstallerException e) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 40af22a..8e11e06 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -586,6 +586,7 @@
char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
+ char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -691,6 +692,10 @@
parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");
parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");
parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
+ property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
+ if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
+ addOption("-Xjitsaveprofilinginfo");
+ }
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index af20679..06f828e 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -24,6 +24,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.ArraySet;
import android.util.Log;
@@ -50,12 +51,13 @@
final AtomicBoolean mIdleTime = new AtomicBoolean(false);
- public static void schedule(Context context, long minLatency) {
+ private boolean useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+
+ public static void schedule(Context context) {
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
- .setMinimumLatency(minLatency)
.setPeriodic(TimeUnit.DAYS.toMillis(1))
.build();
js.schedule(job);
@@ -63,16 +65,17 @@
@Override
public boolean onStartJob(JobParameters params) {
- Log.i(TAG, "onIdleStart");
+ Log.i(TAG, "onStartJob");
final PackageManagerService pm =
(PackageManagerService)ServiceManager.getService("package");
if (pm.isStorageLow()) {
- schedule(BackgroundDexOptService.this, RETRY_LATENCY);
+ Log.i(TAG, "Low storage, skipping this run");
return false;
}
- final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt();
- if (pkgs == null) {
+ final ArraySet<String> pkgs = pm.getOptimizablePackages();
+ if (pkgs == null || pkgs.isEmpty()) {
+ Log.i(TAG, "No packages to optimize");
return false;
}
@@ -83,15 +86,14 @@
public void run() {
for (String pkg : pkgs) {
if (!mIdleTime.get()) {
- // stopped while still working, so we need to reschedule
- schedule(BackgroundDexOptService.this, 0);
+ // Out of the idle state. Stop the compilation.
return;
}
if (sFailedPackageNames.contains(pkg)) {
// skip previously failing package
continue;
}
- if (!pm.performDexOpt(pkg, null /* instruction set */)) {
+ if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles)) {
// there was a problem running dexopt,
// remember this so we do not keep retrying.
sFailedPackageNames.add(pkg);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index a730de4..366edf9 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -143,17 +143,19 @@
}
public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
- int dexFlags) throws InstallerException {
+ int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
assertValidInstructionSet(instructionSet);
- mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
+ mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
+ volumeUuid, useProfiles);
}
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
- int dexoptNeeded, @Nullable String outputPath, int dexFlags)
+ int dexoptNeeded, @Nullable String outputPath, int dexFlags,
+ String volumeUuid, boolean useProfiles)
throws InstallerException {
assertValidInstructionSet(instructionSet);
mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
- outputPath, dexFlags);
+ outputPath, dexFlags, volumeUuid, useProfiles);
}
public void idmap(String targetApkPath, String overlayApkPath, int uid)
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b45a922..44b51d4 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -23,6 +23,7 @@
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -68,6 +69,11 @@
mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*dexopt*");
}
+ static boolean canOptimizePackage(PackageParser.Package pkg) {
+ return pkg.canHaveOatDir() &&
+ ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
+ }
+
/**
* Performs dexopt on all code paths and libraries of the specified package for specified
* instruction sets.
@@ -76,7 +82,7 @@
* {@link PackageManagerService#mInstallLock}.
*/
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
- boolean inclDependencies) {
+ boolean inclDependencies, String volumeUuid, boolean useProfiles) {
ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new ArraySet<String>();
@@ -91,7 +97,7 @@
mDexoptWakeLock.acquire();
}
try {
- return performDexOptLI(pkg, instructionSets, done);
+ return performDexOptLI(pkg, instructionSets, done, volumeUuid, useProfiles);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -101,7 +107,7 @@
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- ArraySet<String> done) {
+ ArraySet<String> done, String volumeUuid, boolean useProfiles) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -115,7 +121,7 @@
}
}
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+ if (!canOptimizePackage(pkg)) {
return DEX_OPT_SKIPPED;
}
@@ -124,18 +130,15 @@
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
boolean performedDexOpt = false;
- // There are three basic cases here:
- // 1.) we need to dexopt, either because we are forced or it is needed
- // 2.) we are deferring a needed dexopt
- // 3.) we are skipping an unneeded dexopt
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- if (pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+ if (!useProfiles && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+ // Skip only if we do not use profiles since they might trigger a recompilation.
continue;
}
for (String path : paths) {
- final int dexoptNeeded;
+ int dexoptNeeded;
try {
dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
dexCodeInstructionSet, /* defer */false);
@@ -144,38 +147,46 @@
return DEX_OPT_FAILED;
}
- if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- final String dexoptType;
- String oatDir = null;
- if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
- dexoptType = "dex2oat";
- oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
- } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
- dexoptType = "patchoat";
- } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
- dexoptType = "self patchoat";
+ if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+ if (useProfiles) {
+ // If we do a profile guided compilation then we might recompile the same
+ // package if more profile information is available.
+ dexoptNeeded = DexFile.DEX2OAT_NEEDED;
} else {
- throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+ // No dexopt needed and we don't use profiles. Nothing to do.
+ continue;
}
+ }
+ final String dexoptType;
+ String oatDir = null;
+ if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
+ dexoptType = "dex2oat";
+ oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
+ } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
+ dexoptType = "patchoat";
+ } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
+ dexoptType = "self patchoat";
+ } else {
+ throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+ }
- Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
- + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
- + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
- + " oatDir = " + oatDir);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final int dexFlags =
- (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
- | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
- | (debuggable ? DEXOPT_DEBUGGABLE : 0)
- | DEXOPT_BOOTCOMPLETE;
- try {
- mPackageManagerService.mInstaller.dexopt(path, sharedGid,
- pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir,
- dexFlags);
- performedDexOpt = true;
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to dexopt", e);
- }
+ Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
+ + " oatDir = " + oatDir);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int dexFlags =
+ (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
+ | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
+ | (debuggable ? DEXOPT_DEBUGGABLE : 0)
+ | DEXOPT_BOOTCOMPLETE;
+ try {
+ mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+ pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir,
+ dexFlags, volumeUuid, useProfiles);
+ performedDexOpt = true;
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to dexopt", e);
}
}
@@ -235,7 +246,10 @@
PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
libName);
if (libPkg != null && !done.contains(libName)) {
- performDexOptLI(libPkg, instructionSets, done);
+ // TODO: Analyze and investigate if we (should) profile libraries.
+ // Currently this will do a full compilation of the library.
+ performDexOptLI(libPkg, instructionSets, done,
+ StorageManager.UUID_PRIVATE_INTERNAL, /*useProfiles*/ false);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8a243a8..88198d4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2093,8 +2093,12 @@
try {
int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ // Shared libraries do not have profiles so we perform a full
+ // AOT compilation.
mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
- dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
+ dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
+ StorageManager.UUID_PRIVATE_INTERNAL,
+ false /*useProfiles*/);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -6647,25 +6651,28 @@
}
}
+ // TODO: this is not used nor needed. Delete it.
@Override
public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
- return performDexOptTraced(packageName, instructionSet);
+ return performDexOptTraced(packageName, instructionSet, false);
}
- public boolean performDexOpt(String packageName, String instructionSet) {
- return performDexOptTraced(packageName, instructionSet);
+ public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles) {
+ return performDexOptTraced(packageName, instructionSet, useProfiles);
}
- private boolean performDexOptTraced(String packageName, String instructionSet) {
+ private boolean performDexOptTraced(String packageName, String instructionSet,
+ boolean useProfiles) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
try {
- return performDexOptInternal(packageName, instructionSet);
+ return performDexOptInternal(packageName, instructionSet, useProfiles);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- private boolean performDexOptInternal(String packageName, String instructionSet) {
+ private boolean performDexOptInternal(String packageName, String instructionSet,
+ boolean useProfiles) {
PackageParser.Package p;
final String targetInstructionSet;
synchronized (mPackages) {
@@ -6677,7 +6684,8 @@
targetInstructionSet = instructionSet != null ? instructionSet :
getPrimaryInstructionSet(p.applicationInfo);
- if (p.mDexOptPerformed.contains(targetInstructionSet)) {
+ if (!useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
+ // Skip only if we do not use profiles since they might trigger a recompilation.
return false;
}
}
@@ -6686,7 +6694,7 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
- true /* inclDependencies */);
+ true /* inclDependencies */, p.volumeUuid, useProfiles);
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
} finally {
@@ -6694,20 +6702,13 @@
}
}
- public ArraySet<String> getPackagesThatNeedDexOpt() {
- ArraySet<String> pkgs = null;
+ public ArraySet<String> getOptimizablePackages() {
+ ArraySet<String> pkgs = new ArraySet<String>();
synchronized (mPackages) {
for (PackageParser.Package p : mPackages.values()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, p.packageName + " mDexOptPerformed=" + p.mDexOptPerformed.toArray());
+ if (PackageDexOptimizer.canOptimizePackage(p)) {
+ pkgs.add(p.packageName);
}
- if (!p.mDexOptPerformed.isEmpty()) {
- continue;
- }
- if (pkgs == null) {
- pkgs = new ArraySet<String>();
- }
- pkgs.add(p.packageName);
}
}
return pkgs;
@@ -6735,8 +6736,10 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Whoever is calling forceDexOpt wants a fully compiled package.
+ // Don't use profiles since that may cause compilation to be skipped.
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
- true /* inclDependencies */);
+ true /* inclDependencies */, pkg.volumeUuid, false /* useProfiles */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ee5f23f..7ce945bf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1051,7 +1051,7 @@
traceBeginAndSlog("StartBackgroundDexOptService");
try {
- BackgroundDexOptService.schedule(context, 0);
+ BackgroundDexOptService.schedule(context);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}