Some refactoring in BackgroundDexOptService.

Extract postOta/idle optimizations in their own method.
In preparation for adding the logic to handle secondary dex files.

Test: device boots, pacakges get compiled
Bug: 32871170

(cherry picked from commit be6a71a0b3)

Change-Id: Ie6cdd8461e7214f5de68bc9172f4171ebf72aa39
This commit is contained in:
Calin Juravle
2016-12-22 18:50:05 +02:00
parent b96dba9bad
commit 95176bb18e

View File

@@ -69,7 +69,7 @@ public class BackgroundDexOptService extends JobService {
*/ */
final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
private final File dataDir = Environment.getDataDirectory(); private final File mDataDir = Environment.getDataDirectory();
public static void schedule(Context context) { public static void schedule(Context context) {
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
@@ -120,7 +120,7 @@ public class BackgroundDexOptService extends JobService {
private long getLowStorageThreshold() { private long getLowStorageThreshold() {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
final long lowThreshold = StorageManager.from(this).getStorageLowBytes(dataDir); final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
if (lowThreshold == 0) { if (lowThreshold == 0) {
Log.e(TAG, "Invalid low storage threshold"); Log.e(TAG, "Invalid low storage threshold");
} }
@@ -134,114 +134,126 @@ public class BackgroundDexOptService extends JobService {
// This job has already been superseded. Do not start it. // This job has already been superseded. Do not start it.
return false; return false;
} }
// Load low battery threshold from the system config. This is a 0-100 integer.
final int lowBatteryThreshold = getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
final long lowThreshold = getLowStorageThreshold();
mAbortPostBootUpdate.set(false);
new Thread("BackgroundDexOptService_PostBootUpdate") { new Thread("BackgroundDexOptService_PostBootUpdate") {
@Override @Override
public void run() { public void run() {
for (String pkg : pkgs) { postBootUpdate(jobParams, pm, pkgs);
if (mAbortPostBootUpdate.get()) { }
// JobScheduler requested an early abort.
return;
}
if (mExitPostBootUpdate.get()) {
// Different job, which supersedes this one, is running.
break;
}
if (getBatteryLevel() < lowBatteryThreshold) {
// Rather bail than completely drain the battery.
break;
}
long usableSpace = dataDir.getUsableSpace();
if (usableSpace < lowThreshold) {
// Rather bail than completely fill up the disk.
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
usableSpace);
break;
}
if (DEBUG_DEXOPT) { }.start();
Log.i(TAG, "Updating package " + pkg); return true;
} }
// Update package if needed. Note that there can be no race between concurrent private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
// jobs because PackageDexOptimizer.performDexOpt is synchronized. ArraySet<String> pkgs) {
// Load low battery threshold from the system config. This is a 0-100 integer.
final int lowBatteryThreshold = getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
final long lowThreshold = getLowStorageThreshold();
// checkProfiles is false to avoid merging profiles during boot which mAbortPostBootUpdate.set(false);
// might interfere with background compilation (b/28612421).
// Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will for (String pkg : pkgs) {
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a if (mAbortPostBootUpdate.get()) {
// trade-off worth doing to save boot time work. // JobScheduler requested an early abort.
pm.performDexOpt(pkg, return;
/* checkProfiles */ false, }
PackageManagerService.REASON_BOOT, if (mExitPostBootUpdate.get()) {
/* force */ false); // Different job, which supersedes this one, is running.
} break;
// Ran to completion, so we abandon our timeslice and do not reschedule. }
jobFinished(jobParams, /* reschedule */ false); if (getBatteryLevel() < lowBatteryThreshold) {
// Rather bail than completely drain the battery.
break;
}
long usableSpace = mDataDir.getUsableSpace();
if (usableSpace < lowThreshold) {
// Rather bail than completely fill up the disk.
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
usableSpace);
break;
}
if (DEBUG_DEXOPT) {
Log.i(TAG, "Updating package " + pkg);
}
// Update package if needed. Note that there can be no race between concurrent
// jobs because PackageDexOptimizer.performDexOpt is synchronized.
// 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
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
// trade-off worth doing to save boot time work.
pm.performDexOpt(pkg,
/* checkProfiles */ false,
PackageManagerService.REASON_BOOT,
/* force */ false);
}
// Ran to completion, so we abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false);
}
private boolean runIdleOptimization(final JobParameters jobParams,
final PackageManagerService pm, final ArraySet<String> pkgs) {
new Thread("BackgroundDexOptService_IdleOptimization") {
@Override
public void run() {
idleOptimization(jobParams, pm, pkgs);
} }
}.start(); }.start();
return true; return true;
} }
private boolean runIdleOptimization(final JobParameters jobParams, private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
final PackageManagerService pm, final ArraySet<String> pkgs) { ArraySet<String> pkgs) {
// If post-boot update is still running, request that it exits early. // If post-boot update is still running, request that it exits early.
mExitPostBootUpdate.set(true); mExitPostBootUpdate.set(true);
mAbortIdleOptimization.set(false); mAbortIdleOptimization.set(false);
final long lowThreshold = getLowStorageThreshold(); final long lowThreshold = getLowStorageThreshold();
for (String pkg : pkgs) {
new Thread("BackgroundDexOptService_IdleOptimization") { if (mAbortIdleOptimization.get()) {
@Override // JobScheduler requested an early abort.
public void run() { return;
for (String pkg : pkgs) {
if (mAbortIdleOptimization.get()) {
// JobScheduler requested an early abort.
return;
}
if (sFailedPackageNames.contains(pkg)) {
// Skip previously failing package
continue;
}
long usableSpace = dataDir.getUsableSpace();
if (usableSpace < lowThreshold) {
// Rather bail than completely fill up the disk.
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
usableSpace);
break;
}
// Conservatively add package to the list of failing ones in case performDexOpt
// never returns.
synchronized (sFailedPackageNames) {
sFailedPackageNames.add(pkg);
}
// Optimize package if needed. Note that there can be no race between
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
if (pm.performDexOpt(pkg,
/* checkProfiles */ true,
PackageManagerService.REASON_BACKGROUND_DEXOPT,
/* force */ false)) {
// Dexopt succeeded, remove package from the list of failing ones.
synchronized (sFailedPackageNames) {
sFailedPackageNames.remove(pkg);
}
}
}
// Ran to completion, so we abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false);
} }
}.start();
return true; synchronized (sFailedPackageNames) {
if (sFailedPackageNames.contains(pkg)) {
// Skip previously failing package
continue;
}
}
long usableSpace = mDataDir.getUsableSpace();
if (usableSpace < lowThreshold) {
// Rather bail than completely fill up the disk.
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
usableSpace);
break;
}
// Conservatively add package to the list of failing ones in case performDexOpt
// never returns.
synchronized (sFailedPackageNames) {
sFailedPackageNames.add(pkg);
}
// Optimize package if needed. Note that there can be no race between
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
if (pm.performDexOpt(pkg,
/* checkProfiles */ true,
PackageManagerService.REASON_BACKGROUND_DEXOPT,
/* force */ false)) {
// Dexopt succeeded, remove package from the list of failing ones.
synchronized (sFailedPackageNames) {
sFailedPackageNames.remove(pkg);
}
}
}
// Ran to completion, so we abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false);
} }
@Override @Override