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