Make BackgroundDexOpt aware of thermal state
This change makes the BackgroundDexOpt service consider the thermal state of the device before running. If the device is in a moderate thermal state or worse background dexopt will not run. Bug: 165935246 Bug: 181795682 Test: Treehugger && atest BackgroundDexOptServiceIntegrationTests Change-Id: Ie5ccbab7aa6d414241780136407f397d326340bf
This commit is contained in:
parent
8a6ffdc597
commit
5d8c1369c1
@ -31,6 +31,9 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.BatteryManagerInternal;
|
||||
import android.os.Environment;
|
||||
import android.os.IThermalService;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
@ -82,10 +85,15 @@ public class BackgroundDexOptService extends JobService {
|
||||
private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2;
|
||||
// Optimizations should be aborted. No space left on device.
|
||||
private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3;
|
||||
// Optimizations should be aborted. Thermal throttling level too high.
|
||||
private static final int OPTIMIZE_ABORT_THERMAL = 4;
|
||||
|
||||
// Used for calculating space threshold for downgrading unused apps.
|
||||
private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2;
|
||||
|
||||
// Thermal cutoff value used if one isn't defined by a system property.
|
||||
private static final int THERMAL_CUTOFF_DEFAULT = PowerManager.THERMAL_STATUS_MODERATE;
|
||||
|
||||
/**
|
||||
* Set of failed packages remembered across job runs.
|
||||
*/
|
||||
@ -107,8 +115,14 @@ public class BackgroundDexOptService extends JobService {
|
||||
private static final long mDowngradeUnusedAppsThresholdInMillis =
|
||||
getDowngradeUnusedAppsThresholdInMillis();
|
||||
|
||||
private final IThermalService mThermalService =
|
||||
IThermalService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.THERMAL_SERVICE));
|
||||
|
||||
private static List<PackagesUpdatedListener> sPackagesUpdatedListeners = new ArrayList<>();
|
||||
|
||||
private int mThermalStatusCutoff = THERMAL_CUTOFF_DEFAULT;
|
||||
|
||||
public static void schedule(Context context) {
|
||||
if (isBackgroundDexoptDisabled()) {
|
||||
return;
|
||||
@ -251,12 +265,18 @@ public class BackgroundDexOptService extends JobService {
|
||||
Slog.w(TAG, "Idle optimizations aborted because of space constraints.");
|
||||
} else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
|
||||
Slog.w(TAG, "Idle optimizations aborted by job scheduler.");
|
||||
} else if (result == OPTIMIZE_ABORT_THERMAL) {
|
||||
Slog.w(TAG, "Idle optimizations aborted by thermal throttling.");
|
||||
} else {
|
||||
Slog.w(TAG, "Idle optimizations ended with unexpected code: " + result);
|
||||
}
|
||||
if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
|
||||
|
||||
if (result == OPTIMIZE_ABORT_THERMAL) {
|
||||
// Abandon our timeslice and reschedule
|
||||
jobFinished(jobParams, /* wantsReschedule */ true);
|
||||
} else if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
|
||||
// Abandon our timeslice and do not reschedule.
|
||||
jobFinished(jobParams, /* reschedule */ false);
|
||||
jobFinished(jobParams, /* wantsReschedule */ false);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
@ -542,6 +562,24 @@ public class BackgroundDexOptService extends JobService {
|
||||
// JobScheduler requested an early abort.
|
||||
return OPTIMIZE_ABORT_BY_JOB_SCHEDULER;
|
||||
}
|
||||
|
||||
// Abort background dexopt if the device is in a moderate or stronger thermal throttling
|
||||
// state.
|
||||
try {
|
||||
final int thermalStatus = mThermalService.getCurrentThermalStatus();
|
||||
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "Thermal throttling status during bgdexopt: " + thermalStatus);
|
||||
}
|
||||
|
||||
if (thermalStatus >= mThermalStatusCutoff) {
|
||||
return OPTIMIZE_ABORT_THERMAL;
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// Because this is a intra-process Binder call it is impossible for a RemoteException
|
||||
// to be raised.
|
||||
}
|
||||
|
||||
long usableSpace = mDataDir.getUsableSpace();
|
||||
if (usableSpace < lowStorageThreshold) {
|
||||
// Rather bail than completely fill up the disk.
|
||||
@ -603,6 +641,9 @@ public class BackgroundDexOptService extends JobService {
|
||||
return false;
|
||||
}
|
||||
|
||||
mThermalStatusCutoff =
|
||||
SystemProperties.getInt("dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT);
|
||||
|
||||
boolean result;
|
||||
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
|
||||
result = runPostBootUpdate(params, pm, pkgs);
|
||||
|
1
tests/BackgroundDexOptServiceIntegrationTests/OWNERS
Normal file
1
tests/BackgroundDexOptServiceIntegrationTests/OWNERS
Normal file
@ -0,0 +1 @@
|
||||
include platform/art:/OWNERS
|
@ -20,6 +20,7 @@ import android.app.AlarmManager;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.Log;
|
||||
@ -201,11 +202,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
|
||||
fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
|
||||
}
|
||||
|
||||
// TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
|
||||
private static void runBackgroundDexOpt() throws IOException {
|
||||
runBackgroundDexOpt("Success");
|
||||
}
|
||||
|
||||
// TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
|
||||
private static void runBackgroundDexOpt(String expectedStatus) throws IOException {
|
||||
String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
|
||||
if (!result.trim().equals("Success")) {
|
||||
throw new IllegalStateException("Expected command success, received >" + result + "<");
|
||||
if (!result.trim().equals(expectedStatus)) {
|
||||
throw new IllegalStateException("Expected status: " + expectedStatus
|
||||
+ "; Received: " + result.trim());
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,6 +248,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
|
||||
runShellCommand(String.format("cmd package compile -f -m %s %s", filter, pkg));
|
||||
}
|
||||
|
||||
// Override the thermal status of the device
|
||||
public static void overrideThermalStatus(int status) throws IOException {
|
||||
runShellCommand("cmd thermalservice override-status " + status);
|
||||
}
|
||||
|
||||
// Reset the thermal status of the device
|
||||
public static void resetThermalStatus() throws IOException {
|
||||
runShellCommand("cmd thermalservice reset");
|
||||
}
|
||||
|
||||
// Test that background dexopt under normal conditions succeeds.
|
||||
@Test
|
||||
public void testBackgroundDexOpt() throws IOException {
|
||||
@ -307,4 +323,17 @@ public final class BackgroundDexOptServiceIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that background dexopt job doesn't trigger if the device is under thermal throttling.
|
||||
@Test
|
||||
public void testBackgroundDexOptThermalThrottling() throws IOException {
|
||||
try {
|
||||
compilePackageWithFilter(PACKAGE_NAME, "verify");
|
||||
overrideThermalStatus(PowerManager.THERMAL_STATUS_MODERATE);
|
||||
// The bgdexopt task should fail when onStartJob is run
|
||||
runBackgroundDexOpt("Failure");
|
||||
Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
|
||||
} finally {
|
||||
resetThermalStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user