BackgroundDexOptService.java revision 2c9655b3d4c1fb0687baa14730c6d97ab5a56789
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.pm; 18 19import android.app.AlarmManager; 20import android.app.job.JobInfo; 21import android.app.job.JobParameters; 22import android.app.job.JobScheduler; 23import android.app.job.JobService; 24import android.content.ComponentName; 25import android.content.Context; 26import android.os.ServiceManager; 27import android.util.ArraySet; 28import android.util.Log; 29 30import java.util.concurrent.atomic.AtomicBoolean; 31 32/** 33 * {@hide} 34 */ 35public class BackgroundDexOptService extends JobService { 36 static final String TAG = "BackgroundDexOptService"; 37 38 static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR; 39 40 static final int BACKGROUND_DEXOPT_JOB = 800; 41 private static ComponentName sDexoptServiceName = new ComponentName( 42 "android", 43 BackgroundDexOptService.class.getName()); 44 45 /** 46 * Set of failed packages remembered across job runs. 47 */ 48 static final ArraySet<String> sFailedPackageNames = new ArraySet<String>(); 49 50 final AtomicBoolean mIdleTime = new AtomicBoolean(false); 51 52 public static void schedule(Context context, long minLatency) { 53 JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 54 JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName) 55 .setRequiresDeviceIdle(true) 56 .setRequiresCharging(true) 57 .setMinimumLatency(minLatency) 58 .build(); 59 js.schedule(job); 60 } 61 62 @Override 63 public boolean onStartJob(JobParameters params) { 64 Log.i(TAG, "onIdleStart"); 65 final PackageManagerService pm = 66 (PackageManagerService)ServiceManager.getService("package"); 67 68 if (pm.isStorageLow()) { 69 schedule(BackgroundDexOptService.this, RETRY_LATENCY); 70 return false; 71 } 72 final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt(); 73 if (pkgs == null) { 74 return false; 75 } 76 77 final JobParameters jobParams = params; 78 mIdleTime.set(true); 79 new Thread("BackgroundDexOptService_DexOpter") { 80 @Override 81 public void run() { 82 for (String pkg : pkgs) { 83 if (!mIdleTime.get()) { 84 // stopped while still working, so we need to reschedule 85 schedule(BackgroundDexOptService.this, 0); 86 return; 87 } 88 if (sFailedPackageNames.contains(pkg)) { 89 // skip previously failing package 90 continue; 91 } 92 if (!pm.performDexOpt(pkg, null /* instruction set */, true)) { 93 // there was a problem running dexopt, 94 // remember this so we do not keep retrying. 95 sFailedPackageNames.add(pkg); 96 } 97 } 98 // ran to completion, so we abandon our timeslice and do not reschedule 99 jobFinished(jobParams, false); 100 } 101 }.start(); 102 return true; 103 } 104 105 @Override 106 public boolean onStopJob(JobParameters params) { 107 Log.i(TAG, "onIdleStop"); 108 mIdleTime.set(false); 109 return false; 110 } 111} 112