BackgroundDexOptService.java revision be6a71a0b3f369843a26c91dd5123d0499f00e7e
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
72be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle    private final File mDataDir = 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")
123be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
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        }
137be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        new Thread("BackgroundDexOptService_PostBootUpdate") {
138be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            @Override
139be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            public void run() {
140be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                postBootUpdate(jobParams, pm, pkgs);
141be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
142be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
143be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        }.start();
144be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        return true;
145be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle    }
146cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate
147be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle    private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
148be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            ArraySet<String> pkgs) {
14937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // Load low battery threshold from the system config. This is a 0-100 integer.
15037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        final int lowBatteryThreshold = getResources().getInteger(
15137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                com.android.internal.R.integer.config_lowBatteryWarningLevel);
1528735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        final long lowThreshold = getLowStorageThreshold();
1538735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
15437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        mAbortPostBootUpdate.set(false);
155be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
156be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        for (String pkg : pkgs) {
157be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (mAbortPostBootUpdate.get()) {
158be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // JobScheduler requested an early abort.
159be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                return;
160be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
161be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (mExitPostBootUpdate.get()) {
162be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // Different job, which supersedes this one, is running.
163be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                break;
164be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
165be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (getBatteryLevel() < lowBatteryThreshold) {
166be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // Rather bail than completely drain the battery.
167be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                break;
168be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
169be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            long usableSpace = mDataDir.getUsableSpace();
170be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (usableSpace < lowThreshold) {
171be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // Rather bail than completely fill up the disk.
172be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
173be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                        usableSpace);
174be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                break;
175be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
176be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
177be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (DEBUG_DEXOPT) {
178be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                Log.i(TAG, "Updating package " + pkg);
179be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
180be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
181be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // Update package if needed. Note that there can be no race between concurrent
182be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // jobs because PackageDexOptimizer.performDexOpt is synchronized.
183be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
184be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // checkProfiles is false to avoid merging profiles during boot which
185be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // might interfere with background compilation (b/28612421).
186be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
187be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
188be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // trade-off worth doing to save boot time work.
189be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            pm.performDexOpt(pkg,
190be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    /* checkProfiles */ false,
191be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    PackageManagerService.REASON_BOOT,
192be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    /* force */ false);
193be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        }
194be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        // Ran to completion, so we abandon our timeslice and do not reschedule.
195be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        jobFinished(jobParams, /* reschedule */ false);
196be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle    }
197be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
198be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle    private boolean runIdleOptimization(final JobParameters jobParams,
199be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            final PackageManagerService pm, final ArraySet<String> pkgs) {
200be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        new Thread("BackgroundDexOptService_IdleOptimization") {
2017395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            @Override
2027395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            public void run() {
203be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                idleOptimization(jobParams, pm, pkgs);
20437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            }
20537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }.start();
20637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        return true;
20737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    }
20837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
209be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle    private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
210be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            ArraySet<String> pkgs) {
21137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        // If post-boot update is still running, request that it exits early.
21237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        mExitPostBootUpdate.set(true);
21337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
21437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        mAbortIdleOptimization.set(false);
2158735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
2168735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        final long lowThreshold = getLowStorageThreshold();
217be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        for (String pkg : pkgs) {
218be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (mAbortIdleOptimization.get()) {
219be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // JobScheduler requested an early abort.
220be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                return;
221be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
2228735f07a698218d311826a140d08d611d3c23db1Narayan Kamath
223be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            synchronized (sFailedPackageNames) {
224be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                if (sFailedPackageNames.contains(pkg)) {
225be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    // Skip previously failing package
226be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    continue;
2277395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom                }
2287395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom            }
229be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
230be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            long usableSpace = mDataDir.getUsableSpace();
231be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (usableSpace < lowThreshold) {
232be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // Rather bail than completely fill up the disk.
233be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
234be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                        usableSpace);
235be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                break;
236be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
237be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle
238be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // Conservatively add package to the list of failing ones in case performDexOpt
239be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // never returns.
240be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            synchronized (sFailedPackageNames) {
241be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                sFailedPackageNames.add(pkg);
242be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
243be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // Optimize package if needed. Note that there can be no race between
244be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
245be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            if (pm.performDexOpt(pkg,
246be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    /* checkProfiles */ true,
247be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    PackageManagerService.REASON_BACKGROUND_DEXOPT,
248be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    /* force */ false)) {
249be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                // Dexopt succeeded, remove package from the list of failing ones.
250be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                synchronized (sFailedPackageNames) {
251be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                    sFailedPackageNames.remove(pkg);
252be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle                }
253be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle            }
254be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        }
255be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        // Ran to completion, so we abandon our timeslice and do not reschedule.
256be6a71a0b3f369843a26c91dd5123d0499f00e7eCalin Juravle        jobFinished(jobParams, /* reschedule */ false);
2577395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom    }
2587395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom
259cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate    @Override
26037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    public boolean onStartJob(JobParameters params) {
26137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (DEBUG_DEXOPT) {
26237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            Log.i(TAG, "onStartJob");
26337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
26437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
2658735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
2668735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        // the checks above. This check is not "live" - the value is determined by a background
2678735f07a698218d311826a140d08d611d3c23db1Narayan Kamath        // restart with a period of ~1 minute.
26837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
26937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (pm.isStorageLow()) {
27037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            if (DEBUG_DEXOPT) {
27137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                Log.i(TAG, "Low storage, skipping this run");
27237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            }
27337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return false;
27437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
27537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
27637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        final ArraySet<String> pkgs = pm.getOptimizablePackages();
27737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (pkgs == null || pkgs.isEmpty()) {
27837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            if (DEBUG_DEXOPT) {
27937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil                Log.i(TAG, "No packages to optimize");
28037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            }
28137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return false;
28237a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
28337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
28437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
28537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return runPostBootUpdate(params, pm, pkgs);
28637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        } else {
28737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            return runIdleOptimization(params, pm, pkgs);
28837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
28937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    }
29037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
29137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil    @Override
292cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate    public boolean onStopJob(JobParameters params) {
29337a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (DEBUG_DEXOPT) {
29437a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            Log.i(TAG, "onStopJob");
29537a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
29637a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil
29737a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
29837a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            mAbortPostBootUpdate.set(true);
29937a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        } else {
30037a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil            mAbortIdleOptimization.set(true);
30137a87698f5b13e8d24475cb05d48a3da7339192cDavid Brazdil        }
302cf1a2f73fc102be2ac7060ac97d4682bb2565ca5Christopher Tate        return false;
3037395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom    }
3047395a8ab8a7c6b03c32500c934694dde80b9ade1Brian Carlstrom}
305