BackgroundDexOptService.java revision f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7
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; 3351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravleimport android.os.SystemProperties; 348735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport android.os.storage.StorageManager; 359f837a99d48c5bb8ad7fbc133943e5bf622ce065Jeff Sharkeyimport android.util.ArraySet; 367395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.util.Log; 377395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 3851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravleimport com.android.server.pm.dex.DexManager; 39f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jacksonimport com.android.server.LocalServices; 40f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jacksonimport com.android.server.PinnerService; 4151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 428735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport java.io.File; 437395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport java.util.concurrent.atomic.AtomicBoolean; 4427c073796978106746e4a51f2100b29068ab37f6Nicolas Geoffrayimport java.util.concurrent.TimeUnit; 457395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom/** 477395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * {@hide} 487395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom */ 49cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tatepublic class BackgroundDexOptService extends JobService { 50a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final String TAG = "BackgroundDexOptService"; 517395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 52a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final boolean DEBUG = false; 532c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate 54a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final int JOB_IDLE_OPTIMIZE = 800; 55a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final int JOB_POST_BOOT_UPDATE = 801; 56a50d58e22630cd651a815381639e70476991bdbfCalin Juravle 57a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG 58a50d58e22630cd651a815381639e70476991bdbfCalin Juravle ? TimeUnit.MINUTES.toMillis(1) 59a50d58e22630cd651a815381639e70476991bdbfCalin Juravle : TimeUnit.DAYS.toMillis(1); 6037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 61cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate private static ComponentName sDexoptServiceName = new ComponentName( 621b8b3aa265190e84467f740e99a0ade3a0e3cd67Christopher Tate "android", 63cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate BackgroundDexOptService.class.getName()); 647395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 6551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Possible return codes of individual optimization steps. 6651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 6751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations finished. All packages were processed. 6851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_PROCESSED = 0; 6951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations should continue. Issued after checking the scheduler, disk space or battery. 7051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_CONTINUE = 1; 7151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations should be aborted. Job scheduler requested it. 7251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2; 7351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations should be aborted. No space left on device. 7451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3; 7551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 76a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom /** 77a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom * Set of failed packages remembered across job runs. 78a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom */ 7951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle static final ArraySet<String> sFailedPackageNamesPrimary = new ArraySet<String>(); 8051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle static final ArraySet<String> sFailedPackageNamesSecondary = new ArraySet<String>(); 81a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom 8237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 8337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomics set to true if the JobScheduler requests an abort. 8437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 8551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false); 8651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false); 8737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 8837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 8937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomic set to true if one job should exit early because another job was started. 9037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 9151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); 927395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 93be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private final File mDataDir = Environment.getDataDirectory(); 948735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 95db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle public static void schedule(Context context) { 96cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 9737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 9837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a one-off job which scans installed packages and updates 9937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // out-of-date oat files. 10037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) 10137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setMinimumLatency(TimeUnit.MINUTES.toMillis(1)) 10237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1)) 10337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 10437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 10537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a daily job which scans installed packages and compiles 10637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // those with fresh profiling data. 10737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName) 10837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresDeviceIdle(true) 10937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresCharging(true) 110a50d58e22630cd651a815381639e70476991bdbfCalin Juravle .setPeriodic(IDLE_OPTIMIZATION_PERIOD) 11137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 11237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 11337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 11437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Jobs scheduled"); 11537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 1167395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 1177395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 118ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil public static void notifyPackageChanged(String packageName) { 119ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // The idle maintanance job skips packages which previously failed to 120ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // compile. The given package has changed and may successfully compile 121ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // now. Remove it from the list of known failing packages. 12251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (sFailedPackageNamesPrimary) { 12351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesPrimary.remove(packageName); 12451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 12551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (sFailedPackageNamesSecondary) { 12651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesSecondary.remove(packageName); 127ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 128ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 129ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil 13037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Returns the current battery level as a 0-100 integer. 13137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private int getBatteryLevel() { 13237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 13337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Intent intent = registerReceiver(null, filter); 13437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 13537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); 136cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 13737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (level < 0 || scale <= 0) { 13837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Battery data unavailable. This should never happen, so assume the worst. 13937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return 0; 1407395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 14137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 14237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return (100 * level / scale); 14337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 14437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 145c660475aafe91269be306c802823cf543005ce36Calin Juravle private long getLowStorageThreshold(Context context) { 1468735f07a698218d311826a140d08d611d3c23db1Narayan Kamath @SuppressWarnings("deprecation") 147c660475aafe91269be306c802823cf543005ce36Calin Juravle final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir); 1488735f07a698218d311826a140d08d611d3c23db1Narayan Kamath if (lowThreshold == 0) { 1498735f07a698218d311826a140d08d611d3c23db1Narayan Kamath Log.e(TAG, "Invalid low storage threshold"); 1508735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1518735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 1528735f07a698218d311826a140d08d611d3c23db1Narayan Kamath return lowThreshold; 1538735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1548735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 15537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private boolean runPostBootUpdate(final JobParameters jobParams, 15637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final PackageManagerService pm, final ArraySet<String> pkgs) { 15737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (mExitPostBootUpdate.get()) { 15837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // This job has already been superseded. Do not start it. 1597395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom return false; 1607395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 161be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_PostBootUpdate") { 162be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle @Override 163be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle public void run() { 164be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle postBootUpdate(jobParams, pm, pkgs); 165be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 166be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 167be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle }.start(); 168be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return true; 169be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 170cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 171be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private void postBootUpdate(JobParameters jobParams, PackageManagerService pm, 172be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle ArraySet<String> pkgs) { 17337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Load low battery threshold from the system config. This is a 0-100 integer. 17437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final int lowBatteryThreshold = getResources().getInteger( 17537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil com.android.internal.R.integer.config_lowBatteryWarningLevel); 176c660475aafe91269be306c802823cf543005ce36Calin Juravle final long lowThreshold = getLowStorageThreshold(this); 1778735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 17837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(false); 179be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 180be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 181be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mAbortPostBootUpdate.get()) { 182be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // JobScheduler requested an early abort. 183be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return; 184be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 185be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mExitPostBootUpdate.get()) { 186be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Different job, which supersedes this one, is running. 187be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 188be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 189be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (getBatteryLevel() < lowBatteryThreshold) { 190be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely drain the battery. 191be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 192be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 193be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle long usableSpace = mDataDir.getUsableSpace(); 194be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (usableSpace < lowThreshold) { 195be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely fill up the disk. 196be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + 197be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle usableSpace); 198be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 199be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 200be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 201be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (DEBUG_DEXOPT) { 202be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.i(TAG, "Updating package " + pkg); 203be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 204be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 205be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Update package if needed. Note that there can be no race between concurrent 206be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // jobs because PackageDexOptimizer.performDexOpt is synchronized. 207be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 208be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // checkProfiles is false to avoid merging profiles during boot which 209be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // might interfere with background compilation (b/28612421). 210be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will 211be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a 212be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // trade-off worth doing to save boot time work. 213be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle pm.performDexOpt(pkg, 214be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* checkProfiles */ false, 215be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle PackageManagerService.REASON_BOOT, 216be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle /* force */ false); 217be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 218be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Ran to completion, so we abandon our timeslice and do not reschedule. 219be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle jobFinished(jobParams, /* reschedule */ false); 220be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 221be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 222be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private boolean runIdleOptimization(final JobParameters jobParams, 223be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle final PackageManagerService pm, final ArraySet<String> pkgs) { 224be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_IdleOptimization") { 2257395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom @Override 2267395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom public void run() { 22751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this); 22851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 22951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle Log.w(TAG, "Idle optimizations aborted because of space constraints."); 230c660475aafe91269be306c802823cf543005ce36Calin Juravle // If we didn't abort we ran to completion (or stopped because of space). 231c660475aafe91269be306c802823cf543005ce36Calin Juravle // Abandon our timeslice and do not reschedule. 232c660475aafe91269be306c802823cf543005ce36Calin Juravle jobFinished(jobParams, /* reschedule */ false); 233c660475aafe91269be306c802823cf543005ce36Calin Juravle } 23437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 23537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil }.start(); 23637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return true; 23737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 23837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 23951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes). 24051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, Context context) { 241a50d58e22630cd651a815381639e70476991bdbfCalin Juravle Log.i(TAG, "Performing idle optimizations"); 24237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // If post-boot update is still running, request that it exits early. 24337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mExitPostBootUpdate.set(true); 24437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(false); 2458735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 246c660475aafe91269be306c802823cf543005ce36Calin Juravle long lowStorageThreshold = getLowStorageThreshold(context); 24751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimize primary apks. 24851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ true, 24951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesPrimary); 25051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 25151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 25251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result; 25351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 25451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 2554466c5ad84e4429284b7d5e13ad8a87c924ea7fcCalin Juravle if (SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) { 25651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle result = reconcileSecondaryDexFiles(pm.getDexManager()); 25751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 25851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result; 25951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 26051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 26151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ false, 26251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesSecondary); 26351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 26451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result; 265c660475aafe91269be306c802823cf543005ce36Calin Juravle } 266c660475aafe91269be306c802823cf543005ce36Calin Juravle 26751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, 26851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle long lowStorageThreshold, boolean is_for_primary_dex, 26951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle ArraySet<String> failedPackageNames) { 270be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 27151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int abort_code = abortIdleOptimizations(lowStorageThreshold); 27251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (abort_code != OPTIMIZE_CONTINUE) { 27351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return abort_code; 274be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 2758735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 27651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (failedPackageNames) { 27751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (failedPackageNames.contains(pkg)) { 278be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Skip previously failing package 279be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle continue; 280c660475aafe91269be306c802823cf543005ce36Calin Juravle } else { 281c660475aafe91269be306c802823cf543005ce36Calin Juravle // Conservatively add package to the list of failing ones in case performDexOpt 282c660475aafe91269be306c802823cf543005ce36Calin Juravle // never returns. 28351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle failedPackageNames.add(pkg); 2847395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 2857395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 286be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 287be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Optimize package if needed. Note that there can be no race between 288be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized. 28951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle boolean success = is_for_primary_dex 29051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle ? pm.performDexOpt(pkg, 29151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle /* checkProfiles */ true, 29251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle PackageManagerService.REASON_BACKGROUND_DEXOPT, 29351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle /* force */ false) 29451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle : pm.performDexOptSecondary(pkg, 295a70b1b120365976f5eeb7cb3f577f5f6ff7ad18eCalin Juravle PackageManagerService.REASON_BACKGROUND_DEXOPT, 296a70b1b120365976f5eeb7cb3f577f5f6ff7ad18eCalin Juravle /* force */ false); 29751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (success) { 298be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Dexopt succeeded, remove package from the list of failing ones. 29951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (failedPackageNames) { 30051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle failedPackageNames.remove(pkg); 301be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 302be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 303be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 30451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_PROCESSED; 30551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 30651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 30751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int reconcileSecondaryDexFiles(DexManager dm) { 30851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // TODO(calin): should we blacklist packages for which we fail to reconcile? 30951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle for (String p : dm.getAllPackagesWithSecondaryDexFiles()) { 31051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (mAbortIdleOptimization.get()) { 31151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_ABORT_BY_JOB_SCHEDULER; 31251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 31351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle dm.reconcileSecondaryDexFiles(p); 31451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 31551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_PROCESSED; 316c660475aafe91269be306c802823cf543005ce36Calin Juravle } 317c660475aafe91269be306c802823cf543005ce36Calin Juravle 31851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Evaluate whether or not idle optimizations should continue. 31951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int abortIdleOptimizations(long lowStorageThreshold) { 320c660475aafe91269be306c802823cf543005ce36Calin Juravle if (mAbortIdleOptimization.get()) { 321c660475aafe91269be306c802823cf543005ce36Calin Juravle // JobScheduler requested an early abort. 32251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_ABORT_BY_JOB_SCHEDULER; 323c660475aafe91269be306c802823cf543005ce36Calin Juravle } 324c660475aafe91269be306c802823cf543005ce36Calin Juravle long usableSpace = mDataDir.getUsableSpace(); 325c660475aafe91269be306c802823cf543005ce36Calin Juravle if (usableSpace < lowStorageThreshold) { 326c660475aafe91269be306c802823cf543005ce36Calin Juravle // Rather bail than completely fill up the disk. 327c660475aafe91269be306c802823cf543005ce36Calin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace); 32851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_ABORT_NO_SPACE_LEFT; 329c660475aafe91269be306c802823cf543005ce36Calin Juravle } 330c660475aafe91269be306c802823cf543005ce36Calin Juravle 33151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_CONTINUE; 3327395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 3337395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 334cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle /** 335cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle * Execute the idle optimizations immediately. 336cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle */ 337cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle public static boolean runIdleOptimizationsNow(PackageManagerService pm, Context context) { 338cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // Create a new object to make sure we don't interfere with the scheduled jobs. 339cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // Note that this may still run at the same time with the job scheduled by the 340cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // JobScheduler but the scheduler will not be able to cancel it. 341cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle BackgroundDexOptService bdos = new BackgroundDexOptService(); 34251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int result = bdos.idleOptimization(pm, pm.getOptimizablePackages(), context); 34351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result == OPTIMIZE_PROCESSED; 344cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle } 345cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle 346cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate @Override 34737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil public boolean onStartJob(JobParameters params) { 34837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 34937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStartJob"); 35037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 35137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 3528735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from 3538735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // the checks above. This check is not "live" - the value is determined by a background 3548735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // restart with a period of ~1 minute. 35537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); 35637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (pm.isStorageLow()) { 35737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 35837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Low storage, skipping this run"); 35937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 36037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 36137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 36237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 36337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final ArraySet<String> pkgs = pm.getOptimizablePackages(); 364c660475aafe91269be306c802823cf543005ce36Calin Juravle if (pkgs.isEmpty()) { 36537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 36637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "No packages to optimize"); 36737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 36837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 36937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 37037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 371f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson boolean result; 37237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 373f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson result = runPostBootUpdate(params, pm, pkgs); 37437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 375f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson result = runIdleOptimization(params, pm, pkgs); 37637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 377f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson 378f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson PinnerService pinnerService = (PinnerService) LocalServices.getService(PinnerService.class); 379f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson if (pinnerService != null) { 380f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson Log.i(TAG, "Pinning optimized code"); 381f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson pinnerService.update(); 382f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson } 383f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson 384f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson return result; 38537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 38637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 38737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil @Override 388cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate public boolean onStopJob(JobParameters params) { 38937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 39037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStopJob"); 39137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 39237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 39337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 39437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(true); 39537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 39637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(true); 39737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 398cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate return false; 3997395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 4007395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom} 401