1 /* 2 * Copyright (C) 2016 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.phone.vvm.omtp.scheduling; 18 19 import android.annotation.CallSuper; 20 import android.annotation.MainThread; 21 import android.annotation.WorkerThread; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.os.SystemClock; 25 import android.support.annotation.NonNull; 26 import android.telephony.SubscriptionManager; 27 import com.android.phone.Assert; 28 import com.android.phone.NeededForTesting; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * Provides common utilities for task implementations, such as execution time and managing {@link 34 * Policy} 35 */ 36 public abstract class BaseTask implements Task { 37 38 private static final String EXTRA_SUB_ID = "extra_sub_id"; 39 40 private Context mContext; 41 42 private int mId; 43 private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 44 45 private boolean mHasStarted; 46 private volatile boolean mHasFailed; 47 48 @NonNull 49 private final List<Policy> mPolicies = new ArrayList<>(); 50 51 private long mExecutionTime; 52 53 private static Clock sClock = new Clock(); 54 BaseTask(int id)55 protected BaseTask(int id) { 56 mId = id; 57 mExecutionTime = getTimeMillis(); 58 } 59 60 /** 61 * Modify the task ID to prevent arbitrary task from executing. Can only be called before {@link 62 * #onCreate(Context, Intent, int, int)} returns. 63 */ 64 @MainThread setId(int id)65 public void setId(int id) { 66 Assert.isMainThread(); 67 mId = id; 68 } 69 70 @MainThread hasStarted()71 public boolean hasStarted() { 72 Assert.isMainThread(); 73 return mHasStarted; 74 } 75 76 @MainThread hasFailed()77 public boolean hasFailed() { 78 Assert.isMainThread(); 79 return mHasFailed; 80 } 81 getContext()82 public Context getContext() { 83 return mContext; 84 } 85 getSubId()86 public int getSubId() { 87 return mSubId; 88 } 89 /** 90 * Should be call in the constructor or {@link Policy#onCreate(BaseTask, Intent, int, int)} will 91 * be missed. 92 */ 93 @MainThread addPolicy(Policy policy)94 public BaseTask addPolicy(Policy policy) { 95 Assert.isMainThread(); 96 mPolicies.add(policy); 97 return this; 98 } 99 100 /** 101 * Indicate the task has failed. {@link Policy#onFail()} will be triggered once the execution 102 * ends. This mechanism is used by policies for actions such as determining whether to schedule 103 * a retry. Must be call inside {@link #onExecuteInBackgroundThread()} 104 */ 105 @WorkerThread fail()106 public void fail() { 107 Assert.isNotMainThread(); 108 mHasFailed = true; 109 } 110 111 @MainThread setExecutionTime(long timeMillis)112 public void setExecutionTime(long timeMillis) { 113 Assert.isMainThread(); 114 mExecutionTime = timeMillis; 115 } 116 getTimeMillis()117 public long getTimeMillis() { 118 return sClock.getTimeMillis(); 119 } 120 121 /** 122 * Creates an intent that can be used to restart the current task. Derived class should build 123 * their intent upon this. 124 */ createRestartIntent()125 public Intent createRestartIntent() { 126 return createIntent(getContext(), this.getClass(), mSubId); 127 } 128 129 /** 130 * Creates an intent that can be used to start the {@link TaskSchedulerService}. Derived class 131 * should build their intent upon this. 132 */ createIntent(Context context, Class<? extends BaseTask> task, int subId)133 public static Intent createIntent(Context context, Class<? extends BaseTask> task, int subId) { 134 Intent intent = TaskSchedulerService.createIntent(context, task); 135 intent.putExtra(EXTRA_SUB_ID, subId); 136 return intent; 137 } 138 139 @Override getId()140 public TaskId getId() { 141 return new TaskId(mId, mSubId); 142 } 143 144 @Override 145 @CallSuper onCreate(Context context, Intent intent, int flags, int startId)146 public void onCreate(Context context, Intent intent, int flags, int startId) { 147 mContext = context; 148 mSubId = intent.getIntExtra(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 149 for (Policy policy : mPolicies) { 150 policy.onCreate(this, intent, flags, startId); 151 } 152 } 153 154 @Override getReadyInMilliSeconds()155 public long getReadyInMilliSeconds() { 156 return mExecutionTime - getTimeMillis(); 157 } 158 159 @Override 160 @CallSuper onBeforeExecute()161 public void onBeforeExecute() { 162 for (Policy policy : mPolicies) { 163 policy.onBeforeExecute(); 164 } 165 mHasStarted = true; 166 } 167 168 @Override 169 @CallSuper onCompleted()170 public void onCompleted() { 171 if (mHasFailed) { 172 for (Policy policy : mPolicies) { 173 policy.onFail(); 174 } 175 } 176 177 for (Policy policy : mPolicies) { 178 policy.onCompleted(); 179 } 180 } 181 182 @Override onDuplicatedTaskAdded(Task task)183 public void onDuplicatedTaskAdded(Task task) { 184 for (Policy policy : mPolicies) { 185 policy.onDuplicatedTaskAdded(); 186 } 187 } 188 189 @NeededForTesting 190 static class Clock { 191 getTimeMillis()192 public long getTimeMillis() { 193 return SystemClock.elapsedRealtime(); 194 } 195 } 196 197 /** 198 * Used to replace the clock with an deterministic clock 199 */ 200 @NeededForTesting setClockForTesting(Clock clock)201 static void setClockForTesting(Clock clock) { 202 sClock = clock; 203 } 204 } 205