BackgroundDexOptService.java revision cb5f41ea11b1a6fcd0977a64ee146dde8f537076
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 { 45a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final String TAG = "BackgroundDexOptService"; 467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 47a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final boolean DEBUG = false; 482c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate 49a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR; 50a50d58e22630cd651a815381639e70476991bdbfCalin Juravle 51a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final int JOB_IDLE_OPTIMIZE = 800; 52a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final int JOB_POST_BOOT_UPDATE = 801; 53a50d58e22630cd651a815381639e70476991bdbfCalin Juravle 54a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG 55a50d58e22630cd651a815381639e70476991bdbfCalin Juravle ? TimeUnit.MINUTES.toMillis(1) 56a50d58e22630cd651a815381639e70476991bdbfCalin Juravle : TimeUnit.DAYS.toMillis(1); 5737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 58cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate private static ComponentName sDexoptServiceName = new ComponentName( 591b8b3aa265190e84467f740e99a0ade3a0e3cd67Christopher Tate "android", 60cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate BackgroundDexOptService.class.getName()); 617395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 62a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom /** 63a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom * Set of failed packages remembered across job runs. 64a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom */ 65a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom static final ArraySet<String> sFailedPackageNames = new ArraySet<String>(); 66a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom 6737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 6837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomics set to true if the JobScheduler requests an abort. 6937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 7037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false); 7137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false); 7237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 7337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 7437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomic set to true if one job should exit early because another job was started. 7537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 7637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); 777395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 78be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private final File mDataDir = Environment.getDataDirectory(); 798735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 80db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle public static void schedule(Context context) { 81cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 8237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 8337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a one-off job which scans installed packages and updates 8437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // out-of-date oat files. 8537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) 8637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setMinimumLatency(TimeUnit.MINUTES.toMillis(1)) 8737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1)) 8837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 8937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 9037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a daily job which scans installed packages and compiles 9137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // those with fresh profiling data. 9237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName) 9337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresDeviceIdle(true) 9437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresCharging(true) 95a50d58e22630cd651a815381639e70476991bdbfCalin Juravle .setPeriodic(IDLE_OPTIMIZATION_PERIOD) 9637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 9737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 9837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 9937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Jobs scheduled"); 10037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 1017395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 1027395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 103ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil public static void notifyPackageChanged(String packageName) { 104ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // The idle maintanance job skips packages which previously failed to 105ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // compile. The given package has changed and may successfully compile 106ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // now. Remove it from the list of known failing packages. 107ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil synchronized (sFailedPackageNames) { 108ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil sFailedPackageNames.remove(packageName); 109ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 110ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 111ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil 11237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Returns the current battery level as a 0-100 integer. 11337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private int getBatteryLevel() { 11437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 11537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Intent intent = registerReceiver(null, filter); 11637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 11737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); 118cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 11937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (level < 0 || scale <= 0) { 12037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Battery data unavailable. This should never happen, so assume the worst. 12137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return 0; 1227395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 12337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 12437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return (100 * level / scale); 12537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 12637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 127c660475aafe91269be306c802823cf543005ce36Calin Juravle private long getLowStorageThreshold(Context context) { 1288735f07a698218d311826a140d08d611d3c23db1Narayan Kamath @SuppressWarnings("deprecation") 129c660475aafe91269be306c802823cf543005ce36Calin Juravle final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir); 1308735f07a698218d311826a140d08d611d3c23db1Narayan Kamath if (lowThreshold == 0) { 1318735f07a698218d311826a140d08d611d3c23db1Narayan Kamath Log.e(TAG, "Invalid low storage threshold"); 1328735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1338735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 1348735f07a698218d311826a140d08d611d3c23db1Narayan Kamath return lowThreshold; 1358735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1368735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 13737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private boolean runPostBootUpdate(final JobParameters jobParams, 13837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final PackageManagerService pm, final ArraySet<String> pkgs) { 13937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (mExitPostBootUpdate.get()) { 14037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // This job has already been superseded. Do not start it. 1417395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom return false; 1427395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 143be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_PostBootUpdate") { 144be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle @Override 145be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle public void run() { 146be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle postBootUpdate(jobParams, pm, pkgs); 147be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 148be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 149be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle }.start(); 150be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return true; 151be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 152cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 153be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private void postBootUpdate(JobParameters jobParams, PackageManagerService pm, 154be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle ArraySet<String> pkgs) { 15537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Load low battery threshold from the system config. This is a 0-100 integer. 15637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final int lowBatteryThreshold = getResources().getInteger( 15737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil com.android.internal.R.integer.config_lowBatteryWarningLevel); 158c660475aafe91269be306c802823cf543005ce36Calin Juravle final long lowThreshold = getLowStorageThreshold(this); 1598735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 16037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(false); 161be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 162be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 163be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mAbortPostBootUpdate.get()) { 164be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // JobScheduler requested an early abort. 165be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return; 166be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 167be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mExitPostBootUpdate.get()) { 168be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Different job, which supersedes this one, is running. 169be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 170be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 171be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (getBatteryLevel() < lowBatteryThreshold) { 172be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely drain the battery. 173be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 174be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 175be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle long usableSpace = mDataDir.getUsableSpace(); 176be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (usableSpace < lowThreshold) { 177be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely fill up the disk. 178be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + 179be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle usableSpace); 180be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 181be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 182be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 183be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (DEBUG_DEXOPT) { 184be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.i(TAG, "Updating package " + pkg); 185be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 186be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 187be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Update package if needed. Note that there can be no race between concurrent 188be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // jobs because PackageDexOptimizer.performDexOpt is synchronized. 189be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 190be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // checkProfiles is false to avoid merging profiles during boot which 191be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // might interfere with background compilation (b/28612421). 192be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will 193be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a 194be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // trade-off worth doing to save boot time work. 195be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle pm.performDexOpt(pkg, 196be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* checkProfiles */ false, 197be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle PackageManagerService.REASON_BOOT, 198be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* force */ false); 199be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 200be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Ran to completion, so we abandon our timeslice and do not reschedule. 201be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle jobFinished(jobParams, /* reschedule */ false); 202be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 203be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 204be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private boolean runIdleOptimization(final JobParameters jobParams, 205be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle final PackageManagerService pm, final ArraySet<String> pkgs) { 206be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_IdleOptimization") { 2077395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom @Override 2087395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom public void run() { 209c660475aafe91269be306c802823cf543005ce36Calin Juravle idleOptimization(pm, pkgs, BackgroundDexOptService.this); 210c660475aafe91269be306c802823cf543005ce36Calin Juravle if (!mAbortIdleOptimization.get()) { 211c660475aafe91269be306c802823cf543005ce36Calin Juravle // If we didn't abort we ran to completion (or stopped because of space). 212c660475aafe91269be306c802823cf543005ce36Calin Juravle // Abandon our timeslice and do not reschedule. 213c660475aafe91269be306c802823cf543005ce36Calin Juravle jobFinished(jobParams, /* reschedule */ false); 214c660475aafe91269be306c802823cf543005ce36Calin Juravle } 21537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 21637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil }.start(); 21737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return true; 21837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 21937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 220c660475aafe91269be306c802823cf543005ce36Calin Juravle // Optimize the given packages and return true if the process was not aborted. 221c660475aafe91269be306c802823cf543005ce36Calin Juravle // The abort can happen either because of job scheduler or because of lack of space. 222c660475aafe91269be306c802823cf543005ce36Calin Juravle private boolean idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, 223c660475aafe91269be306c802823cf543005ce36Calin Juravle Context context) { 224a50d58e22630cd651a815381639e70476991bdbfCalin Juravle Log.i(TAG, "Performing idle optimizations"); 22537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // If post-boot update is still running, request that it exits early. 22637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mExitPostBootUpdate.set(true); 22737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(false); 2288735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 229c660475aafe91269be306c802823cf543005ce36Calin Juravle long lowStorageThreshold = getLowStorageThreshold(context); 230c660475aafe91269be306c802823cf543005ce36Calin Juravle return optimizePackages(pm, pkgs, lowStorageThreshold); 231c660475aafe91269be306c802823cf543005ce36Calin Juravle } 232c660475aafe91269be306c802823cf543005ce36Calin Juravle 233c660475aafe91269be306c802823cf543005ce36Calin Juravle private boolean optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, 234c660475aafe91269be306c802823cf543005ce36Calin Juravle long lowStorageThreshold) { 235be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 236c660475aafe91269be306c802823cf543005ce36Calin Juravle if (abortIdleOptimizations(lowStorageThreshold)) { 237c660475aafe91269be306c802823cf543005ce36Calin Juravle return false; 238be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 2398735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 240be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle synchronized (sFailedPackageNames) { 241be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (sFailedPackageNames.contains(pkg)) { 242be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Skip previously failing package 243be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle continue; 244c660475aafe91269be306c802823cf543005ce36Calin Juravle } else { 245c660475aafe91269be306c802823cf543005ce36Calin Juravle // Conservatively add package to the list of failing ones in case performDexOpt 246c660475aafe91269be306c802823cf543005ce36Calin Juravle // never returns. 247c660475aafe91269be306c802823cf543005ce36Calin Juravle sFailedPackageNames.add(pkg); 2487395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 2497395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 250be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 251be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Optimize package if needed. Note that there can be no race between 252be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized. 253be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (pm.performDexOpt(pkg, 254be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* checkProfiles */ true, 255be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle PackageManagerService.REASON_BACKGROUND_DEXOPT, 256be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* force */ false)) { 257be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Dexopt succeeded, remove package from the list of failing ones. 258be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle synchronized (sFailedPackageNames) { 259be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle sFailedPackageNames.remove(pkg); 260be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 261be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 262be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 263c660475aafe91269be306c802823cf543005ce36Calin Juravle return true; 264c660475aafe91269be306c802823cf543005ce36Calin Juravle } 265c660475aafe91269be306c802823cf543005ce36Calin Juravle 266c660475aafe91269be306c802823cf543005ce36Calin Juravle // Return true if the idle optimizations should be aborted because of a space constraints 267c660475aafe91269be306c802823cf543005ce36Calin Juravle // or because the JobScheduler requested so. 268c660475aafe91269be306c802823cf543005ce36Calin Juravle private boolean abortIdleOptimizations(long lowStorageThreshold) { 269c660475aafe91269be306c802823cf543005ce36Calin Juravle if (mAbortIdleOptimization.get()) { 270c660475aafe91269be306c802823cf543005ce36Calin Juravle // JobScheduler requested an early abort. 271c660475aafe91269be306c802823cf543005ce36Calin Juravle return true; 272c660475aafe91269be306c802823cf543005ce36Calin Juravle } 273c660475aafe91269be306c802823cf543005ce36Calin Juravle long usableSpace = mDataDir.getUsableSpace(); 274c660475aafe91269be306c802823cf543005ce36Calin Juravle if (usableSpace < lowStorageThreshold) { 275c660475aafe91269be306c802823cf543005ce36Calin Juravle // Rather bail than completely fill up the disk. 276c660475aafe91269be306c802823cf543005ce36Calin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace); 277c660475aafe91269be306c802823cf543005ce36Calin Juravle return true; 278c660475aafe91269be306c802823cf543005ce36Calin Juravle } 279c660475aafe91269be306c802823cf543005ce36Calin Juravle 280c660475aafe91269be306c802823cf543005ce36Calin Juravle return false; 2817395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 2827395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 283cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle /** 284cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle * Execute the idle optimizations immediately. 285cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle */ 286cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle public static boolean runIdleOptimizationsNow(PackageManagerService pm, Context context) { 287cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // Create a new object to make sure we don't interfere with the scheduled jobs. 288cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // Note that this may still run at the same time with the job scheduled by the 289cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // JobScheduler but the scheduler will not be able to cancel it. 290cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle BackgroundDexOptService bdos = new BackgroundDexOptService(); 291cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle return bdos.idleOptimization(pm, pm.getOptimizablePackages(), context); 292cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle } 293cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle 294cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate @Override 29537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil public boolean onStartJob(JobParameters params) { 29637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 29737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStartJob"); 29837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 29937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 3008735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from 3018735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // the checks above. This check is not "live" - the value is determined by a background 3028735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // restart with a period of ~1 minute. 30337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); 30437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (pm.isStorageLow()) { 30537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 30637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Low storage, skipping this run"); 30737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 30837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 30937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 31037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 31137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final ArraySet<String> pkgs = pm.getOptimizablePackages(); 312c660475aafe91269be306c802823cf543005ce36Calin Juravle if (pkgs.isEmpty()) { 31337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 31437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "No packages to optimize"); 31537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 31637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 31737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 31837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 31937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 32037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return runPostBootUpdate(params, pm, pkgs); 32137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 32237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return runIdleOptimization(params, pm, pkgs); 32337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 32437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 32537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 32637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil @Override 327cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate public boolean onStopJob(JobParameters params) { 32837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 32937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStopJob"); 33037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 33137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 33237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 33337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(true); 33437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 33537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(true); 33637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 337cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate return false; 3387395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 3397395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom} 340