1 /* 2 * Copyright 2019, 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 24 import static java.util.Objects.requireNonNull; 25 26 import android.annotation.IntDef; 27 import android.app.NotificationManager; 28 import android.content.Context; 29 import android.os.Bundle; 30 import android.os.UserManager; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.managedprovisioning.analytics.DeferredMetricsReader; 34 import com.android.managedprovisioning.common.NotificationHelper; 35 import com.android.managedprovisioning.common.ProvisionLogger; 36 import com.android.managedprovisioning.common.SettingsFacade; 37 import com.android.managedprovisioning.common.Utils; 38 import com.android.managedprovisioning.model.ProvisioningParams; 39 import com.android.managedprovisioning.provisioning.Constants; 40 41 import java.io.File; 42 43 /** 44 * Controller for the finalization of managed provisioning. This class should be invoked after 45 * {@link PreFinalizationController}. Provisioning is finalized via calls to 46 * {@link #provisioningFinalized()} and {@link #commitFinalizedState()}. Different instances of 47 * this class will be tailored to run these two methods at different points in the Setup Wizard user 48 * flows, based on the type of FinalizationControllerLogic they are constructed with. 49 */ 50 public final class FinalizationController { 51 52 static final int PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED = 1; 53 static final int PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED = 2; 54 static final int PROVISIONING_FINALIZED_RESULT_SKIPPED = 3; 55 static final int PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE = 4; 56 static final int PROVISIONING_FINALIZED_RESULT_WORK_PROFILE_NOT_FOUND = 5; 57 58 @IntDef({ 59 PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED, 60 PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED, 61 PROVISIONING_FINALIZED_RESULT_SKIPPED, 62 PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE, 63 PROVISIONING_FINALIZED_RESULT_WORK_PROFILE_NOT_FOUND}) 64 @interface ProvisioningFinalizedResult {} 65 66 private static final int DPC_SETUP_REQUEST_CODE = 1; 67 private static final int FINAL_SCREEN_REQUEST_CODE = 2; 68 69 private final FinalizationControllerLogic mFinalizationControllerLogic; 70 private final Context mContext; 71 private final Utils mUtils; 72 private final SettingsFacade mSettingsFacade; 73 private final UserProvisioningStateHelper mUserProvisioningStateHelper; 74 private final ProvisioningIntentProvider mProvisioningIntentProvider; 75 private final NotificationHelper mNotificationHelper; 76 private final DeferredMetricsReader mDeferredMetricsReader; 77 private @ProvisioningFinalizedResult int mProvisioningFinalizedResult; 78 private ProvisioningParamsUtils mProvisioningParamsUtils; 79 FinalizationController(Context context, FinalizationControllerLogic finalizationControllerLogic, UserProvisioningStateHelper userProvisioningStateHelper)80 public FinalizationController(Context context, 81 FinalizationControllerLogic finalizationControllerLogic, 82 UserProvisioningStateHelper userProvisioningStateHelper) { 83 this( 84 context, 85 finalizationControllerLogic, 86 new Utils(), 87 new SettingsFacade(), 88 userProvisioningStateHelper, 89 new NotificationHelper(context), 90 new DeferredMetricsReader( 91 Constants.getDeferredMetricsFile(context)), 92 new ProvisioningParamsUtils( 93 ProvisioningParamsUtils.DEFAULT_PROVISIONING_PARAMS_FILE_PROVIDER)); 94 } 95 FinalizationController(Context context, FinalizationControllerLogic finalizationControllerLogic)96 public FinalizationController(Context context, 97 FinalizationControllerLogic finalizationControllerLogic) { 98 this( 99 context, 100 finalizationControllerLogic, 101 new Utils(), 102 new SettingsFacade(), 103 new UserProvisioningStateHelper(context), 104 new NotificationHelper(context), 105 new DeferredMetricsReader( 106 Constants.getDeferredMetricsFile(context)), 107 new ProvisioningParamsUtils( 108 ProvisioningParamsUtils.DEFAULT_PROVISIONING_PARAMS_FILE_PROVIDER)); 109 } 110 111 @VisibleForTesting FinalizationController(Context context, FinalizationControllerLogic finalizationControllerLogic, Utils utils, SettingsFacade settingsFacade, UserProvisioningStateHelper helper, NotificationHelper notificationHelper, DeferredMetricsReader deferredMetricsReader, ProvisioningParamsUtils provisioningParamsUtils)112 FinalizationController(Context context, 113 FinalizationControllerLogic finalizationControllerLogic, 114 Utils utils, 115 SettingsFacade settingsFacade, 116 UserProvisioningStateHelper helper, 117 NotificationHelper notificationHelper, 118 DeferredMetricsReader deferredMetricsReader, 119 ProvisioningParamsUtils provisioningParamsUtils) { 120 mContext = checkNotNull(context); 121 mFinalizationControllerLogic = checkNotNull(finalizationControllerLogic); 122 mUtils = checkNotNull(utils); 123 mSettingsFacade = checkNotNull(settingsFacade); 124 mUserProvisioningStateHelper = checkNotNull(helper); 125 mProvisioningIntentProvider = new ProvisioningIntentProvider(); 126 mNotificationHelper = checkNotNull(notificationHelper); 127 mDeferredMetricsReader = checkNotNull(deferredMetricsReader); 128 mProvisioningParamsUtils = provisioningParamsUtils; 129 } 130 131 @VisibleForTesting getPrimaryProfileFinalizationHelper( ProvisioningParams params)132 PrimaryProfileFinalizationHelper getPrimaryProfileFinalizationHelper( 133 ProvisioningParams params) { 134 return new PrimaryProfileFinalizationHelper(params.accountToMigrate, 135 mUtils.getManagedProfile(mContext), params.inferDeviceAdminPackageName()); 136 } 137 138 /** 139 * This method is invoked when provisioning is finalized. 140 * 141 * <p>This method has to be invoked after 142 * {@link PreFinalizationController#deviceManagementEstablished(ProvisioningParams)} 143 * was called. It is commonly invoked at the end of the setup flow, if provisioning occurs 144 * during the setup flow. It loads the provisioning params from the storage, notifies the DPC 145 * about the completed provisioning and sets the right user provisioning states. 146 * 147 * <p>To retrieve the resulting state of this method, use 148 * {@link #getProvisioningFinalizedResult()} 149 * 150 * <p>This method may be called multiple times. {@link #commitFinalizedState()} ()} must be 151 * called after the final call to this method. If this method is called again after that, it 152 * will return immediately without taking any action. 153 */ provisioningFinalized()154 void provisioningFinalized() { 155 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_SKIPPED; 156 157 if (mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) { 158 ProvisionLogger.logw("provisioningFinalized called, but state is finalized or " 159 + "unmanaged"); 160 return; 161 } 162 163 final ProvisioningParams params = loadProvisioningParams(); 164 if (params == null) { 165 ProvisionLogger.logw("FinalizationController invoked, but no stored params"); 166 return; 167 } 168 169 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED; 170 if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 171 var userManager = requireNonNull( 172 /* obj= */ mContext.getSystemService(UserManager.class), 173 /* message= */ "Unable to obtain UserManager"); 174 var userHandle = mUtils.getManagedProfile(mContext); 175 if (userHandle == null) { 176 // DPC setup failed for whatever reason e.g. user cancelled 177 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_WORK_PROFILE_NOT_FOUND; 178 return; 179 } 180 181 if (!userManager.isUserUnlocked(userHandle)) { 182 mProvisioningFinalizedResult = 183 PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE; 184 } else { 185 mProvisioningFinalizedResult = 186 mFinalizationControllerLogic.notifyDpcManagedProfile( 187 params, DPC_SETUP_REQUEST_CODE); 188 } 189 } else { 190 mProvisioningFinalizedResult = 191 mFinalizationControllerLogic.notifyDpcManagedDeviceOrUser( 192 params, DPC_SETUP_REQUEST_CODE); 193 } 194 } 195 196 /** 197 * @throws IllegalStateException if {@link #provisioningFinalized()} was not called before. 198 */ 199 @ProvisioningFinalizedResult getProvisioningFinalizedResult()200 int getProvisioningFinalizedResult() { 201 if (mProvisioningFinalizedResult == 0) { 202 throw new IllegalStateException("provisioningFinalized() has not been called."); 203 } 204 return mProvisioningFinalizedResult; 205 } 206 207 @VisibleForTesting clearParamsFile()208 void clearParamsFile() { 209 final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mContext); 210 if (file != null) { 211 file.delete(); 212 } 213 } 214 loadProvisioningParams()215 private ProvisioningParams loadProvisioningParams() { 216 final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mContext); 217 return ProvisioningParams.load(file); 218 } 219 220 /** 221 * Update the system's provisioning state, and commit any other irreversible changes that 222 * must wait until finalization is 100% completed. 223 */ commitFinalizedState(ProvisioningParams params)224 private void commitFinalizedState(ProvisioningParams params) { 225 if (ACTION_PROVISION_MANAGED_DEVICE.equals(params.provisioningAction)) { 226 mNotificationHelper.showPrivacyReminderNotification( 227 mContext, NotificationManager.IMPORTANCE_DEFAULT); 228 } else if (ACTION_PROVISION_MANAGED_PROFILE.equals(params.provisioningAction) 229 && mFinalizationControllerLogic.shouldFinalizePrimaryProfile(params)) { 230 getPrimaryProfileFinalizationHelper(params) 231 .finalizeProvisioningInPrimaryProfile(mContext, null); 232 } 233 234 mUserProvisioningStateHelper.markUserProvisioningStateFinalized(params); 235 236 mDeferredMetricsReader.scheduleDumpMetrics(mContext); 237 clearParamsFile(); 238 } 239 240 /** 241 * This method is called by the parent activity to force the final commit of all state changes. 242 * After this is called, any further calls to {@link #provisioningFinalized()} will return 243 * immediately without taking any action. 244 */ commitFinalizedState()245 void commitFinalizedState() { 246 final ProvisioningParams params = loadProvisioningParams(); 247 if (params == null) { 248 ProvisionLogger.logw( 249 "Attempt to commitFinalizedState when params have already been deleted"); 250 } else { 251 commitFinalizedState(loadProvisioningParams()); 252 } 253 } 254 255 /** 256 * This method is called when onSaveInstanceState() executes on the finalization activity. 257 */ saveInstanceState(Bundle outState)258 void saveInstanceState(Bundle outState) { 259 mFinalizationControllerLogic.saveInstanceState(outState); 260 } 261 262 /** 263 * When saved instance state is passed to the finalization activity in its onCreate() method, 264 * that state is passed to the FinalizationControllerLogic object here so it can be restored. 265 */ restoreInstanceState(Bundle savedInstanceState)266 void restoreInstanceState(Bundle savedInstanceState) { 267 mFinalizationControllerLogic.restoreInstanceState(savedInstanceState, 268 loadProvisioningParams()); 269 } 270 271 /** 272 * Cleanup that must happen when the finalization activity is destroyed, even if we haven't yet 273 * called {@link #commitFinalizedState()} to finalize the system's provisioning state. 274 */ activityDestroyed(boolean isFinishing)275 void activityDestroyed(boolean isFinishing) { 276 mFinalizationControllerLogic.activityDestroyed(isFinishing); 277 } 278 } 279