Merge "Make BackgroundDexOpt aware of thermal state" into sc-dev

This commit is contained in:
Christian Wailes
2021-05-20 22:26:32 +00:00
committed by Android (Google) Code Review
3 changed files with 76 additions and 5 deletions

View File

@@ -31,6 +31,9 @@ import android.content.IntentFilter;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.os.BatteryManagerInternal; import android.os.BatteryManagerInternal;
import android.os.Environment; import android.os.Environment;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.os.UserHandle; import android.os.UserHandle;
@@ -82,10 +85,15 @@ public class BackgroundDexOptService extends JobService {
private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2; private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2;
// Optimizations should be aborted. No space left on device. // Optimizations should be aborted. No space left on device.
private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3; 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. // Used for calculating space threshold for downgrading unused apps.
private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2; 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. * Set of failed packages remembered across job runs.
*/ */
@@ -107,8 +115,14 @@ public class BackgroundDexOptService extends JobService {
private static final long mDowngradeUnusedAppsThresholdInMillis = private static final long mDowngradeUnusedAppsThresholdInMillis =
getDowngradeUnusedAppsThresholdInMillis(); getDowngradeUnusedAppsThresholdInMillis();
private final IThermalService mThermalService =
IThermalService.Stub.asInterface(
ServiceManager.getService(Context.THERMAL_SERVICE));
private static List<PackagesUpdatedListener> sPackagesUpdatedListeners = new ArrayList<>(); private static List<PackagesUpdatedListener> sPackagesUpdatedListeners = new ArrayList<>();
private int mThermalStatusCutoff = THERMAL_CUTOFF_DEFAULT;
public static void schedule(Context context) { public static void schedule(Context context) {
if (isBackgroundDexoptDisabled()) { if (isBackgroundDexoptDisabled()) {
return; return;
@@ -251,12 +265,18 @@ public class BackgroundDexOptService extends JobService {
Slog.w(TAG, "Idle optimizations aborted because of space constraints."); Slog.w(TAG, "Idle optimizations aborted because of space constraints.");
} else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { } else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
Slog.w(TAG, "Idle optimizations aborted 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 { } else {
Slog.w(TAG, "Idle optimizations ended with unexpected code: " + result); 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. // Abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false); jobFinished(jobParams, /* wantsReschedule */ false);
} }
} }
}.start(); }.start();
@@ -542,6 +562,24 @@ public class BackgroundDexOptService extends JobService {
// JobScheduler requested an early abort. // JobScheduler requested an early abort.
return OPTIMIZE_ABORT_BY_JOB_SCHEDULER; 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(); long usableSpace = mDataDir.getUsableSpace();
if (usableSpace < lowStorageThreshold) { if (usableSpace < lowStorageThreshold) {
// Rather bail than completely fill up the disk. // Rather bail than completely fill up the disk.
@@ -603,6 +641,9 @@ public class BackgroundDexOptService extends JobService {
return false; return false;
} }
mThermalStatusCutoff =
SystemProperties.getInt("dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT);
boolean result; boolean result;
if (params.getJobId() == JOB_POST_BOOT_UPDATE) { if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
result = runPostBootUpdate(params, pm, pkgs); result = runPostBootUpdate(params, pm, pkgs);

View File

@@ -0,0 +1 @@
include platform/art:/OWNERS

View File

@@ -20,6 +20,7 @@ import android.app.AlarmManager;
import android.content.Context; import android.content.Context;
import android.os.Environment; import android.os.Environment;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.util.Log; import android.util.Log;
@@ -201,11 +202,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER)); fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
} }
// TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
private static void runBackgroundDexOpt() throws IOException { 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); String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
if (!result.trim().equals("Success")) { if (!result.trim().equals(expectedStatus)) {
throw new IllegalStateException("Expected command success, received >" + result + "<"); 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)); 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 that background dexopt under normal conditions succeeds.
@Test @Test
public void testBackgroundDexOpt() throws IOException { 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();
}
}
} }