• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.server.pm;
18 
19 import static android.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.MODE_DEFAULT;
21 import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
22 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
23 import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND;
24 import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;
25 import static android.content.pm.CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.junit.Assert.fail;
30 import static org.mockito.ArgumentMatchers.anyInt;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.when;
33 import static org.robolectric.Shadows.shadowOf;
34 
35 import android.Manifest;
36 import android.annotation.UserIdInt;
37 import android.app.ActivityManagerInternal;
38 import android.app.AppOpsManager;
39 import android.app.AppOpsManager.Mode;
40 import android.app.admin.DevicePolicyManagerInternal;
41 import android.content.ComponentName;
42 import android.content.ContextWrapper;
43 import android.content.Intent;
44 import android.content.pm.ActivityInfo;
45 import android.content.pm.ApplicationInfo;
46 import android.content.pm.IPackageManager;
47 import android.content.pm.PackageInfo;
48 import android.content.pm.PackageManager;
49 import android.content.pm.PackageManagerInternal;
50 import android.content.pm.PermissionInfo;
51 import android.content.pm.ResolveInfo;
52 import android.os.Process;
53 import android.os.UserHandle;
54 import android.os.UserManager;
55 import android.platform.test.annotations.Presubmit;
56 
57 import androidx.test.core.app.ApplicationProvider;
58 
59 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
60 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
61 import com.android.server.LocalServices;
62 import com.android.server.pm.parsing.pkg.AndroidPackage;
63 import com.android.server.pm.parsing.pkg.PackageImpl;
64 import com.android.server.pm.parsing.pkg.ParsedPackage;
65 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
66 import com.android.server.testing.shadows.ShadowUserManager;
67 import com.android.server.wm.ActivityTaskManagerInternal;
68 
69 import com.google.android.collect.Lists;
70 
71 import org.junit.Before;
72 import org.junit.Test;
73 import org.junit.runner.RunWith;
74 import org.mockito.Mock;
75 import org.mockito.MockitoAnnotations;
76 import org.robolectric.RobolectricTestRunner;
77 import org.robolectric.annotation.Config;
78 import org.robolectric.shadow.api.Shadow;
79 
80 import java.util.ArrayList;
81 import java.util.HashMap;
82 import java.util.HashSet;
83 import java.util.List;
84 import java.util.Map;
85 import java.util.Set;
86 
87 /** Unit tests for {@link CrossProfileAppsServiceImpl}. */
88 @RunWith(RobolectricTestRunner.class)
89 @Presubmit
90 @Config(shadows = {ShadowUserManager.class, ShadowApplicationPackageManager.class})
91 public class CrossProfileAppsServiceImplRoboTest {
92     private static final int CALLING_UID = 1111;
93     private static final int CALLING_PID = 1000;
94     private static final String CROSS_PROFILE_APP_PACKAGE_NAME =
95             "com.android.server.pm.crossprofileappsserviceimplrobotest.crossprofileapp";
96     @UserIdInt private static final int PERSONAL_PROFILE_USER_ID = 0;
97     private static final int PERSONAL_PROFILE_UID = 2222;
98     @UserIdInt private static final int WORK_PROFILE_USER_ID = 10;
99     private static final int WORK_PROFILE_UID = 3333;
100     private static final int OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID = 20;
101     @UserIdInt private static final int OTHER_PROFILE_GROUP_USER_ID = 30;
102     private static final int OTHER_PROFILE_GROUP_UID = 4444;
103     @UserIdInt private static final int OTHER_PROFILE_GROUP_2_USER_ID = 31;
104     private static final int OTHER_PROFILE_GROUP_2_UID = 5555;
105 
106     private final ContextWrapper mContext = ApplicationProvider.getApplicationContext();
107     private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
108     private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
109     private final PackageManager mPackageManager = mContext.getPackageManager();
110     private final TestInjector mInjector = new TestInjector();
111     private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl =
112             new CrossProfileAppsServiceImpl(mContext, mInjector);
113     private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
114     private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
115     private final Set<Integer> mKilledUids = new HashSet<>();
116 
117     @Mock private PackageManagerInternal mPackageManagerInternal;
118     @Mock private IPackageManager mIPackageManager;
119     @Mock private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
120 
121     @Before
initializeMocks()122     public void initializeMocks() throws Exception {
123         MockitoAnnotations.initMocks(this);
124         initializeInstalledApplicationsMock();
125         mockCrossProfileAppInstalledAndEnabledOnEachProfile();
126         mockCrossProfileAppRequestsInteractAcrossProfiles();
127         mockCrossProfileAppRegistersBroadcastReceiver();
128         mockCrossProfileAppWhitelisted();
129     }
130 
initializeInstalledApplicationsMock()131     private void initializeInstalledApplicationsMock() {
132         when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID)))
133                 .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1)));
134     }
135 
mockCrossProfileAppInstalledAndEnabledOnEachProfile()136     private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() {
137         // They are enabled by default, so we simply have to ensure that a package info with an
138         // application info is returned.
139         final PackageInfo packageInfo = buildTestPackageInfo();
140         mockCrossProfileAppInstalledOnProfile(
141                 packageInfo, PERSONAL_PROFILE_USER_ID, PERSONAL_PROFILE_UID);
142         mockCrossProfileAppInstalledOnProfile(packageInfo, WORK_PROFILE_USER_ID, WORK_PROFILE_UID);
143         mockCrossProfileAppInstalledOnProfile(
144                 packageInfo, OTHER_PROFILE_GROUP_USER_ID, OTHER_PROFILE_GROUP_UID);
145         mockCrossProfileAppInstalledOnProfile(
146                 packageInfo, OTHER_PROFILE_GROUP_2_USER_ID, OTHER_PROFILE_GROUP_2_UID);
147     }
148 
mockCrossProfileAppInstalledOnProfile( PackageInfo packageInfo, @UserIdInt int userId, int uid)149     private void mockCrossProfileAppInstalledOnProfile(
150             PackageInfo packageInfo, @UserIdInt int userId, int uid) {
151         when(mPackageManagerInternal.getPackageInfo(
152                         eq(CROSS_PROFILE_APP_PACKAGE_NAME),
153                         /* flags= */ anyInt(),
154                         /* filterCallingUid= */ anyInt(),
155                         eq(userId)))
156                 .thenReturn(packageInfo);
157         when(mPackageManagerInternal.getPackage(uid))
158                 .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
159                         .hideAsParsed()).hideAsFinal());
160         installedApplications.putIfAbsent(userId, new ArrayList<>());
161         installedApplications.get(userId).add(packageInfo.applicationInfo);
162     }
163 
buildTestPackageInfo()164     private PackageInfo buildTestPackageInfo() {
165         PackageInfo packageInfo = new PackageInfo();
166         packageInfo.applicationInfo = new ApplicationInfo();
167         packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
168         return packageInfo;
169     }
170 
mockCrossProfileAppRequestsInteractAcrossProfiles()171     private void mockCrossProfileAppRequestsInteractAcrossProfiles() throws Exception {
172         final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
173         when(mIPackageManager.getAppOpPermissionPackages(permissionName))
174                 .thenReturn(new String[] {CROSS_PROFILE_APP_PACKAGE_NAME});
175     }
176 
mockCrossProfileAppRegistersBroadcastReceiver()177     private void mockCrossProfileAppRegistersBroadcastReceiver() {
178         final ShadowApplicationPackageManager shadowApplicationPackageManager =
179                 Shadow.extract(mPackageManager);
180         final Intent baseIntent =
181                 new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED)
182                         .setPackage(CROSS_PROFILE_APP_PACKAGE_NAME);
183         final Intent manifestIntent =
184                 new Intent(baseIntent)
185                         .setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
186                                 | Intent.FLAG_RECEIVER_FOREGROUND);
187         final Intent registeredIntent =
188                 new Intent(baseIntent).setFlags(FLAG_RECEIVER_REGISTERED_ONLY);
189         final List<ResolveInfo> resolveInfos = Lists.newArrayList(buildTestResolveInfo());
190         shadowApplicationPackageManager.setResolveInfosForIntent(manifestIntent, resolveInfos);
191         shadowApplicationPackageManager.setResolveInfosForIntent(registeredIntent, resolveInfos);
192     }
193 
buildTestResolveInfo()194     private ResolveInfo buildTestResolveInfo() {
195         final ResolveInfo resolveInfo = new ResolveInfo();
196         resolveInfo.activityInfo = new ActivityInfo();
197         resolveInfo.activityInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
198         resolveInfo.activityInfo.name = CROSS_PROFILE_APP_PACKAGE_NAME + ".Receiver";
199         return resolveInfo;
200     }
201 
mockCrossProfileAppWhitelisted()202     private void mockCrossProfileAppWhitelisted() {
203         when(mDevicePolicyManagerInternal.getAllCrossProfilePackages())
204                 .thenReturn(Lists.newArrayList(CROSS_PROFILE_APP_PACKAGE_NAME));
205     }
206 
207     @Before
setUpCrossProfileAppUidsAndPackageNames()208     public void setUpCrossProfileAppUidsAndPackageNames() {
209         setUpCrossProfileAppUidAndPackageName(
210                 PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID);
211         setUpCrossProfileAppUidAndPackageName(
212                 WORK_PROFILE_UID, WORK_PROFILE_USER_ID);
213         setUpCrossProfileAppUidAndPackageName(
214                 OTHER_PROFILE_GROUP_UID, OTHER_PROFILE_GROUP_USER_ID);
215         setUpCrossProfileAppUidAndPackageName(
216                 OTHER_PROFILE_GROUP_2_UID, OTHER_PROFILE_GROUP_2_USER_ID);
217     }
218 
setUpCrossProfileAppUidAndPackageName(int uid, @UserIdInt int userId)219     private void setUpCrossProfileAppUidAndPackageName(int uid, @UserIdInt int userId) {
220         ShadowApplicationPackageManager.setPackageUidAsUser(
221                 CROSS_PROFILE_APP_PACKAGE_NAME, uid, userId);
222         when(mPackageManagerInternal
223                 .getPackageUid(CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, userId))
224                 .thenReturn(uid);
225     }
226 
227     @Before
grantPermissions()228     public void grantPermissions() {
229         grantPermissions(
230                 Manifest.permission.MANAGE_APP_OPS_MODES,
231                 Manifest.permission.UPDATE_APP_OPS_STATS,
232                 Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
233                 Manifest.permission.INTERACT_ACROSS_USERS,
234                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
235     }
236 
237     @Before
setUpProfiles()238     public void setUpProfiles() {
239         final ShadowUserManager shadowUserManager = Shadow.extract(mUserManager);
240         shadowUserManager.addProfileIds(
241                 PERSONAL_PROFILE_USER_ID,
242                 WORK_PROFILE_USER_ID,
243                 OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID);
244         shadowUserManager.addProfileIds(
245                 OTHER_PROFILE_GROUP_USER_ID,
246                 OTHER_PROFILE_GROUP_2_USER_ID);
247     }
248 
249     @Before
setInteractAcrossProfilesAppOpDefault()250     public void setInteractAcrossProfilesAppOpDefault() {
251         // It seems to be necessary to provide the shadow with the default already specified in
252         // AppOpsManager.
253         final int defaultMode = AppOpsManager.opToDefaultMode(OP_INTERACT_ACROSS_PROFILES);
254         explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, defaultMode);
255         explicitlySetInteractAcrossProfilesAppOp(WORK_PROFILE_UID, defaultMode);
256         explicitlySetInteractAcrossProfilesAppOp(OTHER_PROFILE_GROUP_UID, defaultMode);
257         explicitlySetInteractAcrossProfilesAppOp(OTHER_PROFILE_GROUP_2_UID, defaultMode);
258     }
259 
260     @Test
setInteractAcrossProfilesAppOp_noPermissions_throwsSecurityException()261     public void setInteractAcrossProfilesAppOp_noPermissions_throwsSecurityException() {
262         denyPermissions(
263                 Manifest.permission.MANAGE_APP_OPS_MODES,
264                 Manifest.permission.UPDATE_APP_OPS_STATS,
265                 Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
266                 Manifest.permission.INTERACT_ACROSS_USERS,
267                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
268         try {
269             mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
270                     CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
271             fail();
272         } catch (SecurityException expected) {}
273     }
274 
275     @Test
setInteractAcrossProfilesAppOp_missingInteractAcrossUsersAndFull_throwsSecurityException()276     public void setInteractAcrossProfilesAppOp_missingInteractAcrossUsersAndFull_throwsSecurityException() {
277         denyPermissions(
278                 Manifest.permission.INTERACT_ACROSS_USERS,
279                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
280         grantPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
281         try {
282             mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
283                     CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
284             fail();
285         } catch (SecurityException expected) {}
286     }
287 
288     @Test
setInteractAcrossProfilesAppOp_setsAppOp()289     public void setInteractAcrossProfilesAppOp_setsAppOp() {
290         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
291                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
292         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
293     }
294 
295     @Test
setInteractAcrossProfilesAppOp_configureInteractAcrossProfilesPermissionWithoutAppOpsPermissions_setsAppOp()296     public void setInteractAcrossProfilesAppOp_configureInteractAcrossProfilesPermissionWithoutAppOpsPermissions_setsAppOp() {
297         denyPermissions(
298                 Manifest.permission.MANAGE_APP_OPS_MODES,
299                 Manifest.permission.UPDATE_APP_OPS_STATS);
300         grantPermissions(
301                 Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
302                 Manifest.permission.INTERACT_ACROSS_USERS);
303 
304         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
305                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
306 
307         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
308     }
309 
310     @Test
setInteractAcrossProfilesAppOp_appOpsPermissionsWithoutConfigureInteractAcrossProfilesPermission_setsAppOp()311     public void setInteractAcrossProfilesAppOp_appOpsPermissionsWithoutConfigureInteractAcrossProfilesPermission_setsAppOp() {
312         denyPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
313         grantPermissions(
314                 Manifest.permission.MANAGE_APP_OPS_MODES,
315                 Manifest.permission.UPDATE_APP_OPS_STATS,
316                 Manifest.permission.INTERACT_ACROSS_USERS);
317 
318         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
319                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
320 
321         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
322     }
323 
324     @Test
setInteractAcrossProfilesAppOp_setsAppOpWithUsersAndWithoutFull()325     public void setInteractAcrossProfilesAppOp_setsAppOpWithUsersAndWithoutFull() {
326         denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
327         grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
328         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
329                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
330         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
331     }
332 
333     @Test
setInteractAcrossProfilesAppOp_setsAppOpWithFullAndWithoutUsers()334     public void setInteractAcrossProfilesAppOp_setsAppOpWithFullAndWithoutUsers() {
335         denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
336         grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
337         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
338                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
339         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
340     }
341 
342     @Test
setInteractAcrossProfilesAppOp_setsAppOpOnOtherProfile()343     public void setInteractAcrossProfilesAppOp_setsAppOpOnOtherProfile() {
344         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
345                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
346         assertThat(getCrossProfileAppOp(WORK_PROFILE_UID)).isEqualTo(MODE_ALLOWED);
347     }
348 
349     @Test
setInteractAcrossProfilesAppOp_sendsBroadcast()350     public void setInteractAcrossProfilesAppOp_sendsBroadcast() {
351         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
352                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
353         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isTrue();
354     }
355 
356     @Test
setInteractAcrossProfilesAppOp_sendsBroadcastToOtherProfile()357     public void setInteractAcrossProfilesAppOp_sendsBroadcastToOtherProfile() {
358         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
359                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
360         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast(WORK_PROFILE_USER_ID))
361                 .isTrue();
362     }
363 
364     @Test
setInteractAcrossProfilesAppOp_doesNotSendBroadcastToProfileWithoutPackage()365     public void setInteractAcrossProfilesAppOp_doesNotSendBroadcastToProfileWithoutPackage() {
366         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
367                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
368         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast(
369                         OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID))
370                 .isFalse();
371     }
372 
373     @Test
setInteractAcrossProfilesAppOp_toSameAsCurrent_doesNotSendBroadcast()374     public void setInteractAcrossProfilesAppOp_toSameAsCurrent_doesNotSendBroadcast() {
375         explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
376         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
377                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
378         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isFalse();
379     }
380 
381     @Test
setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSet()382     public void setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSet() {
383         mockCrossProfileAppNotWhitelisted();
384         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
385                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
386         assertThat(getCrossProfileAppOp()).isNotEqualTo(MODE_ALLOWED);
387     }
388 
389     @Test
setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSendBroadcast()390     public void setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSendBroadcast() {
391         mockCrossProfileAppNotWhitelisted();
392         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
393                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
394         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isFalse();
395     }
396 
397     @Test
setInteractAcrossProfilesAppOp_withoutCrossProfileAttribute_manifestReceiversDoNotGetBroadcast()398     public void setInteractAcrossProfilesAppOp_withoutCrossProfileAttribute_manifestReceiversDoNotGetBroadcast() {
399         declareCrossProfileAttributeOnCrossProfileApp(false);
400         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
401                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
402         assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isFalse();
403     }
404 
405     @Test
setInteractAcrossProfilesAppOp_withCrossProfileAttribute_manifestReceiversGetBroadcast()406     public void setInteractAcrossProfilesAppOp_withCrossProfileAttribute_manifestReceiversGetBroadcast() {
407         declareCrossProfileAttributeOnCrossProfileApp(true);
408         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
409                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
410         assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isTrue();
411     }
412 
413     @Test
setInteractAcrossProfilesAppOp_toAllowed_doesNotKillApp()414     public void setInteractAcrossProfilesAppOp_toAllowed_doesNotKillApp() {
415         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
416                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
417         assertThat(mKilledUids).isEmpty();
418     }
419 
420     @Test
setInteractAcrossProfilesAppOp_toDisallowed_killsAppsInBothProfiles()421     public void setInteractAcrossProfilesAppOp_toDisallowed_killsAppsInBothProfiles() {
422         shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
423         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
424                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
425 
426         mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
427                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_DEFAULT);
428 
429         assertThat(mKilledUids).contains(WORK_PROFILE_UID);
430         assertThat(mKilledUids).contains(PERSONAL_PROFILE_UID);
431     }
432 
createCrossProfilesPermissionInfo()433     private PermissionInfo createCrossProfilesPermissionInfo() {
434         PermissionInfo permissionInfo = new PermissionInfo();
435         permissionInfo.name = Manifest.permission.INTERACT_ACROSS_PROFILES;
436         permissionInfo.protectionLevel = PermissionInfo.PROTECTION_FLAG_APPOP;
437         return permissionInfo;
438     }
439 
440     @Test
setInteractAcrossProfilesAppOp_userToSetInDifferentProfileGroupToCaller_setsAppOp()441     public void setInteractAcrossProfilesAppOp_userToSetInDifferentProfileGroupToCaller_setsAppOp() {
442         mCrossProfileAppsServiceImpl.getLocalService().setInteractAcrossProfilesAppOp(
443                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED, OTHER_PROFILE_GROUP_USER_ID);
444         assertThat(getCrossProfileAppOp(OTHER_PROFILE_GROUP_UID)).isEqualTo(MODE_ALLOWED);
445     }
446 
447     @Test
setInteractAcrossProfilesAppOp_userToSetInDifferentProfileGroupToCaller_setsAppOpOnOtherProfile()448     public void setInteractAcrossProfilesAppOp_userToSetInDifferentProfileGroupToCaller_setsAppOpOnOtherProfile() {
449         mCrossProfileAppsServiceImpl.getLocalService().setInteractAcrossProfilesAppOp(
450                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED, OTHER_PROFILE_GROUP_USER_ID);
451         assertThat(getCrossProfileAppOp(OTHER_PROFILE_GROUP_2_UID)).isEqualTo(MODE_ALLOWED);
452     }
453 
454     @Test
setInteractAcrossProfilesAppOp_userToSetInDifferentProfileGroupToCaller_doesNotSetCallerAppOp()455     public void setInteractAcrossProfilesAppOp_userToSetInDifferentProfileGroupToCaller_doesNotSetCallerAppOp() {
456         mCrossProfileAppsServiceImpl.getLocalService().setInteractAcrossProfilesAppOp(
457                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED, OTHER_PROFILE_GROUP_USER_ID);
458         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
459     }
460 
461     @Test
canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse()462     public void canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse() {
463         mockUninstallCrossProfileAppFromWorkProfile();
464         assertThat(mCrossProfileAppsServiceImpl
465                 .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
466                 .isFalse();
467     }
468 
mockUninstallCrossProfileAppFromWorkProfile()469     private void mockUninstallCrossProfileAppFromWorkProfile() {
470         when(mPackageManagerInternal.getPackageInfo(
471                         eq(CROSS_PROFILE_APP_PACKAGE_NAME),
472                         /* flags= */ anyInt(),
473                         /* filterCallingUid= */ anyInt(),
474                         eq(WORK_PROFILE_USER_ID)))
475                 .thenReturn(null);
476         when(mPackageManagerInternal.getPackage(WORK_PROFILE_UID)).thenReturn(null);
477     }
478 
479     @Test
canConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()480     public void canConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()
481             throws Exception {
482         mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
483         assertThat(mCrossProfileAppsServiceImpl
484                 .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
485                 .isFalse();
486     }
487 
mockCrossProfileAppDoesNotRequestInteractAcrossProfiles()488     private void mockCrossProfileAppDoesNotRequestInteractAcrossProfiles() throws Exception {
489         final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
490         when(mIPackageManager.getAppOpPermissionPackages(permissionName))
491                 .thenReturn(new String[] {});
492     }
493 
494     @Test
canConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsFalse()495     public void canConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsFalse() {
496         mockCrossProfileAppNotWhitelisted();
497         assertThat(mCrossProfileAppsServiceImpl
498                 .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
499                 .isFalse();
500     }
501 
502     @Test
canConfigureInteractAcrossProfiles_returnsTrue()503     public void canConfigureInteractAcrossProfiles_returnsTrue() {
504         assertThat(mCrossProfileAppsServiceImpl
505                 .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
506                 .isTrue();
507     }
508 
509     @Test
canUserAttemptToConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsTrue()510     public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsTrue() {
511         mockUninstallCrossProfileAppFromWorkProfile();
512         assertThat(mCrossProfileAppsServiceImpl
513                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
514                 .isTrue();
515     }
516 
517     @Test
canUserAttemptToConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()518     public void canUserAttemptToConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()
519             throws Exception {
520         mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
521         assertThat(mCrossProfileAppsServiceImpl
522                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
523                 .isFalse();
524     }
525 
526     @Test
canUserAttemptToConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsTrue()527     public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsTrue() {
528         mockCrossProfileAppNotWhitelisted();
529         assertThat(mCrossProfileAppsServiceImpl
530                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
531                 .isTrue();
532     }
533 
534     @Test
canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse()535     public void canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse() {
536         mockCrossProfileAppNotWhitelistedByOem();
537         shadowOf(mContext).grantPermissions(
538                 Process.myPid(),
539                 PERSONAL_PROFILE_UID,
540                 Manifest.permission.INTERACT_ACROSS_PROFILES);
541 
542         assertThat(mCrossProfileAppsServiceImpl
543                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
544                 .isFalse();
545     }
546 
547     @Test
canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerWorkProfile_returnsFalse()548     public void canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerWorkProfile_returnsFalse() {
549         when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(WORK_PROFILE_USER_ID))
550                 .thenReturn(buildCrossProfileComponentName());
551         assertThat(mCrossProfileAppsServiceImpl
552                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
553                 .isFalse();
554     }
555 
556     @Test
canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerOtherProfile_returnsFalse()557     public void canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerOtherProfile_returnsFalse() {
558         // Normally, the DPC would not be a profile owner of the personal profile, but for the
559         // purposes of this test, it is just a profile owner of any profile within the profile
560         // group.
561         when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(PERSONAL_PROFILE_USER_ID))
562                 .thenReturn(buildCrossProfileComponentName());
563         assertThat(mCrossProfileAppsServiceImpl
564                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
565                 .isFalse();
566     }
567 
568     @Test
canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerOutsideProfileGroup_returnsTrue()569     public void canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerOutsideProfileGroup_returnsTrue() {
570         when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(OTHER_PROFILE_GROUP_USER_ID))
571                 .thenReturn(buildCrossProfileComponentName());
572         assertThat(mCrossProfileAppsServiceImpl
573                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
574                 .isTrue();
575     }
576 
577     @Test
canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue()578     public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() {
579         assertThat(mCrossProfileAppsServiceImpl
580                 .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
581                 .isTrue();
582     }
583 
584     @Test
clearInteractAcrossProfilesAppOps()585     public void clearInteractAcrossProfilesAppOps() {
586         explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
587         mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps();
588         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
589     }
590 
explicitlySetInteractAcrossProfilesAppOp(@ode int mode)591     private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) {
592         explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode);
593     }
594 
explicitlySetInteractAcrossProfilesAppOp(int uid, @Mode int mode)595     private void explicitlySetInteractAcrossProfilesAppOp(int uid, @Mode int mode) {
596         shadowOf(mAppOpsManager).setMode(
597                 OP_INTERACT_ACROSS_PROFILES, uid, CROSS_PROFILE_APP_PACKAGE_NAME, mode);
598     }
599 
grantPermissions(String... permissions)600     private void grantPermissions(String... permissions) {
601         shadowOf(mContext).grantPermissions(Process.myPid(), CALLING_UID, permissions);
602     }
603 
denyPermissions(String... permissions)604     private void denyPermissions(String... permissions) {
605         shadowOf(mContext).denyPermissions(Process.myPid(), CALLING_UID, permissions);
606     }
607 
getCrossProfileAppOp()608     private @Mode int getCrossProfileAppOp() {
609         return getCrossProfileAppOp(PERSONAL_PROFILE_UID);
610     }
611 
getCrossProfileAppOp(int uid)612     private @Mode int getCrossProfileAppOp(int uid) {
613         return mAppOpsManager.unsafeCheckOpNoThrow(
614                 AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES),
615                 uid,
616                 CROSS_PROFILE_APP_PACKAGE_NAME);
617     }
618 
receivedCanInteractAcrossProfilesChangedBroadcast()619     private boolean receivedCanInteractAcrossProfilesChangedBroadcast() {
620         return receivedCanInteractAcrossProfilesChangedBroadcast(PERSONAL_PROFILE_USER_ID);
621     }
622 
receivedCanInteractAcrossProfilesChangedBroadcast(@serIdInt int userId)623     private boolean receivedCanInteractAcrossProfilesChangedBroadcast(@UserIdInt int userId) {
624         final UserHandle userHandle = UserHandle.of(userId);
625         if (!mSentUserBroadcasts.containsKey(userHandle)) {
626             return false;
627         }
628         return mSentUserBroadcasts.get(userHandle)
629                 .stream()
630                 .anyMatch(this::isBroadcastCanInteractAcrossProfilesChanged);
631     }
632 
isBroadcastCanInteractAcrossProfilesChanged(Intent intent)633     private boolean isBroadcastCanInteractAcrossProfilesChanged(Intent intent) {
634         return intent.getAction().equals(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED)
635                 && CROSS_PROFILE_APP_PACKAGE_NAME.equals(intent.getPackage());
636     }
637 
mockCrossProfileAndroidPackage(AndroidPackage androidPackage)638     private void mockCrossProfileAndroidPackage(AndroidPackage androidPackage) {
639         when(mPackageManagerInternal.getPackage(CROSS_PROFILE_APP_PACKAGE_NAME))
640                 .thenReturn(androidPackage);
641         when(mPackageManagerInternal.getPackage(PERSONAL_PROFILE_UID))
642                 .thenReturn(androidPackage);
643         when(mPackageManagerInternal.getPackage(WORK_PROFILE_UID))
644                 .thenReturn(androidPackage);
645         when(mPackageManagerInternal.getPackage(OTHER_PROFILE_GROUP_UID))
646                 .thenReturn(androidPackage);
647         when(mPackageManagerInternal.getPackage(OTHER_PROFILE_GROUP_2_UID))
648                 .thenReturn(androidPackage);
649     }
650 
mockCrossProfileAppNotWhitelisted()651     private void mockCrossProfileAppNotWhitelisted() {
652         when(mDevicePolicyManagerInternal.getAllCrossProfilePackages())
653                 .thenReturn(new ArrayList<>());
654     }
655 
mockCrossProfileAppNotWhitelistedByOem()656     private void mockCrossProfileAppNotWhitelistedByOem() {
657         when(mDevicePolicyManagerInternal.getDefaultCrossProfilePackages())
658                 .thenReturn(new ArrayList<>());
659     }
660 
receivedManifestCanInteractAcrossProfilesChangedBroadcast()661     private boolean receivedManifestCanInteractAcrossProfilesChangedBroadcast() {
662         final UserHandle userHandle = UserHandle.of(PERSONAL_PROFILE_USER_ID);
663         if (!mSentUserBroadcasts.containsKey(userHandle)) {
664             return false;
665         }
666         return mSentUserBroadcasts.get(userHandle)
667                 .stream()
668                 .anyMatch(this::isBroadcastManifestCanInteractAcrossProfilesChanged);
669     }
670 
isBroadcastManifestCanInteractAcrossProfilesChanged(Intent intent)671     private boolean isBroadcastManifestCanInteractAcrossProfilesChanged(Intent intent) {
672         return isBroadcastCanInteractAcrossProfilesChanged(intent)
673                 && (intent.getFlags() & FLAG_RECEIVER_REGISTERED_ONLY) == 0
674                 && (intent.getFlags() & FLAG_RECEIVER_INCLUDE_BACKGROUND) != 0
675                 && (intent.getFlags() & FLAG_RECEIVER_FOREGROUND) != 0
676                 && intent.getComponent() != null
677                 && intent.getComponent().getPackageName().equals(CROSS_PROFILE_APP_PACKAGE_NAME);
678     }
679 
declareCrossProfileAttributeOnCrossProfileApp(boolean value)680     private void declareCrossProfileAttributeOnCrossProfileApp(boolean value) {
681         mockCrossProfileAndroidPackage(
682                 ((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
683                         .setCrossProfile(value)
684                         .hideAsParsed()).hideAsFinal());
685     }
686 
buildCrossProfileComponentName()687     private ComponentName buildCrossProfileComponentName() {
688         return new ComponentName(CROSS_PROFILE_APP_PACKAGE_NAME, "testClassName");
689     }
690 
691     private class TestInjector implements CrossProfileAppsServiceImpl.Injector {
692 
693         @Override
getCallingUid()694         public int getCallingUid() {
695             return CALLING_UID;
696         }
697 
698         @Override
getCallingPid()699         public int getCallingPid() {
700             return CALLING_PID;
701         }
702 
703         @Override
getCallingUserId()704         public @UserIdInt int getCallingUserId() {
705             return PERSONAL_PROFILE_USER_ID;
706         }
707 
708         @Override
getCallingUserHandle()709         public UserHandle getCallingUserHandle() {
710             return UserHandle.of(getCallingUserId());
711         }
712 
713         @Override
clearCallingIdentity()714         public long clearCallingIdentity() {
715             return 0;
716         }
717 
718         @Override
restoreCallingIdentity(long token)719         public void restoreCallingIdentity(long token) {}
720 
721         @Override
withCleanCallingIdentity(ThrowingRunnable action)722         public void withCleanCallingIdentity(ThrowingRunnable action) {
723             action.run();
724         }
725 
726         @Override
withCleanCallingIdentity(ThrowingSupplier<T> action)727         public <T> T withCleanCallingIdentity(ThrowingSupplier<T> action) {
728             return action.get();
729         }
730 
731         @Override
getUserManager()732         public UserManager getUserManager() {
733             return mUserManager;
734         }
735 
736         @Override
getPackageManagerInternal()737         public PackageManagerInternal getPackageManagerInternal() {
738             return mPackageManagerInternal;
739         }
740 
741         @Override
getPackageManager()742         public PackageManager getPackageManager() {
743             return mPackageManager;
744         }
745 
746         @Override
getAppOpsManager()747         public AppOpsManager getAppOpsManager() {
748             return mAppOpsManager;
749         }
750 
751         @Override
getActivityManagerInternal()752         public ActivityManagerInternal getActivityManagerInternal() {
753             return LocalServices.getService(ActivityManagerInternal.class);
754         }
755 
756         @Override
getActivityTaskManagerInternal()757         public ActivityTaskManagerInternal getActivityTaskManagerInternal() {
758             return LocalServices.getService(ActivityTaskManagerInternal.class);
759         }
760 
761         @Override
getIPackageManager()762         public IPackageManager getIPackageManager() {
763             return mIPackageManager;
764         }
765 
766         @Override
getDevicePolicyManagerInternal()767         public DevicePolicyManagerInternal getDevicePolicyManagerInternal() {
768             return mDevicePolicyManagerInternal;
769         }
770 
771         @Override
sendBroadcastAsUser(Intent intent, UserHandle user)772         public void sendBroadcastAsUser(Intent intent, UserHandle user) {
773             // Robolectric's shadows do not currently support sendBroadcastAsUser.
774             final Set<Intent> broadcasts =
775                     mSentUserBroadcasts.containsKey(user)
776                             ? mSentUserBroadcasts.get(user)
777                             : new HashSet<>();
778             broadcasts.add(intent);
779             mSentUserBroadcasts.put(user, broadcasts);
780             mContext.sendBroadcastAsUser(intent, user);
781         }
782 
783         @Override
checkComponentPermission( String permission, int uid, int owningUid, boolean exported)784         public int checkComponentPermission(
785                 String permission, int uid, int owningUid, boolean exported) {
786             // ActivityManager#checkComponentPermission calls through to
787             // AppGlobals.getPackageManager()#checkUidPermission, which calls through to
788             // ShadowActivityThread with Robolectric. This method is currently not supported there.
789             return mContext.checkPermission(permission, Process.myPid(), uid);
790         }
791 
792         @Override
killUid(int uid)793         public void killUid(int uid) {
794             mKilledUids.add(uid);
795         }
796     }
797 }
798