BackgroundDexOptService.java revision 8735f07a698218d311826a140d08d611d3c23db1
17395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom/*
27395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * Copyright (C) 2014 The Android Open Source Project
37395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom *
47395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
57395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * you may not use this file except in compliance with the License.
67395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * You may obtain a copy of the License at
77395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom *
87395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
97395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom *
107395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * Unless required by applicable law or agreed to in writing, software
117395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
127395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * See the License for the specific language governing permissions and
147395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * limitations under the License.
157395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom */
167395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
177395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrompackage com.android.server.pm;
187395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
1937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
2037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
212c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tateimport android.app.AlarmManager;
22cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobInfo;
23cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobParameters;
24cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobScheduler;
25cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.app.job.JobService;
26cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tateimport android.content.ComponentName;
277395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.content.Context;
2837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport android.content.Intent;
2937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport android.content.IntentFilter;
3037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdilimport android.os.BatteryManager;
318735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport android.os.Environment;
327395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.os.ServiceManager;
338735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport android.os.storage.StorageManager;
349f837a99d48c5bb8ad7fbc133943e5bf622ce065Jeff Sharkeyimport android.util.ArraySet;
357395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport android.util.Log;
367395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
378735f07a698218d311826a140d08d611d3c23db1Narayan Kamathimport java.io.File;
387395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstromimport java.util.concurrent.atomic.AtomicBoolean;
3927c073796978106746e4a51f2100b29068ab37f6Nicolas Geoffrayimport java.util.concurrent.TimeUnit;
407395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
417395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom/**
427395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom * {@hide}
437395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom */
44cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tatepublic class BackgroundDexOptService extends JobService {
457395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom    static final String TAG = "BackgroundDexOptService";
467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
472c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate    static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
482c9655b3d4c1fb0687baa14730c6d97ab5a56789Christopher Tate
4937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    static final int JOB_IDLE_OPTIMIZE = 800;
5037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    static final int JOB_POST_BOOT_UPDATE = 801;
5137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
52cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate    private static ComponentName sDexoptServiceName = new ComponentName(
531b8b3aa265190e84467f740e99a0ade3a0e3cd67Christopher Tate            "android",
54cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate            BackgroundDexOptService.class.getName());
557395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
56a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom    /**
57a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom     * Set of failed packages remembered across job runs.
58a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom     */
59a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom    static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
60a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom
6137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    /**
6237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil     * Atomics set to true if the JobScheduler requests an abort.
6337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil     */
6437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
6537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
6637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
6737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    /**
6837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil     * Atomic set to true if one job should exit early because another job was started.
6937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil     */
7037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
717395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
728735f07a698218d311826a140d08d611d3c23db1Narayan Kamath    private final File dataDir = Environment.getDataDirectory();
738735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
74db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle    public static void schedule(Context context) {
75cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
7637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
7737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // Schedule a one-off job which scans installed packages and updates
7837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // out-of-date oat files.
7937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
8037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
8137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
8237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .build());
8337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
8437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // Schedule a daily job which scans installed packages and compiles
8537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // those with fresh profiling data.
8637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName)
8737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .setRequiresDeviceIdle(true)
8837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .setRequiresCharging(true)
8937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .setPeriodic(TimeUnit.DAYS.toMillis(1))
9037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    .build());
9137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
9237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (DEBUG_DEXOPT) {
9337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            Log.i(TAG, "Jobs scheduled");
9437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
957395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom    }
967395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
97ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil    public static void notifyPackageChanged(String packageName) {
98ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil        // The idle maintanance job skips packages which previously failed to
99ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil        // compile. The given package has changed and may successfully compile
100ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil        // now. Remove it from the list of known failing packages.
101ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil        synchronized (sFailedPackageNames) {
102ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil            sFailedPackageNames.remove(packageName);
103ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil        }
104ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil    }
105ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil
10637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    // Returns the current battery level as a 0-100 integer.
10737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    private int getBatteryLevel() {
10837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
10937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        Intent intent = registerReceiver(null, filter);
11037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
11137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
112cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate
11337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (level < 0 || scale <= 0) {
11437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            // Battery data unavailable. This should never happen, so assume the worst.
11537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return 0;
1167395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom        }
11737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
11837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        return (100 * level / scale);
11937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    }
12037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
1218735f07a698218d311826a140d08d611d3c23db1Narayan Kamath    private long getLowStorageThreshold() {
1228735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        @SuppressWarnings("deprecation")
1238735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(dataDir);
1248735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        if (lowThreshold == 0) {
1258735f07a698218d311826a140d08d611d3c23db1Narayan Kamath            Log.e(TAG, "Invalid low storage threshold");
1268735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        }
1278735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
1288735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        return lowThreshold;
1298735f07a698218d311826a140d08d611d3c23db1Narayan Kamath    }
1308735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
13137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    private boolean runPostBootUpdate(final JobParameters jobParams,
13237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            final PackageManagerService pm, final ArraySet<String> pkgs) {
13337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (mExitPostBootUpdate.get()) {
13437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            // This job has already been superseded. Do not start it.
1357395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            return false;
1367395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom        }
137cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate
13837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // Load low battery threshold from the system config. This is a 0-100 integer.
13937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        final int lowBatteryThreshold = getResources().getInteger(
14037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                com.android.internal.R.integer.config_lowBatteryWarningLevel);
14137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
1428735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        final long lowThreshold = getLowStorageThreshold();
1438735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
14437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        mAbortPostBootUpdate.set(false);
14537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        new Thread("BackgroundDexOptService_PostBootUpdate") {
1467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            @Override
1477395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            public void run() {
1487395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom                for (String pkg : pkgs) {
14937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    if (mAbortPostBootUpdate.get()) {
15037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        // JobScheduler requested an early abort.
15137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        return;
15237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    }
15337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    if (mExitPostBootUpdate.get()) {
15437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        // Different job, which supersedes this one, is running.
15537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        break;
15637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    }
15737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    if (getBatteryLevel() < lowBatteryThreshold) {
15837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        // Rather bail than completely drain the battery.
15937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        break;
16037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    }
1618735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                    long usableSpace = dataDir.getUsableSpace();
1628735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                    if (usableSpace < lowThreshold) {
1638735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                        // Rather bail than completely fill up the disk.
1648735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                        Log.w(TAG, "Aborting background dex opt job due to low storage: " +
1658735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                                usableSpace);
1668735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                        break;
1678735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                    }
1688735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
16937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    if (DEBUG_DEXOPT) {
17037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        Log.i(TAG, "Updating package " + pkg);
17137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    }
1728412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle
17337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    // Update package if needed. Note that there can be no race between concurrent
17437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    // jobs because PackageDexOptimizer.performDexOpt is synchronized.
1758412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle
1768412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle                    // checkProfiles is false to avoid merging profiles during boot which
1778412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle                    // might interfere with background compilation (b/28612421).
1788412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle                    // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
1798412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle                    // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
1808412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle                    // trade-off worth doing to save boot time work.
18137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    pm.performDexOpt(pkg,
1828412cf4daaa437003f4a79a82aa35465c4f0d418Calin Juravle                            /* checkProfiles */ false,
18337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                            PackageManagerService.REASON_BOOT,
18437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                            /* force */ false);
18537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                }
18637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                // Ran to completion, so we abandon our timeslice and do not reschedule.
18737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                jobFinished(jobParams, /* reschedule */ false);
18837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            }
18937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }.start();
19037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        return true;
19137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    }
19237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
19337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    private boolean runIdleOptimization(final JobParameters jobParams,
19437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            final PackageManagerService pm, final ArraySet<String> pkgs) {
19537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // If post-boot update is still running, request that it exits early.
19637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        mExitPostBootUpdate.set(true);
19737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
19837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        mAbortIdleOptimization.set(false);
1998735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
2008735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        final long lowThreshold = getLowStorageThreshold();
2018735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
20237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        new Thread("BackgroundDexOptService_IdleOptimization") {
20337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            @Override
20437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            public void run() {
20537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                for (String pkg : pkgs) {
20637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    if (mAbortIdleOptimization.get()) {
20737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        // JobScheduler requested an early abort.
208cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate                        return;
2097395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom                    }
210a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom                    if (sFailedPackageNames.contains(pkg)) {
21137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                        // Skip previously failing package
212a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom                        continue;
213a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom                    }
2148735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
2158735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                    long usableSpace = dataDir.getUsableSpace();
2168735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                    if (usableSpace < lowThreshold) {
2178735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                        // Rather bail than completely fill up the disk.
2188735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                        Log.w(TAG, "Aborting background dex opt job due to low storage: " +
2198735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                                usableSpace);
2208735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                        break;
2218735f07a698218d311826a140d08d611d3c23db1Narayan Kamath                    }
2228735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
22380932c1418f22fa2ab49aa1eea8337b8f29b9bccDavid Brazdil                    // Conservatively add package to the list of failing ones in case performDexOpt
22480932c1418f22fa2ab49aa1eea8337b8f29b9bccDavid Brazdil                    // never returns.
225ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil                    synchronized (sFailedPackageNames) {
226ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil                        sFailedPackageNames.add(pkg);
227ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil                    }
22837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    // Optimize package if needed. Note that there can be no race between
22937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                    // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
23080932c1418f22fa2ab49aa1eea8337b8f29b9bccDavid Brazdil                    if (pm.performDexOpt(pkg,
23137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                            /* checkProfiles */ true,
23237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
23337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                            /* force */ false)) {
23480932c1418f22fa2ab49aa1eea8337b8f29b9bccDavid Brazdil                        // Dexopt succeeded, remove package from the list of failing ones.
235ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil                        synchronized (sFailedPackageNames) {
236ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil                            sFailedPackageNames.remove(pkg);
237ace80c56d7c63dadead34539b643f69a1b7336e8David Brazdil                        }
238a00be9b4d521287fdf4678fb196c3e3a0053c3e4Brian Carlstrom                    }
2397395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom                }
24037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                // Ran to completion, so we abandon our timeslice and do not reschedule.
24137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                jobFinished(jobParams, /* reschedule */ false);
2427395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            }
2437395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom        }.start();
2447395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom        return true;
2457395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom    }
2467395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
247cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate    @Override
24837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    public boolean onStartJob(JobParameters params) {
24937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (DEBUG_DEXOPT) {
25037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            Log.i(TAG, "onStartJob");
25137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
25237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
2538735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
2548735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        // the checks above. This check is not "live" - the value is determined by a background
2558735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        // restart with a period of ~1 minute.
25637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
25737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (pm.isStorageLow()) {
25837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            if (DEBUG_DEXOPT) {
25937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                Log.i(TAG, "Low storage, skipping this run");
26037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            }
26137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return false;
26237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
26337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
26437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        final ArraySet<String> pkgs = pm.getOptimizablePackages();
26537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (pkgs == null || pkgs.isEmpty()) {
26637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            if (DEBUG_DEXOPT) {
26737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                Log.i(TAG, "No packages to optimize");
26837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            }
26937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return false;
27037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
27137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
27237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
27337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return runPostBootUpdate(params, pm, pkgs);
27437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        } else {
27537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return runIdleOptimization(params, pm, pkgs);
27637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
27737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    }
27837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
27937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    @Override
280cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate    public boolean onStopJob(JobParameters params) {
28137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (DEBUG_DEXOPT) {
28237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            Log.i(TAG, "onStopJob");
28337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
28437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
28537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
28637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            mAbortPostBootUpdate.set(true);
28737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        } else {
28837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            mAbortIdleOptimization.set(true);
28937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
290cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate        return false;
2917395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom    }
2927395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom}
293