BackgroundDexOptService.java revision 27c073796978106746e4a51f2100b29068ab37f6
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; 31import java.util.concurrent.TimeUnit; 32 33/** 34 * {@hide} 35 */ 36public class BackgroundDexOptService extends JobService { 37 static final String TAG = "BackgroundDexOptService"; 38 39 static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR; 40 41 static final int BACKGROUND_DEXOPT_JOB = 800; 42 private static ComponentName sDexoptServiceName = new ComponentName( 43 "android", 44 BackgroundDexOptService.class.getName()); 45 46 /** 47 * Set of failed packages remembered across job runs. 48 */ 49 static final ArraySet<String> sFailedPackageNames = new ArraySet<String>(); 50 51 final AtomicBoolean mIdleTime = new AtomicBoolean(false); 52 53 public static void schedule(Context context, long minLatency) { 54 JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 55 JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName) 56 .setRequiresDeviceIdle(true) 57 .setRequiresCharging(true) 58 .setMinimumLatency(minLatency) 59 .setPeriodic(TimeUnit.DAYS.toMillis(1)) 60 .build(); 61 js.schedule(job); 62 } 63 64 @Override 65 public boolean onStartJob(JobParameters params) { 66 Log.i(TAG, "onIdleStart"); 67 final PackageManagerService pm = 68 (PackageManagerService)ServiceManager.getService("package"); 69 70 if (pm.isStorageLow()) { 71 schedule(BackgroundDexOptService.this, RETRY_LATENCY); 72 return false; 73 } 74 final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt(); 75 if (pkgs == null) { 76 return false; 77 } 78 79 final JobParameters jobParams = params; 80 mIdleTime.set(true); 81 new Thread("BackgroundDexOptService_DexOpter") { 82 @Override 83 public void run() { 84 for (String pkg : pkgs) { 85 if (!mIdleTime.get()) { 86 // stopped while still working, so we need to reschedule 87 schedule(BackgroundDexOptService.this, 0); 88 return; 89 } 90 if (sFailedPackageNames.contains(pkg)) { 91 // skip previously failing package 92 continue; 93 } 94 if (!pm.performDexOpt(pkg, null /* instruction set */)) { 95 // there was a problem running dexopt, 96 // remember this so we do not keep retrying. 97 sFailedPackageNames.add(pkg); 98 } 99 } 100 // ran to completion, so we abandon our timeslice and do not reschedule 101 jobFinished(jobParams, false); 102 } 103 }.start(); 104 return true; 105 } 106 107 @Override 108 public boolean onStopJob(JobParameters params) { 109 Log.i(TAG, "onIdleStop"); 110 mIdleTime.set(false); 111 return false; 112 } 113} 114