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.preprovisioning;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
22 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE;
23 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
24 import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED;
25 import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
26 import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER;
27 import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
28 import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER;
29 import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT;
30 import static android.app.admin.DevicePolicyManager.CODE_OK;
31 import static android.app.admin.DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
32 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
33 
34 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS;
35 import static com.android.internal.util.Preconditions.checkNotNull;
36 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.CANCELLED_BEFORE_PROVISIONING;
37 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
38 
39 import android.annotation.NonNull;
40 import android.annotation.Nullable;
41 import android.app.ActivityManager;
42 import android.app.KeyguardManager;
43 import android.app.admin.DevicePolicyManager;
44 import android.content.ComponentName;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.pm.PackageManager;
48 import android.content.pm.UserInfo;
49 import android.graphics.Bitmap;
50 import android.graphics.BitmapFactory;
51 import android.graphics.drawable.BitmapDrawable;
52 import android.graphics.drawable.Drawable;
53 import android.os.AsyncTask;
54 import android.os.UserManager;
55 import android.service.persistentdata.PersistentDataBlockManager;
56 
57 import com.android.internal.annotations.VisibleForTesting;
58 import com.android.managedprovisioning.R;
59 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
60 import com.android.managedprovisioning.analytics.TimeLogger;
61 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
62 import com.android.managedprovisioning.common.MdmPackageInfo;
63 import com.android.managedprovisioning.common.ProvisionLogger;
64 import com.android.managedprovisioning.common.SettingsFacade;
65 import com.android.managedprovisioning.common.StoreUtils;
66 import com.android.managedprovisioning.common.Utils;
67 import com.android.managedprovisioning.model.CustomizationParams;
68 import com.android.managedprovisioning.model.ProvisioningParams;
69 import com.android.managedprovisioning.parser.MessageParser;
70 import com.android.managedprovisioning.preprovisioning.terms.TermsDocument;
71 import com.android.managedprovisioning.preprovisioning.terms.TermsProvider;
72 
73 import java.util.List;
74 import java.util.stream.Collectors;
75 
76 public class PreProvisioningController {
77     private final Context mContext;
78     private final Ui mUi;
79     private final MessageParser mMessageParser;
80     private final Utils mUtils;
81     private final SettingsFacade mSettingsFacade;
82     private final EncryptionController mEncryptionController;
83 
84     // used system services
85     private final DevicePolicyManager mDevicePolicyManager;
86     private final UserManager mUserManager;
87     private final PackageManager mPackageManager;
88     private final ActivityManager mActivityManager;
89     private final KeyguardManager mKeyguardManager;
90     private final PersistentDataBlockManager mPdbManager;
91     private final TimeLogger mTimeLogger;
92     private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker;
93 
94     private ProvisioningParams mParams;
95 
PreProvisioningController( @onNull Context context, @NonNull Ui ui)96     public PreProvisioningController(
97             @NonNull Context context,
98             @NonNull Ui ui) {
99         this(context, ui,
100                 new TimeLogger(context, PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS),
101                 new MessageParser(context), new Utils(), new SettingsFacade(),
102                 EncryptionController.getInstance(context));
103     }
104 
105     @VisibleForTesting
PreProvisioningController( @onNull Context context, @NonNull Ui ui, @NonNull TimeLogger timeLogger, @NonNull MessageParser parser, @NonNull Utils utils, @NonNull SettingsFacade settingsFacade, @NonNull EncryptionController encryptionController)106     PreProvisioningController(
107             @NonNull Context context,
108             @NonNull Ui ui,
109             @NonNull TimeLogger timeLogger,
110             @NonNull MessageParser parser,
111             @NonNull Utils utils,
112             @NonNull SettingsFacade settingsFacade,
113             @NonNull EncryptionController encryptionController) {
114         mContext = checkNotNull(context, "Context must not be null");
115         mUi = checkNotNull(ui, "Ui must not be null");
116         mTimeLogger = checkNotNull(timeLogger, "Time logger must not be null");
117         mMessageParser = checkNotNull(parser, "MessageParser must not be null");
118         mSettingsFacade = checkNotNull(settingsFacade);
119         mUtils = checkNotNull(utils, "Utils must not be null");
120         mEncryptionController = checkNotNull(encryptionController,
121                 "EncryptionController must not be null");
122 
123         mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
124                 Context.DEVICE_POLICY_SERVICE);
125         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
126         mPackageManager = mContext.getPackageManager();
127         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
128         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
129         mPdbManager = (PersistentDataBlockManager) mContext.getSystemService(
130                 Context.PERSISTENT_DATA_BLOCK_SERVICE);
131         mProvisioningAnalyticsTracker = ProvisioningAnalyticsTracker.getInstance();
132     }
133 
134     interface Ui {
135         /**
136          * Show an error message and cancel provisioning.
137          * @param titleId resource id used to form the user facing error title
138          * @param messageId resource id used to form the user facing error message
139          * @param errorMessage an error message that gets logged for debugging
140          */
showErrorAndClose(Integer titleId, int messageId, String errorMessage)141         void showErrorAndClose(Integer titleId, int messageId, String errorMessage);
142 
143         /**
144          * Request the user to encrypt the device.
145          * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
146          */
requestEncryption(ProvisioningParams params)147         void requestEncryption(ProvisioningParams params);
148 
149         /**
150          * Request the user to choose a wifi network.
151          */
requestWifiPick()152         void requestWifiPick();
153 
154         /**
155          * Initialize the pre provisioning UI
156          * @param layoutRes resource id for the layout
157          * @param titleRes resource id for the title text
158          * @param packageLabel package label
159          * @param packageIcon package icon
160          * @param isProfileOwnerProvisioning false for Device Owner provisioning
161          * @param isComp true if in COMP provisioning mode
162          * @param termsHeaders list of terms headers
163          * @param customization customization parameters
164          */
initiateUi(int layoutRes, int titleRes, @Nullable String packageLabel, @Nullable Drawable packageIcon, boolean isProfileOwnerProvisioning, boolean isComp, @NonNull List<String> termsHeaders, @NonNull CustomizationParams customization)165         void initiateUi(int layoutRes, int titleRes, @Nullable String packageLabel,
166                 @Nullable Drawable packageIcon, boolean isProfileOwnerProvisioning, boolean isComp,
167                 @NonNull List<String> termsHeaders, @NonNull CustomizationParams customization);
168 
169         /**
170          * Start provisioning.
171          * @param userId the id of the user we want to start provisioning on
172          * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
173          */
startProvisioning(int userId, ProvisioningParams params)174         void startProvisioning(int userId, ProvisioningParams params);
175 
176         /**
177          * Show a dialog to delete an existing managed profile.
178          * @param mdmPackageName the {@link ComponentName} of the existing profile's profile owner
179          * @param domainName domain name of the organization which owns the managed profile
180          * @param userId the user id of the existing profile
181          */
showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName, int userId)182         void showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName,
183                 int userId);
184 
185         /**
186          * Show an error dialog indicating that the current launcher does not support managed
187          * profiles and ask the user to choose a different one.
188          */
showCurrentLauncherInvalid()189         void showCurrentLauncherInvalid();
190     }
191 
192     /**
193      * Initiates Profile owner and device owner provisioning.
194      * @param intent Intent that started provisioning.
195      * @param params cached ProvisioningParams if it has been parsed from Intent
196      * @param callingPackage Package that started provisioning.
197      */
initiateProvisioning(Intent intent, ProvisioningParams params, String callingPackage)198     public void initiateProvisioning(Intent intent, ProvisioningParams params,
199             String callingPackage) {
200         mProvisioningAnalyticsTracker.logProvisioningSessionStarted(mContext);
201 
202         if (!checkFactoryResetProtection()) {
203             return;
204         }
205 
206         if (!tryParseParameters(intent, params)) {
207             return;
208         }
209 
210         if (!verifyActionAndCaller(intent, callingPackage)) {
211             return;
212         }
213 
214         // Check whether provisioning is allowed for the current action
215         if (!checkDevicePolicyPreconditions()) {
216             return;
217         }
218 
219         // PO preconditions
220         boolean waitForUserDelete = false;
221         if (isProfileOwnerProvisioning()) {
222             // If there is already a managed profile, setup the profile deletion dialog.
223             int existingManagedProfileUserId = mUtils.alreadyHasManagedProfile(mContext);
224             if (existingManagedProfileUserId != -1) {
225                 ComponentName mdmPackageName = mDevicePolicyManager
226                         .getProfileOwnerAsUser(existingManagedProfileUserId);
227                 String domainName = mDevicePolicyManager
228                         .getProfileOwnerNameAsUser(existingManagedProfileUserId);
229                 mUi.showDeleteManagedProfileDialog(mdmPackageName, domainName,
230                         existingManagedProfileUserId);
231                 waitForUserDelete = true;
232             }
233         }
234 
235         // DO preconditions
236         if (!isProfileOwnerProvisioning()) {
237             // TODO: make a general test based on deviceAdminDownloadInfo field
238             // PO doesn't ever initialize that field, so OK as a general case
239             if (!mUtils.isConnectedToNetwork(mContext) && mParams.wifiInfo == null
240                     && mParams.deviceAdminDownloadInfo != null) {
241                 // Have the user pick a wifi network if necessary.
242                 // It is not possible to ask the user to pick a wifi network if
243                 // the screen is locked.
244                 // TODO: remove this check once we know the screen will not be locked.
245                 if (mKeyguardManager.inKeyguardRestrictedInputMode()) {
246                     // TODO: decide on what to do in that case; fail? retry on screen unlock?
247                     ProvisionLogger.logi("Cannot pick wifi because the screen is locked.");
248                 } else if (canRequestWifiPick()) {
249                     // we resume this method after a successful WiFi pick
250                     // TODO: refactor as evil - logic should be less spread out
251                     mUi.requestWifiPick();
252                     return;
253                 } else {
254                     mUi.showErrorAndClose(R.string.cant_set_up_device,
255                             R.string.contact_your_admin_for_help,
256                             "Cannot pick WiFi because there is no handler to the intent");
257                 }
258             }
259         }
260 
261         mTimeLogger.start();
262         mProvisioningAnalyticsTracker.logPreProvisioningStarted(mContext, intent);
263 
264         // as of now this is only true for COMP provisioning, where we already have a user consent
265         // since the DPC is DO already
266         if (mParams.skipUserConsent || isSilentProvisioningForTestingDeviceOwner()
267                 || isSilentProvisioningForTestingManagedProfile()) {
268             if (!waitForUserDelete) {
269                 continueProvisioningAfterUserConsent();
270             }
271             return;
272         }
273 
274         CustomizationParams customization = CustomizationParams.createInstance(mParams, mContext,
275                 mUtils);
276 
277         // show UI so we can get user's consent to continue
278         if (isProfileOwnerProvisioning()) {
279             boolean isComp = mDevicePolicyManager.isDeviceManaged();
280             mUi.initiateUi(R.layout.intro_profile_owner, R.string.setup_profile, null, null, true,
281                     isComp, getDisclaimerHeadings(), customization);
282         } else {
283             String packageName = mParams.inferDeviceAdminPackageName();
284             MdmPackageInfo packageInfo = MdmPackageInfo.createFromPackageName(mContext,
285                     packageName);
286             // Always take packageInfo first for installed app since PackageManager is more reliable
287             String packageLabel = packageInfo != null ? packageInfo.appLabel
288                     : mParams.deviceAdminLabel != null ? mParams.deviceAdminLabel : packageName;
289             Drawable packageIcon = packageInfo != null ? packageInfo.packageIcon
290                     : getDeviceAdminIconDrawable(mParams.deviceAdminIconFilePath);
291             mUi.initiateUi(R.layout.intro_device_owner,
292                     R.string.setup_device,
293                     packageLabel,
294                     packageIcon,
295                     false  /* isProfileOwnerProvisioning */,
296                     false, /* isComp */
297                     getDisclaimerHeadings(),
298                     customization);
299         }
300     }
301 
getDisclaimerHeadings()302     private @NonNull List<String> getDisclaimerHeadings() {
303         // TODO: only fetch headings, no need to fetch content; now not fast, but at least correct
304         return new TermsProvider(mContext, StoreUtils::readString, mUtils)
305                 .getTerms(mParams, TermsProvider.Flags.SKIP_GENERAL_DISCLAIMER)
306                 .stream()
307                 .map(TermsDocument::getHeading)
308                 .collect(Collectors.toList());
309     }
310 
getDeviceAdminIconDrawable(String deviceAdminIconFilePath)311     private Drawable getDeviceAdminIconDrawable(String deviceAdminIconFilePath) {
312         if (deviceAdminIconFilePath == null) {
313             return null;
314         }
315 
316         Bitmap bitmap = BitmapFactory.decodeFile(mParams.deviceAdminIconFilePath);
317         if (bitmap == null) {
318             return null;
319         }
320         return new BitmapDrawable(mContext.getResources(), bitmap);
321     }
322 
323     /**
324      * Start provisioning for real. In profile owner case, double check that the launcher
325      * supports managed profiles if necessary. In device owner case, possibly create a new user
326      * before starting provisioning.
327      */
continueProvisioningAfterUserConsent()328     public void continueProvisioningAfterUserConsent() {
329         // check if encryption is required
330         if (isEncryptionRequired()) {
331             if (mDevicePolicyManager.getStorageEncryptionStatus()
332                     == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {
333                 mUi.showErrorAndClose(R.string.cant_set_up_device,
334                         R.string.device_doesnt_allow_encryption_contact_admin,
335                         "This device does not support encryption, and "
336                                 + DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION
337                                 + " was not passed.");
338             } else {
339                 mUi.requestEncryption(mParams);
340                 // we come back to this method after returning from encryption dialog
341                 // TODO: refactor as evil - logic should be less spread out
342             }
343             return;
344         }
345 
346         if (isProfileOwnerProvisioning()) { // PO case
347             // Check whether the current launcher supports managed profiles.
348             if (!mUtils.currentLauncherSupportsManagedProfiles(mContext)) {
349                 mUi.showCurrentLauncherInvalid();
350                 // we come back to this method after returning from launcher dialog
351                 // TODO: refactor as evil - logic should be less spread out
352                 return;
353             } else {
354                 // Cancel the boot reminder as provisioning has now started.
355                 mEncryptionController.cancelEncryptionReminder();
356                 stopTimeLogger();
357                 mUi.startProvisioning(mUserManager.getUserHandle(), mParams);
358             }
359         } else { // DO case
360             // Cancel the boot reminder as provisioning has now started.
361             mEncryptionController.cancelEncryptionReminder();
362             if (isMeatUserCreationRequired(mParams.provisioningAction)) {
363                 // Create the primary user, and continue the provisioning in this user.
364                 // successful end of this task triggers provisioning
365                 // TODO: refactor as evil - logic should be less spread out
366                 new CreatePrimaryUserTask().execute();
367             } else {
368                 stopTimeLogger();
369                 mUi.startProvisioning(mUserManager.getUserHandle(), mParams);
370             }
371         }
372     }
373 
374     /** @return False if condition preventing further provisioning */
checkFactoryResetProtection()375     private boolean checkFactoryResetProtection() {
376         if (factoryResetProtected()) {
377             mUi.showErrorAndClose(R.string.cant_set_up_device,
378                     R.string.device_has_reset_protection_contact_admin,
379                     "Factory reset protection blocks provisioning.");
380             return false;
381         }
382         return true;
383     }
384 
385     /** @return False if condition preventing further provisioning */
checkDevicePolicyPreconditions()386     @VisibleForTesting protected boolean checkDevicePolicyPreconditions() {
387         // If isSilentProvisioningForTestingDeviceOwner returns true, the component must be
388         // current device owner, and we can safely ignore isProvisioningAllowed as we don't call
389         // setDeviceOwner.
390         if (isSilentProvisioningForTestingDeviceOwner()) {
391             return true;
392         }
393 
394         int provisioningPreCondition = mDevicePolicyManager.checkProvisioningPreCondition(
395                 mParams.provisioningAction, mParams.inferDeviceAdminPackageName());
396         // Check whether provisioning is allowed for the current action.
397         if (provisioningPreCondition != CODE_OK) {
398             mProvisioningAnalyticsTracker.logProvisioningNotAllowed(mContext,
399                     provisioningPreCondition);
400             showProvisioningErrorAndClose(mParams.provisioningAction, provisioningPreCondition);
401             return false;
402         }
403         return true;
404     }
405 
406     /** @return False if condition preventing further provisioning */
tryParseParameters(Intent intent, ProvisioningParams params)407     private boolean tryParseParameters(Intent intent, ProvisioningParams params) {
408         try {
409             // Read the provisioning params from the provisioning intent
410             mParams = params == null ? mMessageParser.parse(intent) : params;
411         } catch (IllegalProvisioningArgumentException e) {
412             mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
413                     e.getMessage());
414             return false;
415         }
416         return true;
417     }
418 
419     /** @return False if condition preventing further provisioning */
verifyActionAndCaller(Intent intent, String callingPackage)420     @VisibleForTesting protected boolean verifyActionAndCaller(Intent intent,
421             String callingPackage) {
422         if (verifyActionAndCallerInner(intent, callingPackage)) {
423             return true;
424         } else {
425             mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
426                     "invalid intent or calling package");
427             return false;
428         }
429     }
430 
verifyActionAndCallerInner(Intent intent, String callingPackage)431     private boolean verifyActionAndCallerInner(Intent intent, String callingPackage) {
432         // If this is a resume after encryption or trusted intent, we verify the activity alias.
433         // Otherwise, verify that the calling app is trying to set itself as Device/ProfileOwner
434         if (ACTION_RESUME_PROVISIONING.equals(intent.getAction())) {
435             return verifyActivityAlias(intent, "PreProvisioningActivityAfterEncryption");
436         } else if (ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
437             return verifyActivityAlias(intent, "PreProvisioningActivityViaNfc");
438         } else if (ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction())) {
439             return verifyActivityAlias(intent, "PreProvisioningActivityViaTrustedApp");
440         } else {
441             return verifyCaller(callingPackage);
442         }
443     }
444 
verifyActivityAlias(Intent intent, String activityAlias)445     private boolean verifyActivityAlias(Intent intent, String activityAlias) {
446         ComponentName componentName = intent.getComponent();
447         if (componentName == null || componentName.getClassName() == null) {
448             ProvisionLogger.loge("null class in component when verifying activity alias "
449                     + activityAlias);
450             return false;
451         }
452 
453         if (!componentName.getClassName().endsWith(activityAlias)) {
454             ProvisionLogger.loge("Looking for activity alias " + activityAlias + ", but got "
455                     + componentName.getClassName());
456             return false;
457         }
458 
459         return true;
460     }
461 
462     /**
463      * Verify that the caller is trying to set itself as owner.
464      * @return false if the caller is trying to set a different package as owner.
465      */
verifyCaller(@onNull String callingPackage)466     private boolean verifyCaller(@NonNull String callingPackage) {
467         if (callingPackage == null) {
468             ProvisionLogger.loge("Calling package is null. Was startActivityForResult used to "
469                     + "start this activity?");
470             return false;
471         }
472 
473         if (!callingPackage.equals(mParams.inferDeviceAdminPackageName())) {
474             ProvisionLogger.loge("Permission denied, "
475                     + "calling package tried to set a different package as owner. ");
476             return false;
477         }
478 
479         return true;
480     }
481 
482     /**
483      * Returns whether the device needs encryption.
484      */
isEncryptionRequired()485     private boolean isEncryptionRequired() {
486         return !mParams.skipEncryption && mUtils.isEncryptionRequired();
487     }
488 
isSilentProvisioningForTestingDeviceOwner()489     private boolean isSilentProvisioningForTestingDeviceOwner() {
490         final ComponentName currentDeviceOwner =
491                 mDevicePolicyManager.getDeviceOwnerComponentOnCallingUser();
492         final ComponentName targetDeviceAdmin = mParams.deviceAdminComponentName;
493 
494         switch (mParams.provisioningAction) {
495             case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE:
496                 return isPackageTestOnly()
497                         && currentDeviceOwner != null
498                         && targetDeviceAdmin != null
499                         && currentDeviceOwner.equals(targetDeviceAdmin);
500             default:
501                 return false;
502         }
503     }
504 
isSilentProvisioningForTestingManagedProfile()505     private boolean isSilentProvisioningForTestingManagedProfile() {
506         return DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(
507                 mParams.provisioningAction) && isPackageTestOnly();
508     }
509 
isPackageTestOnly()510     private boolean isPackageTestOnly() {
511         return mUtils.isPackageTestOnly(mContext.getPackageManager(),
512                 mParams.inferDeviceAdminPackageName(), mUserManager.getUserHandle());
513     }
514 
515     /**
516      * Returns whether the device is frp protected during setup wizard.
517      */
factoryResetProtected()518     private boolean factoryResetProtected() {
519         // If we are started during setup wizard, check for factory reset protection.
520         // If the device is already setup successfully, do not check factory reset protection.
521         if (mSettingsFacade.isDeviceProvisioned(mContext)) {
522             ProvisionLogger.logd("Device is provisioned, FRP not required.");
523             return false;
524         }
525 
526         if (mPdbManager == null) {
527             ProvisionLogger.logd("Reset protection not supported.");
528             return false;
529         }
530         int size = mPdbManager.getDataBlockSize();
531         ProvisionLogger.logd("Data block size: " + size);
532         return size > 0;
533     }
534 
535     /**
536      * Returns whether meat user creation is required or not.
537      * @param action Intent action that started provisioning
538      */
isMeatUserCreationRequired(String action)539     public boolean isMeatUserCreationRequired(String action) {
540         if (mUtils.isSplitSystemUser()
541                 && ACTION_PROVISION_MANAGED_DEVICE.equals(action)) {
542             List<UserInfo> users = mUserManager.getUsers();
543             if (users.size() > 1) {
544                 mUi.showErrorAndClose(R.string.cant_set_up_device,
545                         R.string.contact_your_admin_for_help,
546                         "Cannot start Device Owner Provisioning because there are already "
547                                 + users.size() + " users");
548                 return false;
549             }
550             return true;
551         } else {
552             return false;
553         }
554     }
555 
556     /**
557      * Returns whether activity to pick wifi can be requested or not.
558      */
canRequestWifiPick()559     private boolean canRequestWifiPick() {
560         return mPackageManager.resolveActivity(mUtils.getWifiPickIntent(), 0) != null;
561     }
562 
563     /**
564      * Returns whether the provisioning process is a profile owner provisioning process.
565      */
isProfileOwnerProvisioning()566     public boolean isProfileOwnerProvisioning() {
567         return mUtils.isProfileOwnerAction(mParams.provisioningAction);
568     }
569 
570     @Nullable
getParams()571     public ProvisioningParams getParams() {
572         return mParams;
573     }
574 
575     /**
576      * Notifies the time logger to stop.
577      */
stopTimeLogger()578     public void stopTimeLogger() {
579         mTimeLogger.stop();
580     }
581 
582     /**
583      * Log if PreProvisioning was cancelled.
584      */
logPreProvisioningCancelled()585     public void logPreProvisioningCancelled() {
586         mProvisioningAnalyticsTracker.logProvisioningCancelled(mContext,
587                 CANCELLED_BEFORE_PROVISIONING);
588     }
589 
590     /**
591      * Removes a user profile. If we are in COMP case, and were blocked by having to delete a user,
592      * resumes COMP provisioning.
593      */
removeUser(int userProfileId)594     public void removeUser(int userProfileId) {
595         // There is a possibility that the DO has set the disallow remove managed profile user
596         // restriction, but is initiating the provisioning. In this case, we still want to remove
597         // the managed profile.
598         // We know that we can remove the managed profile because we checked
599         // DevicePolicyManager.checkProvisioningPreCondition
600         mUserManager.removeUserEvenWhenDisallowed(userProfileId);
601     }
602 
603     /**
604      * See comment in place of usage. Check if we were in silent provisioning, got blocked, and now
605      * can resume.
606      */
checkResumeSilentProvisioning()607     public void checkResumeSilentProvisioning() {
608         if (mParams.skipUserConsent || isSilentProvisioningForTestingDeviceOwner()
609                 || isSilentProvisioningForTestingManagedProfile()) {
610             continueProvisioningAfterUserConsent();
611         }
612     }
613 
614     // TODO: review the use of async task for the case where the activity might have got killed
615     private class CreatePrimaryUserTask extends AsyncTask<Void, Void, UserInfo> {
616         @Override
doInBackground(Void... args)617         protected UserInfo doInBackground(Void... args) {
618             // Create the user where we're going to install the device owner.
619             UserInfo userInfo = mUserManager.createUser(
620                     mContext.getString(R.string.default_first_meat_user_name),
621                     UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN);
622 
623             if (userInfo != null) {
624                 ProvisionLogger.logi("Created user " + userInfo.id + " to hold the device owner");
625             }
626             return userInfo;
627         }
628 
629         @Override
onPostExecute(UserInfo userInfo)630         protected void onPostExecute(UserInfo userInfo) {
631             if (userInfo == null) {
632                 mUi.showErrorAndClose(R.string.cant_set_up_device,
633                         R.string.contact_your_admin_for_help,
634                         "Could not create user to hold the device owner");
635             } else {
636                 mActivityManager.switchUser(userInfo.id);
637                 stopTimeLogger();
638                 // TODO: refactor as evil - logic should be less spread out
639                 mUi.startProvisioning(userInfo.id, mParams);
640             }
641         }
642     }
643 
showProvisioningErrorAndClose(String action, int provisioningPreCondition)644     private void showProvisioningErrorAndClose(String action, int provisioningPreCondition) {
645         // Try to show an error message explaining why provisioning is not allowed.
646         switch (action) {
647             case ACTION_PROVISION_MANAGED_USER:
648                 mUi.showErrorAndClose(R.string.cant_set_up_device,
649                         R.string.contact_your_admin_for_help,
650                         "Exiting managed user provisioning, setup incomplete");
651                 return;
652             case ACTION_PROVISION_MANAGED_PROFILE:
653                 showManagedProfileErrorAndClose(provisioningPreCondition);
654                 return;
655             case ACTION_PROVISION_MANAGED_DEVICE:
656             case ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE:
657                 showDeviceOwnerErrorAndClose(provisioningPreCondition);
658                 return;
659         }
660         // This should never be the case, as showProvisioningError is always called after
661         // verifying the supported provisioning actions.
662     }
663 
showManagedProfileErrorAndClose(int provisioningPreCondition)664     private void showManagedProfileErrorAndClose(int provisioningPreCondition) {
665         UserInfo userInfo = mUserManager.getUserInfo(mUserManager.getUserHandle());
666         ProvisionLogger.logw("DevicePolicyManager.checkProvisioningPreCondition returns code: "
667                 + provisioningPreCondition);
668         switch (provisioningPreCondition) {
669             case CODE_ADD_MANAGED_PROFILE_DISALLOWED:
670             case CODE_MANAGED_USERS_NOT_SUPPORTED:
671                 mUi.showErrorAndClose(R.string.cant_add_work_profile,
672                         R.string.user_cant_have_work_profile_contact_admin,
673                         "Exiting managed profile provisioning, managed profiles feature is not available");
674                 break;
675             case CODE_CANNOT_ADD_MANAGED_PROFILE:
676                 if (!userInfo.canHaveProfile()) {
677                     mUi.showErrorAndClose(R.string.cant_add_work_profile,
678                             R.string.user_cannot_have_work_profiles_contact_admin,
679                             "Exiting managed profile provisioning, calling user cannot have managed profiles");
680                 } else if (isRemovingManagedProfileDisallowed()){
681                     mUi.showErrorAndClose(null,
682                             R.string.managed_provisioning_error_text,
683                             "Exiting managed profile provisioning, removing managed profile is disallowed");
684                 } else {
685                     mUi.showErrorAndClose(R.string.cant_add_work_profile,
686                             R.string.too_many_users_on_device_remove_user_try_again,
687                             "Exiting managed profile provisioning, cannot add more managed profiles");
688                 }
689                 break;
690             case CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER:
691                 mUi.showErrorAndClose(R.string.cant_add_work_profile,
692                         R.string.contact_your_admin_for_help,
693                         "Exiting managed profile provisioning, a device owner exists");
694                 break;
695             default:
696                 mUi.showErrorAndClose(R.string.cant_add_work_profile,
697                         R.string.contact_your_admin_for_help,
698                         "Managed profile provisioning not allowed for an unknown " +
699                         "reason, code: " + provisioningPreCondition);
700         }
701     }
702 
isRemovingManagedProfileDisallowed()703     private boolean isRemovingManagedProfileDisallowed() {
704         return mUtils.alreadyHasManagedProfile(mContext) != -1
705                 && mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
706     }
707 
showDeviceOwnerErrorAndClose(int provisioningPreCondition)708     private void showDeviceOwnerErrorAndClose(int provisioningPreCondition) {
709         switch (provisioningPreCondition) {
710             case CODE_HAS_DEVICE_OWNER:
711                 mUi.showErrorAndClose(R.string.device_already_set_up,
712                         R.string.if_questions_contact_admin, "Device already provisioned.");
713                 return;
714             case CODE_NOT_SYSTEM_USER:
715                 mUi.showErrorAndClose(R.string.cant_set_up_device,
716                         R.string.contact_your_admin_for_help,
717                         "Device owner can only be set up for USER_SYSTEM.");
718                 return;
719             case CODE_NOT_SYSTEM_USER_SPLIT:
720                 mUi.showErrorAndClose(R.string.cant_set_up_device,
721                         R.string.contact_your_admin_for_help,
722                         "System User Device owner can only be set on a split-user system.");
723                 return;
724         }
725         mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
726                 "Device Owner provisioning not allowed for an unknown reason.");
727     }
728 }