1 /* 2 * Copyright (C) 2019 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 17 package com.android.server.connectivity.ipmemorystore; 18 19 import android.app.job.JobInfo; 20 import android.app.job.JobParameters; 21 import android.app.job.JobScheduler; 22 import android.app.job.JobService; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.net.ipmemorystore.IOnStatusListener; 26 import android.net.ipmemorystore.Status; 27 import android.net.ipmemorystore.StatusParcelable; 28 import android.os.IBinder; 29 import android.os.RemoteException; 30 import android.util.Log; 31 32 import java.util.ArrayList; 33 import java.util.concurrent.TimeUnit; 34 35 /** 36 * Regular maintenance job service. 37 * @hide 38 */ 39 public final class RegularMaintenanceJobService extends JobService { 40 // Must be unique within the system server uid. 41 public static final int REGULAR_MAINTENANCE_ID = 3345678; 42 43 /** 44 * Class for interrupt check of maintenance job. 45 */ 46 public static final class InterruptMaintenance { 47 private volatile boolean mIsInterrupted; 48 private final int mJobId; 49 InterruptMaintenance(int jobId)50 public InterruptMaintenance(int jobId) { 51 mJobId = jobId; 52 mIsInterrupted = false; 53 } 54 getJobId()55 public int getJobId() { 56 return mJobId; 57 } 58 setInterrupted(boolean interrupt)59 public void setInterrupted(boolean interrupt) { 60 mIsInterrupted = interrupt; 61 } 62 isInterrupted()63 public boolean isInterrupted() { 64 return mIsInterrupted; 65 } 66 } 67 68 private static final ArrayList<InterruptMaintenance> sInterruptList = new ArrayList<>(); 69 private static IpMemoryStoreService sIpMemoryStoreService; 70 71 @Override onStartJob(JobParameters params)72 public boolean onStartJob(JobParameters params) { 73 if (sIpMemoryStoreService == null) { 74 Log.wtf("RegularMaintenanceJobService", 75 "Can not start job because sIpMemoryStoreService is null."); 76 return false; 77 } 78 final InterruptMaintenance im = new InterruptMaintenance(params.getJobId()); 79 sInterruptList.add(im); 80 81 sIpMemoryStoreService.fullMaintenance(new IOnStatusListener() { 82 @Override 83 public void onComplete(final StatusParcelable statusParcelable) throws RemoteException { 84 final Status result = new Status(statusParcelable); 85 if (!result.isSuccess()) { 86 Log.e("RegularMaintenanceJobService", "Regular maintenance failed." 87 + " Error is " + result.resultCode); 88 } 89 sInterruptList.remove(im); 90 jobFinished(params, !result.isSuccess()); 91 } 92 93 @Override 94 public int getInterfaceVersion() { 95 return this.VERSION; 96 } 97 98 @Override 99 public String getInterfaceHash() { 100 return this.HASH; 101 } 102 103 @Override 104 public IBinder asBinder() { 105 return null; 106 } 107 }, im); 108 return true; 109 } 110 111 @Override onStopJob(JobParameters params)112 public boolean onStopJob(JobParameters params) { 113 final int jobId = params.getJobId(); 114 for (InterruptMaintenance im : sInterruptList) { 115 if (im.getJobId() == jobId) { 116 im.setInterrupted(true); 117 } 118 } 119 return true; 120 } 121 122 /** Schedule regular maintenance job */ schedule(Context context, IpMemoryStoreService ipMemoryStoreService)123 static void schedule(Context context, IpMemoryStoreService ipMemoryStoreService) { 124 final JobScheduler jobScheduler = 125 (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 126 127 final ComponentName maintenanceJobName = 128 new ComponentName(context, RegularMaintenanceJobService.class); 129 130 // Regular maintenance is scheduled for when the device is idle with access power and a 131 // minimum interval of one day. 132 final JobInfo regularMaintenanceJob = 133 new JobInfo.Builder(REGULAR_MAINTENANCE_ID, maintenanceJobName) 134 .setRequiresDeviceIdle(true) 135 .setRequiresCharging(true) 136 .setRequiresBatteryNotLow(true) 137 .setPeriodic(TimeUnit.HOURS.toMillis(24)).build(); 138 139 jobScheduler.schedule(regularMaintenanceJob); 140 sIpMemoryStoreService = ipMemoryStoreService; 141 } 142 143 /** Unschedule regular maintenance job */ unschedule(Context context)144 static void unschedule(Context context) { 145 final JobScheduler jobScheduler = 146 (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 147 jobScheduler.cancel(REGULAR_MAINTENANCE_ID); 148 sIpMemoryStoreService = null; 149 } 150 } 151