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