• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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.managedprovisioning.finalization;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
21 
22 import static com.android.internal.util.Preconditions.checkNotNull;
23 
24 import android.annotation.IntDef;
25 import android.app.NotificationManager;
26 import android.content.Context;
27 import android.os.Bundle;
28 import android.os.UserManager;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.managedprovisioning.analytics.DeferredMetricsReader;
32 import com.android.managedprovisioning.common.NotificationHelper;
33 import com.android.managedprovisioning.common.ProvisionLogger;
34 import com.android.managedprovisioning.common.SettingsFacade;
35 import com.android.managedprovisioning.common.Utils;
36 import com.android.managedprovisioning.model.ProvisioningParams;
37 import com.android.managedprovisioning.provisioning.Constants;
38 
39 import java.io.File;
40 
41 /**
42  * Controller for the finalization of managed provisioning.  This class should be invoked after
43  * {@link PreFinalizationController}.  Provisioning is finalized via calls to
44  * {@link #provisioningFinalized()} and {@link #commitFinalizedState()}.  Different instances of
45  * this class will be tailored to run these two methods at different points in the Setup Wizard user
46  * flows, based on the type of FinalizationControllerLogic they are constructed with.
47  */
48 public final class FinalizationController {
49 
50     static final int PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED = 1;
51     static final int PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED = 2;
52     static final int PROVISIONING_FINALIZED_RESULT_SKIPPED = 3;
53     static final int PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE = 4;
54 
55     @IntDef({
56             PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED,
57             PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED,
58             PROVISIONING_FINALIZED_RESULT_SKIPPED,
59             PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE})
60     @interface ProvisioningFinalizedResult {}
61 
62     private static final int DPC_SETUP_REQUEST_CODE = 1;
63     private static final int FINAL_SCREEN_REQUEST_CODE = 2;
64 
65     private final FinalizationControllerLogic mFinalizationControllerLogic;
66     private final Context mContext;
67     private final Utils mUtils;
68     private final SettingsFacade mSettingsFacade;
69     private final UserProvisioningStateHelper mUserProvisioningStateHelper;
70     private final ProvisioningIntentProvider mProvisioningIntentProvider;
71     private final NotificationHelper mNotificationHelper;
72     private final DeferredMetricsReader mDeferredMetricsReader;
73     private @ProvisioningFinalizedResult int mProvisioningFinalizedResult;
74     private ProvisioningParamsUtils mProvisioningParamsUtils;
75 
FinalizationController(Context context, FinalizationControllerLogic finalizationControllerLogic, UserProvisioningStateHelper userProvisioningStateHelper)76     public FinalizationController(Context context,
77             FinalizationControllerLogic finalizationControllerLogic,
78             UserProvisioningStateHelper userProvisioningStateHelper) {
79         this(
80                 context,
81                 finalizationControllerLogic,
82                 new Utils(),
83                 new SettingsFacade(),
84                 userProvisioningStateHelper,
85                 new NotificationHelper(context),
86                 new DeferredMetricsReader(
87                         Constants.getDeferredMetricsFile(context)),
88                 new ProvisioningParamsUtils(
89                         ProvisioningParamsUtils.DEFAULT_PROVISIONING_PARAMS_FILE_PROVIDER));
90     }
91 
FinalizationController(Context context, FinalizationControllerLogic finalizationControllerLogic)92     public FinalizationController(Context context,
93             FinalizationControllerLogic finalizationControllerLogic) {
94         this(
95                 context,
96                 finalizationControllerLogic,
97                 new Utils(),
98                 new SettingsFacade(),
99                 new UserProvisioningStateHelper(context),
100                 new NotificationHelper(context),
101                 new DeferredMetricsReader(
102                         Constants.getDeferredMetricsFile(context)),
103                 new ProvisioningParamsUtils(
104                         ProvisioningParamsUtils.DEFAULT_PROVISIONING_PARAMS_FILE_PROVIDER));
105     }
106 
107     @VisibleForTesting
FinalizationController(Context context, FinalizationControllerLogic finalizationControllerLogic, Utils utils, SettingsFacade settingsFacade, UserProvisioningStateHelper helper, NotificationHelper notificationHelper, DeferredMetricsReader deferredMetricsReader, ProvisioningParamsUtils provisioningParamsUtils)108     FinalizationController(Context context,
109             FinalizationControllerLogic finalizationControllerLogic,
110             Utils utils,
111             SettingsFacade settingsFacade,
112             UserProvisioningStateHelper helper,
113             NotificationHelper notificationHelper,
114             DeferredMetricsReader deferredMetricsReader,
115             ProvisioningParamsUtils provisioningParamsUtils) {
116         mContext = checkNotNull(context);
117         mFinalizationControllerLogic = checkNotNull(finalizationControllerLogic);
118         mUtils = checkNotNull(utils);
119         mSettingsFacade = checkNotNull(settingsFacade);
120         mUserProvisioningStateHelper = checkNotNull(helper);
121         mProvisioningIntentProvider = new ProvisioningIntentProvider();
122         mNotificationHelper = checkNotNull(notificationHelper);
123         mDeferredMetricsReader = checkNotNull(deferredMetricsReader);
124         mProvisioningParamsUtils = provisioningParamsUtils;
125     }
126 
127     @VisibleForTesting
getPrimaryProfileFinalizationHelper( ProvisioningParams params)128     PrimaryProfileFinalizationHelper getPrimaryProfileFinalizationHelper(
129             ProvisioningParams params) {
130         return new PrimaryProfileFinalizationHelper(params.accountToMigrate,
131                 mUtils.getManagedProfile(mContext), params.inferDeviceAdminPackageName());
132     }
133 
134     /**
135      * This method is invoked when provisioning is finalized.
136      *
137      * <p>This method has to be invoked after
138      * {@link PreFinalizationController#deviceManagementEstablished(ProvisioningParams)}
139      * was called. It is commonly invoked at the end of the setup flow, if provisioning occurs
140      * during the setup flow. It loads the provisioning params from the storage, notifies the DPC
141      * about the completed provisioning and sets the right user provisioning states.
142      *
143      * <p>To retrieve the resulting state of this method, use
144      * {@link #getProvisioningFinalizedResult()}
145      *
146      * <p>This method may be called multiple times.  {@link #commitFinalizedState()} ()} must be
147      * called after the final call to this method.  If this method is called again after that, it
148      * will return immediately without taking any action.
149      */
provisioningFinalized()150     void provisioningFinalized() {
151         mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_SKIPPED;
152 
153         if (mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) {
154             ProvisionLogger.logw("provisioningFinalized called, but state is finalized or "
155                     + "unmanaged");
156             return;
157         }
158 
159         final ProvisioningParams params = loadProvisioningParams();
160         if (params == null) {
161             ProvisionLogger.logw("FinalizationController invoked, but no stored params");
162             return;
163         }
164 
165         mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED;
166         if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
167             UserManager userManager = mContext.getSystemService(UserManager.class);
168             if (!userManager.isUserUnlocked(mUtils.getManagedProfile(mContext))) {
169                 mProvisioningFinalizedResult =
170                         PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE;
171             } else {
172                 mProvisioningFinalizedResult =
173                         mFinalizationControllerLogic.notifyDpcManagedProfile(
174                                 params, DPC_SETUP_REQUEST_CODE);
175             }
176         } else {
177             mProvisioningFinalizedResult =
178                     mFinalizationControllerLogic.notifyDpcManagedDeviceOrUser(
179                             params, DPC_SETUP_REQUEST_CODE);
180         }
181     }
182 
183     /**
184      * @throws IllegalStateException if {@link #provisioningFinalized()} was not called before.
185      */
getProvisioningFinalizedResult()186     @ProvisioningFinalizedResult int getProvisioningFinalizedResult() {
187         if (mProvisioningFinalizedResult == 0) {
188             throw new IllegalStateException("provisioningFinalized() has not been called.");
189         }
190         return mProvisioningFinalizedResult;
191     }
192 
193     @VisibleForTesting
clearParamsFile()194     void clearParamsFile() {
195         final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mContext);
196         if (file != null) {
197             file.delete();
198         }
199     }
200 
loadProvisioningParams()201     private ProvisioningParams loadProvisioningParams() {
202         final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mContext);
203         return ProvisioningParams.load(file);
204     }
205 
206     /**
207      * Update the system's provisioning state, and commit any other irreversible changes that
208      * must wait until finalization is 100% completed.
209      */
commitFinalizedState(ProvisioningParams params)210     private void commitFinalizedState(ProvisioningParams params) {
211         if (ACTION_PROVISION_MANAGED_DEVICE.equals(params.provisioningAction)) {
212             mNotificationHelper.showPrivacyReminderNotification(
213                     mContext, NotificationManager.IMPORTANCE_DEFAULT);
214         } else if (ACTION_PROVISION_MANAGED_PROFILE.equals(params.provisioningAction)
215                 && mFinalizationControllerLogic.shouldFinalizePrimaryProfile(params)) {
216             getPrimaryProfileFinalizationHelper(params)
217                     .finalizeProvisioningInPrimaryProfile(mContext, null);
218         }
219 
220         mUserProvisioningStateHelper.markUserProvisioningStateFinalized(params);
221 
222         mDeferredMetricsReader.scheduleDumpMetrics(mContext);
223         clearParamsFile();
224     }
225 
226     /**
227      * This method is called by the parent activity to force the final commit of all state changes.
228      * After this is called, any further calls to {@link #provisioningFinalized()} will return
229      * immediately without taking any action.
230      */
commitFinalizedState()231     void commitFinalizedState() {
232         final ProvisioningParams params = loadProvisioningParams();
233         if (params == null) {
234             ProvisionLogger.logw(
235                     "Attempt to commitFinalizedState when params have already been deleted");
236         } else {
237             commitFinalizedState(loadProvisioningParams());
238         }
239     }
240 
241     /**
242      * This method is called when onSaveInstanceState() executes on the finalization activity.
243      */
saveInstanceState(Bundle outState)244     void saveInstanceState(Bundle outState) {
245         mFinalizationControllerLogic.saveInstanceState(outState);
246     }
247 
248     /**
249      * When saved instance state is passed to the finalization activity in its onCreate() method,
250      * that state is passed to the FinalizationControllerLogic object here so it can be restored.
251      */
restoreInstanceState(Bundle savedInstanceState)252     void restoreInstanceState(Bundle savedInstanceState) {
253         mFinalizationControllerLogic.restoreInstanceState(savedInstanceState,
254                 loadProvisioningParams());
255     }
256 
257     /**
258      * Cleanup that must happen when the finalization activity is destroyed, even if we haven't yet
259      * called {@link #commitFinalizedState()} to finalize the system's provisioning state.
260      */
activityDestroyed(boolean isFinishing)261     void activityDestroyed(boolean isFinishing) {
262         mFinalizationControllerLogic.activityDestroyed(isFinishing);
263     }
264 }
265