1 /* 2 * Copyright (C) 2016 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.settings.applications; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.doReturn; 22 import static org.mockito.Mockito.spy; 23 import static org.mockito.Mockito.when; 24 25 import android.app.admin.DevicePolicyManager; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.ActivityInfo; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.ComponentInfo; 32 import android.content.pm.IPackageManager; 33 import android.content.pm.PackageManager; 34 import android.content.pm.ResolveInfo; 35 import android.content.pm.UserInfo; 36 import android.location.LocationManager; 37 import android.os.Build; 38 import android.os.SystemConfigManager; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.platform.test.annotations.RequiresFlagsDisabled; 42 import android.platform.test.annotations.RequiresFlagsEnabled; 43 import android.platform.test.flag.junit.CheckFlagsRule; 44 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 45 import android.webkit.Flags; 46 47 import com.android.settings.testutils.ApplicationTestUtils; 48 import com.android.settings.webview.WebViewUpdateServiceWrapper; 49 import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager; 50 import com.android.settingslib.testutils.shadow.ShadowSmsApplication; 51 52 import org.junit.Before; 53 import org.junit.Ignore; 54 import org.junit.Rule; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 import org.mockito.Mock; 58 import org.mockito.junit.MockitoJUnit; 59 import org.mockito.junit.MockitoRule; 60 import org.robolectric.RobolectricTestRunner; 61 import org.robolectric.RuntimeEnvironment; 62 import org.robolectric.android.util.concurrent.PausedExecutorService; 63 import org.robolectric.annotation.Config; 64 import org.robolectric.shadows.ShadowApplication; 65 import org.robolectric.shadows.ShadowLooper; 66 import org.robolectric.shadows.ShadowPausedAsyncTask; 67 import org.robolectric.util.ReflectionHelpers; 68 69 import java.util.ArrayList; 70 import java.util.Arrays; 71 import java.util.List; 72 import java.util.Set; 73 74 /** 75 * Tests for {@link ApplicationFeatureProviderImpl}. 76 */ 77 @RunWith(RobolectricTestRunner.class) 78 public final class ApplicationFeatureProviderImplTest { 79 80 @Rule 81 public final MockitoRule mMockitoRule = MockitoJUnit.rule(); 82 83 @Rule 84 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 85 86 private final int MAIN_USER_ID = 0; 87 private final int MANAGED_PROFILE_ID = 10; 88 89 private final int PER_USER_UID_RANGE = 100000; 90 private final int APP_1_UID = MAIN_USER_ID * PER_USER_UID_RANGE + 1; 91 private final int APP_2_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE + 1; 92 93 private final String APP_1 = "app1"; 94 private final String APP_2 = "app2"; 95 96 private final String PERMISSION = "some.permission"; 97 98 private final List<String> PREVENT_USER_DISABLE_PACKAGES = List.of( 99 "prevent.disable.package1", "prevent.disable.package2", "prevent.disable.package3"); 100 101 @Mock 102 private UserManager mUserManager; 103 @Mock 104 private Context mContext; 105 @Mock 106 private PackageManager mPackageManager; 107 @Mock 108 private IPackageManager mPackageManagerService; 109 @Mock 110 private DevicePolicyManager mDevicePolicyManager; 111 @Mock 112 private LocationManager mLocationManager; 113 @Mock 114 private WebViewUpdateServiceWrapper mWebViewUpdateServiceWrapper; 115 @Mock 116 private SystemConfigManager mSystemConfigManager; 117 118 private ApplicationFeatureProvider mProvider; 119 120 private int mAppCount = -1; 121 private List<UserAppInfo> mAppList = null; 122 private PausedExecutorService mExecutorService; 123 124 @Before setUp()125 public void setUp() { 126 when(mContext.getApplicationContext()).thenReturn(mContext); 127 when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); 128 when(mContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); 129 when(mContext.getSystemService(SystemConfigManager.class)).thenReturn(mSystemConfigManager); 130 131 mProvider = new ApplicationFeatureProviderImpl(mContext, mPackageManager, 132 mPackageManagerService, mDevicePolicyManager, mWebViewUpdateServiceWrapper); 133 134 mExecutorService = new PausedExecutorService(); 135 ShadowPausedAsyncTask.overrideExecutor(mExecutorService); 136 } 137 verifyCalculateNumberOfPolicyInstalledApps(boolean async)138 private void verifyCalculateNumberOfPolicyInstalledApps(boolean async) { 139 setUpUsersAndInstalledApps(); 140 141 when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID))) 142 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN); 143 when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID))) 144 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 145 146 mAppCount = -1; 147 mProvider.calculateNumberOfPolicyInstalledApps(async, (num) -> mAppCount = num); 148 if (async) { 149 ShadowApplication.runBackgroundTasks(); 150 } 151 assertThat(mAppCount).isEqualTo(1); 152 } 153 154 @Test testListPolicyInstalledApps()155 public void testListPolicyInstalledApps() { 156 setUpUsersAndInstalledApps(); 157 158 when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID))) 159 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN); 160 when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID))) 161 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 162 163 mAppList = null; 164 mProvider.listPolicyInstalledApps((list) -> mAppList = list); 165 mExecutorService.runAll(); 166 ShadowLooper.idleMainLooper(); 167 assertThat(mAppList).isNotNull(); 168 assertThat(mAppList.size()).isEqualTo(1); 169 assertThat(mAppList.get(0).appInfo.packageName).isEqualTo(APP_2); 170 } 171 172 @Ignore("b/313578776") 173 @Test testCalculateNumberOfInstalledAppsSync()174 public void testCalculateNumberOfInstalledAppsSync() { 175 verifyCalculateNumberOfPolicyInstalledApps(false /* async */); 176 } 177 178 @Ignore("b/313578776") 179 @Test testCalculateNumberOfInstalledAppsAsync()180 public void testCalculateNumberOfInstalledAppsAsync() { 181 verifyCalculateNumberOfPolicyInstalledApps(true /* async */); 182 } 183 verifyCalculateNumberOfAppsWithAdminGrantedPermissions(boolean async)184 private void verifyCalculateNumberOfAppsWithAdminGrantedPermissions(boolean async) 185 throws Exception { 186 setUpUsersAndInstalledApps(); 187 188 when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION)) 189 .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); 190 when(mDevicePolicyManager.getPermissionGrantState(null, APP_2, PERMISSION)) 191 .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); 192 when(mPackageManagerService.checkUidPermission(PERMISSION, APP_1_UID)) 193 .thenReturn(PackageManager.PERMISSION_DENIED); 194 when(mPackageManagerService.checkUidPermission(PERMISSION, APP_2_UID)) 195 .thenReturn(PackageManager.PERMISSION_GRANTED); 196 when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID))) 197 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN); 198 when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID))) 199 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 200 201 mAppCount = -1; 202 mProvider.calculateNumberOfAppsWithAdminGrantedPermissions(new String[]{PERMISSION}, async, 203 (num) -> mAppCount = num); 204 if (async) { 205 ShadowApplication.runBackgroundTasks(); 206 } 207 assertThat(mAppCount).isEqualTo(2); 208 } 209 210 @Ignore("b/313578776") 211 @Test testCalculateNumberOfAppsWithAdminGrantedPermissionsSync()212 public void testCalculateNumberOfAppsWithAdminGrantedPermissionsSync() throws Exception { 213 verifyCalculateNumberOfAppsWithAdminGrantedPermissions(false /* async */); 214 } 215 216 @Ignore("b/313578776") 217 @Test testCalculateNumberOfAppsWithAdminGrantedPermissionsAsync()218 public void testCalculateNumberOfAppsWithAdminGrantedPermissionsAsync() throws Exception { 219 verifyCalculateNumberOfAppsWithAdminGrantedPermissions(true /* async */); 220 } 221 222 @Test testListAppsWithAdminGrantedPermissions()223 public void testListAppsWithAdminGrantedPermissions() 224 throws Exception { 225 setUpUsersAndInstalledApps(); 226 227 when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION)) 228 .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); 229 when(mDevicePolicyManager.getPermissionGrantState(null, APP_2, PERMISSION)) 230 .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); 231 when(mPackageManagerService.checkUidPermission(PERMISSION, APP_1_UID)) 232 .thenReturn(PackageManager.PERMISSION_DENIED); 233 when(mPackageManagerService.checkUidPermission(PERMISSION, APP_2_UID)) 234 .thenReturn(PackageManager.PERMISSION_GRANTED); 235 when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID))) 236 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN); 237 when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID))) 238 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 239 240 mAppList = null; 241 mProvider.listAppsWithAdminGrantedPermissions(new String[]{PERMISSION}, 242 (list) -> mAppList = list); 243 mExecutorService.runAll(); 244 ShadowLooper.idleMainLooper(); 245 246 assertThat(mAppList).isNotNull(); 247 assertThat(mAppList.size()).isEqualTo(2); 248 assertThat(Arrays.asList(mAppList.get(0).appInfo.packageName, 249 mAppList.get(1).appInfo.packageName).containsAll(Arrays.asList(APP_1, APP_2))) 250 .isTrue(); 251 } 252 253 @Test testFindPersistentPreferredActivities()254 public void testFindPersistentPreferredActivities() throws Exception { 255 final UserInfo mainUser = new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN); 256 final UserInfo managedUser = new UserInfo(MANAGED_PROFILE_ID, "managed", 257 UserInfo.FLAG_MANAGED_PROFILE); 258 259 when(mUserManager.getUserProfiles()).thenReturn(Arrays.asList(new UserHandle(MAIN_USER_ID), 260 new UserHandle(MANAGED_PROFILE_ID))); 261 when(mUserManager.getUserInfo(MAIN_USER_ID)).thenReturn(mainUser); 262 when(mUserManager.getUserInfo(MANAGED_PROFILE_ID)).thenReturn(managedUser); 263 264 final Intent viewIntent = new Intent(Intent.ACTION_VIEW); 265 final Intent editIntent = new Intent(Intent.ACTION_EDIT); 266 final Intent sendIntent = new Intent(Intent.ACTION_SEND); 267 268 final ResolveInfo app1 = createResolveInfo(APP_1); 269 final ResolveInfo app2 = createResolveInfo(APP_2); 270 when(mPackageManagerService.findPersistentPreferredActivity(viewIntent, MAIN_USER_ID)) 271 .thenReturn(app1); 272 when(mPackageManagerService.findPersistentPreferredActivity(viewIntent, MANAGED_PROFILE_ID)) 273 .thenReturn(app1); 274 when(mPackageManagerService.findPersistentPreferredActivity(editIntent, MAIN_USER_ID)) 275 .thenReturn(null); 276 when(mPackageManagerService.findPersistentPreferredActivity(editIntent, MANAGED_PROFILE_ID)) 277 .thenReturn(app2); 278 when(mPackageManagerService.findPersistentPreferredActivity(sendIntent, MAIN_USER_ID)) 279 .thenReturn(app1); 280 when(mPackageManagerService.findPersistentPreferredActivity(sendIntent, MANAGED_PROFILE_ID)) 281 .thenReturn(null); 282 283 final List<UserAppInfo> expectedMainUserActivities = new ArrayList<>(); 284 expectedMainUserActivities.add(new UserAppInfo(mainUser, 285 new ApplicationInfo(app1.activityInfo.applicationInfo))); 286 final List<UserAppInfo> expectedManagedUserActivities = new ArrayList<>(); 287 expectedManagedUserActivities.add(new UserAppInfo(managedUser, 288 new ApplicationInfo(app1.activityInfo.applicationInfo))); 289 expectedManagedUserActivities.add(new UserAppInfo(managedUser, 290 new ApplicationInfo(app2.activityInfo.applicationInfo))); 291 292 assertThat(mProvider.findPersistentPreferredActivities(MAIN_USER_ID, 293 new Intent[]{viewIntent, editIntent, sendIntent})) 294 .isEqualTo(expectedMainUserActivities); 295 assertThat(mProvider.findPersistentPreferredActivities(MANAGED_PROFILE_ID, 296 new Intent[]{viewIntent, editIntent, sendIntent})) 297 .isEqualTo(expectedManagedUserActivities); 298 } 299 300 @Test 301 @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) getKeepEnabledPackages_shouldContainDefaultPhoneAndSmsAndLocationHistory()302 public void getKeepEnabledPackages_shouldContainDefaultPhoneAndSmsAndLocationHistory() { 303 final String testDialer = "com.android.test.defaultdialer"; 304 final String testSms = "com.android.test.defaultsms"; 305 final String testLocationHistory = "com.android.test.location.history"; 306 307 ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); 308 ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); 309 310 // Spy the real context to mock LocationManager. 311 Context spyContext = spy(RuntimeEnvironment.application); 312 when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(testLocationHistory); 313 when(spyContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); 314 315 ReflectionHelpers.setField(mProvider, "mContext", spyContext); 316 317 final Set<String> keepEnabledPackages = mProvider.getKeepEnabledPackages(); 318 319 final List<String> expectedPackages = Arrays.asList(testDialer, testSms, 320 testLocationHistory); 321 assertThat(keepEnabledPackages).containsAtLeastElementsIn(expectedPackages); 322 } 323 324 @Test 325 @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) getKeepEnabledPackages_hasEuiccComponent_shouldContainEuiccPackage()326 public void getKeepEnabledPackages_hasEuiccComponent_shouldContainEuiccPackage() { 327 final String testDialer = "com.android.test.defaultdialer"; 328 final String testSms = "com.android.test.defaultsms"; 329 final String testLocationHistory = "com.android.test.location.history"; 330 final String testEuicc = "com.android.test.euicc"; 331 332 ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); 333 ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); 334 final ComponentInfo componentInfo = new ComponentInfo(); 335 componentInfo.packageName = testEuicc; 336 337 ApplicationFeatureProviderImpl spyProvider = spy(new ApplicationFeatureProviderImpl( 338 mContext, mPackageManager, mPackageManagerService, mDevicePolicyManager)); 339 doReturn(componentInfo).when(spyProvider).findEuiccService(mPackageManager); 340 341 // Spy the real context to mock LocationManager. 342 Context spyContext = spy(RuntimeEnvironment.application); 343 when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(testLocationHistory); 344 when(spyContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); 345 346 ReflectionHelpers.setField(mProvider, "mContext", spyContext); 347 348 final Set<String> keepEnabledPackages = spyProvider.getKeepEnabledPackages(); 349 350 assertThat(keepEnabledPackages).contains(testEuicc); 351 } 352 353 @Test 354 @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) getKeepEnabledPackages_shouldContainSettingsIntelligence()355 public void getKeepEnabledPackages_shouldContainSettingsIntelligence() { 356 final String testDialer = "com.android.test.defaultdialer"; 357 final String testSms = "com.android.test.defaultsms"; 358 final String testLocationHistory = "com.android.test.location.history"; 359 360 ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); 361 ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); 362 363 // Spy the real context to mock LocationManager. 364 Context spyContext = spy(RuntimeEnvironment.application); 365 when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(testLocationHistory); 366 when(spyContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); 367 368 ReflectionHelpers.setField(mProvider, "mContext", spyContext); 369 370 final Set<String> allowlist = mProvider.getKeepEnabledPackages(); 371 372 assertThat(allowlist).contains("com.android.settings.intelligence"); 373 } 374 375 @Test 376 @RequiresFlagsEnabled(Flags.FLAG_UPDATE_SERVICE_V2) getKeepEnabledPackages_shouldContainWebViewPackage()377 public void getKeepEnabledPackages_shouldContainWebViewPackage() { 378 final String testWebViewPackageName = "com.android.webview"; 379 when(mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName()) 380 .thenReturn(testWebViewPackageName); 381 final Set<String> allowlist = mProvider.getKeepEnabledPackages(); 382 assertThat(allowlist).contains(testWebViewPackageName); 383 } 384 385 @Test 386 @RequiresFlagsDisabled(Flags.FLAG_UPDATE_SERVICE_V2) getKeepEnabledPackages_shouldNotContainWebViewPackageIfFlagDisabled()387 public void getKeepEnabledPackages_shouldNotContainWebViewPackageIfFlagDisabled() { 388 final String testWebViewPackageName = "com.android.webview"; 389 when(mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName()) 390 .thenReturn(testWebViewPackageName); 391 final Set<String> allowlist = mProvider.getKeepEnabledPackages(); 392 assertThat(allowlist).doesNotContain(testWebViewPackageName); 393 } 394 395 @Test 396 @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) getKeepEnabledPackages_shouldContainPackageInstaller()397 public void getKeepEnabledPackages_shouldContainPackageInstaller() { 398 final String testDialer = "com.android.test.defaultdialer"; 399 final String testSms = "com.android.test.defaultsms"; 400 final String testLocationHistory = "com.android.test.location.history"; 401 402 ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); 403 ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); 404 405 // Spy the real context to mock LocationManager. 406 Context spyContext = spy(RuntimeEnvironment.application); 407 when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(testLocationHistory); 408 when(spyContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); 409 410 ReflectionHelpers.setField(mProvider, "mContext", spyContext); 411 412 final Set<String> allowlist = mProvider.getKeepEnabledPackages(); 413 414 assertThat(allowlist).contains("com.android.packageinstaller"); 415 } 416 417 @Test getKeepEnabledPackages_shouldContainPreventUserDisablePackages()418 public void getKeepEnabledPackages_shouldContainPreventUserDisablePackages() { 419 when(mSystemConfigManager.getPreventUserDisablePackages()) 420 .thenReturn(PREVENT_USER_DISABLE_PACKAGES); 421 422 final Set<String> keepEnabledPackages = mProvider.getKeepEnabledPackages(); 423 424 assertThat(keepEnabledPackages).containsAtLeastElementsIn(PREVENT_USER_DISABLE_PACKAGES); 425 } 426 setUpUsersAndInstalledApps()427 private void setUpUsersAndInstalledApps() { 428 when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList( 429 new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN), 430 new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0))); 431 432 when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS 433 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS 434 | PackageManager.MATCH_ANY_USER, 435 MAIN_USER_ID)).thenReturn(Arrays.asList( 436 ApplicationTestUtils.buildInfo(APP_1_UID, APP_1, 0 /* flags */, 437 Build.VERSION_CODES.M))); 438 when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS 439 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, 440 MANAGED_PROFILE_ID)).thenReturn(Arrays.asList( 441 ApplicationTestUtils.buildInfo(APP_2_UID, APP_2, 0 /* flags */, 442 Build.VERSION_CODES.LOLLIPOP))); 443 } 444 createResolveInfo(String packageName)445 private ResolveInfo createResolveInfo(String packageName) { 446 final ApplicationInfo applicationInfo = new ApplicationInfo(); 447 applicationInfo.packageName = packageName; 448 final ActivityInfo activityInfo = new ActivityInfo(); 449 activityInfo.packageName = packageName; 450 activityInfo.applicationInfo = applicationInfo; 451 final ResolveInfo resolveInfo = new ResolveInfo(); 452 resolveInfo.activityInfo = activityInfo; 453 return resolveInfo; 454 } 455 } 456