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