1 /* 2 * Copyright 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.managedprovisioning.provisioning; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.annotation.MainThread; 22 import android.content.Context; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.Looper; 26 import android.os.Message; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 30 import com.android.managedprovisioning.common.ProvisionLogger; 31 import com.android.managedprovisioning.finalization.FinalizationController; 32 import com.android.managedprovisioning.model.ProvisioningParams; 33 import com.android.managedprovisioning.task.AbstractProvisioningTask; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * Controller that manages the provisioning process. It controls the order of provisioning tasks, 40 * reacts to errors and user cancellation. 41 */ 42 public abstract class AbstractProvisioningController implements AbstractProvisioningTask.Callback { 43 44 @VisibleForTesting 45 static final int MSG_RUN_TASK = 1; 46 47 protected final Context mContext; 48 protected final ProvisioningParams mParams; 49 protected int mUserId; 50 51 private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker; 52 private final ProvisioningControllerCallback mCallback; 53 private final FinalizationController mFinalizationController; 54 private Handler mWorkerHandler; 55 56 // Provisioning hasn't started yet 57 private static final int STATUS_NOT_STARTED = 0; 58 // Provisioning tasks are being run 59 private static final int STATUS_RUNNING = 1; 60 // Provisioning tasks have completed 61 private static final int STATUS_TASKS_COMPLETED = 2; 62 // Prefinalization has completed 63 private static final int STATUS_DONE = 3; 64 // An error occurred during provisioning 65 private static final int STATUS_ERROR = 4; 66 // Provisioning is being cancelled 67 private static final int STATUS_CANCELLING = 5; 68 // Cleanup has completed. This happens after STATUS_ERROR or STATUS_CANCELLING 69 private static final int STATUS_CLEANED_UP = 6; 70 71 private int mStatus = STATUS_NOT_STARTED; 72 private List<AbstractProvisioningTask> mTasks = new ArrayList<>(); 73 74 protected int mCurrentTaskIndex; 75 AbstractProvisioningController( Context context, ProvisioningParams params, int userId, ProvisioningControllerCallback callback, FinalizationController finalizationController)76 AbstractProvisioningController( 77 Context context, 78 ProvisioningParams params, 79 int userId, 80 ProvisioningControllerCallback callback, 81 FinalizationController finalizationController) { 82 mContext = checkNotNull(context); 83 mParams = checkNotNull(params); 84 mUserId = userId; 85 mCallback = checkNotNull(callback); 86 mFinalizationController = checkNotNull(finalizationController); 87 mProvisioningAnalyticsTracker = ProvisioningAnalyticsTracker.getInstance(); 88 89 setUpTasks(); 90 } 91 92 @MainThread addTasks(AbstractProvisioningTask... tasks)93 protected synchronized void addTasks(AbstractProvisioningTask... tasks) { 94 for (AbstractProvisioningTask task : tasks) { 95 mTasks.add(task); 96 } 97 } 98 setUpTasks()99 protected abstract void setUpTasks(); performCleanup()100 protected abstract void performCleanup(); getErrorTitle()101 protected abstract int getErrorTitle(); getErrorMsgId(AbstractProvisioningTask task, int errorCode)102 protected abstract int getErrorMsgId(AbstractProvisioningTask task, int errorCode); getRequireFactoryReset(AbstractProvisioningTask task, int errorCode)103 protected abstract boolean getRequireFactoryReset(AbstractProvisioningTask task, int errorCode); 104 105 /** 106 * Start the provisioning process. The tasks loaded in {@link #setUpTasks()} ()} will be 107 * processed one by one and the respective callbacks will be given to the UI. 108 */ 109 @MainThread start(Looper looper)110 public synchronized void start(Looper looper) { 111 start(new ProvisioningTaskHandler(looper)); 112 } 113 114 @VisibleForTesting start(Handler handler)115 void start(Handler handler) { 116 if (mStatus != STATUS_NOT_STARTED) { 117 return; 118 } 119 mWorkerHandler = checkNotNull(handler); 120 121 mStatus = STATUS_RUNNING; 122 runTask(0); 123 } 124 125 /** 126 * Cancel the provisioning progress. When the cancellation is complete, the 127 * {@link ProvisioningControllerCallback#cleanUpCompleted()} callback will be given. 128 */ 129 @MainThread cancel()130 public synchronized void cancel() { 131 if (mStatus != STATUS_RUNNING 132 && mStatus != STATUS_TASKS_COMPLETED 133 && mStatus != STATUS_CANCELLING 134 && mStatus != STATUS_CLEANED_UP 135 && mStatus != STATUS_ERROR) { 136 ProvisionLogger.logd("Cancel called, but status is " + mStatus); 137 return; 138 } 139 140 ProvisionLogger.logd("ProvisioningController: cancelled"); 141 mStatus = STATUS_CANCELLING; 142 cleanup(STATUS_CLEANED_UP); 143 } 144 145 @MainThread preFinalize()146 public synchronized void preFinalize() { 147 if (mStatus != STATUS_TASKS_COMPLETED) { 148 return; 149 } 150 151 mStatus = STATUS_DONE; 152 mFinalizationController.provisioningInitiallyDone(mParams); 153 mCallback.preFinalizationCompleted(); 154 } 155 runTask(int index)156 private void runTask(int index) { 157 AbstractProvisioningTask nextTask = mTasks.get(index); 158 Message msg = mWorkerHandler.obtainMessage(MSG_RUN_TASK, mUserId, 0 /* arg2 not used */, 159 nextTask); 160 mWorkerHandler.sendMessage(msg); 161 mCallback.progressUpdate(nextTask.getStatusMsgId()); 162 } 163 tasksCompleted()164 private void tasksCompleted() { 165 mStatus = STATUS_TASKS_COMPLETED; 166 mCurrentTaskIndex = -1; 167 mCallback.provisioningTasksCompleted(); 168 } 169 170 @Override 171 // Note that this callback might come on the main thread onSuccess(AbstractProvisioningTask task)172 public synchronized void onSuccess(AbstractProvisioningTask task) { 173 if (mStatus != STATUS_RUNNING) { 174 return; 175 } 176 177 mCurrentTaskIndex++; 178 if (mCurrentTaskIndex == mTasks.size()) { 179 tasksCompleted(); 180 } else { 181 runTask(mCurrentTaskIndex); 182 } 183 } 184 185 @Override 186 // Note that this callback might come on the main thread onError(AbstractProvisioningTask task, int errorCode)187 public synchronized void onError(AbstractProvisioningTask task, int errorCode) { 188 mStatus = STATUS_ERROR; 189 cleanup(STATUS_ERROR); 190 mProvisioningAnalyticsTracker.logProvisioningError(mContext, task, errorCode); 191 mCallback.error(getErrorTitle(), getErrorMsgId(task, errorCode), 192 getRequireFactoryReset(task, errorCode)); 193 } 194 cleanup(final int newStatus)195 private void cleanup(final int newStatus) { 196 mWorkerHandler.post(() -> { 197 performCleanup(); 198 mStatus = newStatus; 199 mCallback.cleanUpCompleted(); 200 }); 201 } 202 203 /** 204 * Handler that runs the provisioning tasks. 205 * 206 * <p>We're using a {@link HandlerThread} for all the provisioning tasks in order to not 207 * block the UI thread.</p> 208 */ 209 protected static class ProvisioningTaskHandler extends Handler { ProvisioningTaskHandler(Looper looper)210 public ProvisioningTaskHandler(Looper looper) { 211 super(looper); 212 } 213 handleMessage(Message msg)214 public void handleMessage(Message msg) { 215 if (msg.what == MSG_RUN_TASK) { 216 AbstractProvisioningTask task = (AbstractProvisioningTask) msg.obj; 217 ProvisionLogger.logd("Running task: " + task.getClass().getSimpleName()); 218 task.run(msg.arg1); 219 } else { 220 ProvisionLogger.loge("Unknown message: " + msg.what); 221 } 222 } 223 } 224 } 225