Set pm.BackgroundDexOptService as the source of true
The real dexopt maintainance job is
com.android.server.pm.BackgroundDexOptService, and not
com.android.server.BackgroundDexOptJobService
Partial revert of commit 096d304ae3.
Test: manual inspection
Bug: 36140426
Change-Id: I983ac91117f107282095fa7eefdbce08e0dcfce3
This commit is contained in:
@@ -3593,7 +3593,7 @@
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" >
|
||||
</service>
|
||||
|
||||
<service android:name="com.android.server.BackgroundDexOptJobService"
|
||||
<service android:name="com.android.server.pm.BackgroundDexOptService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE">
|
||||
</service>
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
|
||||
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.app.job.JobService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Environment;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import com.android.server.pm.PackageManagerService;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BackgroundDexOptJobService extends JobService {
|
||||
private static final String TAG = "BackgroundDexOptJobService";
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int JOB_IDLE_OPTIMIZE = 800;
|
||||
private static final int JOB_POST_BOOT_UPDATE = 801;
|
||||
|
||||
private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
|
||||
? TimeUnit.MINUTES.toMillis(1)
|
||||
: TimeUnit.DAYS.toMillis(1);
|
||||
|
||||
private static ComponentName sDexoptServiceName = new ComponentName(
|
||||
"android",
|
||||
BackgroundDexOptJobService.class.getName());
|
||||
|
||||
/**
|
||||
* Set of failed packages remembered across job runs.
|
||||
*/
|
||||
static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
|
||||
|
||||
/**
|
||||
* Atomics set to true if the JobScheduler requests an abort.
|
||||
*/
|
||||
final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
|
||||
final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Atomic set to true if one job should exit early because another job was started.
|
||||
*/
|
||||
final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
|
||||
|
||||
private final File mDataDir = Environment.getDataDirectory();
|
||||
|
||||
public static void schedule(Context context) {
|
||||
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
|
||||
// Schedule a one-off job which scans installed packages and updates
|
||||
// out-of-date oat files.
|
||||
js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
|
||||
.setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
|
||||
.setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
|
||||
.build());
|
||||
|
||||
// Schedule a daily job which scans installed packages and compiles
|
||||
// those with fresh profiling data.
|
||||
js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName)
|
||||
.setRequiresDeviceIdle(true)
|
||||
.setRequiresCharging(true)
|
||||
.setPeriodic(IDLE_OPTIMIZATION_PERIOD)
|
||||
.build());
|
||||
|
||||
if (DEBUG_DEXOPT) {
|
||||
Log.i(TAG, "Jobs scheduled");
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyPackageChanged(String packageName) {
|
||||
// The idle maintanance job skips packages which previously failed to
|
||||
// compile. The given package has changed and may successfully compile
|
||||
// now. Remove it from the list of known failing packages.
|
||||
synchronized (sFailedPackageNames) {
|
||||
sFailedPackageNames.remove(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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() {
|
||||
@SuppressWarnings("deprecation")
|
||||
final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
|
||||
if (lowThreshold == 0) {
|
||||
Log.e(TAG, "Invalid low storage threshold");
|
||||
}
|
||||
|
||||
return lowThreshold;
|
||||
}
|
||||
|
||||
private boolean runPostBootUpdate(final JobParameters jobParams,
|
||||
final PackageManagerService pm, final ArraySet<String> pkgs) {
|
||||
if (mExitPostBootUpdate.get()) {
|
||||
// This job has already been superseded. Do not start it.
|
||||
return false;
|
||||
}
|
||||
new Thread("BackgroundDexOptService_PostBootUpdate") {
|
||||
@Override
|
||||
public void run() {
|
||||
postBootUpdate(jobParams, pm, pkgs);
|
||||
}
|
||||
|
||||
}.start();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
|
||||
ArraySet<String> pkgs) {
|
||||
// Load low battery threshold from the system config. This is a 0-100 integer.
|
||||
final int lowBatteryThreshold = getResources().getInteger(
|
||||
com.android.internal.R.integer.config_lowBatteryWarningLevel);
|
||||
final long lowThreshold = getLowStorageThreshold();
|
||||
|
||||
mAbortPostBootUpdate.set(false);
|
||||
|
||||
for (String pkg : pkgs) {
|
||||
if (mAbortPostBootUpdate.get()) {
|
||||
// JobScheduler requested an early abort.
|
||||
return;
|
||||
}
|
||||
if (mExitPostBootUpdate.get()) {
|
||||
// Different job, which supersedes this one, is running.
|
||||
break;
|
||||
}
|
||||
if (getBatteryLevel() < lowBatteryThreshold) {
|
||||
// Rather bail than completely drain the battery.
|
||||
break;
|
||||
}
|
||||
long usableSpace = mDataDir.getUsableSpace();
|
||||
if (usableSpace < lowThreshold) {
|
||||
// Rather bail than completely fill up the disk.
|
||||
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
|
||||
usableSpace);
|
||||
break;
|
||||
}
|
||||
|
||||
if (DEBUG_DEXOPT) {
|
||||
Log.i(TAG, "Updating package " + pkg);
|
||||
}
|
||||
|
||||
// Update package if needed. Note that there can be no race between concurrent
|
||||
// jobs because PackageDexOptimizer.performDexOpt is synchronized.
|
||||
|
||||
// checkProfiles is false to avoid merging profiles during boot which
|
||||
// might interfere with background compilation (b/28612421).
|
||||
// Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
|
||||
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
|
||||
// trade-off worth doing to save boot time work.
|
||||
pm.performDexOpt(pkg,
|
||||
/* checkProfiles */ false,
|
||||
PackageManagerService.REASON_BOOT,
|
||||
/* force */ false);
|
||||
}
|
||||
// Ran to completion, so we abandon our timeslice and do not reschedule.
|
||||
jobFinished(jobParams, /* reschedule */ false);
|
||||
}
|
||||
|
||||
private boolean runIdleOptimization(final JobParameters jobParams,
|
||||
final PackageManagerService pm, final ArraySet<String> pkgs) {
|
||||
new Thread("BackgroundDexOptService_IdleOptimization") {
|
||||
@Override
|
||||
public void run() {
|
||||
idleOptimization(jobParams, pm, pkgs);
|
||||
}
|
||||
}.start();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
|
||||
ArraySet<String> pkgs) {
|
||||
Log.i(TAG, "Performing idle optimizations");
|
||||
// If post-boot update is still running, request that it exits early.
|
||||
mExitPostBootUpdate.set(true);
|
||||
|
||||
mAbortIdleOptimization.set(false);
|
||||
|
||||
final long lowThreshold = getLowStorageThreshold();
|
||||
for (String pkg : pkgs) {
|
||||
if (mAbortIdleOptimization.get()) {
|
||||
// JobScheduler requested an early abort.
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (sFailedPackageNames) {
|
||||
if (sFailedPackageNames.contains(pkg)) {
|
||||
// Skip previously failing package
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
long usableSpace = mDataDir.getUsableSpace();
|
||||
if (usableSpace < lowThreshold) {
|
||||
// Rather bail than completely fill up the disk.
|
||||
Log.w(TAG, "Aborting background dex opt job due to low storage: " +
|
||||
usableSpace);
|
||||
break;
|
||||
}
|
||||
|
||||
// Conservatively add package to the list of failing ones in case performDexOpt
|
||||
// never returns.
|
||||
synchronized (sFailedPackageNames) {
|
||||
sFailedPackageNames.add(pkg);
|
||||
}
|
||||
// Optimize package if needed. Note that there can be no race between
|
||||
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
|
||||
if (pm.performDexOpt(pkg,
|
||||
/* checkProfiles */ true,
|
||||
PackageManagerService.REASON_BACKGROUND_DEXOPT,
|
||||
/* force */ false)) {
|
||||
// Dexopt succeeded, remove package from the list of failing ones.
|
||||
synchronized (sFailedPackageNames) {
|
||||
sFailedPackageNames.remove(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ran to completion, so we abandon our timeslice and do not reschedule.
|
||||
jobFinished(jobParams, /* reschedule */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStartJob(JobParameters params) {
|
||||
if (DEBUG_DEXOPT) {
|
||||
Log.i(TAG, "onStartJob");
|
||||
}
|
||||
|
||||
// NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
|
||||
// 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 == null || pkgs.isEmpty()) {
|
||||
if (DEBUG_DEXOPT) {
|
||||
Log.i(TAG, "No packages to optimize");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
|
||||
return runPostBootUpdate(params, pm, pkgs);
|
||||
} else {
|
||||
return runIdleOptimization(params, pm, pkgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStopJob(JobParameters params) {
|
||||
if (DEBUG_DEXOPT) {
|
||||
Log.i(TAG, "onStopJob");
|
||||
}
|
||||
|
||||
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
|
||||
mAbortPostBootUpdate.set(true);
|
||||
} else {
|
||||
mAbortIdleOptimization.set(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,6 @@ public class BackgroundDexOptService extends JobService {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
|
||||
|
||||
private static final int JOB_IDLE_OPTIMIZE = 800;
|
||||
private static final int JOB_POST_BOOT_UPDATE = 801;
|
||||
|
||||
|
||||
@@ -260,7 +260,6 @@ import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.server.AttributeCache;
|
||||
import com.android.server.BackgroundDexOptJobService;
|
||||
import com.android.server.DeviceIdleController;
|
||||
import com.android.server.EventLogTags;
|
||||
import com.android.server.FgThread;
|
||||
@@ -272,6 +271,7 @@ import com.android.server.SystemConfig;
|
||||
import com.android.server.SystemServerInitThreadPool;
|
||||
import com.android.server.Watchdog;
|
||||
import com.android.server.net.NetworkPolicyManagerInternal;
|
||||
import com.android.server.pm.BackgroundDexOptService;
|
||||
import com.android.server.pm.Installer.InstallerException;
|
||||
import com.android.server.pm.PermissionsState.PermissionState;
|
||||
import com.android.server.pm.Settings.DatabaseVersion;
|
||||
@@ -16850,11 +16850,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
mDexManager.isUsedByOtherApps(pkg.packageName));
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
|
||||
// Notify BackgroundDexOptJobService that the package has been changed.
|
||||
// Notify BackgroundDexOptService that the package has been changed.
|
||||
// If this is an update of a package which used to fail to compile,
|
||||
// BDOS will remove it from its blacklist.
|
||||
// TODO: Layering violation
|
||||
BackgroundDexOptJobService.notifyPackageChanged(pkg.packageName);
|
||||
BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
|
||||
}
|
||||
|
||||
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
|
||||
|
||||
@@ -86,6 +86,7 @@ import com.android.server.notification.NotificationManagerService;
|
||||
import com.android.server.om.OverlayManagerService;
|
||||
import com.android.server.os.DeviceIdentifiersPolicyService;
|
||||
import com.android.server.os.SchedulingPolicyService;
|
||||
import com.android.server.pm.BackgroundDexOptService;
|
||||
import com.android.server.pm.Installer;
|
||||
import com.android.server.pm.LauncherAppsService;
|
||||
import com.android.server.pm.OtaDexoptService;
|
||||
@@ -1428,11 +1429,11 @@ public final class SystemServer {
|
||||
traceEnd();
|
||||
}
|
||||
|
||||
traceBeginAndSlog("StartBackgroundDexOptJobService");
|
||||
traceBeginAndSlog("StartBackgroundDexOptService");
|
||||
try {
|
||||
BackgroundDexOptJobService.schedule(context);
|
||||
BackgroundDexOptService.schedule(context);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting StartBackgroundDexOptJobService", e);
|
||||
reportWtf("starting StartBackgroundDexOptService", e);
|
||||
}
|
||||
traceEnd();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user