Revert "Downgrade the compilation filter of unused apps."

This reverts commit bdcc111625.

Reason for revert: It has been decided to not move forward with this experiment.

Change-Id: If52a2bb8ba57fd60ba736a5d23a254e72d78645b
This commit is contained in:
Carmen Agimof
2019-11-22 13:48:32 +00:00
parent bdcc111625
commit 1ef924bfeb
3 changed files with 45 additions and 275 deletions

View File

@@ -34,8 +34,6 @@ import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.StatsLog;
@@ -86,12 +84,6 @@ public class BackgroundDexOptService extends JobService {
// Used for calculating space threshold for downgrading unused apps.
private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2;
private static final int DEFAULT_INACTIVE_APP_THRESHOLD_DAYS = 10;
private static final String DOWNGRADE_UNUSED_APPS_ENABLED = "downgrade_unused_apps_enabled";
private static final String INACTIVE_APP_THRESHOLD_DAYS = "inactive_app_threshold_days";
private static final String LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE =
"low_storage_threshold_multiplier_for_downgrade";
/**
* Set of failed packages remembered across job runs.
@@ -111,6 +103,8 @@ public class BackgroundDexOptService extends JobService {
private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
private final File mDataDir = Environment.getDataDirectory();
private static final long mDowngradeUnusedAppsThresholdInMillis =
getDowngradeUnusedAppsThresholdInMillis();
public static void schedule(Context context) {
if (isBackgroundDexoptDisabled()) {
@@ -352,14 +346,14 @@ public class BackgroundDexOptService extends JobService {
// Only downgrade apps when space is low on device.
// Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
// up disk before user hits the actual lowStorageThreshold.
final long lowStorageThresholdForDowngrade = getLowThresholdMultiplierForDowngrade()
final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
* lowStorageThreshold;
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
Log.d(TAG, "Should Downgrade " + shouldDowngrade);
if (shouldDowngrade) {
Set<String> unusedPackages =
pm.getUnusedPackages(getDowngradeUnusedAppsThresholdInMillis());
Log.d(TAG, "Unused Packages " + String.join(",", unusedPackages));
pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
if (!unusedPackages.isEmpty()) {
for (String pkg : unusedPackages) {
@@ -368,9 +362,12 @@ public class BackgroundDexOptService extends JobService {
// Should be aborted by the scheduler.
return abortCode;
}
if (downgradePackage(pm, pkg)) {
if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) {
updatedPackages.add(pkg);
}
if (supportSecondaryDex) {
downgradePackage(pm, pkg, /*isForPrimaryDex*/ false);
}
}
pkgs = new ArraySet<>(pkgs);
@@ -418,45 +415,39 @@ public class BackgroundDexOptService extends JobService {
* Try to downgrade the package to a smaller compilation filter.
* eg. if the package is in speed-profile the package will be downgraded to verify.
* @param pm PackageManagerService
* @param pkg The package to be downgraded
* @return true if the package was downgraded
* @param pkg The package to be downgraded.
* @param isForPrimaryDex. Apps can have several dex file, primary and secondary.
* @return true if the package was downgraded.
*/
private boolean downgradePackage(PackageManagerService pm, String pkg) {
private boolean downgradePackage(PackageManagerService pm, String pkg,
boolean isForPrimaryDex) {
Log.d(TAG, "Downgrading " + pkg);
boolean downgradedPrimary = false;
boolean dex_opt_performed = false;
int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB
| DexoptOptions.DEXOPT_DOWNGRADE;
long package_size_before = getPackageSize(pm, pkg);
// An aggressive downgrade deletes the oat files.
boolean aggressive = false;
// This applies for system apps or if packages location is not a directory, i.e.
// monolithic install.
if (!pm.canHaveOatDir(pkg)) {
// For apps that don't have the oat directory, instead of downgrading,
// remove their compiler artifacts from dalvik cache.
pm.deleteOatArtifactsOfPackage(pkg);
aggressive = true;
downgradedPrimary = true;
} else {
downgradedPrimary = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
if (supportSecondaryDex()) {
performDexOptSecondary(pm, pkg, reason, dexoptFlags);
if (isForPrimaryDex) {
// This applies for system apps or if packages location is not a directory, i.e.
// monolithic install.
if (!pm.canHaveOatDir(pkg)) {
// For apps that don't have the oat directory, instead of downgrading,
// remove their compiler artifacts from dalvik cache.
pm.deleteOatArtifactsOfPackage(pkg);
} else {
dex_opt_performed = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
}
} else {
dex_opt_performed = performDexOptSecondary(pm, pkg, reason, dexoptFlags);
}
// This metric aims to log the storage savings when downgrading.
// The way disk size is measured using getPackageSize only looks at the primary apks.
// Any logs that are due to secondary dex files will show 0% size reduction and pollute
// the metrics.
if (downgradedPrimary) {
if (dex_opt_performed) {
StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before,
getPackageSize(pm, pkg), aggressive);
getPackageSize(pm, pkg), /*aggressive=*/ false);
}
return downgradedPrimary;
return dex_opt_performed;
}
private boolean supportSecondaryDex() {
@@ -480,7 +471,7 @@ public class BackgroundDexOptService extends JobService {
* concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
* @param pm An instance of PackageManagerService
* @param pkg The package to be downgraded.
* @param isForPrimaryDex Apps can have several dex file, primary and secondary.
* @param isForPrimaryDex. Apps can have several dex file, primary and secondary.
* @return true if the package was downgraded.
*/
private boolean optimizePackage(PackageManagerService pm, String pkg,
@@ -597,6 +588,12 @@ public class BackgroundDexOptService extends JobService {
// the checks above. This check is not "live" - the value is determined by a background
// restart with a period of ~1 minute.
PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
if (pm.isStorageLow()) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Low storage, skipping this run");
}
return false;
}
final ArraySet<String> pkgs = pm.getOptimizablePackages();
if (pkgs.isEmpty()) {
@@ -646,77 +643,17 @@ public class BackgroundDexOptService extends JobService {
}
private static long getDowngradeUnusedAppsThresholdInMillis() {
long defaultValue = Long.MAX_VALUE;
if (isDowngradeFeatureEnabled()) {
return getInactiveAppsThresholdMillis();
}
final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
String sysPropValue = SystemProperties.get(sysPropKey);
if (sysPropValue == null || sysPropValue.isEmpty()) {
Log.w(TAG, "SysProp " + sysPropKey + " not set");
return defaultValue;
}
try {
return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
} catch (NumberFormatException e) {
Log.w(TAG, "Couldn't parse long for pm.dexopt.downgrade_after_inactive_days: "
+ sysPropValue + ". Returning default value instead.");
return defaultValue;
return Long.MAX_VALUE;
}
return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
}
private static boolean isBackgroundDexoptDisabled() {
return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */,
false /* default */);
}
private static boolean isDowngradeFeatureEnabled() {
// DeviceConfig enables the control of on device features via remotely configurable flags,
// compared to SystemProperties which is only a way of sharing info system-widely, but are
// not configurable on the server-side.
String downgradeUnusedAppsEnabledFlag =
DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
DOWNGRADE_UNUSED_APPS_ENABLED);
return !TextUtils.isEmpty(downgradeUnusedAppsEnabledFlag)
&& Boolean.parseBoolean(downgradeUnusedAppsEnabledFlag);
}
private static long getInactiveAppsThresholdMillis() {
long defaultValue = TimeUnit.DAYS.toMillis(DEFAULT_INACTIVE_APP_THRESHOLD_DAYS);
String inactiveAppThresholdDaysFlag =
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
INACTIVE_APP_THRESHOLD_DAYS);
if (!TextUtils.isEmpty(inactiveAppThresholdDaysFlag)) {
try {
return TimeUnit.DAYS.toMillis(Long.parseLong(inactiveAppThresholdDaysFlag));
} catch (NumberFormatException e) {
Log.w(TAG, "Couldn't parse long for " + INACTIVE_APP_THRESHOLD_DAYS + " flag: "
+ inactiveAppThresholdDaysFlag + ". Returning default value instead.");
return defaultValue;
}
}
return defaultValue;
}
private static int getLowThresholdMultiplierForDowngrade() {
int defaultValue = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE;
if (isDowngradeFeatureEnabled()) {
String lowStorageThresholdMultiplierFlag =
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE);
if (!TextUtils.isEmpty(lowStorageThresholdMultiplierFlag)) {
try {
return Integer.parseInt(lowStorageThresholdMultiplierFlag);
} catch (NumberFormatException e) {
Log.w(TAG, "Couldn't parse long for "
+ LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE + " flag: "
+ lowStorageThresholdMultiplierFlag
+ ". Returning default value instead.");
return defaultValue;
}
}
}
return defaultValue;
}
}

View File

@@ -28,8 +28,6 @@
<uses-permission android:name="android.permission.SET_TIME" />
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application>
<uses-library android:name="android.test.runner" />

View File

@@ -22,7 +22,6 @@ import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -31,9 +30,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -55,13 +52,6 @@ import java.util.concurrent.TimeUnit;
* 3. Under low storage conditions and package is recently used, check
* that dexopt upgrades test app to $(getprop pm.dexopt.bg-dexopt).
*
* When downgrade feature is on (downgrade_unused_apps_enabled flag is set to true):
* 4 On low storage, check that the inactive packages are downgraded.
* 5. On low storage, check that used packages are upgraded.
* 6. On storage completely full, dexopt fails.
* 7. Not on low storage, unused packages are upgraded.
* 8. Low storage, unused app is downgraded. When app is used again, app is upgraded.
*
* Each test case runs "cmd package bg-dexopt-job com.android.frameworks.bgdexopttest".
*
* The setup for these tests make sure this package has been configured to have been recently used
@@ -69,10 +59,6 @@ import java.util.concurrent.TimeUnit;
* recently used, it sets the time forward more than
* `getprop pm.dexopt.downgrade_after_inactive_days` days.
*
* For some of the tests, the DeviceConfig flags inactive_app_threshold_days and
* downgrade_unused_apps_enabled are set. These turn on/off the downgrade unused apps feature for
* all devices and set the time threshold for unused apps.
*
* For tests that require low storage, the phone is filled up.
*
* Run with "atest BackgroundDexOptServiceIntegrationTests".
@@ -94,14 +80,10 @@ public final class BackgroundDexOptServiceIntegrationTests {
"pm.dexopt.downgrade_after_inactive_days", 0);
// Needs to be between 1.0 and 2.0.
private static final double LOW_STORAGE_MULTIPLIER = 1.5;
private static final int DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS = 15;
// The file used to fill up storage.
private File mBigFile;
@Rule
public ExpectedException mExpectedException = ExpectedException.none();
// Remember start time.
@BeforeClass
public static void setUpAll() {
@@ -214,27 +196,11 @@ public final class BackgroundDexOptServiceIntegrationTests {
logSpaceRemaining();
}
private void fillUpStorageCompletely() throws IOException {
fillUpStorage((getStorageLowBytes()));
}
// Fill up storage so that device is in low storage condition.
private void fillUpToLowStorage() throws IOException {
fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
}
private void setInactivePackageThreshold(int threshold) {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"inactive_app_threshold_days", Integer.toString(threshold), false);
}
private void enableDowngradeFeature(boolean enabled) {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"downgrade_unused_apps_enabled", Boolean.toString(enabled), false);
}
// TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
private static void runBackgroundDexOpt() throws IOException {
String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
@@ -278,7 +244,7 @@ public final class BackgroundDexOptServiceIntegrationTests {
// Test that background dexopt under normal conditions succeeds.
@Test
public void testBackgroundDexOpt_normalConditions_dexOptSucceeds() throws IOException {
public void testBackgroundDexOpt() throws IOException {
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "verify");
Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
@@ -291,16 +257,17 @@ public final class BackgroundDexOptServiceIntegrationTests {
// Test that background dexopt under low storage conditions upgrades used packages.
@Test
public void testBackgroundDexOpt_lowStorage_usedPkgsUpgraded() throws IOException {
public void testBackgroundDexOptDowngradeSkipRecentlyUsedPackage() throws IOException {
// Should be less than DOWNGRADE_AFTER_DAYS.
long deltaDays = DOWNGRADE_AFTER_DAYS - 1;
try {
enableDowngradeFeature(false);
// Set time to future.
setTimeFutureDays(deltaDays);
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "quicken");
Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
@@ -315,20 +282,18 @@ public final class BackgroundDexOptServiceIntegrationTests {
}
// Test that background dexopt under low storage conditions downgrades unused packages.
// This happens if the system property pm.dexopt.downgrade_after_inactive_days is set
// (e.g. on Android Go devices).
@Test
public void testBackgroundDexOpt_lowStorage_unusedPkgsDowngraded()
throws IOException {
public void testBackgroundDexOptDowngradeSuccessful() throws IOException {
// Should be more than DOWNGRADE_AFTER_DAYS.
long deltaDays = DOWNGRADE_AFTER_DAYS + 1;
try {
enableDowngradeFeature(false);
// Set time to future.
setTimeFutureDays(deltaDays);
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "quicken");
Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
@@ -342,134 +307,4 @@ public final class BackgroundDexOptServiceIntegrationTests {
}
}
// Test that the background dexopt downgrades inactive packages when the downgrade feature is
// enabled.
@Test
public void testBackgroundDexOpt_downgradeFeatureEnabled_lowStorage_inactivePkgsDowngraded()
throws IOException {
// Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS.
long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1;
try {
enableDowngradeFeature(true);
setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS);
// Set time to future.
setTimeFutureDays(deltaDays);
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "quicken");
Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
runBackgroundDexOpt();
// Verify that downgrade is successful.
Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
} finally {
// Reset time.
setTimeFutureDays(-deltaDays);
}
}
// Test that the background dexopt upgrades used packages when the downgrade feature is enabled.
// This test doesn't fill the device storage completely, but to a multiplier of the low storage
// threshold and this is why apps can still be optimized.
@Test
public void testBackgroundDexOpt_downgradeFeatureEnabled_lowStorage_usedPkgsUpgraded()
throws IOException {
enableDowngradeFeature(true);
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "quicken");
Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
runBackgroundDexOpt();
/// Verify that bg-dexopt is successful in upgrading the used packages.
Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
}
// Test that the background dexopt fails and doesn't change the compilation filter of used
// packages when the downgrade feature is enabled and the storage is filled up completely.
// The bg-dexopt shouldn't optimise nor downgrade these packages.
@Test
public void testBackgroundDexOpt_downgradeFeatureEnabled_fillUpStorageCompletely_dexOptFails()
throws IOException {
enableDowngradeFeature(true);
String previousCompilerFilter = getCompilerFilter(PACKAGE_NAME);
// Fill up storage completely, without using a multiplier for the low storage threshold.
fillUpStorageCompletely();
// When the bg dexopt runs with the storage filled up completely, it will fail.
mExpectedException.expect(IllegalStateException.class);
runBackgroundDexOpt();
/// Verify that bg-dexopt doesn't change the compilation filter of used apps.
Assert.assertEquals(previousCompilerFilter, getCompilerFilter(PACKAGE_NAME));
}
// Test that the background dexopt upgrades the unused packages when the downgrade feature is
// on if the device is not low on storage.
@Test
public void testBackgroundDexOpt_downgradeFeatureEnabled_notLowStorage_unusedPkgsUpgraded()
throws IOException {
// Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS.
long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1;
try {
enableDowngradeFeature(true);
setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS);
// Set time to future.
setTimeFutureDays(deltaDays);
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "quicken");
Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
runBackgroundDexOpt();
// Verify that bg-dexopt is successful in upgrading the unused packages when the device
// is not low on storage.
Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
} finally {
// Reset time.
setTimeFutureDays(-deltaDays);
}
}
// Test that when an unused package (which was downgraded) is used again, it's re-optimized when
// bg-dexopt runs again.
@Test
public void testBackgroundDexOpt_downgradeFeatureEnabled_downgradedPkgsUpgradedAfterUse()
throws IOException {
// Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS.
long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1;
try {
enableDowngradeFeature(true);
setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS);
// Set time to future.
setTimeFutureDays(deltaDays);
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
// Set filter to quicken.
compilePackageWithFilter(PACKAGE_NAME, "quicken");
Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
runBackgroundDexOpt();
// Verify that downgrade is successful.
Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
// Reset time.
setTimeFutureDays(-deltaDays);
deltaDays = 0;
runBackgroundDexOpt();
// Verify that bg-dexopt is successful in upgrading the unused packages that were used
// again.
Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
} finally {
// Reset time.
setTimeFutureDays(-deltaDays);
}
}
}