• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
24 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
25 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES;
26 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMERS;
27 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_IMEI;
28 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION;
29 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED;
30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE;
31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME;
32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT;
33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SERIAL_NUMBER;
34 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS;
35 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION;
36 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE;
37 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
38 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_DEVICE_OWNER;
39 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED;
40 import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE;
41 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC;
42 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE;
43 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
44 import static android.app.admin.DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE;
45 import static android.app.admin.DevicePolicyManager.STATUS_HAS_DEVICE_OWNER;
46 import static android.app.admin.DevicePolicyManager.STATUS_MANAGED_USERS_NOT_SUPPORTED;
47 import static android.app.admin.DevicePolicyManager.STATUS_NOT_SYSTEM_USER;
48 import static android.app.admin.DevicePolicyManager.STATUS_OK;
49 import static android.app.admin.DevicePolicyManager.STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS;
50 import static android.app.admin.DevicePolicyManager.STATUS_USER_SETUP_COMPLETED;
51 
52 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.CANCELLED_BEFORE_PROVISIONING;
53 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
54 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED;
55 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT;
56 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION;
57 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED;
58 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED;
59 
60 import static java.util.Objects.requireNonNull;
61 
62 import android.accounts.Account;
63 import android.annotation.NonNull;
64 import android.annotation.Nullable;
65 import android.app.Activity;
66 import android.app.KeyguardManager;
67 import android.app.admin.DevicePolicyManager;
68 import android.content.ComponentName;
69 import android.content.Context;
70 import android.content.Intent;
71 import android.content.pm.PackageInfo;
72 import android.content.pm.PackageManager;
73 import android.os.Build;
74 import android.os.Bundle;
75 import android.os.PersistableBundle;
76 import android.os.SystemClock;
77 import android.os.UserManager;
78 import android.service.persistentdata.PersistentDataBlockManager;
79 import android.telephony.TelephonyManager;
80 import android.text.TextUtils;
81 
82 import androidx.activity.ComponentActivity;
83 import androidx.lifecycle.LiveData;
84 import androidx.lifecycle.ViewModelProvider;
85 
86 import com.android.internal.annotations.VisibleForTesting;
87 import com.android.managedprovisioning.ManagedProvisioningBaseApplication;
88 import com.android.managedprovisioning.ManagedProvisioningScreens;
89 import com.android.managedprovisioning.R;
90 import com.android.managedprovisioning.analytics.MetricsWriterFactory;
91 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
92 import com.android.managedprovisioning.common.DefaultFeatureFlagChecker;
93 import com.android.managedprovisioning.common.DefaultIntentResolverChecker;
94 import com.android.managedprovisioning.common.DefaultPackageInstallChecker;
95 import com.android.managedprovisioning.common.DeviceManagementRoleHolderHelper;
96 import com.android.managedprovisioning.common.DeviceManagementRoleHolderHelper.DefaultResolveIntentChecker;
97 import com.android.managedprovisioning.common.DeviceManagementRoleHolderHelper.DefaultRoleHolderStubChecker;
98 import com.android.managedprovisioning.common.DeviceManagementRoleHolderUpdaterHelper;
99 import com.android.managedprovisioning.common.GetProvisioningModeUtils;
100 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
101 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
102 import com.android.managedprovisioning.common.PolicyComplianceUtils;
103 import com.android.managedprovisioning.common.ProvisionLogger;
104 import com.android.managedprovisioning.common.RoleHolderProvider;
105 import com.android.managedprovisioning.common.RoleHolderUpdaterProvider;
106 import com.android.managedprovisioning.common.SettingsFacade;
107 import com.android.managedprovisioning.common.StoreUtils;
108 import com.android.managedprovisioning.common.Utils;
109 import com.android.managedprovisioning.model.DisclaimersParam;
110 import com.android.managedprovisioning.model.ProvisioningParams;
111 import com.android.managedprovisioning.model.ProvisioningParams.FlowType;
112 import com.android.managedprovisioning.parser.DisclaimerParser;
113 import com.android.managedprovisioning.parser.DisclaimersParserImpl;
114 import com.android.managedprovisioning.preprovisioning.PreProvisioningViewModel.DefaultConfig;
115 import com.android.managedprovisioning.preprovisioning.PreProvisioningViewModel.PreProvisioningViewModelFactory;
116 import com.android.managedprovisioning.provisioning.Constants;
117 import com.android.managedprovisioning.util.LazyStringResource;
118 
119 import com.google.android.setupdesign.util.DeviceHelper;
120 
121 import java.util.IllformedLocaleException;
122 import java.util.List;
123 import java.util.function.BiFunction;
124 
125 /**
126  * Controller which contains business logic related to provisioning preparation.
127  *
128  * @see PreProvisioningActivity
129  */
130 public class PreProvisioningActivityController {
131     private final Context mContext;
132     private final Ui mUi;
133     private final Utils mUtils;
134     private final PolicyComplianceUtils mPolicyComplianceUtils;
135     private final GetProvisioningModeUtils mGetProvisioningModeUtils;
136     private final SettingsFacade mSettingsFacade;
137 
138     // used system services
139     private final DevicePolicyManager mDevicePolicyManager;
140     private final UserManager mUserManager;
141     private final PackageManager mPackageManager;
142     private final KeyguardManager mKeyguardManager;
143     private final PersistentDataBlockManager mPdbManager;
144     private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker;
145     private final ManagedProvisioningSharedPreferences mSharedPreferences;
146 
147     private final PreProvisioningViewModel mViewModel;
148     private final BiFunction<Context, Long, DisclaimerParser> mDisclaimerParserProvider;
149     private final DeviceManagementRoleHolderHelper mRoleHolderHelper;
150     private final DeviceManagementRoleHolderUpdaterHelper mRoleHolderUpdaterHelper;
151 
PreProvisioningActivityController( @onNull ComponentActivity activity, @NonNull Ui ui)152     public PreProvisioningActivityController(
153             @NonNull ComponentActivity activity,
154             @NonNull Ui ui) {
155         this(activity, ui,
156                 new Utils(), new SettingsFacade(),
157                 new ManagedProvisioningSharedPreferences(activity),
158                 new PolicyComplianceUtils(),
159                 new GetProvisioningModeUtils(),
160                 new ViewModelProvider(
161                         activity,
162                         new PreProvisioningViewModelFactory(
163                                 (ManagedProvisioningBaseApplication) activity.getApplication(),
164                                 new DefaultConfig(),
165                                 new Utils()))
166                                         .get(PreProvisioningViewModel.class),
167                 DisclaimersParserImpl::new,
168                 new DeviceManagementRoleHolderHelper(
169                         RoleHolderProvider.DEFAULT.getPackageName(activity),
170                         new DefaultPackageInstallChecker(activity.getPackageManager(), new Utils()),
171                         new DefaultResolveIntentChecker(),
172                         new DefaultRoleHolderStubChecker(),
173                         new DefaultFeatureFlagChecker(activity.getContentResolver())
174                 ),
175                 new DeviceManagementRoleHolderUpdaterHelper(
176                         RoleHolderUpdaterProvider.DEFAULT.getPackageName(activity),
177                         RoleHolderProvider.DEFAULT.getPackageName(activity),
178                         new DefaultPackageInstallChecker(activity.getPackageManager(), new Utils()),
179                         new DefaultIntentResolverChecker(activity.getPackageManager()),
180                         new DefaultFeatureFlagChecker(activity.getContentResolver())));
181     }
182     @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, @NonNull BiFunction<Context, Long, DisclaimerParser> disclaimerParserProvider, @NonNull DeviceManagementRoleHolderHelper roleHolderHelper, @NonNull DeviceManagementRoleHolderUpdaterHelper roleHolderUpdaterHelper)183     PreProvisioningActivityController(
184             @NonNull Context context,
185             @NonNull Ui ui,
186             @NonNull Utils utils,
187             @NonNull SettingsFacade settingsFacade,
188             @NonNull ManagedProvisioningSharedPreferences sharedPreferences,
189             @NonNull PolicyComplianceUtils policyComplianceUtils,
190             @NonNull GetProvisioningModeUtils getProvisioningModeUtils,
191             @NonNull PreProvisioningViewModel viewModel,
192             @NonNull BiFunction<Context, Long, DisclaimerParser> disclaimerParserProvider,
193             @NonNull DeviceManagementRoleHolderHelper roleHolderHelper,
194             @NonNull DeviceManagementRoleHolderUpdaterHelper roleHolderUpdaterHelper) {
195         mContext = requireNonNull(context, "Context must not be null");
196         mUi = requireNonNull(ui, "Ui must not be null");
197         mSettingsFacade = requireNonNull(settingsFacade);
198         mUtils = requireNonNull(utils, "Utils must not be null");
199         mPolicyComplianceUtils = requireNonNull(policyComplianceUtils,
200                 "PolicyComplianceUtils cannot be null");
201         mGetProvisioningModeUtils = requireNonNull(getProvisioningModeUtils,
202                 "GetProvisioningModeUtils cannot be null");
203         mSharedPreferences = requireNonNull(sharedPreferences);
204         mViewModel = requireNonNull(viewModel);
205 
206         mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
207         mUserManager = mContext.getSystemService(UserManager.class);
208         mPackageManager = mContext.getPackageManager();
209         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
210         mPdbManager = (PersistentDataBlockManager)
211                 mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
212         mProvisioningAnalyticsTracker = new ProvisioningAnalyticsTracker(
213                 MetricsWriterFactory.getMetricsWriter(mContext, mSettingsFacade),
214                 mSharedPreferences);
215         mDisclaimerParserProvider = requireNonNull(disclaimerParserProvider);
216         mRoleHolderHelper = requireNonNull(roleHolderHelper);
217         mRoleHolderUpdaterHelper = requireNonNull(roleHolderUpdaterHelper);
218     }
219 
220     /**
221      * Starts provisioning via the role holder if possible, or if offline provisioning is allowed,
222      * falls back to AOSP ManagedProvisioning provisioning.
223      *
224      * @return {@code true} if any form of provisioning was started (either role holder or
225      * platform).
226      */
startAppropriateProvisioning( Intent managedProvisioningIntent, Bundle roleHolderAdditionalExtras, String callingPackage)227     boolean startAppropriateProvisioning(
228             Intent managedProvisioningIntent,
229             Bundle roleHolderAdditionalExtras,
230             String callingPackage) {
231         boolean isRoleHolderReadyForProvisioning = mRoleHolderHelper
232                 .isRoleHolderReadyForProvisioning(mContext, managedProvisioningIntent);
233         boolean isRoleHolderProvisioningAllowed =
234                 Constants.isRoleHolderProvisioningAllowedForAction(
235                         managedProvisioningIntent.getAction());
236 
237         // In T allowOffline is used here to force platform provisioning.
238         if (getParams().allowOffline) {
239             ProvisionLogger.logw("allowOffline set, provisioning via platform.");
240             performPlatformProvidedProvisioning();
241             return true;
242         }
243 
244         if (isRoleHolderReadyForProvisioning && isRoleHolderProvisioningAllowed) {
245             ProvisionLogger.logw("Provisioning via role holder.");
246             mRoleHolderHelper.ensureRoleGranted(mContext, success -> {
247                 if (success) {
248                     Intent roleHolderProvisioningIntent =
249                             mRoleHolderHelper.createRoleHolderProvisioningIntent(
250                                     managedProvisioningIntent,
251                                     roleHolderAdditionalExtras, callingPackage,
252                                     mViewModel.getRoleHolderState()
253                             );
254                     mSharedPreferences.setIsProvisioningFlowDelegatedToRoleHolder(true);
255                     mViewModel.onRoleHolderProvisioningInitiated();
256                     mUi.startRoleHolderProvisioning(roleHolderProvisioningIntent);
257                 } else {
258                     ProvisionLogger.logw("Falling back to provisioning via platform.");
259                     performPlatformProvidedProvisioning();
260                 }
261             });
262             return true;
263         } else if (!mRoleHolderHelper.isRoleHolderProvisioningEnabled()
264                 || !mRoleHolderUpdaterHelper.isRoleHolderUpdaterDefined()
265                 || !isRoleHolderProvisioningAllowed) {
266             ProvisionLogger.logw("Provisioning via platform.");
267             performPlatformProvidedProvisioning();
268             return true;
269         }
270         ProvisionLogger.logw("Role holder is configured, can't provision via role holder and "
271                 + "PROVISIONING_ALLOW_OFFLINE is false.");
272         return false;
273     }
274 
275     /**
276      * Starts the role holder updater, saving {@code roleHolderState} to be used to restart
277      * the role holder.
278      *
279      * @see DevicePolicyManager#EXTRA_ROLE_HOLDER_STATE
280      * @param roleHolderState
281      */
startRoleHolderUpdater( boolean isRoleHolderRequestedUpdate, @Nullable PersistableBundle roleHolderState)282     public void startRoleHolderUpdater(
283             boolean isRoleHolderRequestedUpdate, @Nullable PersistableBundle roleHolderState) {
284         mViewModel.onRoleHolderUpdateInitiated();
285         mViewModel.setRoleHolderState(roleHolderState);
286         mUi.startRoleHolderUpdater(isRoleHolderRequestedUpdate);
287     }
288 
289     /**
290      * Starts the role holder updater with the last provided role holder state.
291      *
292      * <p>This can be useful in update retry cases.
293      */
startRoleHolderUpdaterWithLastState(boolean isRoleHolderRequestedUpdate)294     public void startRoleHolderUpdaterWithLastState(boolean isRoleHolderRequestedUpdate) {
295         startRoleHolderUpdater(isRoleHolderRequestedUpdate, mViewModel.getRoleHolderState());
296     }
297 
298     interface Ui {
299         /**
300          * Show an error message and cancel provisioning.
301          *
302          * @param title        resource id used to form the user facing error title
303          * @param message      resource id used to form the user facing error message
304          * @param errorMessage an error message that gets logged for debugging
305          */
showErrorAndClose( LazyStringResource title, LazyStringResource message, String errorMessage)306         void showErrorAndClose(
307                 LazyStringResource title, LazyStringResource message, String errorMessage);
308 
309         /**
310          * Show an error message and cancel provisioning.
311          *
312          * @see #showErrorAndClose(LazyStringResource, LazyStringResource, String)
313          */
showErrorAndClose(Integer titleId, int messageId, String errorMessage)314         void showErrorAndClose(Integer titleId, int messageId, String errorMessage);
315 
316         /**
317          * Request the user to encrypt the device.
318          * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
319          */
requestEncryption(ProvisioningParams params)320         void requestEncryption(ProvisioningParams params);
321 
322         /**
323          * Request the user to choose a wifi network.
324          */
requestWifiPick()325         void requestWifiPick();
326 
327         /**
328          * Start provisioning.
329          * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
330          */
startProvisioning(ProvisioningParams params)331         void startProvisioning(ProvisioningParams params);
332 
333         /**
334          * Show an error dialog indicating that the current launcher does not support managed
335          * profiles and ask the user to choose a different one.
336          */
showCurrentLauncherInvalid()337         void showCurrentLauncherInvalid();
338 
showOwnershipDisclaimerScreen(ProvisioningParams params)339         void showOwnershipDisclaimerScreen(ProvisioningParams params);
340 
prepareFinancedDeviceFlow(ProvisioningParams params)341         void prepareFinancedDeviceFlow(ProvisioningParams params);
342 
showFactoryResetDialog(Integer titleId, int messageId)343         void showFactoryResetDialog(Integer titleId, int messageId);
344 
initiateUi(UiParams uiParams)345         void initiateUi(UiParams uiParams);
346 
347         /**
348          *  Abort provisioning and close app
349          */
abortProvisioning()350         void abortProvisioning();
351 
prepareAdminIntegratedFlow(ProvisioningParams params)352         void prepareAdminIntegratedFlow(ProvisioningParams params);
353 
startRoleHolderUpdater(boolean isRoleHolderRequestedUpdate)354         void startRoleHolderUpdater(boolean isRoleHolderRequestedUpdate);
355 
startRoleHolderProvisioning(Intent intent)356         void startRoleHolderProvisioning(Intent intent);
357 
onParamsValidated(ProvisioningParams params)358         void onParamsValidated(ProvisioningParams params);
359 
startPlatformDrivenRoleHolderDownload()360         void startPlatformDrivenRoleHolderDownload();
361     }
362 
363     /**
364      * Wrapper which holds information related to the consent screen.
365      * <p>Does not implement {@link Object#equals(Object)}, {@link Object#hashCode()}
366      * or {@link Object#toString()}.
367      */
368     public static class UiParams {
369         /**
370          * Admin application package name.
371          */
372         public String packageName;
373         /**
374          * List of headings for the organization-provided terms and conditions.
375          */
376         public List<String> disclaimerHeadings;
377         public boolean isDeviceManaged;
378         /**
379          * The original provisioning action, kept for backwards compatibility.
380          */
381         public String provisioningAction;
382         public boolean isOrganizationOwnedProvisioning;
383     }
384 
385     /**
386      * Initiates Profile owner and device owner provisioning.
387      * @param intent Intent that started provisioning.
388      * @param callingPackage Package that started provisioning.
389      */
initiateProvisioning(Intent intent, String callingPackage)390     public void initiateProvisioning(Intent intent, String callingPackage) {
391         mSharedPreferences.writeProvisioningStartedTimestamp(SystemClock.elapsedRealtime());
392         mSharedPreferences.setIsProvisioningFlowDelegatedToRoleHolder(false);
393         mProvisioningAnalyticsTracker.logProvisioningSessionStarted(mContext);
394 
395         logProvisioningExtras(intent);
396 
397         if (!tryParseParameters(intent)) {
398             return;
399         }
400 
401         ProvisioningParams params = mViewModel.getParams();
402         if (!checkFactoryResetProtection(params, callingPackage)) {
403             return;
404         }
405 
406         if (!verifyActionAndCaller(intent, callingPackage)) {
407             return;
408         }
409 
410         mProvisioningAnalyticsTracker.logProvisioningExtras(mContext, intent);
411         mProvisioningAnalyticsTracker.logEntryPoint(mContext, intent, mSettingsFacade);
412 
413         // Check whether provisioning is allowed for the current action. This check needs to happen
414         // before any actions that might affect the state of the device.
415         // Note that checkDevicePolicyPreconditions takes care of calling
416         // showProvisioningErrorAndClose. So we only need to show the factory reset dialog (if
417         // applicable) and return.
418         if (!checkDevicePolicyPreconditions()) {
419             return;
420         }
421 
422         if (!isIntentActionValid(intent.getAction())) {
423             ProvisionLogger.loge(
424                     ACTION_PROVISION_MANAGED_DEVICE + " is no longer a supported intent action.");
425             mUi.abortProvisioning();
426             return;
427         }
428 
429         if (isDeviceOwnerProvisioning()) {
430             // TODO: make a general test based on deviceAdminDownloadInfo field
431             // PO doesn't ever initialize that field, so OK as a general case
432             if (shouldShowWifiPicker(intent)) {
433                 // Have the user pick a wifi network if necessary.
434                 // It is not possible to ask the user to pick a wifi network if
435                 // the screen is locked.
436                 // TODO: remove this check once we know the screen will not be locked.
437                 if (mKeyguardManager.inKeyguardRestrictedInputMode()) {
438                     // TODO: decide on what to do in that case; fail? retry on screen unlock?
439                     ProvisionLogger.logi("Cannot pick wifi because the screen is locked.");
440                 } else if (canRequestWifiPick()) {
441                     // we resume this method after a successful WiFi pick
442                     // TODO: refactor as evil - logic should be less spread out
443                     mUi.requestWifiPick();
444                     return;
445                 } else {
446                     mUi.showErrorAndClose(R.string.cant_set_up_device,
447                             R.string.contact_your_admin_for_help,
448                             "Cannot pick WiFi because there is no handler to the intent");
449                 }
450             }
451         }
452 
453         mUi.onParamsValidated(params);
454 
455         // TODO(b/207376815): Have a PreProvisioningForwarderActivity to forward to either
456         //  platform-provided provisioning or DMRH
457         if (mRoleHolderUpdaterHelper.shouldPlatformDownloadRoleHolder(intent, params)
458                 && !params.allowOffline) {
459             mUi.startPlatformDrivenRoleHolderDownload();
460         } else if (mRoleHolderUpdaterHelper
461                 .shouldStartRoleHolderUpdater(mContext, intent, params) && !params.allowOffline) {
462             resetRoleHolderUpdateRetryCount();
463             startRoleHolderUpdater(
464                     /* isRoleHolderRequestedUpdate= */ false, /* roleHolderState= */ null);
465         } else {
466             boolean isProvisioningStarted =
467                     startAppropriateProvisioning(intent, new Bundle(), callingPackage);
468             if (!isProvisioningStarted) {
469                 mUi.showErrorAndClose(
470                         R.string.cant_set_up_device,
471                         R.string.contact_your_admin_for_help,
472                         "Could not start provisioning.");
473             }
474         }
475     }
476 
logProvisioningExtras(Intent intent)477     private void logProvisioningExtras(Intent intent) {
478         Bundle extras = intent.getExtras();
479         if (extras == null) {
480             ProvisionLogger.logi("No extras have been passed.");
481             return;
482         }
483         ProvisionLogger.logi("Start logging provisioning extras");
484         for (String key : extras.keySet()) {
485             ProvisionLogger.logi("Extra key: " + key + ", extra value: " + extras.get(key));
486         }
487         ProvisionLogger.logi("Finish logging provisioning extras");
488     }
489 
performPlatformProvidedProvisioning()490     void performPlatformProvidedProvisioning() {
491         ProvisionLogger.logw("Provisioning via platform-provided provisioning");
492         ProvisioningParams params = mViewModel.getParams();
493 
494         mViewModel.getTimeLogger().start();
495         mViewModel.onPlatformProvisioningInitiated();
496 
497         if (mUtils.checkAdminIntegratedFlowPreconditions(params)) {
498             if (mUtils.shouldShowOwnershipDisclaimerScreen(params)) {
499                 mUi.showOwnershipDisclaimerScreen(params);
500             } else {
501                 mUi.prepareAdminIntegratedFlow(params);
502             }
503             mViewModel.onAdminIntegratedFlowInitiated();
504         } else if (mUtils.isFinancedDeviceAction(params.provisioningAction)) {
505             mUi.prepareFinancedDeviceFlow(params);
506         } else if (isProfileOwnerProvisioning()) {
507             startManagedProfileFlow();
508         }
509     }
510 
isIntentActionValid(String action)511     private boolean isIntentActionValid(String action) {
512         return !ACTION_PROVISION_MANAGED_DEVICE.equals(action);
513     }
514 
startManagedProfileFlow()515     private void startManagedProfileFlow() {
516         ProvisionLogger.logi("Starting the managed profile flow.");
517         showUserConsentScreen();
518     }
519 
isNfcProvisioning(Intent intent)520     private boolean isNfcProvisioning(Intent intent) {
521         return intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_UNSPECIFIED)
522                 == PROVISIONING_TRIGGER_NFC;
523     }
524 
isQrCodeProvisioning(Intent intent)525     private boolean isQrCodeProvisioning(Intent intent) {
526         if (!ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction())) {
527             return false;
528         }
529         final int provisioningTrigger = intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER,
530                 PROVISIONING_TRIGGER_UNSPECIFIED);
531         return provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE;
532     }
533 
shouldShowWifiPicker(Intent intent)534     private boolean shouldShowWifiPicker(Intent intent) {
535         if (mSharedPreferences.isEstablishNetworkConnectionRun()) {
536             return false;
537         }
538         ProvisioningParams params = mViewModel.getParams();
539         if (params.wifiInfo != null) {
540             return false;
541         }
542         if (params.deviceAdminDownloadInfo == null) {
543             return false;
544         }
545         var networkCapabilities = mUtils.getActiveNetworkCapabilities(mContext);
546         if (networkCapabilities != null
547                 && (mUtils.isNetworkConnectedToInternetViaWiFi(networkCapabilities)
548                         || mUtils.isNetworkConnectedToInternetViaEthernet(networkCapabilities))) {
549             return false;
550         }
551         // we intentionally disregard whether mobile is connected for QR and NFC
552         // provisioning. b/153442588 for context
553         if (params.useMobileData
554                 && (isQrCodeProvisioning(intent) || isNfcProvisioning(intent))) {
555             return false;
556         }
557         if (params.useMobileData) {
558             return !mUtils.isMobileNetworkConnectedToInternet(mContext);
559         }
560         return true;
561     }
562 
showUserConsentScreen()563     void showUserConsentScreen() {
564         // Check whether provisioning is allowed for the current action
565         if (!checkDevicePolicyPreconditions()) {
566             return;
567         }
568 
569         if (mViewModel.getParams().provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)
570                 && mViewModel.getParams().isOrganizationOwnedProvisioning) {
571             mProvisioningAnalyticsTracker.logOrganizationOwnedManagedProfileProvisioning();
572         }
573 
574         // show UI so we can get user's consent to continue
575         final String packageName = mViewModel.getParams().inferDeviceAdminPackageName();
576         final UiParams uiParams = new UiParams();
577         uiParams.provisioningAction = mViewModel.getParams().provisioningAction;
578         uiParams.packageName = packageName;
579         uiParams.isDeviceManaged = mDevicePolicyManager.isDeviceManaged();
580         uiParams.isOrganizationOwnedProvisioning =
581                 mViewModel.getParams().isOrganizationOwnedProvisioning;
582 
583         mUi.initiateUi(uiParams);
584         mViewModel.onShowUserConsent();
585     }
586 
updateProvisioningParamsFromIntent(Intent resultIntent)587     boolean updateProvisioningParamsFromIntent(Intent resultIntent) {
588         final int provisioningMode = resultIntent.getIntExtra(
589                 DevicePolicyManager.EXTRA_PROVISIONING_MODE, 0);
590         if (!mViewModel.getParams().allowedProvisioningModes.contains(provisioningMode)) {
591             ProvisionLogger.loge("Invalid provisioning mode chosen by the DPC: " + provisioningMode
592                     + ", but expected one of "
593                     + mViewModel.getParams().allowedProvisioningModes.toString());
594             return false;
595         }
596         switch (provisioningMode) {
597             case DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE:
598                 updateParamsPostProvisioningModeDecision(
599                         resultIntent,
600                         ACTION_PROVISION_MANAGED_DEVICE,
601                         /* isOrganizationOwnedProvisioning */ true,
602                         /* updateAccountToMigrate */ false);
603                 return true;
604             case DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE:
605                 updateParamsPostProvisioningModeDecision(
606                         resultIntent,
607                         ACTION_PROVISION_MANAGED_PROFILE,
608                         mUtils.isOrganizationOwnedAllowed(mViewModel.getParams()),
609                         /* updateAccountToMigrate */ true);
610                 return true;
611             case PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE:
612                 updateParamsPostProvisioningModeDecision(
613                         resultIntent,
614                         ACTION_PROVISION_MANAGED_PROFILE,
615                         /* isOrganizationOwnedProvisioning */ false,
616                         /* updateAccountToMigrate */ true);
617                 return true;
618             default:
619                 ProvisionLogger.logw("Unknown returned provisioning mode:"
620                         + provisioningMode);
621                 return false;
622         }
623     }
624 
updateParamsPostProvisioningModeDecision(Intent resultIntent, String provisioningAction, boolean isOrganizationOwnedProvisioning, boolean updateAccountToMigrate)625     private void updateParamsPostProvisioningModeDecision(Intent resultIntent,
626             String provisioningAction, boolean isOrganizationOwnedProvisioning,
627             boolean updateAccountToMigrate) {
628         ProvisioningParams.Builder builder = mViewModel.getParams().toBuilder();
629         builder.setFlowType(FLOW_TYPE_ADMIN_INTEGRATED);
630         builder.setProvisioningAction(provisioningAction);
631         builder.setIsOrganizationOwnedProvisioning(isOrganizationOwnedProvisioning);
632         maybeUpdateAdminExtrasBundle(builder, resultIntent);
633         maybeUpdateSkipEducationScreens(builder, resultIntent);
634         maybeUpdateDisclaimers(builder, resultIntent);
635         maybeUpdateSkipEncryption(builder, resultIntent);
636         if (updateAccountToMigrate) {
637             maybeUpdateAccountToMigrate(builder, resultIntent);
638         }
639         if (provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
640             maybeUpdateKeepAccountMigrated(builder, resultIntent);
641             maybeUpdateLeaveAllSystemAppsEnabled(builder, resultIntent);
642         }
643         else if (provisioningAction.equals(ACTION_PROVISION_MANAGED_DEVICE)){
644             maybeUpdateDeviceOwnerPermissionGrantOptOut(builder, resultIntent);
645             maybeUpdateLocale(builder, resultIntent);
646             maybeUpdateLocalTime(builder, resultIntent);
647             maybeUpdateTimeZone(builder, resultIntent);
648         }
649         mViewModel.updateParams(builder.build());
650     }
651 
maybeUpdateDeviceOwnerPermissionGrantOptOut( ProvisioningParams.Builder builder, Intent resultIntent)652     private void maybeUpdateDeviceOwnerPermissionGrantOptOut(
653             ProvisioningParams.Builder builder, Intent resultIntent) {
654         if (resultIntent.hasExtra(EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT)) {
655             builder.setDeviceOwnerPermissionGrantOptOut(resultIntent.getBooleanExtra(
656                     EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT,
657                     DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT));
658         }
659     }
660 
maybeUpdateSkipEncryption( ProvisioningParams.Builder builder, Intent resultIntent)661     private void maybeUpdateSkipEncryption(
662             ProvisioningParams.Builder builder, Intent resultIntent) {
663         if (resultIntent.hasExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION)) {
664             builder.setSkipEncryption(resultIntent.getBooleanExtra(
665                     EXTRA_PROVISIONING_SKIP_ENCRYPTION,
666                     DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION));
667         }
668     }
669 
maybeUpdateTimeZone(ProvisioningParams.Builder builder, Intent resultIntent)670     private void maybeUpdateTimeZone(ProvisioningParams.Builder builder, Intent resultIntent) {
671         if (resultIntent.hasExtra(EXTRA_PROVISIONING_TIME_ZONE)) {
672             builder.setTimeZone(resultIntent.getStringExtra(EXTRA_PROVISIONING_TIME_ZONE));
673         }
674     }
675 
maybeUpdateLocalTime(ProvisioningParams.Builder builder, Intent resultIntent)676     private void maybeUpdateLocalTime(ProvisioningParams.Builder builder, Intent resultIntent) {
677         if (resultIntent.hasExtra(EXTRA_PROVISIONING_LOCAL_TIME)) {
678             builder.setLocalTime(resultIntent.getLongExtra(
679                     EXTRA_PROVISIONING_LOCAL_TIME, ProvisioningParams.DEFAULT_LOCAL_TIME));
680         }
681     }
682 
maybeUpdateLocale(ProvisioningParams.Builder builder, Intent resultIntent)683     private void maybeUpdateLocale(ProvisioningParams.Builder builder, Intent resultIntent) {
684         if (resultIntent.hasExtra(EXTRA_PROVISIONING_LOCALE)) {
685             try {
686                 builder.setLocale(StoreUtils.stringToLocale(
687                         resultIntent.getStringExtra(EXTRA_PROVISIONING_LOCALE)));
688             } catch (IllformedLocaleException e) {
689                 ProvisionLogger.loge("Could not parse locale.", e);
690             }
691         }
692     }
693 
maybeUpdateDisclaimers(ProvisioningParams.Builder builder, Intent resultIntent)694     private void maybeUpdateDisclaimers(ProvisioningParams.Builder builder, Intent resultIntent) {
695         if (resultIntent.hasExtra(EXTRA_PROVISIONING_DISCLAIMERS)) {
696             try {
697                 DisclaimersParam disclaimersParam = mDisclaimerParserProvider.apply(
698                         mContext,
699                         mSharedPreferences.getProvisioningId())
700                         .parse(resultIntent.getParcelableArrayExtra(
701                                 EXTRA_PROVISIONING_DISCLAIMERS));
702                 builder.setDisclaimersParam(disclaimersParam);
703             } catch (ClassCastException e) {
704                 ProvisionLogger.loge("Could not parse disclaimer params.", e);
705             }
706         }
707     }
708 
maybeUpdateSkipEducationScreens(ProvisioningParams.Builder builder, Intent resultIntent)709     private void maybeUpdateSkipEducationScreens(ProvisioningParams.Builder builder,
710             Intent resultIntent) {
711         if (resultIntent.hasExtra(EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS)) {
712             builder.setSkipEducationScreens(resultIntent.getBooleanExtra(
713                     EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS, /* defaultValue */ false));
714         }
715     }
716 
maybeUpdateAccountToMigrate(ProvisioningParams.Builder builder, Intent resultIntent)717     private void maybeUpdateAccountToMigrate(ProvisioningParams.Builder builder,
718             Intent resultIntent) {
719         if (resultIntent.hasExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)) {
720             final Account account = resultIntent.getParcelableExtra(
721                     EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE);
722             builder.setAccountToMigrate(account);
723         }
724     }
725 
726     /**
727      * Appends the admin bundle in {@code resultIntent}, if provided, to the existing admin bundle,
728      * if it exists, and stores the result in {@code builder}.
729      */
maybeUpdateAdminExtrasBundle(ProvisioningParams.Builder builder, Intent resultIntent)730     private void maybeUpdateAdminExtrasBundle(ProvisioningParams.Builder builder,
731             Intent resultIntent) {
732         if (resultIntent.hasExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)) {
733             PersistableBundle resultBundle =
734                     resultIntent.getParcelableExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE);
735             if (mViewModel.getParams().adminExtrasBundle != null) {
736                 PersistableBundle existingBundle =
737                         new PersistableBundle(mViewModel.getParams().adminExtrasBundle);
738                 existingBundle.putAll(resultBundle);
739                 resultBundle = existingBundle;
740             }
741             builder.setAdminExtrasBundle(resultBundle);
742         }
743     }
744 
maybeUpdateKeepAccountMigrated( ProvisioningParams.Builder builder, Intent resultIntent)745     private void maybeUpdateKeepAccountMigrated(
746             ProvisioningParams.Builder builder,
747             Intent resultIntent) {
748         if (resultIntent.hasExtra(EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION)) {
749             final boolean keepAccountMigrated = resultIntent.getBooleanExtra(
750                     EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION,
751                     DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED);
752             builder.setKeepAccountMigrated(keepAccountMigrated);
753         }
754     }
755 
maybeUpdateLeaveAllSystemAppsEnabled( ProvisioningParams.Builder builder, Intent resultIntent)756     private void maybeUpdateLeaveAllSystemAppsEnabled(
757             ProvisioningParams.Builder builder,
758             Intent resultIntent) {
759         if (resultIntent.hasExtra(EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED)) {
760             final boolean leaveAllSystemAppsEnabled = resultIntent.getBooleanExtra(
761                     EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
762                     DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED);
763             builder.setLeaveAllSystemAppsEnabled(leaveAllSystemAppsEnabled);
764         }
765     }
766 
updateProvisioningFlowState(@lowType int flowType)767     void updateProvisioningFlowState(@FlowType int flowType) {
768         mViewModel.updateParams(mViewModel.getParams().toBuilder().setFlowType(flowType).build());
769     }
770 
getAdditionalExtrasForGetProvisioningModeIntent()771     Bundle getAdditionalExtrasForGetProvisioningModeIntent() {
772         Bundle bundle = new Bundle();
773         if (shouldPassPersonalDataToAdminApp()) {
774             final TelephonyManager telephonyManager = mContext.getSystemService(
775                     TelephonyManager.class);
776             bundle.putString(EXTRA_PROVISIONING_IMEI, telephonyManager.getImei());
777             bundle.putString(EXTRA_PROVISIONING_SERIAL_NUMBER, Build.getSerial());
778         }
779         ProvisioningParams params = mViewModel.getParams();
780         bundle.putParcelable(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
781                 params.adminExtrasBundle);
782         bundle.putIntegerArrayList(EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES,
783                 params.allowedProvisioningModes);
784 
785         if (params.allowedProvisioningModes.contains(
786                 DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE)) {
787             bundle.putBoolean(EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT,
788                     params.deviceOwnerPermissionGrantOptOut);
789         }
790         return bundle;
791     }
792 
shouldPassPersonalDataToAdminApp()793     private boolean shouldPassPersonalDataToAdminApp() {
794         ProvisioningParams params = mViewModel.getParams();
795         return params.initiatorRequestedProvisioningModes == FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED
796                 || params.initiatorRequestedProvisioningModes == FLAG_SUPPORTED_MODES_DEVICE_OWNER;
797     }
798 
createViewTermsIntent()799     protected Intent createViewTermsIntent() {
800         return new Intent(mContext, getTermsActivityClass())
801                 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, mViewModel.getParams());
802     }
803 
getTermsActivityClass()804     private Class<? extends Activity> getTermsActivityClass() {
805         return getBaseApplication().getActivityClassForScreen(ManagedProvisioningScreens.TERMS);
806     }
807 
getBaseApplication()808     private ManagedProvisioningBaseApplication getBaseApplication() {
809         return (ManagedProvisioningBaseApplication) mContext.getApplicationContext();
810     }
811 
812     /**
813      * Start provisioning for real. In profile owner case, double check that the launcher
814      * supports managed profiles if necessary. In device owner case, possibly create a new user
815      * before starting provisioning.
816      */
continueProvisioningAfterUserConsent()817     public void continueProvisioningAfterUserConsent() {
818         mProvisioningAnalyticsTracker.logProvisioningAction(
819                 mContext, mViewModel.getParams().provisioningAction);
820         // check if encryption is required
821         if (isEncryptionRequired()) {
822             if (mDevicePolicyManager.getStorageEncryptionStatus()
823                     == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {
824                 CharSequence deviceName = DeviceHelper.getDeviceName(mContext);
825                 mUi.showErrorAndClose(
826                         LazyStringResource.of(R.string.cant_set_up_device),
827                         LazyStringResource.of(
828                                 R.string.device_doesnt_allow_encryption_contact_admin, deviceName),
829                         "This device does not support encryption, and "
830                                 + DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION
831                                 + " was not passed.");
832             } else {
833                 mUi.requestEncryption(mViewModel.getParams());
834                 // we come back to this method after returning from encryption dialog
835                 // TODO: refactor as evil - logic should be less spread out
836             }
837             return;
838         }
839 
840         if (isProfileOwnerProvisioning()) { // PO case
841             // Check whether the current launcher supports managed profiles.
842             if (!mUtils.currentLauncherSupportsManagedProfiles(mContext)) {
843                 mUi.showCurrentLauncherInvalid();
844                 // we come back to this method after returning from launcher dialog
845                 // TODO: refactor as evil - logic should be less spread out
846                 return;
847             }
848         }
849         // Cancel the boot reminder as provisioning has now started.
850         mViewModel.getEncryptionController().cancelEncryptionReminder();
851         stopTimeLogger();
852         mUi.startProvisioning(mViewModel.getParams());
853 
854         mViewModel.onProvisioningStartedAfterUserConsent();
855     }
856 
857     /**
858      * @return False if condition preventing further provisioning
859      */
860     @VisibleForTesting
checkFactoryResetProtection(ProvisioningParams params, String callingPackage)861     boolean checkFactoryResetProtection(ProvisioningParams params, String callingPackage) {
862         if (skipFactoryResetProtectionCheck(params, callingPackage)) {
863             return true;
864         }
865         if (factoryResetProtected()) {
866             CharSequence deviceName = DeviceHelper.getDeviceName(mContext);
867             mUi.showErrorAndClose(
868                     LazyStringResource.of(R.string.cant_set_up_device),
869                     LazyStringResource.of(
870                             R.string.device_has_reset_protection_contact_admin, deviceName),
871                     "Factory reset protection blocks provisioning.");
872             return false;
873         }
874         return true;
875     }
876 
skipFactoryResetProtectionCheck( ProvisioningParams params, String callingPackage)877     private boolean skipFactoryResetProtectionCheck(
878             ProvisioningParams params, String callingPackage) {
879         if (TextUtils.isEmpty(callingPackage)) {
880             return false;
881         }
882         String persistentDataPackageName = mContext.getResources()
883                 .getString(com.android.internal.R.string.config_persistentDataPackageName);
884         try {
885             // Only skip the FRP check if the caller is the package responsible for maintaining FRP
886             // - i.e. if this is a flow for restoring device owner after factory reset.
887             PackageInfo callingPackageInfo = mPackageManager.getPackageInfo(callingPackage, 0);
888             return callingPackageInfo != null
889                     && callingPackageInfo.applicationInfo != null
890                     && callingPackageInfo.applicationInfo.isSystemApp()
891                     && !TextUtils.isEmpty(persistentDataPackageName)
892                     && callingPackage.equals(persistentDataPackageName)
893                     && params != null
894                     && params.startedByTrustedSource;
895         } catch (PackageManager.NameNotFoundException e) {
896             ProvisionLogger.loge("Calling package not found.", e);
897             return false;
898         }
899     }
900 
901     /** @return False if condition preventing further provisioning */
checkDevicePolicyPreconditions()902     @VisibleForTesting protected boolean checkDevicePolicyPreconditions() {
903         ProvisioningParams params = mViewModel.getParams();
904         int provisioningPreCondition = mDevicePolicyManager.checkProvisioningPrecondition(
905                 params.provisioningAction,
906                 params.inferDeviceAdminPackageName());
907         // Check whether provisioning is allowed for the current action.
908         if (provisioningPreCondition != STATUS_OK) {
909             mProvisioningAnalyticsTracker.logProvisioningNotAllowed(mContext,
910                     provisioningPreCondition);
911             showProvisioningErrorAndClose(
912                     params.provisioningAction, provisioningPreCondition);
913             return false;
914         }
915         return true;
916     }
917 
918     /** @return False if condition preventing further provisioning */
tryParseParameters(Intent intent)919     private boolean tryParseParameters(Intent intent) {
920         try {
921             // Read the provisioning params from the provisioning intent
922             mViewModel.loadParamsIfNecessary(intent);
923         } catch (IllegalProvisioningArgumentException e) {
924             mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
925                     e.getMessage());
926             return false;
927         }
928         return true;
929     }
930 
931     /** @return False if condition preventing further provisioning */
verifyActionAndCaller(Intent intent, String callingPackage)932     @VisibleForTesting protected boolean verifyActionAndCaller(Intent intent,
933             String callingPackage) {
934         if (verifyActionAndCallerInner(intent, callingPackage)) {
935             return true;
936         } else {
937             mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
938                     "invalid intent or calling package");
939             return false;
940         }
941     }
942 
verifyActionAndCallerInner(Intent intent, String callingPackage)943     private boolean verifyActionAndCallerInner(Intent intent, String callingPackage) {
944         // If this is a resume after encryption or trusted intent, we verify the activity alias.
945         // Otherwise, verify that the calling app is trying to set itself as Device/ProfileOwner
946         if (ACTION_RESUME_PROVISIONING.equals(intent.getAction())) {
947             return verifyActivityAlias(intent, "PreProvisioningActivityAfterEncryption");
948         } else if (ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction())
949                 || ACTION_PROVISION_FINANCED_DEVICE.equals(intent.getAction())) {
950             return verifyActivityAlias(intent, "PreProvisioningActivityViaTrustedApp");
951         } else {
952             return verifyCaller(callingPackage);
953         }
954     }
955 
verifyActivityAlias(Intent intent, String activityAlias)956     private boolean verifyActivityAlias(Intent intent, String activityAlias) {
957         ComponentName componentName = intent.getComponent();
958         if (componentName == null || componentName.getClassName() == null) {
959             ProvisionLogger.loge("null class in component when verifying activity alias "
960                     + activityAlias);
961             return false;
962         }
963 
964         if (!componentName.getClassName().endsWith(activityAlias)) {
965             ProvisionLogger.loge("Looking for activity alias " + activityAlias + ", but got "
966                     + componentName.getClassName());
967             return false;
968         }
969 
970         return true;
971     }
972 
973     /**
974      * Verify that the caller is trying to set itself as owner.
975      * @return false if the caller is trying to set a different package as owner.
976      */
verifyCaller(@onNull String callingPackage)977     private boolean verifyCaller(@NonNull String callingPackage) {
978         if (callingPackage == null) {
979             ProvisionLogger.loge("Calling package is null. Was startActivityForResult used to "
980                     + "start this activity?");
981             return false;
982         }
983 
984         if (!callingPackage.equals(mViewModel.getParams().inferDeviceAdminPackageName())) {
985             ProvisionLogger.loge("Permission denied, "
986                     + "calling package tried to set a different package as owner. ");
987             return false;
988         }
989 
990         return true;
991     }
992 
993     /**
994      * Returns whether the device needs encryption.
995      */
isEncryptionRequired()996     private boolean isEncryptionRequired() {
997         return !mViewModel.getParams().skipEncryption && mUtils.isEncryptionRequired();
998     }
999 
1000     /**
1001      * Returns whether the device is frp protected during setup wizard.
1002      */
factoryResetProtected()1003     private boolean factoryResetProtected() {
1004         // If we are started during setup wizard, check for factory reset protection.
1005         // If the device is already setup successfully, do not check factory reset protection.
1006         if (mSettingsFacade.isDeviceProvisioned(mContext)) {
1007             ProvisionLogger.logd("Device is provisioned, FRP not required.");
1008             return false;
1009         }
1010 
1011         if (mPdbManager == null) {
1012             ProvisionLogger.logd("Reset protection not supported.");
1013             return false;
1014         }
1015         int size = mPdbManager.getDataBlockSize();
1016         ProvisionLogger.logd("Data block size: " + size);
1017         return size > 0;
1018     }
1019 
1020     /**
1021      * Returns whether activity to pick wifi can be requested or not.
1022      */
canRequestWifiPick()1023     private boolean canRequestWifiPick() {
1024         return mPackageManager.resolveActivity(mUtils.getWifiPickIntent(), 0) != null;
1025     }
1026 
1027     /**
1028      * Returns whether the provisioning process is a profile owner provisioning process.
1029      */
isProfileOwnerProvisioning()1030     public boolean isProfileOwnerProvisioning() {
1031         return mUtils.isProfileOwnerAction(mViewModel.getParams().provisioningAction);
1032     }
1033 
1034     /**
1035      * Returns whether the provisioning process is a device owner provisioning process.
1036      */
isDeviceOwnerProvisioning()1037     public boolean isDeviceOwnerProvisioning() {
1038         return mUtils.isDeviceOwnerAction(mViewModel.getParams().provisioningAction);
1039     }
1040 
1041 
1042     @Nullable
getParams()1043     public ProvisioningParams getParams() {
1044         return mViewModel.getParams();
1045     }
1046 
1047     /**
1048      * Notifies the time logger to stop.
1049      */
stopTimeLogger()1050     public void stopTimeLogger() {
1051         mViewModel.getTimeLogger().stop();
1052     }
1053 
1054     /**
1055      * Log if PreProvisioning was cancelled.
1056      */
logPreProvisioningCancelled()1057     public void logPreProvisioningCancelled() {
1058         mProvisioningAnalyticsTracker.logProvisioningCancelled(mContext,
1059                 CANCELLED_BEFORE_PROVISIONING);
1060     }
1061 
1062     /**
1063      * Logs the provisioning flow type.
1064      */
logProvisioningFlowType()1065     public void logProvisioningFlowType() {
1066         mProvisioningAnalyticsTracker.logProvisioningFlowType(mViewModel.getParams());
1067     }
1068 
1069     /**
1070      * Removes a user profile. If we are in COMP case, and were blocked by having to delete a user,
1071      * resumes COMP provisioning.
1072      */
removeUser(int userProfileId)1073     public void removeUser(int userProfileId) {
1074         // There is a possibility that the DO has set the disallow remove managed profile user
1075         // restriction, but is initiating the provisioning. In this case, we still want to remove
1076         // the managed profile.
1077         // We know that we can remove the managed profile because we checked
1078         // DevicePolicyManager.checkProvisioningPreCondition
1079         mUserManager.removeUserEvenWhenDisallowed(userProfileId);
1080     }
1081 
getSettingsFacade()1082     SettingsFacade getSettingsFacade() {
1083         return mSettingsFacade;
1084     }
1085 
getPolicyComplianceUtils()1086     public PolicyComplianceUtils getPolicyComplianceUtils() {
1087         return mPolicyComplianceUtils;
1088     }
1089 
getGetProvisioningModeUtils()1090     public GetProvisioningModeUtils getGetProvisioningModeUtils() {
1091         return mGetProvisioningModeUtils;
1092     }
1093 
onReturnFromProvisioning()1094     void onReturnFromProvisioning() {
1095         mViewModel.onReturnFromProvisioning();
1096     }
1097 
getState()1098     LiveData<Integer> getState() {
1099         return mViewModel.getState();
1100     }
1101 
incrementRoleHolderUpdateRetryCount()1102     void incrementRoleHolderUpdateRetryCount() {
1103         mViewModel.incrementRoleHolderUpdateRetryCount();
1104     }
1105 
resetRoleHolderUpdateRetryCount()1106     void resetRoleHolderUpdateRetryCount() {
1107         mViewModel.resetRoleHolderUpdateRetryCount();
1108     }
1109 
canRetryRoleHolderUpdate()1110     boolean canRetryRoleHolderUpdate() {
1111         return mViewModel.canRetryRoleHolderUpdate();
1112     }
1113 
showProvisioningErrorAndClose(String action, int provisioningPreCondition)1114     private void showProvisioningErrorAndClose(String action, int provisioningPreCondition) {
1115         // Try to show an error message explaining why provisioning is not allowed.
1116         switch (action) {
1117             case ACTION_PROVISION_MANAGED_PROFILE:
1118                 showManagedProfileErrorAndClose(provisioningPreCondition);
1119                 return;
1120             case ACTION_PROVISION_MANAGED_DEVICE:
1121                 showDeviceOwnerErrorAndClose(provisioningPreCondition);
1122         }
1123         // This should never be the case, as showProvisioningError is always called after
1124         // verifying the supported provisioning actions.
1125     }
1126 
showManagedProfileErrorAndClose(int provisioningPreCondition)1127     private void showManagedProfileErrorAndClose(int provisioningPreCondition) {
1128         var userInfo = mUserManager.getUserInfo(mUserManager.getProcessUserId());
1129         ProvisionLogger.logw(
1130                 "DevicePolicyManager.checkProvisioningPrecondition returns code: "
1131                         + provisioningPreCondition);
1132         // If this is organization-owned provisioning, do not show any other error dialog, just
1133         // show the factory reset dialog and return.
1134         // This cannot be abused by regular apps to force a factory reset because
1135         // isOrganizationOwnedProvisioning is only set to true if the provisioning action was
1136         // from a trusted source. See Utils.isOrganizationOwnedProvisioning where we check for
1137         // ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE which is guarded by the
1138         // DISPATCH_PROVISIONING_MESSAGE system|privileged permission.
1139         if (mUtils.isOrganizationOwnedAllowed(mViewModel.getParams())) {
1140             ProvisionLogger.loge(
1141                     "Provisioning preconditions failed for organization-owned provisioning.");
1142             mUi.showFactoryResetDialog(R.string.cant_set_up_device,
1143                     R.string.contact_your_admin_for_help);
1144             return;
1145         }
1146         CharSequence deviceName = DeviceHelper.getDeviceName(mContext);
1147         switch (provisioningPreCondition) {
1148             case STATUS_MANAGED_USERS_NOT_SUPPORTED:
1149                 mUi.showErrorAndClose(
1150                         LazyStringResource.of(R.string.cant_add_work_profile),
1151                         LazyStringResource.of(
1152                                 R.string.work_profile_cant_be_added_contact_admin, deviceName),
1153                         "Exiting managed profile provisioning, managed profiles "
1154                                 + "feature is not available");
1155                 break;
1156             case STATUS_CANNOT_ADD_MANAGED_PROFILE:
1157                 String errorMessage;
1158                 if (!userInfo.canHaveProfile()) {
1159                     errorMessage = "Exiting managed profile provisioning, calling user cannot "
1160                             + "have managed profiles";
1161                 } else if (!canAddManagedProfile()) {
1162                     errorMessage = "Exiting managed profile provisioning, a managed profile "
1163                             + "already exists";
1164                 } else {
1165                     errorMessage = "Exiting managed profile provisioning, cannot add more managed "
1166                             + "profiles";
1167                 }
1168                 mUi.showErrorAndClose(
1169                         LazyStringResource.of(R.string.cant_add_work_profile),
1170                         LazyStringResource.of(
1171                                 R.string.work_profile_cant_be_added_contact_admin, deviceName),
1172                         errorMessage);
1173                 break;
1174             case STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS:
1175                 mUi.showErrorAndClose(
1176                         LazyStringResource.of(R.string.cant_add_work_profile),
1177                         LazyStringResource.of(
1178                                 R.string.work_profile_cant_be_added_contact_admin, deviceName),
1179                         "Exiting managed profile provisioning, "
1180                                 + "provisioning not allowed by OEM");
1181                 break;
1182             default:
1183                 mUi.showErrorAndClose(
1184                         R.string.cant_add_work_profile,
1185                         R.string.contact_your_admin_for_help,
1186                         "Managed profile provisioning not allowed for an unknown "
1187                                 + "reason, code: "
1188                                 + provisioningPreCondition);
1189         }
1190     }
1191 
canAddManagedProfile()1192     private boolean canAddManagedProfile() {
1193         return mUserManager.canAddMoreManagedProfiles(
1194                 mContext.getUserId(), /* allowedToRemoveOne= */ false);
1195     }
1196 
showDeviceOwnerErrorAndClose(int provisioningPreCondition)1197     private void showDeviceOwnerErrorAndClose(int provisioningPreCondition) {
1198         CharSequence deviceName = DeviceHelper.getDeviceName(mContext);
1199         switch (provisioningPreCondition) {
1200             case STATUS_HAS_DEVICE_OWNER:
1201             case STATUS_USER_SETUP_COMPLETED:
1202                 mUi.showErrorAndClose(
1203                         LazyStringResource.of(R.string.device_already_set_up, deviceName),
1204                         LazyStringResource.of(R.string.if_questions_contact_admin),
1205                         "Device already provisioned.");
1206                 return;
1207             case STATUS_NOT_SYSTEM_USER:
1208                 mUi.showErrorAndClose(
1209                         R.string.cant_set_up_device,
1210                         R.string.contact_your_admin_for_help,
1211                         "Device owner can only be set up for USER_SYSTEM.");
1212                 return;
1213             case STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS:
1214                 mUi.showErrorAndClose(
1215                         R.string.cant_set_up_device,
1216                         R.string.contact_your_admin_for_help,
1217                         "Provisioning not allowed by OEM");
1218                 return;
1219         }
1220         mUi.showErrorAndClose(
1221                 R.string.cant_set_up_device,
1222                 R.string.contact_your_admin_for_help,
1223                 "Device Owner provisioning not allowed for an unknown reason.");
1224     }
1225 }
1226