FinalizationActivity.java revision ba113214d1820f32e5132cd83a06fa1eaedd2866
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
17package com.android.managedprovisioning;
18
19import android.app.Activity;
20import android.app.admin.DevicePolicyManager;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.os.Bundle;
25import android.os.UserHandle;
26
27import com.android.managedprovisioning.Utils.IllegalProvisioningArgumentException;
28
29import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
30import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
31import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
32
33/*
34 * This class is used to make sure that we start the MDM after we shut the setup wizard down.
35 * The shut down of the setup wizard is initiated in the DeviceOwnerProvisioningActivity or
36 * ProfileOwnerProvisioningActivity by calling
37 * {@link DevicePolicyManager.setUserProvisioningState()}. This will cause the
38 * Setup wizard to shut down and send a ACTION_PROVISIONING_FINALIZATION intent. This intent is
39 * caught by this receiver instead which will send the
40 * ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to the MDM, which can then present it's own
41 * activities.
42 */
43public class FinalizationActivity extends Activity {
44
45    private ProvisioningParams mParams;
46
47    private static final String INTENT_STORE_NAME = "finalization-receiver";
48
49    @Override
50    public void onCreate(Bundle savedInstanceState) {
51        super.onCreate(savedInstanceState);
52
53        try {
54            DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
55            int currentState = dpm.getUserProvisioningState();
56
57            switch (currentState) {
58                case DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE:
59                case DevicePolicyManager.STATE_USER_SETUP_COMPLETE:
60                case DevicePolicyManager.STATE_USER_PROFILE_COMPLETE:
61                    finalizeProvisioning(dpm);
62                    break;
63                case DevicePolicyManager.STATE_USER_UNMANAGED:
64                case DevicePolicyManager.STATE_USER_SETUP_FINALIZED:
65                    // Nothing to do in these cases.
66                    ProvisionLogger.logw("Received ACTION_PROVISIONING_FINALIZATION intent, but "
67                            + "nothing to do in state: " + currentState);
68                    break;
69            }
70        } finally {
71            // TODO: Remove this once HomeReceiverActivity is removed.
72            HomeReceiverActivity.disableComponent(this);
73        }
74
75        finish();
76    }
77
78    public static void storeProvisioningParams(Context context, ProvisioningParams params) {
79        Intent intent = new MessageParser().getIntentFromProvisioningParams(params);
80        getIntentStore(context).save(intent);
81    }
82
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        Utils.markUserProvisioningStateFinalized(this, mParams);
110    }
111
112    private void finalizeManagedProfileOwnerProvisioning(Intent provisioningCompleteIntent) {
113        UserHandle managedUserHandle = Utils.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.deviceAdminPackageName);
120
121        sendOrderedBroadcastAsUser(provisioningCompleteIntent, managedUserHandle, null,
122                mdmReceivedSuccessReceiver, null, Activity.RESULT_OK, null, null);
123    }
124
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(Utils.findDeviceAdmin(dpm.getDeviceOwner(),
136                        null /* mdmComponentName */, this));
137            } else if (dpm.getProfileOwner() != null) {
138                intent.setComponent(Utils.findDeviceAdmin(dpm.getProfileOwner().getPackageName(),
139                        null /* mdmComponentName */, this));
140            } else {
141                return null;
142            }
143        } catch (Utils.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
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()).parseNonNfcIntent(intent, this, true /* trusted */);
165        } catch (IllegalProvisioningArgumentException e) {
166            ProvisionLogger.loge("Failed to parse provisioning intent", e);
167        }
168        return null;
169    }
170
171    private static IntentStore getIntentStore(Context context) {
172        return new IntentStore(context, INTENT_STORE_NAME);
173    }
174}
175