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