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