BackgroundDexOptService.java revision be6a71a0b3f369843a26c91dd5123d0499f00e7e
17395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom/* 27395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * Copyright (C) 2014 The Android Open Source Project 37395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * 47395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 57395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * you may not use this file except in compliance with the License. 67395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * You may obtain a copy of the License at 77395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * 87395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 97395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * 107395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * Unless required by applicable law or agreed to in writing, software 117395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 127395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * See the License for the specific language governing permissions and 147395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * limitations under the License. 157395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom */ 167395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 177395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrompackage com.android.server.pm; 187395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 1937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; 2037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 212c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tateimport android.app.AlarmManager; 22cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobInfo; 23cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobParameters; 24cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobScheduler; 25cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobService; 26cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.content.ComponentName; 277395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.content.Context; 2837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport android.content.Intent; 2937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport android.content.IntentFilter; 3037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport android.os.BatteryManager; 318735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport android.os.Environment; 327395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.os.ServiceManager; 338735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport android.os.storage.StorageManager; 349f837a99d48c5bb8ad7fbc133943e5bf622ce065Jeff Sharkeyimport android.util.ArraySet; 357395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.util.Log; 367395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 378735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport java.io.File; 387395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport java.util.concurrent.atomic.AtomicBoolean; 3927c073796978106746e4a51f2100b29068ab37f6Nicolas Geoffrayimport java.util.concurrent.TimeUnit; 407395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 417395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom/** 427395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * {@hide} 437395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom */ 44cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tatepublic class BackgroundDexOptService extends JobService { 457395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom static final String TAG = "BackgroundDexOptService"; 467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 472c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR; 482c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate 4937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil static final int JOB_IDLE_OPTIMIZE = 800; 5037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil static final int JOB_POST_BOOT_UPDATE = 801; 5137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 52cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate private static ComponentName sDexoptServiceName = new ComponentName( 531b8b3aa265190e84467f740e99a0ade3a0e3cd67Christopher Tate "android", 54cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate BackgroundDexOptService.class.getName()); 557395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 56a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom /** 57a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom * Set of failed packages remembered across job runs. 58a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom */ 59a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom static final ArraySet<String> sFailedPackageNames = new ArraySet<String>(); 60a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom 6137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 6237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomics set to true if the JobScheduler requests an abort. 6337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 6437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false); 6537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false); 6637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 6737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 6837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomic set to true if one job should exit early because another job was started. 6937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 7037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); 717395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 72be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private final File mDataDir = Environment.getDataDirectory(); 738735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 74db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle public static void schedule(Context context) { 75cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 7637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 7737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a one-off job which scans installed packages and updates 7837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // out-of-date oat files. 7937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) 8037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setMinimumLatency(TimeUnit.MINUTES.toMillis(1)) 8137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1)) 8237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 8337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 8437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a daily job which scans installed packages and compiles 8537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // those with fresh profiling data. 8637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName) 8737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresDeviceIdle(true) 8837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresCharging(true) 8937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setPeriodic(TimeUnit.DAYS.toMillis(1)) 9037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 9137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 9237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 9337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Jobs scheduled"); 9437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 957395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 967395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 97ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil public static void notifyPackageChanged(String packageName) { 98ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // The idle maintanance job skips packages which previously failed to 99ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // compile. The given package has changed and may successfully compile 100ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // now. Remove it from the list of known failing packages. 101ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil synchronized (sFailedPackageNames) { 102ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil sFailedPackageNames.remove(packageName); 103ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 104ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 105ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil 10637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Returns the current battery level as a 0-100 integer. 10737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private int getBatteryLevel() { 10837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 10937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Intent intent = registerReceiver(null, filter); 11037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 11137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); 112cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 11337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (level < 0 || scale <= 0) { 11437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Battery data unavailable. This should never happen, so assume the worst. 11537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return 0; 1167395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 11737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 11837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return (100 * level / scale); 11937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 12037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 1218735f07a698218d311826a140d08d611d3c23db1Narayan Kamath private long getLowStorageThreshold() { 1228735f07a698218d311826a140d08d611d3c23db1Narayan Kamath @SuppressWarnings("deprecation") 123be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir); 1248735f07a698218d311826a140d08d611d3c23db1Narayan Kamath if (lowThreshold == 0) { 1258735f07a698218d311826a140d08d611d3c23db1Narayan Kamath Log.e(TAG, "Invalid low storage threshold"); 1268735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1278735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 1288735f07a698218d311826a140d08d611d3c23db1Narayan Kamath return lowThreshold; 1298735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1308735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 13137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private boolean runPostBootUpdate(final JobParameters jobParams, 13237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final PackageManagerService pm, final ArraySet<String> pkgs) { 13337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (mExitPostBootUpdate.get()) { 13437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // This job has already been superseded. Do not start it. 1357395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom return false; 1367395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 137be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_PostBootUpdate") { 138be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle @Override 139be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle public void run() { 140be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle postBootUpdate(jobParams, pm, pkgs); 141be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 142be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 143be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle }.start(); 144be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return true; 145be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 146cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 147be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private void postBootUpdate(JobParameters jobParams, PackageManagerService pm, 148be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle ArraySet<String> pkgs) { 14937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Load low battery threshold from the system config. This is a 0-100 integer. 15037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final int lowBatteryThreshold = getResources().getInteger( 15137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil com.android.internal.R.integer.config_lowBatteryWarningLevel); 1528735f07a698218d311826a140d08d611d3c23db1Narayan Kamath final long lowThreshold = getLowStorageThreshold(); 1538735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 15437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(false); 155be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 156be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 157be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mAbortPostBootUpdate.get()) { 158be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // JobScheduler requested an early abort. 159be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return; 160be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 161be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mExitPostBootUpdate.get()) { 162be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Different job, which supersedes this one, is running. 163be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 164be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 165be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (getBatteryLevel() < lowBatteryThreshold) { 166be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely drain the battery. 167be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 168be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 169be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle long usableSpace = mDataDir.getUsableSpace(); 170be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (usableSpace < lowThreshold) { 171be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely fill up the disk. 172be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + 173be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle usableSpace); 174be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 175be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 176be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 177be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (DEBUG_DEXOPT) { 178be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.i(TAG, "Updating package " + pkg); 179be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 180be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 181be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Update package if needed. Note that there can be no race between concurrent 182be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // jobs because PackageDexOptimizer.performDexOpt is synchronized. 183be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 184be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // checkProfiles is false to avoid merging profiles during boot which 185be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // might interfere with background compilation (b/28612421). 186be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will 187be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a 188be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // trade-off worth doing to save boot time work. 189be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle pm.performDexOpt(pkg, 190be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* checkProfiles */ false, 191be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle PackageManagerService.REASON_BOOT, 192be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* force */ false); 193be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 194be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Ran to completion, so we abandon our timeslice and do not reschedule. 195be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle jobFinished(jobParams, /* reschedule */ false); 196be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 197be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 198be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private boolean runIdleOptimization(final JobParameters jobParams, 199be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle final PackageManagerService pm, final ArraySet<String> pkgs) { 200be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_IdleOptimization") { 2017395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom @Override 2027395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom public void run() { 203be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle idleOptimization(jobParams, pm, pkgs); 20437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 20537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil }.start(); 20637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return true; 20737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 20837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 209be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private void idleOptimization(JobParameters jobParams, PackageManagerService pm, 210be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle ArraySet<String> pkgs) { 21137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // If post-boot update is still running, request that it exits early. 21237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mExitPostBootUpdate.set(true); 21337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 21437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(false); 2158735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 2168735f07a698218d311826a140d08d611d3c23db1Narayan Kamath final long lowThreshold = getLowStorageThreshold(); 217be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 218be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mAbortIdleOptimization.get()) { 219be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // JobScheduler requested an early abort. 220be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return; 221be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 2228735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 223be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle synchronized (sFailedPackageNames) { 224be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (sFailedPackageNames.contains(pkg)) { 225be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Skip previously failing package 226be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle continue; 2277395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 2287395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 229be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 230be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle long usableSpace = mDataDir.getUsableSpace(); 231be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (usableSpace < lowThreshold) { 232be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely fill up the disk. 233be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + 234be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle usableSpace); 235be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 236be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 237be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 238be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Conservatively add package to the list of failing ones in case performDexOpt 239be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // never returns. 240be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle synchronized (sFailedPackageNames) { 241be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle sFailedPackageNames.add(pkg); 242be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 243be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Optimize package if needed. Note that there can be no race between 244be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized. 245be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (pm.performDexOpt(pkg, 246be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* checkProfiles */ true, 247be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle PackageManagerService.REASON_BACKGROUND_DEXOPT, 248be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* force */ false)) { 249be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Dexopt succeeded, remove package from the list of failing ones. 250be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle synchronized (sFailedPackageNames) { 251be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle sFailedPackageNames.remove(pkg); 252be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 253be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 254be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 255be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Ran to completion, so we abandon our timeslice and do not reschedule. 256be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle jobFinished(jobParams, /* reschedule */ false); 2577395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 2587395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 259cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate @Override 26037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil public boolean onStartJob(JobParameters params) { 26137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 26237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStartJob"); 26337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 26437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 2658735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from 2668735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // the checks above. This check is not "live" - the value is determined by a background 2678735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // restart with a period of ~1 minute. 26837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); 26937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (pm.isStorageLow()) { 27037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 27137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Low storage, skipping this run"); 27237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 27337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 27437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 27537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 27637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final ArraySet<String> pkgs = pm.getOptimizablePackages(); 27737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (pkgs == null || pkgs.isEmpty()) { 27837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 27937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "No packages to optimize"); 28037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 28137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 28237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 28337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 28437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 28537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return runPostBootUpdate(params, pm, pkgs); 28637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 28737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return runIdleOptimization(params, pm, pkgs); 28837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 28937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 29037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 29137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil @Override 292cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate public boolean onStopJob(JobParameters params) { 29337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 29437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStopJob"); 29537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 29637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 29737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 29837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(true); 29937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 30037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(true); 30137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 302cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate return false; 3037395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 3047395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom} 305