1 /*
2  * Copyright (C) 2019 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 
17 package com.android.managedprovisioning.finalization;
18 
19 import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
20 import static android.app.admin.DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE;
21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL;
22 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
23 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
24 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
25 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
26 
27 import static com.android.managedprovisioning.finalization.SendDpcBroadcastService.EXTRA_PROVISIONING_PARAMS;
28 
29 import static com.google.common.truth.Truth.assertThat;
30 
31 import static org.robolectric.Shadows.shadowOf;
32 
33 import android.app.Application;
34 import android.app.ApplicationPackageManager;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.pm.ResolveInfo;
39 import android.os.PersistableBundle;
40 import android.os.UserManager;
41 
42 import com.android.managedprovisioning.model.ProvisioningParams;
43 
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.robolectric.Robolectric;
48 import org.robolectric.RobolectricTestRunner;
49 import org.robolectric.RuntimeEnvironment;
50 import org.robolectric.android.controller.ServiceController;
51 
52 import java.util.List;
53 
54 /**
55  * Unit tests for {@link SendDpcBroadcastService}.
56  */
57 @RunWith(RobolectricTestRunner.class)
58 public class SendDpcBroadcastServiceTest {
59 
60     private final Context mContext = RuntimeEnvironment.application;
61     private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
62     private final ApplicationPackageManager mPackageManager =
63             (ApplicationPackageManager) mContext.getApplicationContext().getPackageManager();
64     private ServiceController<SendDpcBroadcastService> mController;
65 
66     private static final int USER_HANDLE = 0;
67     private static final int PROFILE_USER_HANDLE = 2;
68 
69     private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name";
70     private static final String TEST_MDM_ADMIN_RECEIVER = TEST_MDM_PACKAGE_NAME + ".AdminReceiver";
71     private static final ComponentName TEST_MDM_ADMIN = new ComponentName(TEST_MDM_PACKAGE_NAME,
72             TEST_MDM_ADMIN_RECEIVER);
73     private static final PersistableBundle TEST_MDM_EXTRA_BUNDLE = new PersistableBundle();
74     private static final ProvisioningParams PARAMS =
75             ProvisioningParams.Builder.builder()
76                     .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
77                     .setDeviceAdminComponentName(TEST_MDM_ADMIN)
78                     .setAdminExtrasBundle(TEST_MDM_EXTRA_BUNDLE)
79                     .setFlowType(ProvisioningParams.FLOW_TYPE_UNSPECIFIED)
80                     .build();
81     private static final ProvisioningParams PARAMS_TRUSTED_SOURCE =
82             ProvisioningParams.Builder.builder()
83                     .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE)
84                     .setDeviceAdminComponentName(TEST_MDM_ADMIN)
85                     .setAdminExtrasBundle(TEST_MDM_EXTRA_BUNDLE)
86                     .setStartedByTrustedSource(true)
87                     .setFlowType(ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED)
88                     .build();
89 
90     private static final String BOOL_KEY = "mybool";
91     private static final boolean BOOL_VALUE = false;
92     private static final String STRING_KEY = "mystring";
93     private static final String STRING_VALUE = "some string";
94     private static final String INT_KEY = "myint";
95     private static final int INT_VALUE = 1234;
96 
97     static {
TEST_MDM_EXTRA_BUNDLE.putBoolean(BOOL_KEY, BOOL_VALUE)98         TEST_MDM_EXTRA_BUNDLE.putBoolean(BOOL_KEY, BOOL_VALUE);
TEST_MDM_EXTRA_BUNDLE.putString(STRING_KEY, STRING_VALUE)99         TEST_MDM_EXTRA_BUNDLE.putString(STRING_KEY, STRING_VALUE);
TEST_MDM_EXTRA_BUNDLE.putInt(INT_KEY, INT_VALUE)100         TEST_MDM_EXTRA_BUNDLE.putInt(INT_KEY, INT_VALUE);
101     }
102 
103     @Before
setUp()104     public void setUp() {
105         final Intent intent =
106                 new Intent(RuntimeEnvironment.application, SendDpcBroadcastService.class)
107                 .putExtra(EXTRA_PROVISIONING_PARAMS, PARAMS);
108         mController = Robolectric.buildService(SendDpcBroadcastService.class, intent);
109 
110         shadowOf(mUserManager).addProfile(
111                 /* userHandle= */ USER_HANDLE,
112                 /* profileUserHandle= */ PROFILE_USER_HANDLE,
113                 /* profileName= */ "profile",
114                 /* profileFlags= */ FLAG_MANAGED_PROFILE);
115     }
116 
117     @Test
onStartCommand_legacyFlow_launchesDpcProvisioningSuccessful()118     public void onStartCommand_legacyFlow_launchesDpcProvisioningSuccessful() {
119         shadowOf(mPackageManager)
120                 .addResolveInfoForIntent(createDpcLaunchIntent(), new ResolveInfo());
121 
122         mController.startCommand(/* flags= */ 0, /* startId= */ 0);
123 
124         Intent launchedActivityIntent = shadowOf((Application) mContext).getNextStartedActivity();
125         assertThat(launchedActivityIntent.getPackage()).isEqualTo(TEST_MDM_PACKAGE_NAME);
126         assertThat(launchedActivityIntent.getAction()).isEqualTo(ACTION_PROVISIONING_SUCCESSFUL);
127         assertThat(launchedActivityIntent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK);
128         assertExtras(launchedActivityIntent);
129     }
130 
131     @Test
onStartCommand_adminIntegratedFlow_launchesDpcPolicyCompliance()132     public void onStartCommand_adminIntegratedFlow_launchesDpcPolicyCompliance() {
133         addCreatePolicyComplianceResolveInfo();
134         ServiceController<SendDpcBroadcastService> serviceController =
135                 buildServiceControllerForPolicyCompliance();
136 
137         serviceController.startCommand(/* flags= */ 0, /* startId= */ 0);
138 
139         Intent launchedActivityIntent = shadowOf((Application) mContext).getNextStartedActivity();
140         assertThat(launchedActivityIntent.getPackage()).isEqualTo(TEST_MDM_PACKAGE_NAME);
141         assertThat(launchedActivityIntent.getAction()).isEqualTo(ACTION_ADMIN_POLICY_COMPLIANCE);
142         assertThat(launchedActivityIntent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK);
143         assertExtras(launchedActivityIntent);
144     }
145 
146     @Test
onStartCommand_nonSpecifiedFlow_sendsOrderedBroadcast()147     public void onStartCommand_nonSpecifiedFlow_sendsOrderedBroadcast() {
148         shadowOf(mPackageManager)
149                 .addResolveInfoForIntent(createDpcLaunchIntent(), new ResolveInfo());
150 
151         mController.startCommand(/* flags= */ 0, /* startId= */ 0);
152 
153         Intent broadcastIntent = getBroadcastIntentForAction(ACTION_PROFILE_PROVISIONING_COMPLETE);
154         assertThat(broadcastIntent.getComponent()).isEqualTo(TEST_MDM_ADMIN);
155         assertExtras(broadcastIntent);
156     }
157 
158     @Test
onStartCommand_adminIntegratedFlow_doesNotSendOrderedBroadcast()159     public void onStartCommand_adminIntegratedFlow_doesNotSendOrderedBroadcast() {
160         ServiceController<SendDpcBroadcastService> controller =
161                 buildServiceControllerForPolicyCompliance();
162         addCreatePolicyComplianceResolveInfo();
163 
164         controller.startCommand(/* flags= */ 0, /* startId= */ 0);
165 
166         Intent broadcastIntent = getBroadcastIntentForAction(ACTION_PROFILE_PROVISIONING_COMPLETE);
167         assertThat(broadcastIntent).isNull();
168     }
169 
buildServiceControllerForPolicyCompliance()170     private ServiceController<SendDpcBroadcastService> buildServiceControllerForPolicyCompliance() {
171         final Intent intent =
172                 new Intent(RuntimeEnvironment.application, SendDpcBroadcastService.class)
173                         .putExtra(EXTRA_PROVISIONING_PARAMS, PARAMS_TRUSTED_SOURCE);
174         return Robolectric.buildService(SendDpcBroadcastService.class, intent);
175     }
176 
addCreatePolicyComplianceResolveInfo()177     private void addCreatePolicyComplianceResolveInfo() {
178         shadowOf(mPackageManager)
179                 .addResolveInfoForIntent(
180                         createPolicyComplianceIntent(TEST_MDM_PACKAGE_NAME),
181                         new ResolveInfo());
182     }
183 
getBroadcastIntentForAction(String action)184     private Intent getBroadcastIntentForAction(String action) {
185         List<Intent> broadcastIntents = shadowOf((Application) mContext).getBroadcastIntents();
186         for (Intent intent : broadcastIntents) {
187             if (intent.getAction().equals(action)) {
188                 return intent;
189             }
190         }
191         return null;
192     }
193 
assertExtras(Intent intent)194     private void assertExtras(Intent intent) {
195         final PersistableBundle bundle =
196                 (PersistableBundle) intent.getExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE);
197         assertThat(
198                 bundle.getBoolean(BOOL_KEY)).isEqualTo(TEST_MDM_EXTRA_BUNDLE.getBoolean(BOOL_KEY));
199         assertThat(
200                 bundle.getInt(INT_KEY)).isEqualTo(TEST_MDM_EXTRA_BUNDLE.getInt(INT_KEY));
201         assertThat(
202                 bundle.getInt(STRING_KEY)).isEqualTo(TEST_MDM_EXTRA_BUNDLE.getInt(STRING_KEY));
203     }
204 
createDpcLaunchIntent()205     private Intent createDpcLaunchIntent() {
206         final Intent intent = new Intent(ACTION_PROVISIONING_SUCCESSFUL);
207         final String packageName = PARAMS.inferDeviceAdminPackageName();
208         intent.setPackage(packageName);
209         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
210         intent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, PARAMS.adminExtrasBundle);
211         return intent;
212     }
213 
createPolicyComplianceIntent(String packageName)214     private Intent createPolicyComplianceIntent(String packageName) {
215         final Intent intent = new Intent(ACTION_ADMIN_POLICY_COMPLIANCE);
216         intent.setPackage(packageName);
217         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
218         return intent;
219     }
220 }
221