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