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