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
17package com.android.managedprovisioning.preprovisioning;
18
19import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
21import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
22import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE;
23import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
24import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED;
25import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
26import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER;
27import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
28import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER;
29import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT;
30import static android.app.admin.DevicePolicyManager.CODE_OK;
31import static android.app.admin.DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
32import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
33
34import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS;
35import static com.android.internal.util.Preconditions.checkNotNull;
36import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.CANCELLED_BEFORE_PROVISIONING;
37import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
38
39import android.annotation.NonNull;
40import android.annotation.Nullable;
41import android.app.ActivityManager;
42import android.app.KeyguardManager;
43import android.app.admin.DevicePolicyManager;
44import android.content.ComponentName;
45import android.content.Context;
46import android.content.Intent;
47import android.content.pm.PackageManager;
48import android.content.pm.UserInfo;
49import android.graphics.Bitmap;
50import android.graphics.BitmapFactory;
51import android.graphics.drawable.BitmapDrawable;
52import android.graphics.drawable.Drawable;
53import android.os.AsyncTask;
54import android.os.UserManager;
55import android.service.persistentdata.PersistentDataBlockManager;
56
57import com.android.internal.annotations.VisibleForTesting;
58import com.android.managedprovisioning.R;
59import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
60import com.android.managedprovisioning.analytics.TimeLogger;
61import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
62import com.android.managedprovisioning.common.MdmPackageInfo;
63import com.android.managedprovisioning.common.ProvisionLogger;
64import com.android.managedprovisioning.common.SettingsFacade;
65import com.android.managedprovisioning.common.StoreUtils;
66import com.android.managedprovisioning.common.Utils;
67import com.android.managedprovisioning.model.CustomizationParams;
68import com.android.managedprovisioning.model.ProvisioningParams;
69import com.android.managedprovisioning.parser.MessageParser;
70import com.android.managedprovisioning.preprovisioning.terms.TermsDocument;
71import com.android.managedprovisioning.preprovisioning.terms.TermsProvider;
72
73import java.util.List;
74import java.util.stream.Collectors;
75
76public 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}