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 2109dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanksimport android.annotation.Nullable; 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; 411d0e83d2cee794ba576d573119e826905a4422cdCalin Juravleimport com.android.server.pm.dex.DexoptOptions; 4251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 438735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport java.io.File; 4409dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanksimport java.util.List; 45246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmeraimport java.util.Set; 467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport java.util.concurrent.atomic.AtomicBoolean; 4727c073796978106746e4a51f2100b29068ab37f6Nicolas Geoffrayimport java.util.concurrent.TimeUnit; 487395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 497395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom/** 507395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * {@hide} 517395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom */ 52cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tatepublic class BackgroundDexOptService extends JobService { 53a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final String TAG = "BackgroundDexOptService"; 547395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 55a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final boolean DEBUG = false; 562c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate 57a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final int JOB_IDLE_OPTIMIZE = 800; 58a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final int JOB_POST_BOOT_UPDATE = 801; 59a50d58e22630cd651a815381639e70476991bdbfCalin Juravle 60a50d58e22630cd651a815381639e70476991bdbfCalin Juravle private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG 61a50d58e22630cd651a815381639e70476991bdbfCalin Juravle ? TimeUnit.MINUTES.toMillis(1) 62a50d58e22630cd651a815381639e70476991bdbfCalin Juravle : TimeUnit.DAYS.toMillis(1); 6337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 64cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate private static ComponentName sDexoptServiceName = new ComponentName( 651b8b3aa265190e84467f740e99a0ade3a0e3cd67Christopher Tate "android", 66cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate BackgroundDexOptService.class.getName()); 677395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 6851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Possible return codes of individual optimization steps. 6951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 7051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations finished. All packages were processed. 7151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_PROCESSED = 0; 7251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations should continue. Issued after checking the scheduler, disk space or battery. 7351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_CONTINUE = 1; 7451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations should be aborted. Job scheduler requested it. 7551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2; 7651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimizations should be aborted. No space left on device. 7751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3; 7851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 79246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // Used for calculating space threshold for downgrading unused apps. 80246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2; 81246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 82a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom /** 83a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom * Set of failed packages remembered across job runs. 84a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom */ 8551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle static final ArraySet<String> sFailedPackageNamesPrimary = new ArraySet<String>(); 8651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle static final ArraySet<String> sFailedPackageNamesSecondary = new ArraySet<String>(); 87a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom 8837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 8937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomics set to true if the JobScheduler requests an abort. 9037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 9151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false); 9251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false); 9337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 9437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil /** 9537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil * Atomic set to true if one job should exit early because another job was started. 9637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil */ 9751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); 987395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 99be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private final File mDataDir = Environment.getDataDirectory(); 1008735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 101246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera private static final long mDowngradeUnusedAppsThresholdInMillis = 102246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera getDowngradeUnusedAppsThresholdInMillis(); 103246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 104db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle public static void schedule(Context context) { 1053067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera if (isBackgroundDexoptDisabled()) { 1063067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera return; 1073067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera } 1083067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera 109cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 11037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 11137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a one-off job which scans installed packages and updates 11237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // out-of-date oat files. 11337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) 11437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setMinimumLatency(TimeUnit.MINUTES.toMillis(1)) 11537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1)) 11637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 11737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 11837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Schedule a daily job which scans installed packages and compiles 11937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // those with fresh profiling data. 12037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName) 12137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresDeviceIdle(true) 12237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .setRequiresCharging(true) 123a50d58e22630cd651a815381639e70476991bdbfCalin Juravle .setPeriodic(IDLE_OPTIMIZATION_PERIOD) 12437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil .build()); 12537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 12637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 12737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Jobs scheduled"); 12837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 1297395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 1307395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 131ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil public static void notifyPackageChanged(String packageName) { 132ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // The idle maintanance job skips packages which previously failed to 133ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // compile. The given package has changed and may successfully compile 134ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil // now. Remove it from the list of known failing packages. 13551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (sFailedPackageNamesPrimary) { 13651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesPrimary.remove(packageName); 13751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 13851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (sFailedPackageNamesSecondary) { 13951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesSecondary.remove(packageName); 140ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 141ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil } 142ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil 14337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Returns the current battery level as a 0-100 integer. 14437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private int getBatteryLevel() { 14537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 14637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Intent intent = registerReceiver(null, filter); 14737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 14837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); 1491cd7cc85651b4b34314e6ab53765a1eecde0f7c0Todd Poynor boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); 1501cd7cc85651b4b34314e6ab53765a1eecde0f7c0Todd Poynor 1511cd7cc85651b4b34314e6ab53765a1eecde0f7c0Todd Poynor if (!present) { 1521cd7cc85651b4b34314e6ab53765a1eecde0f7c0Todd Poynor // No battery, treat as if 100%, no possibility of draining battery. 1531cd7cc85651b4b34314e6ab53765a1eecde0f7c0Todd Poynor return 100; 1541cd7cc85651b4b34314e6ab53765a1eecde0f7c0Todd Poynor } 155cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 15637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (level < 0 || scale <= 0) { 15737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Battery data unavailable. This should never happen, so assume the worst. 15837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return 0; 1597395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 16037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 16137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return (100 * level / scale); 16237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 16337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 164c660475aafe91269be306c802823cf543005ce36Calin Juravle private long getLowStorageThreshold(Context context) { 1658735f07a698218d311826a140d08d611d3c23db1Narayan Kamath @SuppressWarnings("deprecation") 166c660475aafe91269be306c802823cf543005ce36Calin Juravle final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir); 1678735f07a698218d311826a140d08d611d3c23db1Narayan Kamath if (lowThreshold == 0) { 1688735f07a698218d311826a140d08d611d3c23db1Narayan Kamath Log.e(TAG, "Invalid low storage threshold"); 1698735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1708735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 1718735f07a698218d311826a140d08d611d3c23db1Narayan Kamath return lowThreshold; 1728735f07a698218d311826a140d08d611d3c23db1Narayan Kamath } 1738735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 17437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil private boolean runPostBootUpdate(final JobParameters jobParams, 17537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final PackageManagerService pm, final ArraySet<String> pkgs) { 17637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (mExitPostBootUpdate.get()) { 17737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // This job has already been superseded. Do not start it. 1787395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom return false; 1797395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 180be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_PostBootUpdate") { 181be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle @Override 182be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle public void run() { 183be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle postBootUpdate(jobParams, pm, pkgs); 184be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 185be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 186be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle }.start(); 187be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return true; 188be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 189cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate 190be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private void postBootUpdate(JobParameters jobParams, PackageManagerService pm, 191be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle ArraySet<String> pkgs) { 19237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // Load low battery threshold from the system config. This is a 0-100 integer. 19337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final int lowBatteryThreshold = getResources().getInteger( 19437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil com.android.internal.R.integer.config_lowBatteryWarningLevel); 195c660475aafe91269be306c802823cf543005ce36Calin Juravle final long lowThreshold = getLowStorageThreshold(this); 1968735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 19737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(false); 198be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 19931ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle ArraySet<String> updatedPackages = new ArraySet<>(); 200be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 201be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mAbortPostBootUpdate.get()) { 202be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // JobScheduler requested an early abort. 203be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle return; 204be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 205be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (mExitPostBootUpdate.get()) { 206be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Different job, which supersedes this one, is running. 207be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 208be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 209be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (getBatteryLevel() < lowBatteryThreshold) { 210be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely drain the battery. 211be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 212be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 213be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle long usableSpace = mDataDir.getUsableSpace(); 214be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (usableSpace < lowThreshold) { 215be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Rather bail than completely fill up the disk. 216be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + 217be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle usableSpace); 218be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle break; 219be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 220be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 221be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle if (DEBUG_DEXOPT) { 222be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle Log.i(TAG, "Updating package " + pkg); 223be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 224be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 225be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Update package if needed. Note that there can be no race between concurrent 226be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // jobs because PackageDexOptimizer.performDexOpt is synchronized. 227be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 228be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // checkProfiles is false to avoid merging profiles during boot which 229be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // might interfere with background compilation (b/28612421). 230be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will 231be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a 232be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // trade-off worth doing to save boot time work. 2331d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle int result = pm.performDexOptWithStatus(new DexoptOptions( 2341d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle pkg, 235be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle PackageManagerService.REASON_BOOT, 2361d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle DexoptOptions.DEXOPT_BOOT_COMPLETE)); 23731ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) { 23831ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle updatedPackages.add(pkg); 23931ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle } 240be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 24131ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle notifyPinService(updatedPackages); 242be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Ran to completion, so we abandon our timeslice and do not reschedule. 243be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle jobFinished(jobParams, /* reschedule */ false); 244be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 245be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 246be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle private boolean runIdleOptimization(final JobParameters jobParams, 247be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle final PackageManagerService pm, final ArraySet<String> pkgs) { 248be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle new Thread("BackgroundDexOptService_IdleOptimization") { 2497395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom @Override 2507395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom public void run() { 25151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this); 25251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 25351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle Log.w(TAG, "Idle optimizations aborted because of space constraints."); 254c660475aafe91269be306c802823cf543005ce36Calin Juravle // If we didn't abort we ran to completion (or stopped because of space). 255c660475aafe91269be306c802823cf543005ce36Calin Juravle // Abandon our timeslice and do not reschedule. 256c660475aafe91269be306c802823cf543005ce36Calin Juravle jobFinished(jobParams, /* reschedule */ false); 257c660475aafe91269be306c802823cf543005ce36Calin Juravle } 25837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 25937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil }.start(); 26037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return true; 26137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 26237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 26351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes). 264246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, 265246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera Context context) { 266a50d58e22630cd651a815381639e70476991bdbfCalin Juravle Log.i(TAG, "Performing idle optimizations"); 26737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil // If post-boot update is still running, request that it exits early. 26837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mExitPostBootUpdate.set(true); 26937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(false); 2708735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 271c660475aafe91269be306c802823cf543005ce36Calin Juravle long lowStorageThreshold = getLowStorageThreshold(context); 27251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Optimize primary apks. 27351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ true, 27451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesPrimary); 27551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 27651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 27751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result; 27851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 27951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 2804466c5ad84e4429284b7d5e13ad8a87c924ea7fcCalin Juravle if (SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) { 28151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle result = reconcileSecondaryDexFiles(pm.getDexManager()); 28251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 28351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result; 28451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 28551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 28651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ false, 28751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle sFailedPackageNamesSecondary); 28851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 28951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result; 290c660475aafe91269be306c802823cf543005ce36Calin Juravle } 291c660475aafe91269be306c802823cf543005ce36Calin Juravle 29251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, 29351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle long lowStorageThreshold, boolean is_for_primary_dex, 29451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle ArraySet<String> failedPackageNames) { 29531ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle ArraySet<String> updatedPackages = new ArraySet<>(); 296246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis); 297246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // Only downgrade apps when space is low on device. 298246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean 299246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // up disk before user hits the actual lowStorageThreshold. 300246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * 301246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera lowStorageThreshold; 302246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade); 303be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle for (String pkg : pkgs) { 30451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle int abort_code = abortIdleOptimizations(lowStorageThreshold); 305246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera if (abort_code == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { 30651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return abort_code; 307be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 3088735f07a698218d311826a140d08d611d3c23db1Narayan Kamath 30951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (failedPackageNames) { 31051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (failedPackageNames.contains(pkg)) { 311be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Skip previously failing package 312be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle continue; 313246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 314246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 315246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 316246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera int reason; 317246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera boolean downgrade; 318246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // Downgrade unused packages. 319246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera if (unusedPackages.contains(pkg) && shouldDowngrade) { 320246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // This applies for system apps or if packages location is not a directory, i.e. 321246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // monolithic install. 322246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera if (is_for_primary_dex && !pm.canHaveOatDir(pkg)) { 323246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // For apps that don't have the oat directory, instead of downgrading, 324246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // remove their compiler artifacts from dalvik cache. 325246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera pm.deleteOatArtifactsOfPackage(pkg); 326246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera continue; 327c660475aafe91269be306c802823cf543005ce36Calin Juravle } else { 328246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE; 329246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera downgrade = true; 3307395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 331246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } else if (abort_code != OPTIMIZE_ABORT_NO_SPACE_LEFT) { 332246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera reason = PackageManagerService.REASON_BACKGROUND_DEXOPT; 333246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera downgrade = false; 334246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } else { 335246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // can't dexopt because of low space. 336246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera continue; 337246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 338246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 339246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera synchronized (failedPackageNames) { 340246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // Conservatively add package to the list of failing ones in case 341246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // performDexOpt never returns. 342246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera failedPackageNames.add(pkg); 3437395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 344be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle 345be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Optimize package if needed. Note that there can be no race between 346be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized. 34731ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle boolean success; 3481d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle int dexoptFlags = 3491d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES | 3501d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle DexoptOptions.DEXOPT_BOOT_COMPLETE | 3512118ec4d7e176b0ea96a79ca3b45e1cca9724eedDavid Sehr (downgrade ? DexoptOptions.DEXOPT_DOWNGRADE : 0) | 3522118ec4d7e176b0ea96a79ca3b45e1cca9724eedDavid Sehr DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB; 35331ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle if (is_for_primary_dex) { 354d8200866ae2d0289e855d257b4d0c6c24aa09478Shubham Ajmera int result = pm.performDexOptWithStatus(new DexoptOptions(pkg, reason, 3551d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle dexoptFlags)); 35631ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle success = result != PackageDexOptimizer.DEX_OPT_FAILED; 35731ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) { 35831ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle updatedPackages.add(pkg); 35931ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle } 36031ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle } else { 3611d0e83d2cee794ba576d573119e826905a4422cdCalin Juravle success = pm.performDexOpt(new DexoptOptions(pkg, 362d8200866ae2d0289e855d257b4d0c6c24aa09478Shubham Ajmera reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX)); 36331ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle } 36451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (success) { 365be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle // Dexopt succeeded, remove package from the list of failing ones. 36651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (failedPackageNames) { 36751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle failedPackageNames.remove(pkg); 368be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 369be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 370be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle } 37131ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle notifyPinService(updatedPackages); 37251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_PROCESSED; 37351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 37451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 37551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int reconcileSecondaryDexFiles(DexManager dm) { 37651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // TODO(calin): should we blacklist packages for which we fail to reconcile? 37751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle for (String p : dm.getAllPackagesWithSecondaryDexFiles()) { 37851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (mAbortIdleOptimization.get()) { 37951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_ABORT_BY_JOB_SCHEDULER; 38051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 38151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle dm.reconcileSecondaryDexFiles(p); 38251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 38351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_PROCESSED; 384c660475aafe91269be306c802823cf543005ce36Calin Juravle } 385c660475aafe91269be306c802823cf543005ce36Calin Juravle 38651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle // Evaluate whether or not idle optimizations should continue. 38751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle private int abortIdleOptimizations(long lowStorageThreshold) { 388c660475aafe91269be306c802823cf543005ce36Calin Juravle if (mAbortIdleOptimization.get()) { 389c660475aafe91269be306c802823cf543005ce36Calin Juravle // JobScheduler requested an early abort. 39051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_ABORT_BY_JOB_SCHEDULER; 391c660475aafe91269be306c802823cf543005ce36Calin Juravle } 392c660475aafe91269be306c802823cf543005ce36Calin Juravle long usableSpace = mDataDir.getUsableSpace(); 393c660475aafe91269be306c802823cf543005ce36Calin Juravle if (usableSpace < lowStorageThreshold) { 394c660475aafe91269be306c802823cf543005ce36Calin Juravle // Rather bail than completely fill up the disk. 395c660475aafe91269be306c802823cf543005ce36Calin Juravle Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace); 39651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_ABORT_NO_SPACE_LEFT; 397c660475aafe91269be306c802823cf543005ce36Calin Juravle } 398c660475aafe91269be306c802823cf543005ce36Calin Juravle 39951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return OPTIMIZE_CONTINUE; 4007395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 4017395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom 402246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera // Evaluate whether apps should be downgraded. 403246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera private boolean shouldDowngrade(long lowStorageThresholdForDowngrade) { 404246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera long usableSpace = mDataDir.getUsableSpace(); 405246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera if (usableSpace < lowStorageThresholdForDowngrade) { 406246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera return true; 407246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 408246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 409246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera return false; 410246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 411246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 412cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle /** 41309dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks * Execute idle optimizations immediately on packages in packageNames. If packageNames is null, 41409dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks * then execute on all packages. 415cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle */ 41609dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks public static boolean runIdleOptimizationsNow(PackageManagerService pm, Context context, 41709dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks @Nullable List<String> packageNames) { 418cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // Create a new object to make sure we don't interfere with the scheduled jobs. 419cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // Note that this may still run at the same time with the job scheduled by the 420cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle // JobScheduler but the scheduler will not be able to cancel it. 421cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle BackgroundDexOptService bdos = new BackgroundDexOptService(); 42209dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks ArraySet<String> packagesToOptimize; 42309dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks if (packageNames == null) { 42409dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks packagesToOptimize = pm.getOptimizablePackages(); 42509dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks } else { 42609dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks packagesToOptimize = new ArraySet<>(packageNames); 42709dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks } 42809dd1ec4b2dedb862b6276763268380ec037a58eArthur Eubanks int result = bdos.idleOptimization(pm, packagesToOptimize, context); 42951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return result == OPTIMIZE_PROCESSED; 430cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle } 431cb5f41ea11b1a6fcd0977a64ee146dde8f537076Calin Juravle 432cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate @Override 43337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil public boolean onStartJob(JobParameters params) { 43437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 43537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStartJob"); 43637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 43737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 4388735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from 4398735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // the checks above. This check is not "live" - the value is determined by a background 4408735f07a698218d311826a140d08d611d3c23db1Narayan Kamath // restart with a period of ~1 minute. 44137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); 44237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (pm.isStorageLow()) { 44337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 44437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "Low storage, skipping this run"); 44537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 44637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 44737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 44837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 44937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil final ArraySet<String> pkgs = pm.getOptimizablePackages(); 450c660475aafe91269be306c802823cf543005ce36Calin Juravle if (pkgs.isEmpty()) { 45137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 45237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "No packages to optimize"); 45337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 45437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil return false; 45537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 45637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 457f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson boolean result; 45837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 459f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson result = runPostBootUpdate(params, pm, pkgs); 46037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 461f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson result = runIdleOptimization(params, pm, pkgs); 46237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 463f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson 464f107a23ff165bbb7f0ae145f9ac85ddca8b43ed7Carmen Jackson return result; 46537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 46637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 46737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil @Override 468cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate public boolean onStopJob(JobParameters params) { 46937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (DEBUG_DEXOPT) { 47037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil Log.i(TAG, "onStopJob"); 47137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 47237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil 47337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil if (params.getJobId() == JOB_POST_BOOT_UPDATE) { 47437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortPostBootUpdate.set(true); 4756da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe 4766da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe // Do not reschedule. 4776da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe // TODO: We should reschedule if we didn't process all apps, yet. 4786da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe return false; 47937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } else { 48037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil mAbortIdleOptimization.set(true); 4816da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe 4826da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe // Reschedule the run. 4836da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe // TODO: Should this be dependent on the stop reason? 4846da7d879772ed75520ac925130b9111cae9e397eAndreas Gampe return true; 48537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil } 4867395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom } 48731ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle 48831ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle private void notifyPinService(ArraySet<String> updatedPackages) { 48931ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle PinnerService pinnerService = LocalServices.getService(PinnerService.class); 49031ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle if (pinnerService != null) { 49131ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle Log.i(TAG, "Pinning optimized code " + updatedPackages); 49231ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle pinnerService.update(updatedPackages); 49331ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle } 49431ce3a8a56e78ecc17d9befbc64a1e529b6b78e9Calin Juravle } 495246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera 496246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera private static long getDowngradeUnusedAppsThresholdInMillis() { 497246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days"; 498246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera String sysPropValue = SystemProperties.get(sysPropKey); 499246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera if (sysPropValue == null || sysPropValue.isEmpty()) { 500246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera Log.w(TAG, "SysProp " + sysPropKey + " not set"); 501246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera return Long.MAX_VALUE; 502246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 503246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue)); 504246dccf9327631597767afe418ce43ae6d07d102Shubham Ajmera } 5053067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera 5063067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera private static boolean isBackgroundDexoptDisabled() { 5073067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */, 5083067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera false /* default */); 5093067a1dd8bf7faf7f03b2e23dd25369a7f441a1aShubham Ajmera } 5107395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom} 511