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