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