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