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