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 2157a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackbornimport android.app.ActivityManagerNative; 227060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobInfo; 237060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobParameters; 247060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobScheduler; 257060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobService; 26115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tateimport android.content.ComponentName; 27115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tateimport android.content.Context; 2857a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackbornimport android.os.RemoteException; 29d417d625d244356bc770e2692fd59e754a72f59fChristopher Tateimport android.util.Slog; 30d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 317060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tatepublic class MountServiceIdler extends JobService { 32d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate private static final String TAG = "MountServiceIdler"; 33d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 34115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate private static ComponentName sIdleService = 35f8ad7a909436250fed920a8c4c56f69cd97b1b60Christopher Tate new ComponentName("android", MountServiceIdler.class.getName()); 36115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 377060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private static int MOUNT_JOB_ID = 808; 38115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 39115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate private boolean mStarted; 407060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private JobParameters mJobParams; 41d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate private Runnable mFinishCallback = new Runnable() { 42d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate @Override 43d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate public void run() { 44d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate Slog.i(TAG, "Got mount service completion callback"); 45115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate synchronized (mFinishCallback) { 46115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate if (mStarted) { 477060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate jobFinished(mJobParams, false); 48115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate mStarted = false; 49115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 50115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 51115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate // ... and try again tomorrow 52115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate scheduleIdlePass(MountServiceIdler.this); 53d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 54d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate }; 55d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 56d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate @Override 577060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public boolean onStartJob(JobParameters params) { 5857a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn // First have the activity manager do its idle maintenance. (Yes this job 5957a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn // is really more than just mount, some day it should be renamed to be system 6057a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn // idleer). 6157a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn try { 6257a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn ActivityManagerNative.getDefault().performIdleMaintenance(); 6357a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn } catch (RemoteException e) { 6457a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn } 65d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // The mount service will run an fstrim operation asynchronously 66d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // on a designated separate thread, so we provide it with a callback 67d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // that lets us cleanly end our idle timeslice. It's safe to call 68d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate // finishIdle() from any thread. 697060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate mJobParams = params; 70d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate MountService ms = MountService.sSelf; 71d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate if (ms != null) { 72115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate synchronized (mFinishCallback) { 73115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate mStarted = true; 74115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 75d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate ms.runIdleMaintenance(mFinishCallback); 76d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 77d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate return ms != null; 78d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 79d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate 80d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate @Override 817060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public boolean onStopJob(JobParameters params) { 82115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate // Once we kick off the fstrim we aren't actually interruptible; just note 837060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate // that we don't need to call jobFinished(), and let everything happen in 84115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate // the callback from the mount service. 85115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate synchronized (mFinishCallback) { 86115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate mStarted = false; 87115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 88115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate return false; 89115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 90115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 91115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate /** 92115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate * Schedule the idle job that will ping the mount service 93115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate */ 94115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate public static void scheduleIdlePass(Context context) { 957060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 96115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 97115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate Calendar calendar = tomorrowMidnight(); 98115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis(); 99115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 1007060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); 101115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate builder.setRequiresDeviceIdle(true); 102115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate builder.setRequiresCharging(true); 103115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate builder.setMinimumLatency(timeToMidnight); 104115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate tm.schedule(builder.build()); 105115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate } 106115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate 107115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate private static Calendar tomorrowMidnight() { 108115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate Calendar calendar = Calendar.getInstance(); 109115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.setTimeInMillis(System.currentTimeMillis()); 11057a873fcaa4dd95fc844887b0c255f650b9159e5Dianne Hackborn calendar.set(Calendar.HOUR_OF_DAY, 3); 111115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.MINUTE, 0); 112115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.SECOND, 0); 113115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.set(Calendar.MILLISECOND, 0); 114115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate calendar.add(Calendar.DAY_OF_MONTH, 1); 115115afdadb5863a02f0b0daefcc0511bfd35b531eChristopher Tate return calendar; 116d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate } 117d417d625d244356bc770e2692fd59e754a72f59fChristopher Tate} 118