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