1 /*
2  * Copyright (C) 2016 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.preprovisioning;
17 
18 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
20 import static org.mockito.Mockito.any;
21 import static org.mockito.Mockito.eq;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.res.Resources;
30 import android.content.pm.PackageManager;
31 import android.os.Handler;
32 import android.os.Looper;
33 import android.test.AndroidTestCase;
34 import android.test.suitebuilder.annotation.SmallTest;
35 
36 import com.android.managedprovisioning.common.NotificationHelper;
37 import com.android.managedprovisioning.common.SettingsFacade;
38 import com.android.managedprovisioning.common.Utils;
39 import com.android.managedprovisioning.model.ProvisioningParams;
40 
41 import java.util.concurrent.Semaphore;
42 import java.util.concurrent.TimeUnit;
43 import org.mockito.ArgumentCaptor;
44 import org.mockito.Mock;
45 import org.mockito.MockitoAnnotations;
46 
47 @SmallTest
48 public class EncryptionControllerTest extends AndroidTestCase {
49     private static final int TEST_USER_ID = 10;
50     private static final String MP_PACKAGE_NAME = "com.android.managedprovisioning";
51     private static final ComponentName TEST_HOME_RECEIVER = new ComponentName(MP_PACKAGE_NAME,
52             ".HomeReceiverActivity");
53     private static final String TEST_MDM_PACKAGE = "com.admin.test";
54     private static final int RESUME_PROVISIONING_TIMEOUT_MS = 1000;
55 
56     @Mock private Context mContext;
57     @Mock private Utils mUtils;
58     @Mock private SettingsFacade mSettingsFacade;
59     @Mock private Resources mResources;
60     @Mock private PackageManager mPackageManager;
61     @Mock private NotificationHelper mNotificationHelper;
62 
63     private EncryptionController mController;
64 
65     @Override
setUp()66     public void setUp() {
67         // this is necessary for mockito to work
68         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
69 
70         MockitoAnnotations.initMocks(this);
71 
72         when(mUtils.isPhysicalDeviceEncrypted()).thenReturn(true);
73         when(mContext.getApplicationContext()).thenReturn(mContext);
74         when(mContext.getPackageManager()).thenReturn(mPackageManager);
75         when(mContext.getFilesDir()).thenReturn(getContext().getFilesDir());
76 
77         mController = createEncryptionController();
78         mController.getProvisioningParamsFile(mContext).delete();
79     }
80 
testDeviceOwner()81     public void testDeviceOwner() throws Exception {
82         // GIVEN we've set a provisioning reminder for device owner provisioning.
83         when(mSettingsFacade.isUserSetupCompleted(mContext)).thenReturn(false);
84         ProvisioningParams params = createProvisioningParams(ACTION_PROVISION_MANAGED_DEVICE);
85         setReminder(params);
86         verify(mUtils).enableComponent(TEST_HOME_RECEIVER, TEST_USER_ID);
87         verify(mPackageManager).flushPackageRestrictionsAsUser(TEST_USER_ID);
88         // WHEN resuming the provisioning
89         runResumeProvisioningOnUiThread();
90         // THEN the pre provisioning activity is started
91         verifyStartPreProvisioningActivity(params);
92     }
93 
testProfileOwnerAfterSuw()94     public void testProfileOwnerAfterSuw() throws Exception {
95         // GIVEN we set a provisioning reminder for managed profile provisioning after SUW
96         when(mSettingsFacade.isUserSetupCompleted(mContext)).thenReturn(true);
97         ProvisioningParams params = createProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE);
98         setReminder(params);
99         // WHEN resuming the provisioning
100         runResumeProvisioningOnUiThread();
101         // THEN we show a notification
102         verifyShowResumeNotification(params);
103     }
104 
testProfileOwnerDuringSuw()105     public void testProfileOwnerDuringSuw() throws Exception {
106         // GIVEN we set a provisioning reminder for managed profile provisioning during SUW
107         when(mSettingsFacade.isUserSetupCompleted(mContext)).thenReturn(false);
108         ProvisioningParams params = createProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE);
109         setReminder(params);
110         verify(mUtils).enableComponent(TEST_HOME_RECEIVER, TEST_USER_ID);
111         verify(mPackageManager).flushPackageRestrictionsAsUser(TEST_USER_ID);
112         // WHEN resuming the provisioning
113         runResumeProvisioningOnUiThread();
114         // THEN we start the pre provisioning activity
115         verifyStartPreProvisioningActivity(params);
116     }
117 
testDeviceNotEncrypted()118     public void testDeviceNotEncrypted() throws Exception {
119         // GIVEN an intent was stored to resume device owner provisioning, but the device
120         // is not encrypted
121         ProvisioningParams params = createProvisioningParams(ACTION_PROVISION_MANAGED_DEVICE);
122         setReminder(params);
123         when(mUtils.isPhysicalDeviceEncrypted()).thenReturn(false);
124         // WHEN resuming provisioning
125         runResumeProvisioningOnUiThread();
126         // THEN nothing should happen
127         verifyNothingStarted();
128     }
129 
testResumeProvisioningNoIntent()130     public void testResumeProvisioningNoIntent() throws Exception {
131         // GIVEN no reminder is set
132         // WHEN resuming the provisioning
133         runResumeProvisioningOnUiThread();
134         // THEN nothing should happen
135         verifyNothingStarted();
136     }
137 
testCancelProvisioningReminder()138     public void testCancelProvisioningReminder() throws Exception {
139         // WHEN we've set a provisioning reminder
140         when(mSettingsFacade.isUserSetupCompleted(mContext)).thenReturn(true);
141         ProvisioningParams params = createProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE);
142         setReminder(params);
143         // WHEN canceling the reminder and then resuming the provisioning
144         mController.cancelEncryptionReminder();
145         verify(mUtils).disableComponent(TEST_HOME_RECEIVER, TEST_USER_ID);
146         runResumeProvisioningOnUiThread();
147         // THEN nothing should start
148         verifyNothingStarted();
149     }
150 
createProvisioningParams(String action)151     private ProvisioningParams createProvisioningParams(String action) {
152         return new ProvisioningParams.Builder()
153                 .setProvisioningAction(action)
154                 .setDeviceAdminPackageName(TEST_MDM_PACKAGE)
155                 .build();
156     }
157 
runResumeProvisioningOnUiThread()158     private void runResumeProvisioningOnUiThread() throws InterruptedException {
159         final Semaphore semaphore = new Semaphore(0);
160         new Handler(Looper.getMainLooper()).post(new Runnable() {
161             @Override
162             public void run() {
163                 // In a real case, the device may have rebooted between the moment when the
164                 // reminder was set and the moment we resume the provisioning. Recreate the
165                 // encryption controller to simulate this.
166                 createEncryptionController().resumeProvisioning();
167                 semaphore.release();
168             }
169         });
170         assertTrue("Timeout trying to resume provisioning",
171                 semaphore.tryAcquire(RESUME_PROVISIONING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
172     }
173 
createEncryptionController()174     private EncryptionController createEncryptionController() {
175         return new EncryptionController(mContext, mUtils, mSettingsFacade, TEST_HOME_RECEIVER,
176             mNotificationHelper, TEST_USER_ID);
177     }
178 
setReminder(ProvisioningParams params)179     private void setReminder(ProvisioningParams params) {
180         mController.setEncryptionReminder(params);
181     }
182 
verifyStartPreProvisioningActivity(ProvisioningParams params)183     private void verifyStartPreProvisioningActivity(ProvisioningParams params) throws Exception {
184         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
185         verify(mContext).startActivity(intentCaptor.capture());
186         assertEquals(params, intentCaptor.getValue().getParcelableExtra(
187                 ProvisioningParams.EXTRA_PROVISIONING_PARAMS));
188         verify(mNotificationHelper, never()).showResumeNotification(any(Intent.class));
189     }
190 
verifyShowResumeNotification(ProvisioningParams params)191     private void verifyShowResumeNotification(ProvisioningParams params) throws Exception {
192         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
193         verify(mNotificationHelper).showResumeNotification(intentCaptor.capture());
194         assertEquals(params, intentCaptor.getValue().getParcelableExtra(
195                 ProvisioningParams.EXTRA_PROVISIONING_PARAMS));
196         verify(mContext, never()).startActivity(any(Intent.class));
197     }
198 
verifyNothingStarted()199     private void verifyNothingStarted() throws Exception {
200         verify(mContext, never()).startActivity(any(Intent.class));
201         verify(mNotificationHelper, never()).showResumeNotification(any(Intent.class));
202     }
203 }
204