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