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