1 /* 2 * Copyright 2014, 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; 18 19 import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 22 23 import android.app.Activity; 24 import android.app.admin.DevicePolicyManager; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.os.Bundle; 29 import android.os.UserHandle; 30 31 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 32 import com.android.managedprovisioning.common.Utils; 33 import com.android.managedprovisioning.model.ProvisioningParams; 34 import com.android.managedprovisioning.parser.MessageParser; 35 36 /* 37 * This class is used to make sure that we start the MDM after we shut the setup wizard down. 38 * The shut down of the setup wizard is initiated in the DeviceOwnerProvisioningActivity or 39 * ProfileOwnerProvisioningActivity by calling 40 * {@link DevicePolicyManager.setUserProvisioningState()}. This will cause the 41 * Setup wizard to shut down and send a ACTION_PROVISIONING_FINALIZATION intent. This intent is 42 * caught by this receiver instead which will send the 43 * ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to the MDM, which can then present it's own 44 * activities. 45 */ 46 public class FinalizationActivity extends Activity { 47 48 private ProvisioningParams mParams; 49 50 private static final String INTENT_STORE_NAME = "finalization-receiver"; 51 52 private final Utils mUtils = new Utils(); 53 54 @Override onCreate(Bundle savedInstanceState)55 public void onCreate(Bundle savedInstanceState) { 56 super.onCreate(savedInstanceState); 57 58 DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); 59 int currentState = dpm.getUserProvisioningState(); 60 61 switch (currentState) { 62 case DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE: 63 case DevicePolicyManager.STATE_USER_SETUP_COMPLETE: 64 case DevicePolicyManager.STATE_USER_PROFILE_COMPLETE: 65 finalizeProvisioning(dpm); 66 break; 67 case DevicePolicyManager.STATE_USER_UNMANAGED: 68 case DevicePolicyManager.STATE_USER_SETUP_FINALIZED: 69 // Nothing to do in these cases. 70 ProvisionLogger.logw("Received ACTION_PROVISIONING_FINALIZATION intent, but " 71 + "nothing to do in state: " + currentState); 72 break; 73 } 74 75 finish(); 76 } 77 storeProvisioningParams(Context context, ProvisioningParams params)78 public static void storeProvisioningParams(Context context, ProvisioningParams params) { 79 Intent intent = new MessageParser().getIntentFromProvisioningParams(params); 80 getIntentStore(context).save(intent); 81 } 82 finalizeProvisioning(DevicePolicyManager dpm)83 private void finalizeProvisioning(DevicePolicyManager dpm) { 84 mParams = loadProvisioningParamsAndClearIntentStore(); 85 Intent provisioningCompleteIntent = getProvisioningCompleteIntent(dpm); 86 if (provisioningCompleteIntent == null) { 87 return; 88 } 89 90 // It maybe the case that mParams is null at this point - we expect this to be the case if 91 // ManagedProvisioning wasn't invoked to perform setup. We'll simply trigger the normal 92 // broadcast so that the installed DPC knows that user-setup completed. Concrete use-case 93 // is a user being setup through DevicePolicyManager.createAndInitializeUser() by the 94 // device-owner, which sets profile-owner and then launches the user. Setup-wizard on the 95 // user runs, and at the end of it's activity flow will trigger the finalization intent, 96 // which then allows us to notify the DPC that profile setup is complete. 97 if (mParams != null && 98 mParams.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 99 // For the managed profile owner case, we need to send the provisioning complete 100 // intent to the mdm. Once it has been received, we'll send 101 // ACTION_MANAGED_PROFILE_PROVISIONED in the parent. 102 finalizeManagedProfileOwnerProvisioning(provisioningCompleteIntent); 103 } else { 104 // For managed user and device owner, we just need to send the provisioning complete 105 // intent to the mdm. 106 sendBroadcast(provisioningCompleteIntent); 107 } 108 109 mUtils.markUserProvisioningStateFinalized(this, mParams); 110 } 111 finalizeManagedProfileOwnerProvisioning(Intent provisioningCompleteIntent)112 private void finalizeManagedProfileOwnerProvisioning(Intent provisioningCompleteIntent) { 113 UserHandle managedUserHandle = mUtils.getManagedProfile(this); 114 if (managedUserHandle == null) { 115 ProvisionLogger.loge("Failed to retrieve the userHandle of the managed profile."); 116 return; 117 } 118 BroadcastReceiver mdmReceivedSuccessReceiver = new MdmReceivedSuccessReceiver( 119 mParams.accountToMigrate, mParams.deviceAdminComponentName.getPackageName()); 120 121 sendOrderedBroadcastAsUser(provisioningCompleteIntent, managedUserHandle, null, 122 mdmReceivedSuccessReceiver, null, Activity.RESULT_OK, null, null); 123 } 124 getProvisioningCompleteIntent(DevicePolicyManager dpm)125 private Intent getProvisioningCompleteIntent(DevicePolicyManager dpm) { 126 Intent intent = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE); 127 try { 128 // mParams maybe null for cases where DevicePolicyManager has directly set DO or PO and 129 // ManagedProvisioning wasn't involved. In that case, we may still want to use the same 130 // mechanism after setup-wizard to invoke the MDM, hence why we fallback to inspecting 131 // device and profile-owner. 132 if (mParams != null) { 133 intent.setComponent(mParams.inferDeviceAdminComponentName(this)); 134 } else if (dpm.getDeviceOwner() != null) { 135 intent.setComponent(mUtils.findDeviceAdmin(dpm.getDeviceOwner(), 136 null /* mdmComponentName */, this)); 137 } else if (dpm.getProfileOwner() != null) { 138 intent.setComponent(mUtils.findDeviceAdmin(dpm.getProfileOwner().getPackageName(), 139 null /* mdmComponentName */, this)); 140 } else { 141 return null; 142 } 143 } catch (IllegalProvisioningArgumentException e) { 144 ProvisionLogger.loge("Failed to infer the device admin component name", e); 145 return null; 146 } 147 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | Intent.FLAG_RECEIVER_FOREGROUND); 148 if (mParams != null && mParams.adminExtrasBundle != null) { 149 intent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, mParams.adminExtrasBundle); 150 } 151 return intent; 152 } 153 loadProvisioningParamsAndClearIntentStore()154 private ProvisioningParams loadProvisioningParamsAndClearIntentStore() { 155 IntentStore intentStore = getIntentStore(this); 156 Intent intent = intentStore.load(); 157 if (intent == null) { 158 ProvisionLogger.loge("Fail to retrieve ProvisioningParams from intent store."); 159 return null; 160 } 161 intentStore.clear(); 162 163 try { 164 return new MessageParser().parse(intent, this); 165 } catch (IllegalProvisioningArgumentException e) { 166 ProvisionLogger.loge("Failed to parse provisioning intent", e); 167 } 168 return null; 169 } 170 getIntentStore(Context context)171 private static IntentStore getIntentStore(Context context) { 172 return new IntentStore(context, INTENT_STORE_NAME); 173 } 174 } 175