MountServiceIdler.java revision f8ad7a909436250fed920a8c4c56f69cd97b1b60
1d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate/* 2d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * Copyright (C) 2014 The Android Open Source Project 3d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * 4d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * Licensed under the Apache License, Version 2.0 (the "License"); 5d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * you may not use this file except in compliance with the License. 6d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * You may obtain a copy of the License at 7d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * 8d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * http://www.apache.org/licenses/LICENSE-2.0 9d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * 10d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * Unless required by applicable law or agreed to in writing, software 11d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * distributed under the License is distributed on an "AS IS" BASIS, 12d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * See the License for the specific language governing permissions and 14d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate * limitations under the License. 15d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate */ 16d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 17d417d625d244356bc770e2692fd59e754a72f59fChristopher Tatepackage com.android.server; 18d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 19115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tateimport java.util.Calendar; 20115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 217060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobInfo; 227060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobParameters; 237060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobScheduler; 247060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobService; 25115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tateimport android.content.ComponentName; 26115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tateimport android.content.Context; 27d417d625d244356bc770e2692fd59e754a72f59fChristopher Tateimport android.util.Slog; 28d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 297060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tatepublic class MountServiceIdler extends JobService { 30d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate private static final String TAG = "MountServiceIdler"; 31d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 32115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate private static ComponentName sIdleService = 33f8ad7a909436250fed920a8c4c56f69cd97b1b60Christopher Tate new ComponentName("android", MountServiceIdler.class.getName()); 34115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 357060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private static int MOUNT_JOB_ID = 808; 36115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 37115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate private boolean mStarted; 387060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private JobParameters mJobParams; 39d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate private Runnable mFinishCallback = new Runnable() { 40d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate @Override 41d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate public void run() { 42d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate Slog.i(TAG, "Got mount service completion callback"); 43115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate synchronized (mFinishCallback) { 44115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate if (mStarted) { 457060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate jobFinished(mJobParams, false); 46115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate mStarted = false; 47115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 48115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 49115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate // ... and try again tomorrow 50115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate scheduleIdlePass(MountServiceIdler.this); 51d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 52d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate }; 53d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 54d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate @Override 557060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public boolean onStartJob(JobParameters params) { 56d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // The mount service will run an fstrim operation asynchronously 57d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // on a designated separate thread, so we provide it with a callback 58d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // that lets us cleanly end our idle timeslice. It's safe to call 59d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // finishIdle() from any thread. 607060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate mJobParams = params; 61d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate MountService ms = MountService.sSelf; 62d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate if (ms != null) { 63115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate synchronized (mFinishCallback) { 64115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate mStarted = true; 65115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 66d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate ms.runIdleMaintenance(mFinishCallback); 67d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 68d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate return ms != null; 69d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 70d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 71d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate @Override 727060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public boolean onStopJob(JobParameters params) { 73115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate // Once we kick off the fstrim we aren't actually interruptible; just note 747060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate // that we don't need to call jobFinished(), and let everything happen in 75115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate // the callback from the mount service. 76115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate synchronized (mFinishCallback) { 77115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate mStarted = false; 78115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 79115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate return false; 80115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 81115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 82115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate /** 83115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate * Schedule the idle job that will ping the mount service 84115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate */ 85115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate public static void scheduleIdlePass(Context context) { 867060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 87115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 88115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate Calendar calendar = tomorrowMidnight(); 89115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis(); 90115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 917060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); 92115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate builder.setRequiresDeviceIdle(true); 93115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate builder.setRequiresCharging(true); 94115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate builder.setMinimumLatency(timeToMidnight); 95115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate tm.schedule(builder.build()); 96115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 97115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 98115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate private static Calendar tomorrowMidnight() { 99115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate Calendar calendar = Calendar.getInstance(); 100115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.setTimeInMillis(System.currentTimeMillis()); 101115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.HOUR, 0); 102115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.MINUTE, 0); 103115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.SECOND, 0); 104115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.MILLISECOND, 0); 105115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.add(Calendar.DAY_OF_MONTH, 1); 106115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate return calendar; 107d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 108d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate} 109