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_FINANCED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; 22 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 23 import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; 24 import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER; 25 import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED; 26 import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER; 27 import static android.app.admin.DevicePolicyManager.CODE_OK; 28 import static android.app.admin.DevicePolicyManager.CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS; 29 import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED; 30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES; 33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_IMEI; 34 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION; 35 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED; 36 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT; 37 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SERIAL_NUMBER; 38 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS; 39 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; 40 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_DEVICE_OWNER; 41 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED; 42 import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE; 43 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE; 44 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED; 45 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED; 46 47 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.CANCELLED_BEFORE_PROVISIONING; 48 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING; 49 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED; 50 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED; 51 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED; 52 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_LEGACY; 53 54 import static java.util.Objects.requireNonNull; 55 56 import android.accounts.Account; 57 import android.annotation.NonNull; 58 import android.annotation.Nullable; 59 import android.app.Activity; 60 import android.app.KeyguardManager; 61 import android.app.admin.DevicePolicyManager; 62 import android.content.ComponentName; 63 import android.content.Context; 64 import android.content.Intent; 65 import android.content.pm.PackageInfo; 66 import android.content.pm.PackageManager; 67 import android.content.pm.UserInfo; 68 import android.net.ConnectivityManager; 69 import android.os.Build; 70 import android.os.Bundle; 71 import android.os.PersistableBundle; 72 import android.os.SystemClock; 73 import android.os.UserManager; 74 import android.service.persistentdata.PersistentDataBlockManager; 75 import android.telephony.TelephonyManager; 76 import android.text.TextUtils; 77 78 import androidx.activity.ComponentActivity; 79 import androidx.lifecycle.LiveData; 80 import androidx.lifecycle.ViewModelProvider; 81 82 import com.android.internal.annotations.VisibleForTesting; 83 import com.android.managedprovisioning.ManagedProvisioningBaseApplication; 84 import com.android.managedprovisioning.ManagedProvisioningScreens; 85 import com.android.managedprovisioning.R; 86 import com.android.managedprovisioning.analytics.MetricsWriterFactory; 87 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 88 import com.android.managedprovisioning.common.GetProvisioningModeUtils; 89 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 90 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 91 import com.android.managedprovisioning.common.PolicyComplianceUtils; 92 import com.android.managedprovisioning.common.ProvisionLogger; 93 import com.android.managedprovisioning.common.SettingsFacade; 94 import com.android.managedprovisioning.common.Utils; 95 import com.android.managedprovisioning.model.CustomizationParams; 96 import com.android.managedprovisioning.model.ProvisioningParams; 97 import com.android.managedprovisioning.model.ProvisioningParams.FlowType; 98 import com.android.managedprovisioning.preprovisioning.PreProvisioningViewModel.PreProvisioningViewModelFactory; 99 100 import java.util.List; 101 102 /** 103 * Controller which contains business logic related to provisioning preparation. 104 * 105 * @see PreProvisioningActivity 106 */ 107 public class PreProvisioningActivityController { 108 private final Context mContext; 109 private final Ui mUi; 110 private final Utils mUtils; 111 private final PolicyComplianceUtils mPolicyComplianceUtils; 112 private final GetProvisioningModeUtils mGetProvisioningModeUtils; 113 private final SettingsFacade mSettingsFacade; 114 115 // used system services 116 private final DevicePolicyManager mDevicePolicyManager; 117 private final UserManager mUserManager; 118 private final PackageManager mPackageManager; 119 private final KeyguardManager mKeyguardManager; 120 private final PersistentDataBlockManager mPdbManager; 121 private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker; 122 private final ManagedProvisioningSharedPreferences mSharedPreferences; 123 124 private final PreProvisioningViewModel mViewModel; 125 PreProvisioningActivityController( @onNull ComponentActivity activity, @NonNull Ui ui)126 public PreProvisioningActivityController( 127 @NonNull ComponentActivity activity, 128 @NonNull Ui ui) { 129 this(activity, ui, 130 new Utils(), new SettingsFacade(), 131 new ManagedProvisioningSharedPreferences(activity), 132 new PolicyComplianceUtils(), 133 new GetProvisioningModeUtils(), 134 new ViewModelProvider( 135 activity, 136 new PreProvisioningViewModelFactory( 137 (ManagedProvisioningBaseApplication) activity.getApplication())) 138 .get(PreProvisioningViewModel.class)); 139 } 140 @VisibleForTesting PreProvisioningActivityController( @onNull Context context, @NonNull Ui ui, @NonNull Utils utils, @NonNull SettingsFacade settingsFacade, @NonNull ManagedProvisioningSharedPreferences sharedPreferences, @NonNull PolicyComplianceUtils policyComplianceUtils, @NonNull GetProvisioningModeUtils getProvisioningModeUtils, @NonNull PreProvisioningViewModel viewModel)141 PreProvisioningActivityController( 142 @NonNull Context context, 143 @NonNull Ui ui, 144 @NonNull Utils utils, 145 @NonNull SettingsFacade settingsFacade, 146 @NonNull ManagedProvisioningSharedPreferences sharedPreferences, 147 @NonNull PolicyComplianceUtils policyComplianceUtils, 148 @NonNull GetProvisioningModeUtils getProvisioningModeUtils, 149 @NonNull PreProvisioningViewModel viewModel) { 150 mContext = requireNonNull(context, "Context must not be null"); 151 mUi = requireNonNull(ui, "Ui must not be null"); 152 mSettingsFacade = requireNonNull(settingsFacade); 153 mUtils = requireNonNull(utils, "Utils must not be null"); 154 mPolicyComplianceUtils = requireNonNull(policyComplianceUtils, 155 "PolicyComplianceUtils cannot be null"); 156 mGetProvisioningModeUtils = requireNonNull(getProvisioningModeUtils, 157 "GetProvisioningModeUtils cannot be null"); 158 mSharedPreferences = requireNonNull(sharedPreferences); 159 mViewModel = requireNonNull(viewModel); 160 161 mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); 162 mUserManager = mContext.getSystemService(UserManager.class); 163 mPackageManager = mContext.getPackageManager(); 164 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 165 mPdbManager = (PersistentDataBlockManager) mContext.getSystemService( 166 Context.PERSISTENT_DATA_BLOCK_SERVICE); 167 mProvisioningAnalyticsTracker = new ProvisioningAnalyticsTracker( 168 MetricsWriterFactory.getMetricsWriter(mContext, mSettingsFacade), 169 mSharedPreferences); 170 } 171 172 interface Ui { 173 /** 174 * Show an error message and cancel provisioning. 175 * @param titleId resource id used to form the user facing error title 176 * @param messageId resource id used to form the user facing error message 177 * @param errorMessage an error message that gets logged for debugging 178 */ showErrorAndClose(Integer titleId, int messageId, String errorMessage)179 void showErrorAndClose(Integer titleId, int messageId, String errorMessage); 180 181 /** 182 * Request the user to encrypt the device. 183 * @param params the {@link ProvisioningParams} object related to the ongoing provisioning 184 */ requestEncryption(ProvisioningParams params)185 void requestEncryption(ProvisioningParams params); 186 187 /** 188 * Request the user to choose a wifi network. 189 */ requestWifiPick()190 void requestWifiPick(); 191 192 /** 193 * Start provisioning. 194 * @param params the {@link ProvisioningParams} object related to the ongoing provisioning 195 */ startProvisioning(ProvisioningParams params)196 void startProvisioning(ProvisioningParams params); 197 198 /** 199 * Show an error dialog indicating that the current launcher does not support managed 200 * profiles and ask the user to choose a different one. 201 */ showCurrentLauncherInvalid()202 void showCurrentLauncherInvalid(); 203 showOwnershipDisclaimerScreen(ProvisioningParams params)204 void showOwnershipDisclaimerScreen(ProvisioningParams params); 205 prepareFinancedDeviceFlow(ProvisioningParams params)206 void prepareFinancedDeviceFlow(ProvisioningParams params); 207 showFactoryResetDialog(Integer titleId, int messageId)208 void showFactoryResetDialog(Integer titleId, int messageId); 209 initiateUi(UiParams uiParams)210 void initiateUi(UiParams uiParams); 211 212 /** 213 * Abort provisioning and close app 214 */ abortProvisioning()215 void abortProvisioning(); 216 prepareAdminIntegratedFlow(ProvisioningParams params)217 void prepareAdminIntegratedFlow(ProvisioningParams params); 218 } 219 220 /** 221 * Wrapper which holds information related to the consent screen. 222 * <p>Does not implement {@link Object#equals(Object)}, {@link Object#hashCode()} 223 * or {@link Object#toString()}. 224 */ 225 public static class UiParams { 226 /** 227 * Admin application package name. 228 */ 229 public String packageName; 230 /** 231 * Various organization-defined customizations, e.g. colors, organization name. 232 */ 233 public CustomizationParams customization; 234 /** 235 * List of headings for the organization-provided terms and conditions. 236 */ 237 public List<String> disclaimerHeadings; 238 public boolean isDeviceManaged; 239 /** 240 * The original provisioning action, kept for backwards compatibility. 241 */ 242 public String provisioningAction; 243 public boolean isOrganizationOwnedProvisioning; 244 } 245 246 /** 247 * Initiates Profile owner and device owner provisioning. 248 * @param intent Intent that started provisioning. 249 * @param callingPackage Package that started provisioning. 250 */ initiateProvisioning(Intent intent, String callingPackage)251 public void initiateProvisioning(Intent intent, String callingPackage) { 252 mSharedPreferences.writeProvisioningStartedTimestamp(SystemClock.elapsedRealtime()); 253 mProvisioningAnalyticsTracker.logProvisioningSessionStarted(mContext); 254 255 if (!tryParseParameters(intent)) { 256 return; 257 } 258 259 ProvisioningParams params = mViewModel.getParams(); 260 if (!checkFactoryResetProtection(params, callingPackage)) { 261 return; 262 } 263 264 if (!verifyActionAndCaller(intent, callingPackage)) { 265 return; 266 } 267 268 // Check whether provisioning is allowed for the current action. This check needs to happen 269 // before any actions that might affect the state of the device. 270 // Note that checkDevicePolicyPreconditions takes care of calling 271 // showProvisioningErrorAndClose. So we only need to show the factory reset dialog (if 272 // applicable) and return. 273 if (!checkDevicePolicyPreconditions()) { 274 return; 275 } 276 277 if (!isIntentActionValid(intent.getAction())) { 278 ProvisionLogger.loge( 279 ACTION_PROVISION_MANAGED_DEVICE + " is no longer a supported intent action."); 280 mUi.abortProvisioning(); 281 return; 282 } 283 284 if (isDeviceOwnerProvisioning()) { 285 // TODO: make a general test based on deviceAdminDownloadInfo field 286 // PO doesn't ever initialize that field, so OK as a general case 287 if (shouldShowWifiPicker(intent)) { 288 // Have the user pick a wifi network if necessary. 289 // It is not possible to ask the user to pick a wifi network if 290 // the screen is locked. 291 // TODO: remove this check once we know the screen will not be locked. 292 if (mKeyguardManager.inKeyguardRestrictedInputMode()) { 293 // TODO: decide on what to do in that case; fail? retry on screen unlock? 294 ProvisionLogger.logi("Cannot pick wifi because the screen is locked."); 295 } else if (canRequestWifiPick()) { 296 // we resume this method after a successful WiFi pick 297 // TODO: refactor as evil - logic should be less spread out 298 mUi.requestWifiPick(); 299 return; 300 } else { 301 mUi.showErrorAndClose(R.string.cant_set_up_device, 302 R.string.contact_your_admin_for_help, 303 "Cannot pick WiFi because there is no handler to the intent"); 304 } 305 } 306 } 307 308 mViewModel.getTimeLogger().start(); 309 mProvisioningAnalyticsTracker.logPreProvisioningStarted(mContext, intent); 310 mViewModel.onProvisioningInitiated(); 311 312 if (mUtils.checkAdminIntegratedFlowPreconditions(params)) { 313 if (mUtils.shouldShowOwnershipDisclaimerScreen(params)) { 314 mUi.showOwnershipDisclaimerScreen(params); 315 } else { 316 mUi.prepareAdminIntegratedFlow(params); 317 } 318 mViewModel.onAdminIntegratedFlowInitiated(); 319 } else if (mUtils.isFinancedDeviceAction(params.provisioningAction)) { 320 mUi.prepareFinancedDeviceFlow(params); 321 } else if (params.isNfc) { 322 // TODO(b/177849035): Remove NFC-specific logic 323 if (mUtils.shouldShowOwnershipDisclaimerScreen(params)) { 324 mUi.showOwnershipDisclaimerScreen(params); 325 } else { 326 startNfcFlow(); 327 } 328 } else if (isProfileOwnerProvisioning()) { 329 startManagedProfileFlow(); 330 } else if (isDpcTriggeredManagedDeviceProvisioning(intent)) { 331 // TODO(b/175678720): Fail provisioning if flow started by PROVISION_MANAGED_DEVICE 332 startManagedDeviceFlow(); 333 } 334 } 335 isIntentActionValid(String action)336 private boolean isIntentActionValid(String action) { 337 return !ACTION_PROVISION_MANAGED_DEVICE.equals(action); 338 } 339 startNfcFlow()340 void startNfcFlow() { 341 ProvisionLogger.logi("Starting the NFC provisioning flow."); 342 updateProvisioningFlowState(FLOW_TYPE_LEGACY); 343 showUserConsentScreen(); 344 } 345 startManagedProfileFlow()346 private void startManagedProfileFlow() { 347 ProvisionLogger.logi("Starting the managed profile flow."); 348 showUserConsentScreen(); 349 } 350 startManagedDeviceFlow()351 private void startManagedDeviceFlow() { 352 ProvisionLogger.logi("Starting the legacy managed device flow."); 353 showUserConsentScreen(); 354 } 355 isDpcTriggeredManagedDeviceProvisioning(Intent intent)356 private boolean isDpcTriggeredManagedDeviceProvisioning(Intent intent) { 357 return ACTION_PROVISION_MANAGED_DEVICE.equals(intent.getAction()); 358 } 359 isNfcProvisioning(Intent intent)360 private boolean isNfcProvisioning(Intent intent) { 361 return ACTION_NDEF_DISCOVERED.equals(intent.getAction()); 362 } 363 isQrCodeProvisioning(Intent intent)364 private boolean isQrCodeProvisioning(Intent intent) { 365 if (!ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction())) { 366 return false; 367 } 368 final int provisioningTrigger = intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER, 369 PROVISIONING_TRIGGER_UNSPECIFIED); 370 return provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE; 371 } 372 shouldShowWifiPicker(Intent intent)373 private boolean shouldShowWifiPicker(Intent intent) { 374 ProvisioningParams params = mViewModel.getParams(); 375 if (params.wifiInfo != null) { 376 return false; 377 } 378 if (params.deviceAdminDownloadInfo == null) { 379 return false; 380 } 381 if (mUtils.isNetworkTypeConnected(mContext, ConnectivityManager.TYPE_WIFI, 382 ConnectivityManager.TYPE_ETHERNET)) { 383 return false; 384 } 385 // we intentionally disregard whether mobile is connected for QR and NFC 386 // provisioning. b/153442588 for context 387 if (params.useMobileData 388 && (isQrCodeProvisioning(intent) || isNfcProvisioning(intent))) { 389 return false; 390 } 391 if (params.useMobileData) { 392 return !mUtils.isMobileNetworkConnectedToInternet(mContext); 393 } 394 return true; 395 } 396 showUserConsentScreen()397 void showUserConsentScreen() { 398 // Check whether provisioning is allowed for the current action 399 if (!checkDevicePolicyPreconditions()) { 400 return; 401 } 402 403 if (mViewModel.getParams().provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE) 404 && mViewModel.getParams().isOrganizationOwnedProvisioning) { 405 mProvisioningAnalyticsTracker.logOrganizationOwnedManagedProfileProvisioning(); 406 } 407 408 CustomizationParams customization = 409 CustomizationParams.createInstance(mViewModel.getParams(), mContext, mUtils); 410 411 // show UI so we can get user's consent to continue 412 final String packageName = mViewModel.getParams().inferDeviceAdminPackageName(); 413 final UiParams uiParams = new UiParams(); 414 uiParams.customization = customization; 415 uiParams.provisioningAction = mViewModel.getParams().provisioningAction; 416 uiParams.packageName = packageName; 417 uiParams.isDeviceManaged = mDevicePolicyManager.isDeviceManaged(); 418 uiParams.isOrganizationOwnedProvisioning = 419 mViewModel.getParams().isOrganizationOwnedProvisioning; 420 421 mUi.initiateUi(uiParams); 422 mViewModel.onShowUserConsent(); 423 } 424 updateProvisioningParamsFromIntent(Intent resultIntent)425 boolean updateProvisioningParamsFromIntent(Intent resultIntent) { 426 final int provisioningMode = resultIntent.getIntExtra( 427 DevicePolicyManager.EXTRA_PROVISIONING_MODE, 0); 428 if (!mViewModel.getParams().allowedProvisioningModes.contains(provisioningMode)) { 429 ProvisionLogger.loge("Invalid provisioning mode chosen by the DPC: " + provisioningMode 430 + ", but expected one of " 431 + mViewModel.getParams().allowedProvisioningModes.toString()); 432 return false; 433 } 434 switch (provisioningMode) { 435 case DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE: 436 updateParamsPostProvisioningModeDecision( 437 resultIntent, 438 ACTION_PROVISION_MANAGED_DEVICE, 439 /* isOrganizationOwnedProvisioning */ true, 440 /* updateAccountToMigrate */ false); 441 return true; 442 case DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE: 443 updateParamsPostProvisioningModeDecision( 444 resultIntent, 445 ACTION_PROVISION_MANAGED_PROFILE, 446 mUtils.isOrganizationOwnedAllowed(mViewModel.getParams()), 447 /* updateAccountToMigrate */ true); 448 return true; 449 case PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE: 450 updateParamsPostProvisioningModeDecision( 451 resultIntent, 452 ACTION_PROVISION_MANAGED_PROFILE, 453 /* isOrganizationOwnedProvisioning */ false, 454 /* updateAccountToMigrate */ true); 455 return true; 456 default: 457 ProvisionLogger.logw("Unknown returned provisioning mode:" 458 + provisioningMode); 459 return false; 460 } 461 } 462 updateParamsPostProvisioningModeDecision(Intent resultIntent, String provisioningAction, boolean isOrganizationOwnedProvisioning, boolean updateAccountToMigrate)463 private void updateParamsPostProvisioningModeDecision(Intent resultIntent, 464 String provisioningAction, boolean isOrganizationOwnedProvisioning, 465 boolean updateAccountToMigrate) { 466 ProvisioningParams.Builder builder = mViewModel.getParams().toBuilder(); 467 builder.setFlowType(FLOW_TYPE_ADMIN_INTEGRATED); 468 builder.setProvisioningAction(provisioningAction); 469 builder.setIsOrganizationOwnedProvisioning(isOrganizationOwnedProvisioning); 470 maybeUpdateAdminExtrasBundle(builder, resultIntent); 471 maybeUpdateSkipEducationScreens(builder, resultIntent); 472 if (updateAccountToMigrate) { 473 maybeUpdateAccountToMigrate(builder, resultIntent); 474 } 475 if (provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 476 maybeUpdateKeepAccountMigrated(builder, resultIntent); 477 maybeUpdateLeaveAllSystemAppsEnabled(builder, resultIntent); 478 } 479 mViewModel.updateParams(builder.build()); 480 } 481 maybeUpdateSkipEducationScreens(ProvisioningParams.Builder builder, Intent resultIntent)482 private void maybeUpdateSkipEducationScreens(ProvisioningParams.Builder builder, 483 Intent resultIntent) { 484 if (resultIntent.hasExtra(EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS)) { 485 builder.setSkipEducationScreens(resultIntent.getBooleanExtra( 486 EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS, /* defaultValue */ false)); 487 } 488 } 489 maybeUpdateAccountToMigrate(ProvisioningParams.Builder builder, Intent resultIntent)490 private void maybeUpdateAccountToMigrate(ProvisioningParams.Builder builder, 491 Intent resultIntent) { 492 if (resultIntent.hasExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)) { 493 final Account account = resultIntent.getParcelableExtra( 494 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE); 495 builder.setAccountToMigrate(account); 496 } 497 } 498 499 /** 500 * Appends the admin bundle in {@code resultIntent}, if provided, to the existing admin bundle, 501 * if it exists, and stores the result in {@code builder}. 502 */ maybeUpdateAdminExtrasBundle(ProvisioningParams.Builder builder, Intent resultIntent)503 private void maybeUpdateAdminExtrasBundle(ProvisioningParams.Builder builder, 504 Intent resultIntent) { 505 if (resultIntent.hasExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)) { 506 PersistableBundle resultBundle = 507 resultIntent.getParcelableExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE); 508 if (mViewModel.getParams().adminExtrasBundle != null) { 509 PersistableBundle existingBundle = 510 new PersistableBundle(mViewModel.getParams().adminExtrasBundle); 511 existingBundle.putAll(resultBundle); 512 resultBundle = existingBundle; 513 } 514 builder.setAdminExtrasBundle(resultBundle); 515 } 516 } 517 maybeUpdateKeepAccountMigrated( ProvisioningParams.Builder builder, Intent resultIntent)518 private void maybeUpdateKeepAccountMigrated( 519 ProvisioningParams.Builder builder, 520 Intent resultIntent) { 521 if (resultIntent.hasExtra(EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION)) { 522 final boolean keepAccountMigrated = resultIntent.getBooleanExtra( 523 EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION, 524 DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED); 525 builder.setKeepAccountMigrated(keepAccountMigrated); 526 } 527 } 528 maybeUpdateLeaveAllSystemAppsEnabled( ProvisioningParams.Builder builder, Intent resultIntent)529 private void maybeUpdateLeaveAllSystemAppsEnabled( 530 ProvisioningParams.Builder builder, 531 Intent resultIntent) { 532 if (resultIntent.hasExtra(EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED)) { 533 final boolean leaveAllSystemAppsEnabled = resultIntent.getBooleanExtra( 534 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 535 DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED); 536 builder.setLeaveAllSystemAppsEnabled(leaveAllSystemAppsEnabled); 537 } 538 } 539 updateProvisioningFlowState(@lowType int flowType)540 void updateProvisioningFlowState(@FlowType int flowType) { 541 mViewModel.updateParams(mViewModel.getParams().toBuilder().setFlowType(flowType).build()); 542 } 543 getAdditionalExtrasForGetProvisioningModeIntent()544 Bundle getAdditionalExtrasForGetProvisioningModeIntent() { 545 Bundle bundle = new Bundle(); 546 if (shouldPassPersonalDataToAdminApp()) { 547 final TelephonyManager telephonyManager = mContext.getSystemService( 548 TelephonyManager.class); 549 bundle.putString(EXTRA_PROVISIONING_IMEI, telephonyManager.getImei()); 550 bundle.putString(EXTRA_PROVISIONING_SERIAL_NUMBER, Build.getSerial()); 551 } 552 ProvisioningParams params = mViewModel.getParams(); 553 bundle.putParcelable(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, 554 params.adminExtrasBundle); 555 bundle.putIntegerArrayList(EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES, 556 params.allowedProvisioningModes); 557 558 if (params.allowedProvisioningModes.contains( 559 DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE)) { 560 bundle.putBoolean(EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT, 561 params.deviceOwnerPermissionGrantOptOut); 562 } 563 return bundle; 564 } 565 shouldPassPersonalDataToAdminApp()566 private boolean shouldPassPersonalDataToAdminApp() { 567 ProvisioningParams params = mViewModel.getParams(); 568 return params.initiatorRequestedProvisioningModes == FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED 569 || params.initiatorRequestedProvisioningModes == FLAG_SUPPORTED_MODES_DEVICE_OWNER; 570 } 571 createViewTermsIntent()572 protected Intent createViewTermsIntent() { 573 return new Intent(mContext, getTermsActivityClass()) 574 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, mViewModel.getParams()); 575 } 576 getTermsActivityClass()577 private Class<? extends Activity> getTermsActivityClass() { 578 return getBaseApplication().getActivityClassForScreen(ManagedProvisioningScreens.TERMS); 579 } 580 getBaseApplication()581 private ManagedProvisioningBaseApplication getBaseApplication() { 582 return (ManagedProvisioningBaseApplication) mContext.getApplicationContext(); 583 } 584 585 /** 586 * Start provisioning for real. In profile owner case, double check that the launcher 587 * supports managed profiles if necessary. In device owner case, possibly create a new user 588 * before starting provisioning. 589 */ continueProvisioningAfterUserConsent()590 public void continueProvisioningAfterUserConsent() { 591 mProvisioningAnalyticsTracker.logProvisioningAction( 592 mContext, mViewModel.getParams().provisioningAction); 593 594 // check if encryption is required 595 if (isEncryptionRequired()) { 596 if (mDevicePolicyManager.getStorageEncryptionStatus() 597 == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) { 598 mUi.showErrorAndClose(R.string.cant_set_up_device, 599 R.string.device_doesnt_allow_encryption_contact_admin, 600 "This device does not support encryption, and " 601 + DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION 602 + " was not passed."); 603 } else { 604 mUi.requestEncryption(mViewModel.getParams()); 605 // we come back to this method after returning from encryption dialog 606 // TODO: refactor as evil - logic should be less spread out 607 } 608 return; 609 } 610 611 if (isProfileOwnerProvisioning()) { // PO case 612 // Check whether the current launcher supports managed profiles. 613 if (!mUtils.currentLauncherSupportsManagedProfiles(mContext)) { 614 mUi.showCurrentLauncherInvalid(); 615 // we come back to this method after returning from launcher dialog 616 // TODO: refactor as evil - logic should be less spread out 617 return; 618 } else { 619 // Cancel the boot reminder as provisioning has now started. 620 mViewModel.getEncryptionController().cancelEncryptionReminder(); 621 stopTimeLogger(); 622 mUi.startProvisioning(mViewModel.getParams()); 623 } 624 } else { // DO case 625 // Cancel the boot reminder as provisioning has now started. 626 mViewModel.getEncryptionController().cancelEncryptionReminder(); 627 stopTimeLogger(); 628 mUi.startProvisioning(mViewModel.getParams()); 629 } 630 631 mViewModel.onProvisioningStartedAfterUserConsent(); 632 } 633 634 /** @return False if condition preventing further provisioning */ 635 @VisibleForTesting checkFactoryResetProtection(ProvisioningParams params, String callingPackage)636 boolean checkFactoryResetProtection(ProvisioningParams params, String callingPackage) { 637 if (skipFactoryResetProtectionCheck(params, callingPackage)) { 638 return true; 639 } 640 if (factoryResetProtected()) { 641 mUi.showErrorAndClose(R.string.cant_set_up_device, 642 R.string.device_has_reset_protection_contact_admin, 643 "Factory reset protection blocks provisioning."); 644 return false; 645 } 646 return true; 647 } 648 skipFactoryResetProtectionCheck( ProvisioningParams params, String callingPackage)649 private boolean skipFactoryResetProtectionCheck( 650 ProvisioningParams params, String callingPackage) { 651 if (TextUtils.isEmpty(callingPackage)) { 652 return false; 653 } 654 String persistentDataPackageName = mContext.getResources() 655 .getString(com.android.internal.R.string.config_persistentDataPackageName); 656 try { 657 // Only skip the FRP check if the caller is the package responsible for maintaining FRP 658 // - i.e. if this is a flow for restoring device owner after factory reset. 659 PackageInfo callingPackageInfo = mPackageManager.getPackageInfo(callingPackage, 0); 660 return callingPackageInfo != null 661 && callingPackageInfo.applicationInfo != null 662 && callingPackageInfo.applicationInfo.isSystemApp() 663 && !TextUtils.isEmpty(persistentDataPackageName) 664 && callingPackage.equals(persistentDataPackageName) 665 && params != null 666 && params.startedByTrustedSource; 667 } catch (PackageManager.NameNotFoundException e) { 668 ProvisionLogger.loge("Calling package not found.", e); 669 return false; 670 } 671 } 672 673 /** @return False if condition preventing further provisioning */ checkDevicePolicyPreconditions()674 @VisibleForTesting protected boolean checkDevicePolicyPreconditions() { 675 ProvisioningParams params = mViewModel.getParams(); 676 int provisioningPreCondition = mDevicePolicyManager.checkProvisioningPreCondition( 677 params.provisioningAction, 678 params.inferDeviceAdminPackageName()); 679 // Check whether provisioning is allowed for the current action. 680 if (provisioningPreCondition != CODE_OK) { 681 mProvisioningAnalyticsTracker.logProvisioningNotAllowed(mContext, 682 provisioningPreCondition); 683 showProvisioningErrorAndClose( 684 params.provisioningAction, provisioningPreCondition); 685 return false; 686 } 687 return true; 688 } 689 690 /** @return False if condition preventing further provisioning */ tryParseParameters(Intent intent)691 private boolean tryParseParameters(Intent intent) { 692 try { 693 // Read the provisioning params from the provisioning intent 694 mViewModel.loadParamsIfNecessary(intent); 695 } catch (IllegalProvisioningArgumentException e) { 696 mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help, 697 e.getMessage()); 698 return false; 699 } 700 return true; 701 } 702 703 /** @return False if condition preventing further provisioning */ verifyActionAndCaller(Intent intent, String callingPackage)704 @VisibleForTesting protected boolean verifyActionAndCaller(Intent intent, 705 String callingPackage) { 706 if (verifyActionAndCallerInner(intent, callingPackage)) { 707 return true; 708 } else { 709 mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help, 710 "invalid intent or calling package"); 711 return false; 712 } 713 } 714 verifyActionAndCallerInner(Intent intent, String callingPackage)715 private boolean verifyActionAndCallerInner(Intent intent, String callingPackage) { 716 // If this is a resume after encryption or trusted intent, we verify the activity alias. 717 // Otherwise, verify that the calling app is trying to set itself as Device/ProfileOwner 718 if (ACTION_RESUME_PROVISIONING.equals(intent.getAction())) { 719 return verifyActivityAlias(intent, "PreProvisioningActivityAfterEncryption"); 720 } else if (ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { 721 return verifyActivityAlias(intent, "PreProvisioningActivityViaNfc"); 722 } else if (ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction()) 723 || ACTION_PROVISION_FINANCED_DEVICE.equals(intent.getAction())) { 724 return verifyActivityAlias(intent, "PreProvisioningActivityViaTrustedApp"); 725 } else { 726 return verifyCaller(callingPackage); 727 } 728 } 729 verifyActivityAlias(Intent intent, String activityAlias)730 private boolean verifyActivityAlias(Intent intent, String activityAlias) { 731 ComponentName componentName = intent.getComponent(); 732 if (componentName == null || componentName.getClassName() == null) { 733 ProvisionLogger.loge("null class in component when verifying activity alias " 734 + activityAlias); 735 return false; 736 } 737 738 if (!componentName.getClassName().endsWith(activityAlias)) { 739 ProvisionLogger.loge("Looking for activity alias " + activityAlias + ", but got " 740 + componentName.getClassName()); 741 return false; 742 } 743 744 return true; 745 } 746 747 /** 748 * Verify that the caller is trying to set itself as owner. 749 * @return false if the caller is trying to set a different package as owner. 750 */ verifyCaller(@onNull String callingPackage)751 private boolean verifyCaller(@NonNull String callingPackage) { 752 if (callingPackage == null) { 753 ProvisionLogger.loge("Calling package is null. Was startActivityForResult used to " 754 + "start this activity?"); 755 return false; 756 } 757 758 if (!callingPackage.equals(mViewModel.getParams().inferDeviceAdminPackageName())) { 759 ProvisionLogger.loge("Permission denied, " 760 + "calling package tried to set a different package as owner. "); 761 return false; 762 } 763 764 return true; 765 } 766 767 /** 768 * Returns whether the device needs encryption. 769 */ isEncryptionRequired()770 private boolean isEncryptionRequired() { 771 return !mViewModel.getParams().skipEncryption && mUtils.isEncryptionRequired(); 772 } 773 774 /** 775 * Returns whether the device is frp protected during setup wizard. 776 */ factoryResetProtected()777 private boolean factoryResetProtected() { 778 // If we are started during setup wizard, check for factory reset protection. 779 // If the device is already setup successfully, do not check factory reset protection. 780 if (mSettingsFacade.isDeviceProvisioned(mContext)) { 781 ProvisionLogger.logd("Device is provisioned, FRP not required."); 782 return false; 783 } 784 785 if (mPdbManager == null) { 786 ProvisionLogger.logd("Reset protection not supported."); 787 return false; 788 } 789 int size = mPdbManager.getDataBlockSize(); 790 ProvisionLogger.logd("Data block size: " + size); 791 return size > 0; 792 } 793 794 /** 795 * Returns whether activity to pick wifi can be requested or not. 796 */ canRequestWifiPick()797 private boolean canRequestWifiPick() { 798 return mPackageManager.resolveActivity(mUtils.getWifiPickIntent(), 0) != null; 799 } 800 801 /** 802 * Returns whether the provisioning process is a profile owner provisioning process. 803 */ isProfileOwnerProvisioning()804 public boolean isProfileOwnerProvisioning() { 805 return mUtils.isProfileOwnerAction(mViewModel.getParams().provisioningAction); 806 } 807 808 /** 809 * Returns whether the provisioning process is a device owner provisioning process. 810 */ isDeviceOwnerProvisioning()811 public boolean isDeviceOwnerProvisioning() { 812 return mUtils.isDeviceOwnerAction(mViewModel.getParams().provisioningAction); 813 } 814 815 816 @Nullable getParams()817 public ProvisioningParams getParams() { 818 return mViewModel.getParams(); 819 } 820 821 /** 822 * Notifies the time logger to stop. 823 */ stopTimeLogger()824 public void stopTimeLogger() { 825 mViewModel.getTimeLogger().stop(); 826 } 827 828 /** 829 * Log if PreProvisioning was cancelled. 830 */ logPreProvisioningCancelled()831 public void logPreProvisioningCancelled() { 832 mProvisioningAnalyticsTracker.logProvisioningCancelled(mContext, 833 CANCELLED_BEFORE_PROVISIONING); 834 } 835 836 /** 837 * Logs the provisioning flow type. 838 */ logProvisioningFlowType()839 public void logProvisioningFlowType() { 840 mProvisioningAnalyticsTracker.logProvisioningFlowType(mViewModel.getParams()); 841 } 842 843 /** 844 * Removes a user profile. If we are in COMP case, and were blocked by having to delete a user, 845 * resumes COMP provisioning. 846 */ removeUser(int userProfileId)847 public void removeUser(int userProfileId) { 848 // There is a possibility that the DO has set the disallow remove managed profile user 849 // restriction, but is initiating the provisioning. In this case, we still want to remove 850 // the managed profile. 851 // We know that we can remove the managed profile because we checked 852 // DevicePolicyManager.checkProvisioningPreCondition 853 mUserManager.removeUserEvenWhenDisallowed(userProfileId); 854 } 855 getSettingsFacade()856 SettingsFacade getSettingsFacade() { 857 return mSettingsFacade; 858 } 859 getPolicyComplianceUtils()860 public PolicyComplianceUtils getPolicyComplianceUtils() { 861 return mPolicyComplianceUtils; 862 } 863 getGetProvisioningModeUtils()864 public GetProvisioningModeUtils getGetProvisioningModeUtils() { 865 return mGetProvisioningModeUtils; 866 } 867 onReturnFromProvisioning()868 void onReturnFromProvisioning() { 869 mViewModel.onReturnFromProvisioning(); 870 } 871 getState()872 LiveData<Integer> getState() { 873 return mViewModel.getState(); 874 } 875 showProvisioningErrorAndClose(String action, int provisioningPreCondition)876 private void showProvisioningErrorAndClose(String action, int provisioningPreCondition) { 877 // Try to show an error message explaining why provisioning is not allowed. 878 switch (action) { 879 case ACTION_PROVISION_MANAGED_PROFILE: 880 showManagedProfileErrorAndClose(provisioningPreCondition); 881 return; 882 case ACTION_PROVISION_MANAGED_DEVICE: 883 showDeviceOwnerErrorAndClose(provisioningPreCondition); 884 return; 885 } 886 // This should never be the case, as showProvisioningError is always called after 887 // verifying the supported provisioning actions. 888 } 889 showManagedProfileErrorAndClose(int provisioningPreCondition)890 private void showManagedProfileErrorAndClose(int provisioningPreCondition) { 891 UserInfo userInfo = mUserManager.getUserInfo(mUserManager.getUserHandle()); 892 ProvisionLogger.logw("DevicePolicyManager.checkProvisioningPreCondition returns code: " 893 + provisioningPreCondition); 894 // If this is organization-owned provisioning, do not show any other error dialog, just 895 // show the factory reset dialog and return. 896 // This cannot be abused by regular apps to force a factory reset because 897 // isOrganizationOwnedProvisioning is only set to true if the provisioning action was 898 // from a trusted source. See Utils.isOrganizationOwnedProvisioning where we check for 899 // ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE which is guarded by the 900 // DISPATCH_PROVISIONING_MESSAGE system|privileged permission. 901 if (mUtils.isOrganizationOwnedAllowed(mViewModel.getParams())) { 902 ProvisionLogger.loge( 903 "Provisioning preconditions failed for organization-owned provisioning."); 904 mUi.showFactoryResetDialog(R.string.cant_set_up_device, 905 R.string.contact_your_admin_for_help); 906 return; 907 } 908 switch (provisioningPreCondition) { 909 case CODE_MANAGED_USERS_NOT_SUPPORTED: 910 mUi.showErrorAndClose(R.string.cant_add_work_profile, 911 R.string.work_profile_cant_be_added_contact_admin, 912 "Exiting managed profile provisioning, managed profiles " 913 + "feature is not available"); 914 break; 915 case CODE_CANNOT_ADD_MANAGED_PROFILE: 916 if (!userInfo.canHaveProfile()) { 917 mUi.showErrorAndClose(R.string.cant_add_work_profile, 918 R.string.work_profile_cant_be_added_contact_admin, 919 "Exiting managed profile provisioning, calling user cannot " 920 + "have managed profiles"); 921 } else if (!canAddManagedProfile()) { 922 mUi.showErrorAndClose(R.string.cant_add_work_profile, 923 R.string.work_profile_cant_be_added_contact_admin, 924 "Exiting managed profile provisioning, a managed profile " 925 + "already exists"); 926 } else { 927 mUi.showErrorAndClose(R.string.cant_add_work_profile, 928 R.string.work_profile_cant_be_added_contact_admin, 929 "Exiting managed profile provisioning, cannot add more managed " 930 + "profiles"); 931 } 932 break; 933 case CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS: 934 mUi.showErrorAndClose(R.string.cant_add_work_profile, 935 R.string.work_profile_cant_be_added_contact_admin, 936 "Exiting managed profile provisioning, " 937 + "provisioning not allowed by OEM"); 938 break; 939 default: 940 mUi.showErrorAndClose(R.string.cant_add_work_profile, 941 R.string.contact_your_admin_for_help, 942 "Managed profile provisioning not allowed for an unknown " 943 + "reason, code: " + provisioningPreCondition); 944 } 945 } 946 canAddManagedProfile()947 private boolean canAddManagedProfile() { 948 return mUserManager.canAddMoreManagedProfiles( 949 mContext.getUserId(), /* allowedToRemoveOne= */ false); 950 } 951 showDeviceOwnerErrorAndClose(int provisioningPreCondition)952 private void showDeviceOwnerErrorAndClose(int provisioningPreCondition) { 953 switch (provisioningPreCondition) { 954 case CODE_HAS_DEVICE_OWNER: 955 case CODE_USER_SETUP_COMPLETED: 956 mUi.showErrorAndClose(R.string.device_already_set_up, 957 R.string.if_questions_contact_admin, "Device already provisioned."); 958 return; 959 case CODE_NOT_SYSTEM_USER: 960 mUi.showErrorAndClose(R.string.cant_set_up_device, 961 R.string.contact_your_admin_for_help, 962 "Device owner can only be set up for USER_SYSTEM."); 963 return; 964 case CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS: 965 mUi.showErrorAndClose(R.string.cant_set_up_device, 966 R.string.contact_your_admin_for_help, 967 "Provisioning not allowed by OEM"); 968 return; 969 } 970 mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help, 971 "Device Owner provisioning not allowed for an unknown reason."); 972 } 973 } 974