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.uiflows;
18
19import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE;
21import static com.android.internal.util.Preconditions.checkNotNull;
22import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
23
24import android.annotation.NonNull;
25import android.annotation.Nullable;
26import android.app.ActivityManager;
27import android.app.admin.DevicePolicyManager;
28import android.app.KeyguardManager;
29import android.content.ComponentName;
30import android.content.Context;
31import android.content.Intent;
32import android.content.pm.ApplicationInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.UserInfo;
35import android.os.AsyncTask;
36import android.os.UserHandle;
37import android.os.UserManager;
38import android.provider.Settings.Global;
39import android.service.persistentdata.PersistentDataBlockManager;
40import android.text.TextUtils;
41
42import com.android.internal.annotations.VisibleForTesting;
43import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
44import com.android.managedprovisioning.common.Utils;
45import com.android.managedprovisioning.model.ProvisioningParams;
46import com.android.managedprovisioning.parser.MessageParser;
47import com.android.managedprovisioning.ProvisionLogger;
48import com.android.managedprovisioning.R;
49
50import java.util.List;
51
52public class PreProvisioningController {
53    private final Context mContext;
54    private final Ui mUi;
55    private final MessageParser mMessageParser;
56    private final Utils mUtils;
57    private final EncryptionController mEncryptionController;
58
59    // used system services
60    private final DevicePolicyManager mDevicePolicyManager;
61    private final UserManager mUserManager;
62    private final PackageManager mPackageManager;
63    private final ActivityManager mActivityManager;
64    private final KeyguardManager mKeyguardManager;
65    private final PersistentDataBlockManager mPdbManager;
66
67    private ProvisioningParams mParams;
68    private boolean mIsProfileOwnerProvisioning;
69
70    public PreProvisioningController(
71            @NonNull Context context,
72            @NonNull Ui ui) {
73        this(context, ui, new MessageParser(), new Utils(),
74                EncryptionController.getInstance(context));
75    }
76
77    @VisibleForTesting
78    PreProvisioningController(
79            @NonNull Context context,
80            @NonNull Ui ui,
81            @NonNull MessageParser parser,
82            @NonNull Utils utils,
83            @NonNull EncryptionController encryptionController) {
84        mContext = checkNotNull(context, "Context must not be null");
85        mUi = checkNotNull(ui, "Ui must not be null");
86        mMessageParser = checkNotNull(parser, "MessageParser must not be null");
87        mUtils = checkNotNull(utils, "Utils must not be null");
88        mEncryptionController = checkNotNull(encryptionController,
89                "EncryptionController must not be null");
90
91        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
92                Context.DEVICE_POLICY_SERVICE);
93        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
94        mPackageManager = mContext.getPackageManager();
95        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
96        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
97        mPdbManager = (PersistentDataBlockManager) mContext.getSystemService(
98                Context.PERSISTENT_DATA_BLOCK_SERVICE);
99    }
100
101    interface Ui {
102        /**
103         * Show an error message and cancel provisioning.
104         *
105         * @param resId resource id used to form the user facing error message
106         * @param errorMessage an error message that gets logged for debugging
107         */
108        void showErrorAndClose(int resId, String errorMessage);
109
110        /**
111         * Request the user to encrypt the device.
112         *
113         * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
114         */
115        void requestEncryption(ProvisioningParams params);
116
117        /**
118         * Request the user to choose a wifi network.
119         */
120        void requestWifiPick();
121
122        /**
123         * Initialize the pre provisioning UI with the mdm info and the relevant strings.
124         *
125         * @param headerRes resource id for the header text
126         * @param titleRes resource id for the title text
127         * @param consentRes resource id of the consent text
128         * @param mdmInfoRes resource id for the mdm info text
129         * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
130         */
131        void initiateUi(int headerRes, int titleRes, int consentRes, int mdmInfoRes,
132                ProvisioningParams params);
133
134        /**
135         * Start device owner provisioning.
136         *
137         * @param userId the id of the user we want to start provisioning on
138         * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
139         */
140        void startDeviceOwnerProvisioning(int userId, ProvisioningParams params);
141
142        /**
143         * Start profile owner provisioning.
144         *
145         * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
146         */
147        void startProfileOwnerProvisioning(ProvisioningParams params);
148
149        /**
150         * Show a user consent dialog.
151         *
152         * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
153         * @param isProfileOwnerProvisioning whether we're provisioning a profile owner
154         */
155        void showUserConsentDialog(ProvisioningParams params, boolean isProfileOwnerProvisioning);
156
157        /**
158         * Show a dialog to delete an existing managed profile.
159         *
160         * @param mdmPackageName the {@link ComponentName} of the existing profile's profile owner
161         * @param domainName domain name of the organization which owns the managed profile
162         *
163         * @param userId the user id of the existing profile
164         */
165        void showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName,
166                int userId);
167
168        /**
169         * Show an error dialog indicating that the current launcher does not support managed
170         * profiles and ask the user to choose a different one.
171         */
172        void showCurrentLauncherInvalid();
173    }
174
175    public void initiateProvisioning(Intent intent, String callingPackage) {
176        // Check factory reset protection as the first thing
177        if (factoryResetProtected()) {
178            mUi.showErrorAndClose(R.string.device_owner_error_frp,
179                    "Factory reset protection blocks provisioning.");
180            return;
181        }
182
183        try {
184            // Read the provisioning params from the provisioning intent
185            mParams = mMessageParser.parse(intent, mContext);
186
187            // If this is a resume after encryption or trusted intent, we don't need to verify the
188            // caller. Otherwise, verify that the calling app is trying to set itself as
189            // Device/ProfileOwner
190            if (!ACTION_RESUME_PROVISIONING.equals(intent.getAction()) &&
191                    !mParams.startedByTrustedSource) {
192                verifyCaller(callingPackage);
193            }
194        } catch (IllegalProvisioningArgumentException e) {
195            // TODO: make this a generic error message
196            mUi.showErrorAndClose(R.string.device_owner_error_general, e.getMessage());
197            return;
198        }
199
200        mIsProfileOwnerProvisioning = mUtils.isProfileOwnerAction(mParams.provisioningAction);
201        // Check whether provisioning is allowed for the current action
202        if (!mDevicePolicyManager.isProvisioningAllowed(mParams.provisioningAction)) {
203            showProvisioningError(mParams.provisioningAction);
204            return;
205        }
206
207        // Initiate the corresponding provisioning mode
208        if (mIsProfileOwnerProvisioning) {
209            initiateProfileOwnerProvisioning(intent);
210        } else {
211            initiateDeviceOwnerProvisioning(intent);
212        }
213    }
214
215    /**
216     * Verify that the caller is trying to set itself as owner.
217     *
218     * @throws IllegalProvisioningArgumentException if the caller is trying to set a different
219     * package as owner.
220     */
221    private void verifyCaller(@NonNull String callingPackage)
222            throws IllegalProvisioningArgumentException {
223        checkNotNull(callingPackage,
224                "Calling package is null. Was startActivityForResult used to start this activity?");
225        if (!callingPackage.equals(mParams.inferDeviceAdminPackageName())) {
226            throw new IllegalProvisioningArgumentException("Permission denied, "
227                    + "calling package tried to set a different package as owner. ");
228        }
229    }
230
231    private void initiateDeviceOwnerProvisioning(Intent intent) {
232        if (!mParams.startedByTrustedSource) {
233            mUi.initiateUi(
234                    R.string.setup_work_device,
235                    R.string.setup_device_start_setup,
236                    R.string.company_controls_device,
237                    R.string.the_following_is_your_mdm_for_device,
238                    mParams);
239        }
240
241        // Ask to encrypt the device before proceeding
242        if (isEncryptionRequired()) {
243            maybeTriggerEncryption();
244            return;
245        }
246
247        // Have the user pick a wifi network if necessary.
248        // It is not possible to ask the user to pick a wifi network if
249        // the screen is locked.
250        // TODO: remove this check once we know the screen will not be locked.
251        if (mKeyguardManager.inKeyguardRestrictedInputMode()) {
252            ProvisionLogger.logi("Cannot pick wifi because the screen is locked.");
253            // Have the user pick a wifi network if necessary.
254        } else if (!mUtils.isConnectedToNetwork(mContext) && mParams.wifiInfo == null
255               && mParams.deviceAdminDownloadInfo != null) {
256            if (canRequestWifiPick()) {
257                mUi.requestWifiPick();
258                return;
259            } else {
260                ProvisionLogger.logi(
261                        "Cannot pick wifi because there is no handler to the intent");
262            }
263        }
264        askForConsentOrStartDeviceOwnerProvisioning();
265    }
266
267    private void initiateProfileOwnerProvisioning(Intent intent) {
268        mUi.initiateUi(
269                R.string.setup_work_profile,
270                R.string.setup_profile_start_setup,
271                R.string.company_controls_workspace,
272                R.string.the_following_is_your_mdm,
273                mParams);
274
275        // If there is already a managed profile, setup the profile deletion dialog.
276        int existingManagedProfileUserId = mUtils.alreadyHasManagedProfile(mContext);
277        if (existingManagedProfileUserId != -1) {
278            ComponentName mdmPackageName = mDevicePolicyManager
279                    .getProfileOwnerAsUser(existingManagedProfileUserId);
280            String domainName = mDevicePolicyManager
281                    .getProfileOwnerNameAsUser(existingManagedProfileUserId);
282            mUi.showDeleteManagedProfileDialog(mdmPackageName, domainName,
283                    existingManagedProfileUserId);
284        }
285    }
286
287    /**
288     * Start provisioning for real. In profile owner case, double check that the launcher
289     * supports managed profiles if necessary. In device owner case, possibly create a new user
290     * before starting provisioning.
291     */
292    public void continueProvisioningAfterUserConsent() {
293        if (isProfileOwnerProvisioning()) {
294            checkLauncherAndStartProfileOwnerProvisioning();
295        } else {
296            maybeCreateUserAndStartDeviceOwnerProvisioning();
297        }
298    }
299
300    /**
301     * Invoked when the user continues provisioning by pressing the next button.
302     *
303     * <p>If device hasn't been encrypted yet, invoke the encryption flow. Otherwise, show a user
304     * consent before starting provisioning.
305     */
306    public void afterNavigateNext() {
307        if (isEncryptionRequired()) {
308            maybeTriggerEncryption();
309        } else {
310            // Notify the user once more that the admin will have full control over the profile,
311            // then start provisioning.
312            mUi.showUserConsentDialog(mParams, mIsProfileOwnerProvisioning);
313        }
314    }
315
316    /**
317     * Returns whether the device needs encryption.
318     *
319     * @param skip indicating whether the parameter to skip encryption was given.
320     */
321    private boolean isEncryptionRequired() {
322        return !mParams.skipEncryption && mUtils.isEncryptionRequired();
323    }
324
325    /**
326     * Check whether the device supports encryption. If it does not support encryption, but
327     * encryption is requested, show an error dialog.
328     */
329    private void maybeTriggerEncryption() {
330        if (mDevicePolicyManager.getStorageEncryptionStatus() ==
331                DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {
332            mUi.showErrorAndClose(R.string.preprovisioning_error_encryption_not_supported,
333                    "This device does not support encryption, but "
334                    + DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION
335                    + " was not passed.");
336        } else {
337            mUi.requestEncryption(mParams);
338        }
339    }
340
341    private void checkLauncherAndStartProfileOwnerProvisioning() {
342        // Check whether the current launcher supports managed profiles.
343        if (!mUtils.currentLauncherSupportsManagedProfiles(mContext)) {
344            mUi.showCurrentLauncherInvalid();
345        } else {
346            // Cancel the boot reminder as provisioning has now started.
347            mEncryptionController.cancelEncryptionReminder();
348            mUi.startProfileOwnerProvisioning(mParams);
349        }
350    }
351
352    public void askForConsentOrStartDeviceOwnerProvisioning() {
353        // If we are started by Nfc and the device supports FRP, we need to ask for user consent
354        // since FRP will not be activated at the end of the flow.
355        if (mParams.startedByTrustedSource) {
356            if (mUtils.isFrpSupported(mContext)) {
357                mUi.showUserConsentDialog(mParams, false);
358            } else {
359                maybeCreateUserAndStartDeviceOwnerProvisioning();
360            }
361        }
362        // In other provisioning modes we wait for the user to press next.
363    }
364
365    private void maybeCreateUserAndStartDeviceOwnerProvisioning() {
366        // Cancel the boot reminder as provisioning has now started.
367        mEncryptionController.cancelEncryptionReminder();
368        if (isMeatUserCreationRequired(mParams.provisioningAction)) {
369            // Create the primary user, and continue the provisioning in this user.
370            new CreatePrimaryUserTask().execute();
371        } else {
372            mUi.startDeviceOwnerProvisioning(mUserManager.getUserHandle(), mParams);
373        }
374    }
375
376    private boolean factoryResetProtected() {
377        // If we are started during setup wizard, check for factory reset protection.
378        // If the device is already setup successfully, do not check factory reset protection.
379        if (mUtils.isDeviceProvisioned(mContext)) {
380            ProvisionLogger.logd("Device is provisioned, FRP not required.");
381            return false;
382        }
383
384        if (mPdbManager == null) {
385            ProvisionLogger.logd("Reset protection not supported.");
386            return false;
387        }
388        int size = mPdbManager.getDataBlockSize();
389        ProvisionLogger.logd("Data block size: " + size);
390        return size > 0;
391    }
392
393    public boolean isMeatUserCreationRequired(String action) {
394        if (mUtils.isSplitSystemUser()
395                && ACTION_PROVISION_MANAGED_DEVICE.equals(action)) {
396            List<UserInfo> users = mUserManager.getUsers();
397            if (users.size() > 1) {
398                mUi.showErrorAndClose(R.string.device_owner_error_general,
399                        "Cannot start Device Owner Provisioning because there are already "
400                        + users.size() + " users");
401                return false;
402            }
403            return true;
404        } else {
405            return false;
406        }
407    }
408
409    private boolean canRequestWifiPick() {
410        return mPackageManager.resolveActivity(mUtils.getWifiPickIntent(), 0) != null;
411    }
412
413    private boolean systemHasManagedProfileFeature() {
414        return mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
415    }
416
417    /**
418     * Returns whether the provisioning process is a profile owner provisioning process.
419     */
420    public boolean isProfileOwnerProvisioning() {
421        return mIsProfileOwnerProvisioning;
422    }
423
424    @NonNull
425    public ProvisioningParams getParams() {
426        if (mParams == null) {
427            throw new IllegalStateException("ProvisioningParams are null");
428        }
429        return mParams;
430    }
431
432    // TODO: review the use of async task for the case where the activity might have got killed
433    private class CreatePrimaryUserTask extends AsyncTask<Void, Void, UserInfo> {
434        @Override
435        protected UserInfo doInBackground(Void... args) {
436            // Create the user where we're going to install the device owner.
437            UserInfo userInfo = mUserManager.createUser(
438                    mContext.getString(R.string.default_first_meat_user_name),
439                    UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN);
440
441            if (userInfo != null) {
442                ProvisionLogger.logi("Created user " + userInfo.id + " to hold the device owner");
443            }
444            return userInfo;
445        }
446
447        @Override
448        protected void onPostExecute(UserInfo userInfo) {
449            if (userInfo == null) {
450                mUi.showErrorAndClose(R.string.device_owner_error_general,
451                        "Could not create user to hold the device owner");
452            } else {
453                mActivityManager.switchUser(userInfo.id);
454                mUi.startDeviceOwnerProvisioning(userInfo.id, mParams);
455            }
456        }
457    }
458
459    private void showProvisioningError(String action) {
460        UserInfo userInfo = mUserManager.getUserInfo(mUserManager.getUserHandle());
461        if (DevicePolicyManager.ACTION_PROVISION_MANAGED_USER.equals(action)) {
462            mUi.showErrorAndClose(R.string.user_setup_incomplete,
463                        "Exiting managed user provisioning, setup incomplete");
464        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
465            // Try to show an error message explaining why provisioning is not allowed.
466            if (!systemHasManagedProfileFeature()) {
467                mUi.showErrorAndClose(R.string.managed_provisioning_not_supported,
468                        "Exiting managed profile provisioning, "
469                        + "managed profiles feature is not available");
470            } else if (!userInfo.canHaveProfile()) {
471                mUi.showErrorAndClose(R.string.user_cannot_have_work_profile,
472                        "Exiting managed profile provisioning, calling user cannot have managed"
473                        + "profiles.");
474            } else if (mUtils.isDeviceManaged(mContext)) {
475                // The actual check in isProvisioningAllowed() is more than just "is there DO?",
476                // but for error message showing purpose, isDeviceManaged() will do.
477                mUi.showErrorAndClose(R.string.device_owner_exists,
478                        "Exiting managed profile provisioning, a device owner exists");
479            } else if (!mUserManager.canAddMoreManagedProfiles(UserHandle.myUserId(),
480                    true /* after removing one eventual existing managed profile */)) {
481                mUi.showErrorAndClose(R.string.maximum_user_limit_reached,
482                        "Exiting managed profile provisioning, cannot add more managed profiles.");
483            } else {
484                mUi.showErrorAndClose(R.string.managed_provisioning_error_text, "Managed profile"
485                        + " provisioning not allowed for an unknown reason.");
486            }
487        } else if (mUtils.isDeviceProvisioned(mContext)) {
488            mUi.showErrorAndClose(R.string.device_owner_error_already_provisioned,
489                    "Device already provisioned.");
490        } else if (!mUtils.isCurrentUserSystem()) {
491            mUi.showErrorAndClose(R.string.device_owner_error_general,
492                    "Device owner can only be set up for USER_SYSTEM.");
493        } else if (action.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE) &&
494                !UserManager.isSplitSystemUser()) {
495            mUi.showErrorAndClose(R.string.device_owner_error_general,
496                    "System User Device owner can only be set on a split-user system.");
497        } else {
498            // TODO: show generic error
499            mUi.showErrorAndClose(R.string.device_owner_error_general,
500                    "Device Owner provisioning not allowed for an unknown reason.");
501        }
502    }
503}
504