Loading services/core/java/com/android/server/pm/BackgroundDexOptService.java +43 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. */ Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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. Loading Loading @@ -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); Loading tests/BackgroundDexOptServiceIntegrationTests/OWNERS 0 → 100644 +1 −0 Original line number Diff line number Diff line include platform/art:/OWNERS tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java +32 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } Loading Loading @@ -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 { Loading Loading @@ -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
services/core/java/com/android/server/pm/BackgroundDexOptService.java +43 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. */ Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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. Loading Loading @@ -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); Loading
tests/BackgroundDexOptServiceIntegrationTests/OWNERS 0 → 100644 +1 −0 Original line number Diff line number Diff line include platform/art:/OWNERS
tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java +32 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } Loading Loading @@ -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 { Loading Loading @@ -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(); } } }