Home | History | Annotate | Download | only in preprovisioning
      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 
     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
    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          */
    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          */
    147         void requestEncryption(ProvisioningParams params);
    148 
    149         /**
    150          * Request the user to choose a wifi network.
    151          */
    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          */
    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          */
    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          */
    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          */
    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      */
    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 
    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 
    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      */
    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 */
    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 */
    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 */
    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 */
    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 
    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 
    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      */
    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      */
    485     private boolean isEncryptionRequired() {
    486         return !mParams.skipEncryption && mUtils.isEncryptionRequired();
    487     }
    488 
    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 
    505     private boolean isSilentProvisioningForTestingManagedProfile() {
    506         return DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(
    507                 mParams.provisioningAction) && isPackageTestOnly();
    508     }
    509 
    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      */
    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      */
    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      */
    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      */
    566     public boolean isProfileOwnerProvisioning() {
    567         return mUtils.isProfileOwnerAction(mParams.provisioningAction);
    568     }
    569 
    570     @Nullable
    571     public ProvisioningParams getParams() {
    572         return mParams;
    573     }
    574 
    575     /**
    576      * Notifies the time logger to stop.
    577      */
    578     public void stopTimeLogger() {
    579         mTimeLogger.stop();
    580     }
    581 
    582     /**
    583      * Log if PreProvisioning was cancelled.
    584      */
    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      */
    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      */
    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
    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
    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 
    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 
    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 
    703     private boolean isRemovingManagedProfileDisallowed() {
    704         return mUtils.alreadyHasManagedProfile(mContext) != -1
    705                 && mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
    706     }
    707 
    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 }