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.finalization; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 21 22 import static com.android.internal.util.Preconditions.checkNotNull; 23 import static com.android.managedprovisioning.finalization.SendDpcBroadcastService.EXTRA_PROVISIONING_PARAMS; 24 25 import android.annotation.IntDef; 26 import android.app.NotificationManager; 27 import android.app.admin.DevicePolicyManager; 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.pm.PackageManager.NameNotFoundException; 32 import android.os.UserHandle; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.managedprovisioning.analytics.DeferredMetricsReader; 36 import com.android.managedprovisioning.common.NotificationHelper; 37 import com.android.managedprovisioning.common.ProvisionLogger; 38 import com.android.managedprovisioning.common.SettingsFacade; 39 import com.android.managedprovisioning.common.Utils; 40 import com.android.managedprovisioning.model.ProvisioningParams; 41 import com.android.managedprovisioning.provisioning.Constants; 42 43 import java.io.File; 44 45 /** 46 * Controller for the finalization of managed provisioning. 47 * 48 * <p>This controller is invoked when the active provisioning is completed via 49 * {@link #provisioningInitiallyDone(ProvisioningParams)}. In the case of provisioning during SUW, 50 * it is invoked again when provisioning is finalized via {@link #provisioningFinalized()}.</p> 51 */ 52 public class FinalizationController { 53 private static final String PROVISIONING_PARAMS_FILE_NAME = 54 "finalization_activity_provisioning_params.xml"; 55 static final int PROVISIONING_FINALIZED_RESULT_DEFAULT = 1; 56 static final int PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH = 2; 57 static final int PROVISIONING_FINALIZED_RESULT_EARLY_EXIT = 3; 58 @IntDef({ 59 PROVISIONING_FINALIZED_RESULT_DEFAULT, 60 PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH, 61 PROVISIONING_FINALIZED_RESULT_EARLY_EXIT}) 62 @interface ProvisioningFinalizedResult {} 63 64 private final Context mContext; 65 private final Utils mUtils; 66 private final SettingsFacade mSettingsFacade; 67 private final UserProvisioningStateHelper mUserProvisioningStateHelper; 68 private final ProvisioningIntentProvider mProvisioningIntentProvider; 69 private final NotificationHelper mNotificationHelper; 70 private final DeferredMetricsReader mDeferredMetricsReader; 71 private @ProvisioningFinalizedResult int mProvisioningFinalizedResult; 72 FinalizationController(Context context, UserProvisioningStateHelper userProvisioningStateHelper)73 public FinalizationController(Context context, 74 UserProvisioningStateHelper userProvisioningStateHelper) { 75 this( 76 context, 77 new Utils(), 78 new SettingsFacade(), 79 userProvisioningStateHelper, 80 new NotificationHelper(context), 81 new DeferredMetricsReader( 82 Constants.getDeferredMetricsFile(context))); 83 } 84 FinalizationController(Context context)85 public FinalizationController(Context context) { 86 this( 87 context, 88 new Utils(), 89 new SettingsFacade(), 90 new UserProvisioningStateHelper(context), 91 new NotificationHelper(context), 92 new DeferredMetricsReader( 93 Constants.getDeferredMetricsFile(context))); 94 } 95 96 @VisibleForTesting FinalizationController(Context context, Utils utils, SettingsFacade settingsFacade, UserProvisioningStateHelper helper, NotificationHelper notificationHelper, DeferredMetricsReader deferredMetricsReader)97 FinalizationController(Context context, 98 Utils utils, 99 SettingsFacade settingsFacade, 100 UserProvisioningStateHelper helper, 101 NotificationHelper notificationHelper, 102 DeferredMetricsReader deferredMetricsReader) { 103 mContext = checkNotNull(context); 104 mUtils = checkNotNull(utils); 105 mSettingsFacade = checkNotNull(settingsFacade); 106 mUserProvisioningStateHelper = checkNotNull(helper); 107 mProvisioningIntentProvider = new ProvisioningIntentProvider(); 108 mNotificationHelper = checkNotNull(notificationHelper); 109 mDeferredMetricsReader = checkNotNull(deferredMetricsReader); 110 } 111 112 /** 113 * This method is invoked when the provisioning process is done. 114 * 115 * <p>If provisioning happens as part of SUW, we rely on {@link #provisioningFinalized()} to be 116 * called at the end of SUW. Otherwise, this method will finalize provisioning. If called after 117 * SUW, this method notifies the DPC about the completed provisioning; otherwise, it stores the 118 * provisioning params for later digestion.</p> 119 * 120 * <p>Note that fully managed device provisioning is only possible during SUW. 121 * 122 * @param params the provisioning params 123 */ provisioningInitiallyDone(ProvisioningParams params)124 public void provisioningInitiallyDone(ProvisioningParams params) { 125 if (!mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) { 126 // In any other state than STATE_USER_UNMANAGED and STATE_USER_SETUP_FINALIZED, we've 127 // already run this method, so don't do anything. 128 // STATE_USER_SETUP_FINALIZED can occur here if a managed profile is provisioned on a 129 // device owner device. 130 ProvisionLogger.logw("provisioningInitiallyDone called, but state is not finalized or " 131 + "unmanaged"); 132 return; 133 } 134 135 mUserProvisioningStateHelper.markUserProvisioningStateInitiallyDone(params); 136 if (ACTION_PROVISION_MANAGED_PROFILE.equals(params.provisioningAction)) { 137 if (params.isOrganizationOwnedProvisioning) { 138 setProfileOwnerCanAccessDeviceIds(); 139 } 140 if (!mSettingsFacade.isDuringSetupWizard(mContext)) { 141 // If a managed profile was provisioned after SUW, notify the DPC straight away. 142 notifyDpcManagedProfile(params); 143 } 144 } 145 if (mSettingsFacade.isDuringSetupWizard(mContext)) { 146 // Store the information and wait for provisioningFinalized to be called 147 storeProvisioningParams(params); 148 } 149 } 150 setProfileOwnerCanAccessDeviceIds()151 private void setProfileOwnerCanAccessDeviceIds() { 152 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); 153 final int managedProfileUserId = mUtils.getManagedProfile(mContext).getIdentifier(); 154 final ComponentName admin = dpm.getProfileOwnerAsUser(managedProfileUserId); 155 if (admin != null) { 156 try { 157 final Context profileContext = mContext.createPackageContextAsUser( 158 mContext.getPackageName(), 0 /* flags */, 159 UserHandle.of(managedProfileUserId)); 160 final DevicePolicyManager profileDpm = 161 profileContext.getSystemService(DevicePolicyManager.class); 162 profileDpm.setProfileOwnerCanAccessDeviceIds(admin); 163 } catch (NameNotFoundException e) { 164 ProvisionLogger.logw("Error setting access to Device IDs: " + e.getMessage()); 165 } 166 } 167 } 168 169 @VisibleForTesting getPrimaryProfileFinalizationHelper( ProvisioningParams params)170 PrimaryProfileFinalizationHelper getPrimaryProfileFinalizationHelper( 171 ProvisioningParams params) { 172 return new PrimaryProfileFinalizationHelper(params.accountToMigrate, 173 params.keepAccountMigrated, mUtils.getManagedProfile(mContext), 174 params.inferDeviceAdminPackageName(), mUtils, 175 mUtils.isAdminIntegratedFlow(params)); 176 } 177 178 /** 179 * This method is invoked when provisioning is finalized. 180 * 181 * <p>This method has to be invoked after {@link #provisioningInitiallyDone(ProvisioningParams)} 182 * was called. It is commonly invoked at the end of SUW if provisioning occurs during SUW. It 183 * loads the provisioning params from the storage, notifies the DPC about the completed 184 * provisioning and sets the right user provisioning states. 185 * 186 * <p>To retrieve the resulting state of this method, use 187 * {@link #getProvisioningFinalizedResult()} 188 */ provisioningFinalized()189 void provisioningFinalized() { 190 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_EARLY_EXIT; 191 mDeferredMetricsReader.scheduleDumpMetrics(mContext); 192 193 if (mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) { 194 ProvisionLogger.logw("provisioningInitiallyDone called, but state is finalized or " 195 + "unmanaged"); 196 return; 197 } 198 199 final ProvisioningParams params = loadProvisioningParamsAndClearFile(); 200 if (params == null) { 201 ProvisionLogger.logw("FinalizationController invoked, but no stored params"); 202 return; 203 } 204 205 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_DEFAULT; 206 if (mUtils.isAdminIntegratedFlow(params)) { 207 // Don't send ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to DPC or launch DPC by 208 // ACTION_PROVISIONING_SUCCESSFUL intent if it's admin integrated flow. 209 if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 210 getPrimaryProfileFinalizationHelper(params) 211 .finalizeProvisioningInPrimaryProfile(mContext, null); 212 } else if (ACTION_PROVISION_MANAGED_DEVICE.equals(params.provisioningAction)) { 213 mNotificationHelper.showPrivacyReminderNotification( 214 mContext, NotificationManager.IMPORTANCE_DEFAULT); 215 } 216 mProvisioningIntentProvider.launchFinalizationScreen(mContext, params); 217 } else { 218 if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 219 notifyDpcManagedProfile(params); 220 final UserHandle managedProfileUserHandle = mUtils.getManagedProfile(mContext); 221 final int userId = managedProfileUserHandle.getIdentifier(); 222 mProvisioningFinalizedResult = 223 mProvisioningIntentProvider.canLaunchDpc(params, userId, mUtils, mContext) 224 ? PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH 225 : PROVISIONING_FINALIZED_RESULT_DEFAULT; 226 } else { 227 // For managed user and device owner, we send the provisioning complete intent and 228 // maybe launch the DPC. 229 final int userId = UserHandle.myUserId(); 230 final Intent provisioningCompleteIntent = mProvisioningIntentProvider 231 .createProvisioningCompleteIntent(params, userId, mUtils, mContext); 232 if (provisioningCompleteIntent == null) { 233 return; 234 } 235 mContext.sendBroadcast(provisioningCompleteIntent); 236 237 mProvisioningIntentProvider.maybeLaunchDpc(params, userId, mUtils, mContext); 238 239 if (ACTION_PROVISION_MANAGED_DEVICE.equals(params.provisioningAction)) { 240 mNotificationHelper.showPrivacyReminderNotification( 241 mContext, NotificationManager.IMPORTANCE_DEFAULT); 242 } 243 } 244 } 245 246 mUserProvisioningStateHelper.markUserProvisioningStateFinalized(params); 247 } 248 249 /** 250 * @throws IllegalStateException if {@link #provisioningFinalized()} was not called before. 251 */ getProvisioningFinalizedResult()252 @ProvisioningFinalizedResult int getProvisioningFinalizedResult() { 253 if (mProvisioningFinalizedResult == 0) { 254 throw new IllegalStateException("provisioningFinalized() has not been called."); 255 } 256 return mProvisioningFinalizedResult; 257 } 258 259 /** 260 * Start a service which notifies the DPC on the managed profile that provisioning has 261 * completed. When the DPC has received the intent, send notify the primary instance that the 262 * profile is ready. The service is needed to prevent the managed provisioning process from 263 * getting killed while the user is on the DPC screen. 264 */ notifyDpcManagedProfile(ProvisioningParams params)265 private void notifyDpcManagedProfile(ProvisioningParams params) { 266 mContext.startService( 267 new Intent(mContext, SendDpcBroadcastService.class) 268 .putExtra(EXTRA_PROVISIONING_PARAMS, params)); 269 } 270 storeProvisioningParams(ProvisioningParams params)271 private void storeProvisioningParams(ProvisioningParams params) { 272 params.save(getProvisioningParamsFile()); 273 } 274 getProvisioningParamsFile()275 private File getProvisioningParamsFile() { 276 return new File(mContext.getFilesDir(), PROVISIONING_PARAMS_FILE_NAME); 277 } 278 279 @VisibleForTesting loadProvisioningParamsAndClearFile()280 ProvisioningParams loadProvisioningParamsAndClearFile() { 281 File file = getProvisioningParamsFile(); 282 ProvisioningParams result = ProvisioningParams.load(file); 283 file.delete(); 284 return result; 285 } 286 } 287