Merge changes I87740397,I0cc4538b,Iaceb2b7c
* changes: Wait for BOOT_COMPLETE event before scheduling the bootDexoptJob Use BatteryManagerInternal to determine low battery. BackgroundDexOptService: defer post-boot job further
This commit is contained in:
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.server.pm;
|
package com.android.server.pm;
|
||||||
|
|
||||||
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
|
|
||||||
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
|
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -24,12 +23,13 @@ import android.app.job.JobInfo;
|
|||||||
import android.app.job.JobParameters;
|
import android.app.job.JobParameters;
|
||||||
import android.app.job.JobScheduler;
|
import android.app.job.JobScheduler;
|
||||||
import android.app.job.JobService;
|
import android.app.job.JobService;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManagerInternal;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
@@ -37,6 +37,7 @@ import android.os.UserHandle;
|
|||||||
import android.os.storage.StorageManager;
|
import android.os.storage.StorageManager;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.internal.util.FrameworkStatsLog;
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
@@ -65,9 +66,7 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
private static final int JOB_IDLE_OPTIMIZE = 800;
|
private static final int JOB_IDLE_OPTIMIZE = 800;
|
||||||
private static final int JOB_POST_BOOT_UPDATE = 801;
|
private static final int JOB_POST_BOOT_UPDATE = 801;
|
||||||
|
|
||||||
private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
|
private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1);
|
||||||
? TimeUnit.MINUTES.toMillis(1)
|
|
||||||
: TimeUnit.DAYS.toMillis(1);
|
|
||||||
|
|
||||||
private static ComponentName sDexoptServiceName = new ComponentName(
|
private static ComponentName sDexoptServiceName = new ComponentName(
|
||||||
"android",
|
"android",
|
||||||
@@ -115,14 +114,24 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
final JobScheduler js = context.getSystemService(JobScheduler.class);
|
||||||
|
|
||||||
// Schedule a one-off job which scans installed packages and updates
|
// Schedule a one-off job which scans installed packages and updates
|
||||||
// out-of-date oat files.
|
// out-of-date oat files. Schedule it 10 minutes after the boot complete event,
|
||||||
js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
|
// so that we don't overload the boot with additional dex2oat compilations.
|
||||||
.setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
|
context.registerReceiver(new BroadcastReceiver() {
|
||||||
.setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
|
@Override
|
||||||
.build());
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
|
||||||
|
.setMinimumLatency(TimeUnit.MINUTES.toMillis(10))
|
||||||
|
.setOverrideDeadline(TimeUnit.MINUTES.toMillis(60))
|
||||||
|
.build());
|
||||||
|
context.unregisterReceiver(this);
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.i(TAG, "BootBgDexopt scheduled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
|
||||||
|
|
||||||
// Schedule a daily job which scans installed packages and compiles
|
// Schedule a daily job which scans installed packages and compiles
|
||||||
// those with fresh profiling data.
|
// those with fresh profiling data.
|
||||||
@@ -132,8 +141,8 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
.setPeriodic(IDLE_OPTIMIZATION_PERIOD)
|
.setPeriodic(IDLE_OPTIMIZATION_PERIOD)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
if (DEBUG_DEXOPT) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "Jobs scheduled");
|
Slog.d(TAG, "BgDexopt scheduled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,32 +158,11 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the current battery level as a 0-100 integer.
|
|
||||||
private int getBatteryLevel() {
|
|
||||||
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
|
||||||
Intent intent = registerReceiver(null, filter);
|
|
||||||
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
|
||||||
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
|
||||||
boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
|
|
||||||
|
|
||||||
if (!present) {
|
|
||||||
// No battery, treat as if 100%, no possibility of draining battery.
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level < 0 || scale <= 0) {
|
|
||||||
// Battery data unavailable. This should never happen, so assume the worst.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (100 * level / scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getLowStorageThreshold(Context context) {
|
private long getLowStorageThreshold(Context context) {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir);
|
final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir);
|
||||||
if (lowThreshold == 0) {
|
if (lowThreshold == 0) {
|
||||||
Log.e(TAG, "Invalid low storage threshold");
|
Slog.e(TAG, "Invalid low storage threshold");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lowThreshold;
|
return lowThreshold;
|
||||||
@@ -198,9 +186,8 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
|
|
||||||
private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
|
private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
|
||||||
ArraySet<String> pkgs) {
|
ArraySet<String> pkgs) {
|
||||||
// Load low battery threshold from the system config. This is a 0-100 integer.
|
final BatteryManagerInternal batteryManagerInternal =
|
||||||
final int lowBatteryThreshold = getResources().getInteger(
|
LocalServices.getService(BatteryManagerInternal.class);
|
||||||
com.android.internal.R.integer.config_lowBatteryWarningLevel);
|
|
||||||
final long lowThreshold = getLowStorageThreshold(this);
|
final long lowThreshold = getLowStorageThreshold(this);
|
||||||
|
|
||||||
mAbortPostBootUpdate.set(false);
|
mAbortPostBootUpdate.set(false);
|
||||||
@@ -215,20 +202,19 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
// Different job, which supersedes this one, is running.
|
// Different job, which supersedes this one, is running.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (getBatteryLevel() < lowBatteryThreshold) {
|
if (batteryManagerInternal.getBatteryLevelLow()) {
|
||||||
// Rather bail than completely drain the battery.
|
// Rather bail than completely drain the battery.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
long usableSpace = mDataDir.getUsableSpace();
|
long usableSpace = mDataDir.getUsableSpace();
|
||||||
if (usableSpace < lowThreshold) {
|
if (usableSpace < lowThreshold) {
|
||||||
// Rather bail than completely fill up the disk.
|
// Rather bail than completely fill up the disk.
|
||||||
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
|
Slog.w(TAG, "Aborting background dex opt job due to low storage: " +
|
||||||
usableSpace);
|
usableSpace);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (DEBUG) {
|
||||||
if (DEBUG_DEXOPT) {
|
Slog.i(TAG, "Updating package " + pkg);
|
||||||
Log.i(TAG, "Updating package " + pkg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update package if needed. Note that there can be no race between concurrent
|
// Update package if needed. Note that there can be no race between concurrent
|
||||||
@@ -260,13 +246,13 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
public void run() {
|
public void run() {
|
||||||
int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
|
int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
|
||||||
if (result == OPTIMIZE_PROCESSED) {
|
if (result == OPTIMIZE_PROCESSED) {
|
||||||
Log.i(TAG, "Idle optimizations completed.");
|
Slog.i(TAG, "Idle optimizations completed.");
|
||||||
} else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
|
} else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
|
||||||
Log.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) {
|
||||||
Log.w(TAG, "Idle optimizations aborted by job scheduler.");
|
Slog.w(TAG, "Idle optimizations aborted by job scheduler.");
|
||||||
} else {
|
} else {
|
||||||
Log.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_BY_JOB_SCHEDULER) {
|
||||||
// Abandon our timeslice and do not reschedule.
|
// Abandon our timeslice and do not reschedule.
|
||||||
@@ -280,7 +266,7 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
// Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
|
// Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
|
||||||
private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
|
private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
|
||||||
Context context) {
|
Context context) {
|
||||||
Log.i(TAG, "Performing idle optimizations");
|
Slog.i(TAG, "Performing idle optimizations");
|
||||||
// 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);
|
||||||
@@ -355,11 +341,15 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
|
final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
|
||||||
* lowStorageThreshold;
|
* lowStorageThreshold;
|
||||||
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
|
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
|
||||||
Log.d(TAG, "Should Downgrade " + shouldDowngrade);
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
|
||||||
|
}
|
||||||
if (shouldDowngrade) {
|
if (shouldDowngrade) {
|
||||||
Set<String> unusedPackages =
|
Set<String> unusedPackages =
|
||||||
pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
|
pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
|
||||||
Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
|
||||||
|
}
|
||||||
|
|
||||||
if (!unusedPackages.isEmpty()) {
|
if (!unusedPackages.isEmpty()) {
|
||||||
for (String pkg : unusedPackages) {
|
for (String pkg : unusedPackages) {
|
||||||
@@ -431,7 +421,9 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
*/
|
*/
|
||||||
private boolean downgradePackage(PackageManagerService pm, String pkg,
|
private boolean downgradePackage(PackageManagerService pm, String pkg,
|
||||||
boolean isForPrimaryDex) {
|
boolean isForPrimaryDex) {
|
||||||
Log.d(TAG, "Downgrading " + pkg);
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Downgrading " + pkg);
|
||||||
|
}
|
||||||
boolean dex_opt_performed = false;
|
boolean dex_opt_performed = false;
|
||||||
int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
|
int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
|
||||||
int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
|
int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
|
||||||
@@ -553,7 +545,7 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
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.
|
||||||
Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
|
Slog.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
|
||||||
return OPTIMIZE_ABORT_NO_SPACE_LEFT;
|
return OPTIMIZE_ABORT_NO_SPACE_LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,8 +584,8 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(JobParameters params) {
|
public boolean onStartJob(JobParameters params) {
|
||||||
if (DEBUG_DEXOPT) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "onStartJob");
|
Slog.i(TAG, "onStartJob");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
|
// NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
|
||||||
@@ -601,17 +593,13 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
// restart with a period of ~1 minute.
|
// restart with a period of ~1 minute.
|
||||||
PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
|
PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
|
||||||
if (pm.isStorageLow()) {
|
if (pm.isStorageLow()) {
|
||||||
if (DEBUG_DEXOPT) {
|
Slog.i(TAG, "Low storage, skipping this run");
|
||||||
Log.i(TAG, "Low storage, skipping this run");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArraySet<String> pkgs = pm.getOptimizablePackages();
|
final ArraySet<String> pkgs = pm.getOptimizablePackages();
|
||||||
if (pkgs.isEmpty()) {
|
if (pkgs.isEmpty()) {
|
||||||
if (DEBUG_DEXOPT) {
|
Slog.i(TAG, "No packages to optimize");
|
||||||
Log.i(TAG, "No packages to optimize");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,8 +615,8 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStopJob(JobParameters params) {
|
public boolean onStopJob(JobParameters params) {
|
||||||
if (DEBUG_DEXOPT) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "onStopJob");
|
Slog.d(TAG, "onStopJob");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
|
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
|
||||||
@@ -649,7 +637,7 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
private void notifyPinService(ArraySet<String> updatedPackages) {
|
private void notifyPinService(ArraySet<String> updatedPackages) {
|
||||||
PinnerService pinnerService = LocalServices.getService(PinnerService.class);
|
PinnerService pinnerService = LocalServices.getService(PinnerService.class);
|
||||||
if (pinnerService != null) {
|
if (pinnerService != null) {
|
||||||
Log.i(TAG, "Pinning optimized code " + updatedPackages);
|
Slog.i(TAG, "Pinning optimized code " + updatedPackages);
|
||||||
pinnerService.update(updatedPackages, false /* force */);
|
pinnerService.update(updatedPackages, false /* force */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -684,7 +672,7 @@ public class BackgroundDexOptService extends JobService {
|
|||||||
final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
|
final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
|
||||||
String sysPropValue = SystemProperties.get(sysPropKey);
|
String sysPropValue = SystemProperties.get(sysPropKey);
|
||||||
if (sysPropValue == null || sysPropValue.isEmpty()) {
|
if (sysPropValue == null || sysPropValue.isEmpty()) {
|
||||||
Log.w(TAG, "SysProp " + sysPropKey + " not set");
|
Slog.w(TAG, "SysProp " + sysPropKey + " not set");
|
||||||
return Long.MAX_VALUE;
|
return Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
|
return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
|
||||||
|
|||||||
Reference in New Issue
Block a user