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.concurrent.CopyOnWriteArrayList; 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 CopyOnWriteArrayList<InterruptMaintenance> sInterruptList = 69 new CopyOnWriteArrayList<>(); 70 private static IpMemoryStoreService sIpMemoryStoreService; 71 72 @Override onStartJob(JobParameters params)73 public boolean onStartJob(JobParameters params) { 74 if (sIpMemoryStoreService == null) { 75 Log.wtf("RegularMaintenanceJobService", 76 "Can not start job because sIpMemoryStoreService is null."); 77 return false; 78 } 79 final InterruptMaintenance im = new InterruptMaintenance(params.getJobId()); 80 sInterruptList.add(im); 81 82 sIpMemoryStoreService.fullMaintenance(new IOnStatusListener() { 83 @Override 84 public void onComplete(final StatusParcelable statusParcelable) throws RemoteException { 85 final Status result = new Status(statusParcelable); 86 if (!result.isSuccess()) { 87 Log.e("RegularMaintenanceJobService", "Regular maintenance failed." 88 + " Error is " + result.resultCode); 89 } 90 sInterruptList.remove(im); 91 jobFinished(params, !result.isSuccess()); 92 } 93 94 @Override 95 public int getInterfaceVersion() { 96 return this.VERSION; 97 } 98 99 @Override 100 public String getInterfaceHash() { 101 return this.HASH; 102 } 103 104 @Override 105 public IBinder asBinder() { 106 return null; 107 } 108 }, im); 109 return true; 110 } 111 112 @Override onStopJob(JobParameters params)113 public boolean onStopJob(JobParameters params) { 114 final int jobId = params.getJobId(); 115 for (InterruptMaintenance im : sInterruptList) { 116 if (im.getJobId() == jobId) { 117 im.setInterrupted(true); 118 } 119 } 120 return true; 121 } 122 123 /** Schedule regular maintenance job */ schedule(Context context, IpMemoryStoreService ipMemoryStoreService)124 static void schedule(Context context, IpMemoryStoreService ipMemoryStoreService) { 125 final JobScheduler jobScheduler = 126 (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 127 128 final ComponentName maintenanceJobName = 129 new ComponentName(context, RegularMaintenanceJobService.class); 130 131 // Regular maintenance is scheduled for when the device is idle with access power and a 132 // minimum interval of one day. 133 final JobInfo regularMaintenanceJob = 134 new JobInfo.Builder(REGULAR_MAINTENANCE_ID, maintenanceJobName) 135 .setRequiresDeviceIdle(true) 136 .setRequiresCharging(true) 137 .setRequiresBatteryNotLow(true) 138 .setPeriodic(TimeUnit.HOURS.toMillis(24)).build(); 139 140 jobScheduler.schedule(regularMaintenanceJob); 141 sIpMemoryStoreService = ipMemoryStoreService; 142 } 143 144 /** Unschedule regular maintenance job */ unschedule(Context context)145 static void unschedule(Context context) { 146 final JobScheduler jobScheduler = 147 (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); 148 jobScheduler.cancel(REGULAR_MAINTENANCE_ID); 149 sIpMemoryStoreService = null; 150 } 151 } 152