1 package com.android.server.pm; 2 3 import static com.google.common.truth.Truth.assertThat; 4 5 import static org.mockito.ArgumentMatchers.any; 6 import static org.mockito.ArgumentMatchers.anyInt; 7 import static org.mockito.ArgumentMatchers.anyString; 8 import static org.mockito.ArgumentMatchers.eq; 9 import static org.mockito.ArgumentMatchers.nullable; 10 import static org.mockito.Mockito.doAnswer; 11 import static org.mockito.Mockito.never; 12 import static org.mockito.Mockito.verify; 13 import static org.mockito.Mockito.when; 14 import static org.testng.Assert.assertThrows; 15 16 import android.app.ActivityManagerInternal; 17 import android.app.AppOpsManager; 18 import android.app.IApplicationThread; 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.ActivityInfo; 23 import android.content.pm.ApplicationInfo; 24 import android.content.pm.PackageInfo; 25 import android.content.pm.PackageManager; 26 import android.content.pm.PackageManagerInternal; 27 import android.content.pm.ResolveInfo; 28 import android.os.Bundle; 29 import android.os.UserHandle; 30 import android.os.UserManager; 31 import android.platform.test.annotations.Presubmit; 32 import android.util.SparseArray; 33 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.mockito.Mock; 38 import org.mockito.junit.MockitoJUnitRunner; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.List; 43 44 /** 45 * Build/Install/Run: 46 * atest FrameworksServicesTests:com.android.server.pm.CrossProfileAppsServiceImplTest 47 */ 48 @Presubmit 49 @RunWith(MockitoJUnitRunner.class) 50 public class CrossProfileAppsServiceImplTest { 51 private static final String PACKAGE_ONE = "com.one"; 52 private static final int PACKAGE_ONE_UID = 1111; 53 private static final ComponentName ACTIVITY_COMPONENT = 54 new ComponentName("com.one", "test"); 55 56 private static final String PACKAGE_TWO = "com.two"; 57 private static final int PACKAGE_TWO_UID = 2222; 58 59 private static final int PRIMARY_USER = 0; 60 private static final int PROFILE_OF_PRIMARY_USER = 10; 61 private static final int SECONDARY_USER = 11; 62 63 @Mock 64 private Context mContext; 65 @Mock 66 private UserManager mUserManager; 67 @Mock 68 private PackageManager mPackageManager; 69 @Mock 70 private PackageManagerInternal mPackageManagerInternal; 71 @Mock 72 private AppOpsManager mAppOpsManager; 73 @Mock 74 private ActivityManagerInternal mActivityManagerInternal; 75 76 private TestInjector mTestInjector; 77 private ActivityInfo mActivityInfo; 78 private CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl; 79 private IApplicationThread mIApplicationThread; 80 81 private SparseArray<Boolean> mUserEnabled = new SparseArray<>(); 82 83 @Before 84 public void initCrossProfileAppsServiceImpl() { 85 mTestInjector = new TestInjector(); 86 mCrossProfileAppsServiceImpl = new CrossProfileAppsServiceImpl(mContext, mTestInjector); 87 } 88 89 @Before 90 public void setupEnabledProfiles() { 91 mUserEnabled.put(PRIMARY_USER, true); 92 mUserEnabled.put(PROFILE_OF_PRIMARY_USER, true); 93 mUserEnabled.put(SECONDARY_USER, true); 94 95 when(mUserManager.getEnabledProfileIds(anyInt())).thenAnswer( 96 invocation -> { 97 List<Integer> users = new ArrayList<>(); 98 final int targetUser = invocation.getArgument(0); 99 users.add(targetUser); 100 101 int profileUserId = -1; 102 if (targetUser == PRIMARY_USER) { 103 profileUserId = PROFILE_OF_PRIMARY_USER; 104 } else if (targetUser == PROFILE_OF_PRIMARY_USER) { 105 profileUserId = PRIMARY_USER; 106 } 107 108 if (profileUserId != -1 && mUserEnabled.get(profileUserId)) { 109 users.add(profileUserId); 110 } 111 return users.stream().mapToInt(i -> i).toArray(); 112 }); 113 } 114 115 @Before 116 public void setupCaller() { 117 mTestInjector.setCallingUid(PACKAGE_ONE_UID); 118 mTestInjector.setCallingUserId(PRIMARY_USER); 119 } 120 121 @Before 122 public void setupPackage() throws Exception { 123 // PACKAGE_ONE are installed in all users. 124 mockAppsInstalled(PACKAGE_ONE, PRIMARY_USER, true); 125 mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, true); 126 mockAppsInstalled(PACKAGE_ONE, SECONDARY_USER, true); 127 128 // Packages are resolved to their corresponding UID. 129 doAnswer(invocation -> { 130 final int uid = invocation.getArgument(0); 131 final String packageName = invocation.getArgument(1); 132 if (uid == PACKAGE_ONE_UID && PACKAGE_ONE.equals(packageName)) { 133 return null; 134 } else if (uid ==PACKAGE_TWO_UID && PACKAGE_TWO.equals(packageName)) { 135 return null; 136 } 137 throw new SecurityException("Not matching"); 138 }).when(mAppOpsManager).checkPackage(anyInt(), anyString()); 139 140 // The intent is resolved to the ACTIVITY_COMPONENT. 141 mockActivityLaunchIntentResolvedTo(ACTIVITY_COMPONENT); 142 } 143 144 @Test 145 public void getTargetUserProfiles_fromPrimaryUser_installed() throws Exception { 146 List<UserHandle> targetProfiles = 147 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE); 148 assertThat(targetProfiles).containsExactly(UserHandle.of(PROFILE_OF_PRIMARY_USER)); 149 } 150 151 @Test 152 public void getTargetUserProfiles_fromPrimaryUser_notInstalled() throws Exception { 153 mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, false); 154 155 List<UserHandle> targetProfiles = 156 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE); 157 assertThat(targetProfiles).isEmpty(); 158 } 159 160 @Test 161 public void getTargetUserProfiles_fromPrimaryUser_userNotEnabled() throws Exception { 162 mUserEnabled.put(PROFILE_OF_PRIMARY_USER, false); 163 164 List<UserHandle> targetProfiles = 165 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE); 166 assertThat(targetProfiles).isEmpty(); 167 } 168 169 @Test 170 public void getTargetUserProfiles_fromSecondaryUser() throws Exception { 171 mTestInjector.setCallingUserId(SECONDARY_USER); 172 173 List<UserHandle> targetProfiles = 174 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE); 175 assertThat(targetProfiles).isEmpty(); 176 } 177 178 @Test 179 public void getTargetUserProfiles_fromProfile_installed() throws Exception { 180 mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER); 181 182 List<UserHandle> targetProfiles = 183 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE); 184 assertThat(targetProfiles).containsExactly(UserHandle.of(PRIMARY_USER)); 185 } 186 187 @Test 188 public void getTargetUserProfiles_fromProfile_notInstalled() throws Exception { 189 mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER); 190 mockAppsInstalled(PACKAGE_ONE, PRIMARY_USER, false); 191 192 List<UserHandle> targetProfiles = 193 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE); 194 assertThat(targetProfiles).isEmpty(); 195 } 196 197 @Test(expected = SecurityException.class) 198 public void getTargetUserProfiles_fakeCaller() throws Exception { 199 mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_TWO); 200 } 201 202 @Test 203 public void startActivityAsUser_currentUser() throws Exception { 204 assertThrows( 205 SecurityException.class, 206 () -> 207 mCrossProfileAppsServiceImpl.startActivityAsUser( 208 mIApplicationThread, 209 PACKAGE_ONE, 210 ACTIVITY_COMPONENT, 211 UserHandle.of(PRIMARY_USER))); 212 213 verify(mActivityManagerInternal, never()) 214 .startActivityAsUser( 215 nullable(IApplicationThread.class), 216 anyString(), 217 any(Intent.class), 218 nullable(Bundle.class), 219 anyInt()); 220 } 221 222 @Test 223 public void startActivityAsUser_profile_notInstalled() throws Exception { 224 mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, false); 225 226 assertThrows( 227 SecurityException.class, 228 () -> 229 mCrossProfileAppsServiceImpl.startActivityAsUser( 230 mIApplicationThread, 231 PACKAGE_ONE, 232 ACTIVITY_COMPONENT, 233 UserHandle.of(PROFILE_OF_PRIMARY_USER))); 234 235 verify(mActivityManagerInternal, never()) 236 .startActivityAsUser( 237 nullable(IApplicationThread.class), 238 anyString(), 239 any(Intent.class), 240 nullable(Bundle.class), 241 anyInt()); 242 } 243 244 @Test 245 public void startActivityAsUser_profile_fakeCaller() throws Exception { 246 assertThrows( 247 SecurityException.class, 248 () -> 249 mCrossProfileAppsServiceImpl.startActivityAsUser( 250 mIApplicationThread, 251 PACKAGE_TWO, 252 ACTIVITY_COMPONENT, 253 UserHandle.of(PROFILE_OF_PRIMARY_USER))); 254 255 verify(mActivityManagerInternal, never()) 256 .startActivityAsUser( 257 nullable(IApplicationThread.class), 258 anyString(), 259 any(Intent.class), 260 nullable(Bundle.class), 261 anyInt()); 262 } 263 264 @Test 265 public void startActivityAsUser_profile_notExported() throws Exception { 266 mActivityInfo.exported = false; 267 268 assertThrows( 269 SecurityException.class, 270 () -> 271 mCrossProfileAppsServiceImpl.startActivityAsUser( 272 mIApplicationThread, 273 PACKAGE_ONE, 274 ACTIVITY_COMPONENT, 275 UserHandle.of(PROFILE_OF_PRIMARY_USER))); 276 277 verify(mActivityManagerInternal, never()) 278 .startActivityAsUser( 279 nullable(IApplicationThread.class), 280 anyString(), 281 any(Intent.class), 282 nullable(Bundle.class), 283 anyInt()); 284 } 285 286 @Test 287 public void startActivityAsUser_profile_anotherPackage() throws Exception { 288 assertThrows( 289 SecurityException.class, 290 () -> 291 mCrossProfileAppsServiceImpl.startActivityAsUser( 292 mIApplicationThread, 293 PACKAGE_ONE, 294 new ComponentName(PACKAGE_TWO, "test"), 295 UserHandle.of(PROFILE_OF_PRIMARY_USER))); 296 297 verify(mActivityManagerInternal, never()) 298 .startActivityAsUser( 299 nullable(IApplicationThread.class), 300 anyString(), 301 any(Intent.class), 302 nullable(Bundle.class), 303 anyInt()); 304 } 305 306 @Test 307 public void startActivityAsUser_secondaryUser() throws Exception { 308 assertThrows( 309 SecurityException.class, 310 () -> 311 mCrossProfileAppsServiceImpl.startActivityAsUser( 312 mIApplicationThread, 313 PACKAGE_ONE, 314 ACTIVITY_COMPONENT, 315 UserHandle.of(SECONDARY_USER))); 316 317 verify(mActivityManagerInternal, never()) 318 .startActivityAsUser( 319 nullable(IApplicationThread.class), 320 anyString(), 321 any(Intent.class), 322 nullable(Bundle.class), 323 anyInt()); 324 } 325 326 @Test 327 public void startActivityAsUser_fromProfile_success() throws Exception { 328 mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER); 329 330 mCrossProfileAppsServiceImpl.startActivityAsUser( 331 mIApplicationThread, 332 PACKAGE_ONE, 333 ACTIVITY_COMPONENT, 334 UserHandle.of(PRIMARY_USER)); 335 336 verify(mActivityManagerInternal) 337 .startActivityAsUser( 338 nullable(IApplicationThread.class), 339 eq(PACKAGE_ONE), 340 any(Intent.class), 341 nullable(Bundle.class), 342 eq(PRIMARY_USER)); 343 } 344 345 private void mockAppsInstalled(String packageName, int user, boolean installed) { 346 when(mPackageManagerInternal.getPackageInfo( 347 eq(packageName), 348 anyInt(), 349 anyInt(), 350 eq(user))) 351 .thenReturn(installed ? createInstalledPackageInfo() : null); 352 } 353 354 private PackageInfo createInstalledPackageInfo() { 355 PackageInfo packageInfo = new PackageInfo(); 356 packageInfo.applicationInfo = new ApplicationInfo(); 357 packageInfo.applicationInfo.enabled = true; 358 return packageInfo; 359 } 360 361 private void mockActivityLaunchIntentResolvedTo(ComponentName componentName) { 362 ResolveInfo resolveInfo = new ResolveInfo(); 363 ActivityInfo activityInfo = new ActivityInfo(); 364 activityInfo.packageName = componentName.getPackageName(); 365 activityInfo.name = componentName.getClassName(); 366 activityInfo.exported = true; 367 resolveInfo.activityInfo = activityInfo; 368 mActivityInfo = activityInfo; 369 370 when(mPackageManagerInternal.queryIntentActivities( 371 any(Intent.class), anyInt(), anyInt(), anyInt())) 372 .thenReturn(Collections.singletonList(resolveInfo)); 373 } 374 375 private class TestInjector implements CrossProfileAppsServiceImpl.Injector { 376 private int mCallingUid; 377 private int mCallingUserId; 378 379 public void setCallingUid(int uid) { 380 mCallingUid = uid; 381 } 382 383 public void setCallingUserId(int userId) { 384 mCallingUserId = userId; 385 } 386 387 @Override 388 public int getCallingUid() { 389 return mCallingUid; 390 } 391 392 @Override 393 public int getCallingUserId() { 394 return mCallingUserId; 395 } 396 397 @Override 398 public UserHandle getCallingUserHandle() { 399 return UserHandle.of(mCallingUserId); 400 } 401 402 @Override 403 public long clearCallingIdentity() { 404 return 0; 405 } 406 407 @Override 408 public void restoreCallingIdentity(long token) { 409 } 410 411 @Override 412 public UserManager getUserManager() { 413 return mUserManager; 414 } 415 416 @Override 417 public PackageManagerInternal getPackageManagerInternal() { 418 return mPackageManagerInternal; 419 } 420 421 @Override 422 public PackageManager getPackageManager() { 423 return mPackageManager; 424 } 425 426 @Override 427 public AppOpsManager getAppOpsManager() { 428 return mAppOpsManager; 429 } 430 431 @Override 432 public ActivityManagerInternal getActivityManagerInternal() { 433 return mActivityManagerInternal; 434 } 435 } 436 } 437