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.uiflows; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE; 21 import static com.android.internal.util.Preconditions.checkNotNull; 22 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.ActivityManager; 27 import android.app.admin.DevicePolicyManager; 28 import android.app.KeyguardManager; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.ApplicationInfo; 33 import android.content.pm.PackageManager; 34 import android.content.pm.UserInfo; 35 import android.os.AsyncTask; 36 import android.os.UserHandle; 37 import android.os.UserManager; 38 import android.provider.Settings.Global; 39 import android.service.persistentdata.PersistentDataBlockManager; 40 import android.text.TextUtils; 41 42 import com.android.internal.annotations.VisibleForTesting; 43 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 44 import com.android.managedprovisioning.common.Utils; 45 import com.android.managedprovisioning.model.ProvisioningParams; 46 import com.android.managedprovisioning.parser.MessageParser; 47 import com.android.managedprovisioning.ProvisionLogger; 48 import com.android.managedprovisioning.R; 49 50 import java.util.List; 51 52 public 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 PreProvisioningController( @onNull Context context, @NonNull Ui ui)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 PreProvisioningController( @onNull Context context, @NonNull Ui ui, @NonNull MessageParser parser, @NonNull Utils utils, @NonNull EncryptionController encryptionController)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 */ showErrorAndClose(int resId, String errorMessage)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 */ requestEncryption(ProvisioningParams params)115 void requestEncryption(ProvisioningParams params); 116 117 /** 118 * Request the user to choose a wifi network. 119 */ requestWifiPick()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 */ initiateUi(int headerRes, int titleRes, int consentRes, int mdmInfoRes, ProvisioningParams params)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 */ startDeviceOwnerProvisioning(int userId, ProvisioningParams params)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 */ startProfileOwnerProvisioning(ProvisioningParams params)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 */ showUserConsentDialog(ProvisioningParams params, boolean isProfileOwnerProvisioning)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 */ showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName, int userId)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 */ showCurrentLauncherInvalid()172 void showCurrentLauncherInvalid(); 173 } 174 initiateProvisioning(Intent intent, String callingPackage)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 */ verifyCaller(@onNull String callingPackage)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 initiateDeviceOwnerProvisioning(Intent intent)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 if (canRequestWifiPick()) { 256 mUi.requestWifiPick(); 257 return; 258 } else { 259 ProvisionLogger.logi( 260 "Cannot pick wifi because there is no handler to the intent"); 261 } 262 } 263 askForConsentOrStartDeviceOwnerProvisioning(); 264 } 265 initiateProfileOwnerProvisioning(Intent intent)266 private void initiateProfileOwnerProvisioning(Intent intent) { 267 mUi.initiateUi( 268 R.string.setup_work_profile, 269 R.string.setup_profile_start_setup, 270 R.string.company_controls_workspace, 271 R.string.the_following_is_your_mdm, 272 mParams); 273 274 // If there is already a managed profile, setup the profile deletion dialog. 275 int existingManagedProfileUserId = mUtils.alreadyHasManagedProfile(mContext); 276 if (existingManagedProfileUserId != -1) { 277 ComponentName mdmPackageName = mDevicePolicyManager 278 .getProfileOwnerAsUser(existingManagedProfileUserId); 279 String domainName = mDevicePolicyManager 280 .getProfileOwnerNameAsUser(existingManagedProfileUserId); 281 mUi.showDeleteManagedProfileDialog(mdmPackageName, domainName, 282 existingManagedProfileUserId); 283 } 284 } 285 286 /** 287 * Start provisioning for real. In profile owner case, double check that the launcher 288 * supports managed profiles if necessary. In device owner case, possibly create a new user 289 * before starting provisioning. 290 */ continueProvisioningAfterUserConsent()291 public void continueProvisioningAfterUserConsent() { 292 if (isProfileOwnerProvisioning()) { 293 checkLauncherAndStartProfileOwnerProvisioning(); 294 } else { 295 maybeCreateUserAndStartDeviceOwnerProvisioning(); 296 } 297 } 298 299 /** 300 * Invoked when the user continues provisioning by pressing the next button. 301 * 302 * <p>If device hasn't been encrypted yet, invoke the encryption flow. Otherwise, show a user 303 * consent before starting provisioning. 304 */ afterNavigateNext()305 public void afterNavigateNext() { 306 if (isEncryptionRequired()) { 307 maybeTriggerEncryption(); 308 } else { 309 // Notify the user once more that the admin will have full control over the profile, 310 // then start provisioning. 311 mUi.showUserConsentDialog(mParams, mIsProfileOwnerProvisioning); 312 } 313 } 314 315 /** 316 * Returns whether the device needs encryption. 317 * 318 * @param skip indicating whether the parameter to skip encryption was given. 319 */ isEncryptionRequired()320 private boolean isEncryptionRequired() { 321 return !mParams.skipEncryption && mUtils.isEncryptionRequired(); 322 } 323 324 /** 325 * Check whether the device supports encryption. If it does not support encryption, but 326 * encryption is requested, show an error dialog. 327 */ maybeTriggerEncryption()328 private void maybeTriggerEncryption() { 329 if (mDevicePolicyManager.getStorageEncryptionStatus() == 330 DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) { 331 mUi.showErrorAndClose(R.string.preprovisioning_error_encryption_not_supported, 332 "This device does not support encryption, but " 333 + DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION 334 + " was not passed."); 335 } else { 336 mUi.requestEncryption(mParams); 337 } 338 } 339 checkLauncherAndStartProfileOwnerProvisioning()340 private void checkLauncherAndStartProfileOwnerProvisioning() { 341 // Check whether the current launcher supports managed profiles. 342 if (!mUtils.currentLauncherSupportsManagedProfiles(mContext)) { 343 mUi.showCurrentLauncherInvalid(); 344 } else { 345 // Cancel the boot reminder as provisioning has now started. 346 mEncryptionController.cancelEncryptionReminder(); 347 mUi.startProfileOwnerProvisioning(mParams); 348 } 349 } 350 askForConsentOrStartDeviceOwnerProvisioning()351 public void askForConsentOrStartDeviceOwnerProvisioning() { 352 // If we are started by Nfc and the device supports FRP, we need to ask for user consent 353 // since FRP will not be activated at the end of the flow. 354 if (mParams.startedByTrustedSource) { 355 if (mUtils.isFrpSupported(mContext)) { 356 mUi.showUserConsentDialog(mParams, false); 357 } else { 358 maybeCreateUserAndStartDeviceOwnerProvisioning(); 359 } 360 } 361 // In other provisioning modes we wait for the user to press next. 362 } 363 maybeCreateUserAndStartDeviceOwnerProvisioning()364 private void maybeCreateUserAndStartDeviceOwnerProvisioning() { 365 // Cancel the boot reminder as provisioning has now started. 366 mEncryptionController.cancelEncryptionReminder(); 367 if (isMeatUserCreationRequired(mParams.provisioningAction)) { 368 // Create the primary user, and continue the provisioning in this user. 369 new CreatePrimaryUserTask().execute(); 370 } else { 371 mUi.startDeviceOwnerProvisioning(mUserManager.getUserHandle(), mParams); 372 } 373 } 374 factoryResetProtected()375 private boolean factoryResetProtected() { 376 // If we are started during setup wizard, check for factory reset protection. 377 // If the device is already setup successfully, do not check factory reset protection. 378 if (mUtils.isDeviceProvisioned(mContext)) { 379 ProvisionLogger.logd("Device is provisioned, FRP not required."); 380 return false; 381 } 382 383 if (mPdbManager == null) { 384 ProvisionLogger.logd("Reset protection not supported."); 385 return false; 386 } 387 int size = mPdbManager.getDataBlockSize(); 388 ProvisionLogger.logd("Data block size: " + size); 389 return size > 0; 390 } 391 isMeatUserCreationRequired(String action)392 public boolean isMeatUserCreationRequired(String action) { 393 if (mUtils.isSplitSystemUser() 394 && ACTION_PROVISION_MANAGED_DEVICE.equals(action)) { 395 List<UserInfo> users = mUserManager.getUsers(); 396 if (users.size() > 1) { 397 mUi.showErrorAndClose(R.string.device_owner_error_general, 398 "Cannot start Device Owner Provisioning because there are already " 399 + users.size() + " users"); 400 return false; 401 } 402 return true; 403 } else { 404 return false; 405 } 406 } 407 canRequestWifiPick()408 private boolean canRequestWifiPick() { 409 return mPackageManager.resolveActivity(mUtils.getWifiPickIntent(), 0) != null; 410 } 411 systemHasManagedProfileFeature()412 private boolean systemHasManagedProfileFeature() { 413 return mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS); 414 } 415 416 /** 417 * Returns whether the provisioning process is a profile owner provisioning process. 418 */ isProfileOwnerProvisioning()419 public boolean isProfileOwnerProvisioning() { 420 return mIsProfileOwnerProvisioning; 421 } 422 423 @NonNull getParams()424 public ProvisioningParams getParams() { 425 if (mParams == null) { 426 throw new IllegalStateException("ProvisioningParams are null"); 427 } 428 return mParams; 429 } 430 431 // TODO: review the use of async task for the case where the activity might have got killed 432 private class CreatePrimaryUserTask extends AsyncTask<Void, Void, UserInfo> { 433 @Override doInBackground(Void... args)434 protected UserInfo doInBackground(Void... args) { 435 // Create the user where we're going to install the device owner. 436 UserInfo userInfo = mUserManager.createUser( 437 mContext.getString(R.string.default_first_meat_user_name), 438 UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN); 439 440 if (userInfo != null) { 441 ProvisionLogger.logi("Created user " + userInfo.id + " to hold the device owner"); 442 } 443 return userInfo; 444 } 445 446 @Override onPostExecute(UserInfo userInfo)447 protected void onPostExecute(UserInfo userInfo) { 448 if (userInfo == null) { 449 mUi.showErrorAndClose(R.string.device_owner_error_general, 450 "Could not create user to hold the device owner"); 451 } else { 452 mActivityManager.switchUser(userInfo.id); 453 mUi.startDeviceOwnerProvisioning(userInfo.id, mParams); 454 } 455 } 456 } 457 showProvisioningError(String action)458 private void showProvisioningError(String action) { 459 UserInfo userInfo = mUserManager.getUserInfo(mUserManager.getUserHandle()); 460 if (DevicePolicyManager.ACTION_PROVISION_MANAGED_USER.equals(action)) { 461 mUi.showErrorAndClose(R.string.user_setup_incomplete, 462 "Exiting managed user provisioning, setup incomplete"); 463 } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) { 464 // Try to show an error message explaining why provisioning is not allowed. 465 if (!systemHasManagedProfileFeature()) { 466 mUi.showErrorAndClose(R.string.managed_provisioning_not_supported, 467 "Exiting managed profile provisioning, " 468 + "managed profiles feature is not available"); 469 } else if (!userInfo.canHaveProfile()) { 470 mUi.showErrorAndClose(R.string.user_cannot_have_work_profile, 471 "Exiting managed profile provisioning, calling user cannot have managed" 472 + "profiles."); 473 } else if (mUtils.isDeviceManaged(mContext)) { 474 // The actual check in isProvisioningAllowed() is more than just "is there DO?", 475 // but for error message showing purpose, isDeviceManaged() will do. 476 mUi.showErrorAndClose(R.string.device_owner_exists, 477 "Exiting managed profile provisioning, a device owner exists"); 478 } else if (!mUserManager.canAddMoreManagedProfiles(UserHandle.myUserId(), 479 true /* after removing one eventual existing managed profile */)) { 480 mUi.showErrorAndClose(R.string.maximum_user_limit_reached, 481 "Exiting managed profile provisioning, cannot add more managed profiles."); 482 } else { 483 mUi.showErrorAndClose(R.string.managed_provisioning_error_text, "Managed profile" 484 + " provisioning not allowed for an unknown reason."); 485 } 486 } else if (mUtils.isDeviceProvisioned(mContext)) { 487 mUi.showErrorAndClose(R.string.device_owner_error_already_provisioned, 488 "Device already provisioned."); 489 } else if (!mUtils.isCurrentUserSystem()) { 490 mUi.showErrorAndClose(R.string.device_owner_error_general, 491 "Device owner can only be set up for USER_SYSTEM."); 492 } else if (action.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE) && 493 !UserManager.isSplitSystemUser()) { 494 mUi.showErrorAndClose(R.string.device_owner_error_general, 495 "System User Device owner can only be set on a split-user system."); 496 } else { 497 // TODO: show generic error 498 mUi.showErrorAndClose(R.string.device_owner_error_general, 499 "Device Owner provisioning not allowed for an unknown reason."); 500 } 501 } 502 } 503