• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.managedprovisioning;
17 
18 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
23 
24 import android.app.Notification;
25 import android.app.NotificationManager;
26 import android.app.PendingIntent;
27 import android.content.BroadcastReceiver;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Bundle;
32 
33 /**
34  * Class that handles the resuming process that takes place after a reboot during the provisioning
35  * process. The reboot could be an unexpected reboot or a reboot during the encryption process.
36  */
37 public class BootReminder extends BroadcastReceiver {
38     private static final int NOTIFY_ID = 1;
39 
40     /*
41      * Profile owner parameters that are stored in the IntentStore for resuming provisioning after
42      * encryption.
43      */
44     private static final String PROFILE_OWNER_ENCRYPTION_PREFERENCES_NAME =
45             "profile-owner-encryption-resume";
46 
47     /*
48      * Profile owner parameters that are stored in the IntentStore for resuming provisioning after
49      * Setup wizard has shutdown.
50      */
51     private static final String PROFILE_OWNER_FINALIZING_PREFERENCES_NAME =
52             "profile-owner-finalizing-resume";
53 
54     private static final ComponentName PROFILE_OWNER_INTENT_TARGET =
55             ProfileOwnerPreProvisioningActivity.ALIAS_NO_CHECK_CALLER;
56 
57     /*
58      * Device owner parameters that are stored in the IntentStore for resuming provisioning after
59      * encryption.
60      */
61     private static final String DEVICE_OWNER_ENCRYPTION_PREFERENCES_NAME =
62             "device-owner-encryption-resume";
63 
64     // Device owner parameter stored for resuming provisioning after unexpected device reboot during
65     // finalizing stage.
66     private static final String DEVICE_OWNER_FINALIZING_PREFERENCES_NAME =
67             "device-owner-finalizing-resume";
68 
69     private static final ComponentName DEVICE_OWNER_INTENT_TARGET =
70             new ComponentName("com.android.managedprovisioning",
71                     "com.android.managedprovisioning.DeviceOwnerPreProvisioningActivity");
72 
73     private static final ComponentName HOME_RECEIVER_INTENT_TARGET =
74             new ComponentName("com.android.managedprovisioning",
75                     "com.android.managedprovisioning.HomeReceiverActivity");
76 
77     @Override
onReceive(Context context, Intent intent)78     public void onReceive(Context context, Intent intent) {
79         if (android.content.Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
80 
81             // Resume profile owner provisioning if applicable.
82             IntentStore profileOwnerIntentStore =
83                     getProfileOwnerEncryptionResumptionIntentStore(context);
84             final Intent resumeProfileOwnerPrvIntent = profileOwnerIntentStore.load();
85             if (resumeProfileOwnerPrvIntent != null && EncryptDeviceActivity.isDeviceEncrypted()) {
86                 profileOwnerIntentStore.clear();
87                 if (Utils.isUserSetupCompleted(context)) {
88                     // Show reminder notification and then forget about it for next boot
89                     setNotification(context, resumeProfileOwnerPrvIntent);
90                 } else {
91                     resumeProfileOwnerPrvIntent.setAction(ACTION_PROVISION_MANAGED_PROFILE);
92                     TrampolineActivity.startActivity(context, resumeProfileOwnerPrvIntent);
93                 }
94             }
95 
96             // Resume device owner provisioning after encryption if applicable.
97             IntentStore deviceOwnerIntentStore =
98                     getDeviceOwnerEncryptionResumptionIntentStore(context);
99             Intent resumeDeviceOwnerPrvIntent = deviceOwnerIntentStore.load();
100             if (resumeDeviceOwnerPrvIntent != null) {
101                 deviceOwnerIntentStore.clear();
102                 resumeDeviceOwnerPrvIntent.setAction(
103                         DeviceOwnerPreProvisioningActivity.LEGACY_ACTION_PROVISION_MANAGED_DEVICE);
104                 TrampolineActivity.startActivity(context, resumeDeviceOwnerPrvIntent);
105             }
106         }
107     }
108 
109     /**
110      * Schedule a provisioning reminder notification for the next reboot.
111      *
112      * {@code extras} should be a Bundle containing the
113      * {@link EncryptDeviceActivity.EXTRA_RESUME_TARGET}.
114      * This field has only two supported values {@link EncryptDeviceActivity.TARGET_PROFILE_OWNER}
115      * and {@link EncryptDeviceActivity.TARGET_DEVICE_OWNER}
116      *
117      * <p> In case of TARGET_PROFILE_OWNER {@code extras} should further contain a value for at
118      * least the key: {@link EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}, a {@link String}
119      * which, when unflattened to a componentName, specifies the component to set as profile owner.
120      *
121      * <p>
122      * See {@link MessageParser} for the TARGET_DEVICE_OWNER case.
123      * </ul>
124      *
125      * <p> These fields will be persisted and restored to the provisioner after rebooting. Any other
126      * key/value pairs will be ignored.
127      */
setProvisioningReminder(Context context, Bundle extras)128     public static void setProvisioningReminder(Context context, Bundle extras) {
129         IntentStore intentStore;
130         String resumeTarget = extras.getString(EncryptDeviceActivity.EXTRA_RESUME_TARGET, null);
131         if (resumeTarget == null) {
132             return;
133         }
134         if (resumeTarget.equals(EncryptDeviceActivity.TARGET_PROFILE_OWNER)) {
135             intentStore = getProfileOwnerEncryptionResumptionIntentStore(context);
136         } else if (resumeTarget.equals(EncryptDeviceActivity.TARGET_DEVICE_OWNER)) {
137             intentStore = getDeviceOwnerEncryptionResumptionIntentStore(context);
138         } else {
139             ProvisionLogger.loge("Unknown resume target for bootreminder.");
140             return;
141         }
142         intentStore.save(extras);
143     }
144 
145     /**
146      * Cancel all active provisioning reminders.
147      */
cancelProvisioningReminder(Context context)148     public static void cancelProvisioningReminder(Context context) {
149         getProfileOwnerEncryptionResumptionIntentStore(context).clear();
150         getDeviceOwnerEncryptionResumptionIntentStore(context).clear();
151         setNotification(context, null);
152     }
153 
getProfileOwnerIntentStore(Context context, ComponentName intentTarget, String storeName)154     private static IntentStore getProfileOwnerIntentStore(Context context,
155             ComponentName intentTarget, String storeName) {
156         return new IntentStore(context, intentTarget, storeName)
157                 .setComponentNameKeys(MessageParser.PROFILE_OWNER_COMPONENT_NAME_EXTRAS)
158                 .setStringKeys(MessageParser.PROFILE_OWNER_STRING_EXTRAS)
159                 .setPersistableBundleKeys(MessageParser.PROFILE_OWNER_PERSISTABLE_BUNDLE_EXTRAS)
160                 .setAccountKeys(MessageParser.PROFILE_OWNER_ACCOUNT_EXTRAS);
161     }
162 
getDeviceOwnerIntentStore(Context context, ComponentName intentTarget, String storeName)163     private static IntentStore getDeviceOwnerIntentStore(Context context,
164             ComponentName intentTarget, String storeName) {
165         return new IntentStore(context, intentTarget, storeName)
166                 .setComponentNameKeys(MessageParser.DEVICE_OWNER_COMPONENT_NAME_EXTRAS)
167                 .setStringKeys(MessageParser.DEVICE_OWNER_STRING_EXTRAS)
168                 .setLongKeys(MessageParser.DEVICE_OWNER_LONG_EXTRAS)
169                 .setIntKeys(MessageParser.DEVICE_OWNER_INT_EXTRAS)
170                 .setBooleanKeys(MessageParser.DEVICE_OWNER_BOOLEAN_EXTRAS)
171                 .setPersistableBundleKeys(MessageParser.DEVICE_OWNER_PERSISTABLE_BUNDLE_EXTRAS);
172     }
173 
getDeviceOwnerEncryptionResumptionIntentStore(Context context)174     private static IntentStore getDeviceOwnerEncryptionResumptionIntentStore(Context context) {
175         return getDeviceOwnerIntentStore(context, DEVICE_OWNER_INTENT_TARGET,
176                 DEVICE_OWNER_ENCRYPTION_PREFERENCES_NAME);
177     }
178 
getDeviceOwnerFinalizingIntentStore(Context context)179     protected static IntentStore getDeviceOwnerFinalizingIntentStore(Context context) {
180         return getDeviceOwnerIntentStore(context, HOME_RECEIVER_INTENT_TARGET,
181                 DEVICE_OWNER_FINALIZING_PREFERENCES_NAME);
182     }
183 
getProfileOwnerEncryptionResumptionIntentStore(Context context)184     private static IntentStore getProfileOwnerEncryptionResumptionIntentStore(Context context) {
185         return getProfileOwnerIntentStore(context, PROFILE_OWNER_INTENT_TARGET,
186                 PROFILE_OWNER_ENCRYPTION_PREFERENCES_NAME);
187     }
188 
getProfileOwnerFinalizingIntentStore(Context context)189     protected static IntentStore getProfileOwnerFinalizingIntentStore(Context context) {
190         return getProfileOwnerIntentStore(context, HOME_RECEIVER_INTENT_TARGET,
191                 PROFILE_OWNER_FINALIZING_PREFERENCES_NAME);
192     }
193 
194     /** Create and show the provisioning reminder notification. */
setNotification(Context context, Intent intent)195     private static void setNotification(Context context, Intent intent) {
196         final NotificationManager notificationManager = (NotificationManager)
197                 context.getSystemService(Context.NOTIFICATION_SERVICE);
198         if (intent == null) {
199             notificationManager.cancel(NOTIFY_ID);
200             return;
201         }
202         final PendingIntent resumePendingIntent = PendingIntent.getActivity(
203                 context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
204         final Notification.Builder notify = new Notification.Builder(context)
205                 .setContentIntent(resumePendingIntent)
206                 .setContentTitle(context.getString(R.string.continue_provisioning_notify_title))
207                 .setContentText(context.getString(R.string.continue_provisioning_notify_text))
208                 .setSmallIcon(com.android.internal.R.drawable.ic_corp_statusbar_icon)
209                 .setVisibility(Notification.VISIBILITY_PUBLIC)
210                 .setColor(context.getResources().getColor(
211                         com.android.internal.R.color.system_notification_accent_color))
212                 .setAutoCancel(true);
213         notificationManager.notify(NOTIFY_ID, notify.build());
214     }
215 }
216