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