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