1 /*
2  * Copyright (C) 2019 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.notification;
18 
19 import static android.app.role.RoleManager.ROLE_BROWSER;
20 import static android.app.role.RoleManager.ROLE_DIALER;
21 import static android.app.role.RoleManager.ROLE_EMERGENCY;
22 import static android.content.pm.PackageManager.MATCH_ALL;
23 
24 import static junit.framework.Assert.assertFalse;
25 import static junit.framework.Assert.assertTrue;
26 
27 import static org.mockito.ArgumentMatchers.anyBoolean;
28 import static org.mockito.Matchers.eq;
29 import static org.mockito.Mockito.any;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.times;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 
35 import static java.util.Arrays.asList;
36 
37 import android.app.ActivityManager;
38 import android.app.ActivityManagerInternal;
39 import android.app.AppOpsManager;
40 import android.app.IActivityManager;
41 import android.app.IUriGrantsManager;
42 import android.app.StatsManager;
43 import android.app.admin.DevicePolicyManagerInternal;
44 import android.app.role.RoleManager;
45 import android.app.usage.UsageStatsManagerInternal;
46 import android.companion.ICompanionDeviceManager;
47 import android.content.Context;
48 import android.content.pm.IPackageManager;
49 import android.content.pm.PackageManager;
50 import android.os.Looper;
51 import android.os.PowerManager;
52 import android.os.UserHandle;
53 import android.os.UserManager;
54 import android.permission.PermissionManager;
55 import android.telecom.TelecomManager;
56 import android.telephony.TelephonyManager;
57 import android.test.suitebuilder.annotation.SmallTest;
58 import android.testing.AndroidTestingRunner;
59 import android.testing.TestableLooper;
60 import android.testing.TestableLooper.RunWithLooper;
61 import android.util.ArraySet;
62 import android.util.AtomicFile;
63 import android.util.Pair;
64 
65 import androidx.test.InstrumentationRegistry;
66 
67 import com.android.internal.config.sysui.TestableFlagResolver;
68 import com.android.internal.logging.InstanceIdSequence;
69 import com.android.internal.logging.InstanceIdSequenceFake;
70 import com.android.server.LocalServices;
71 import com.android.server.UiServiceTestCase;
72 import com.android.server.lights.LightsManager;
73 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
74 import com.android.server.notification.NotificationManagerService.NotificationListeners;
75 import com.android.server.uri.UriGrantsManagerInternal;
76 import com.android.server.utils.quota.MultiRateLimiter;
77 import com.android.server.wm.ActivityTaskManagerInternal;
78 import com.android.server.wm.WindowManagerInternal;
79 
80 import org.junit.After;
81 import org.junit.Before;
82 import org.junit.Test;
83 import org.junit.runner.RunWith;
84 import org.mockito.Mock;
85 import org.mockito.MockitoAnnotations;
86 
87 import java.util.ArrayList;
88 import java.util.List;
89 
90 @SmallTest
91 @RunWith(AndroidTestingRunner.class)
92 @RunWithLooper
93 // TODO (b/194833441): remove when notification permission is enabled
94 public class RoleObserverTest extends UiServiceTestCase {
95     private TestableNotificationManagerService mService;
96     private NotificationManagerService.RoleObserver mRoleObserver;
97 
98     @Mock
99     private PreferencesHelper mPreferencesHelper;
100     @Mock
101     private IPackageManager mPm;
102     @Mock
103     private UserManager mUm;
104     @Mock
105     private RoleManager mRoleManager;
106     @Mock
107     private Looper mMainLooper;
108     private TestableLooper mTestableLooper;
109     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
110     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
111             1 << 30);
112     private List<UserHandle> mUsers;
113 
114     private static class TestableNotificationManagerService extends NotificationManagerService {
TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence)115         TestableNotificationManagerService(Context context,
116                 NotificationRecordLogger logger,
117                 InstanceIdSequence notificationInstanceIdSequence) {
118             super(context, logger, notificationInstanceIdSequence);
119         }
120 
121         @Override
handleSavePolicyFile()122         protected void handleSavePolicyFile() { }
123 
124         @Override
loadPolicyFile()125         protected void loadPolicyFile() { }
126     }
127 
128     @Before
setUp()129     public void setUp() throws Exception {
130         MockitoAnnotations.initMocks(this);
131         // Shell permisssions will override permissions of our app, so add all necessary permissions
132         // for this test here:
133         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
134                 "android.permission.READ_CONTACTS");
135 
136         LocalServices.removeServiceForTest(WindowManagerInternal.class);
137         LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
138         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
139 
140         mUsers = new ArrayList<>();
141         mUsers.add(new UserHandle(0));
142         mUsers.add(new UserHandle(10));
143         when(mUm.getUserHandles(anyBoolean())).thenReturn(mUsers);
144 
145         when(mMainLooper.isCurrentThread()).thenReturn(true);
146 
147         mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
148                 mNotificationInstanceIdSequence);
149         mRoleObserver = mService.new RoleObserver(mContext, mRoleManager, mPm, mMainLooper);
150         mTestableLooper = TestableLooper.get(this);
151 
152         try {
153             mService.init(mService.new WorkerHandler(mTestableLooper.getLooper()),
154                     mock(RankingHandler.class),
155                     mock(IPackageManager.class), mock(PackageManager.class),
156                     mock(LightsManager.class),
157                     mock(NotificationListeners.class), mock(NotificationAssistants.class),
158                     mock(ConditionProviders.class), mock(ICompanionDeviceManager.class),
159                     mock(SnoozeHelper.class), mock(NotificationUsageStats.class),
160                     mock(AtomicFile.class), mock(ActivityManager.class),
161                     mock(GroupHelper.class), mock(IActivityManager.class),
162                     mock(ActivityTaskManagerInternal.class),
163                     mock(UsageStatsManagerInternal.class),
164                     mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
165                     mock(UriGrantsManagerInternal.class),
166                     mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
167                     mock(StatsManager.class), mock(TelephonyManager.class),
168                     mock(ActivityManagerInternal.class),
169                     mock(MultiRateLimiter.class), mock(PermissionHelper.class),
170                     mock(UsageStatsManagerInternal.class), mock(TelecomManager.class),
171                     mock(NotificationChannelLogger.class), new TestableFlagResolver(),
172                     mock(PermissionManager.class),
173                     mock(PowerManager.class),
174                     new NotificationManagerService.PostNotificationTrackerFactory() {});
175         } catch (SecurityException e) {
176             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
177                 throw e;
178             }
179         }
180         mService.setPreferencesHelper(mPreferencesHelper);
181     }
182 
183     @After
tearDown()184     public void tearDown() {
185         InstrumentationRegistry.getInstrumentation()
186                 .getUiAutomation().dropShellPermissionIdentity();
187     }
188 
189     @Test
testInit_forNonBlockableDefaultApps()190     public void testInit_forNonBlockableDefaultApps() throws Exception {
191         List<String> dialer0 = new ArrayList<>();
192         dialer0.add("dialer");
193         List<String> emer0 = new ArrayList<>();
194         emer0.add("emergency");
195 
196         ArraySet<Pair<String, Integer>> dialer0Pair = new ArraySet<>();
197         dialer0Pair.add(new Pair("dialer", 30));
198         when(mPm.getPackageUid("dialer", MATCH_ALL, 0)).thenReturn(30);
199 
200         ArraySet<Pair<String, Integer>> emer0Pair = new ArraySet<>();
201         emer0Pair.add(new Pair("emergency", 40));
202         when(mPm.getPackageUid("emergency", MATCH_ALL, 0)).thenReturn(40);
203 
204 
205         when(mRoleManager.getRoleHoldersAsUser(
206                 ROLE_DIALER,
207                 mUsers.get(0)))
208                 .thenReturn(dialer0);
209         when(mRoleManager.getRoleHoldersAsUser(
210                 ROLE_EMERGENCY,
211                 mUsers.get(0)))
212                 .thenReturn(emer0);
213 
214         mRoleObserver.init();
215 
216         // verify internal records of current state of the world
217         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
218                 ROLE_DIALER, dialer0.get(0), mUsers.get(0).getIdentifier()));
219         assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
220                 ROLE_DIALER, dialer0.get(0), mUsers.get(1).getIdentifier()));
221 
222         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
223                 ROLE_EMERGENCY, emer0.get(0), mUsers.get(0).getIdentifier()));
224         assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
225                 ROLE_EMERGENCY, emer0.get(0), mUsers.get(1).getIdentifier()));
226 
227         // make sure we're listening to updates
228         verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser(
229                 any(), any(), eq(UserHandle.ALL));
230 
231         // make sure we told pref helper about the state of the world
232         verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, dialer0Pair);
233         verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, emer0Pair);
234     }
235 
236     @Test
testInit_forTrampolines()237     public void testInit_forTrampolines() throws Exception {
238         when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30);
239         when(mRoleManager.getRoleHoldersAsUser(
240                 ROLE_BROWSER,
241                 mUsers.get(0)))
242                 .thenReturn(asList("com.browser"));
243 
244         mRoleObserver.init();
245 
246         assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30));
247 
248         // make sure we're listening to updates
249         verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser(any(), any(),
250                 eq(UserHandle.ALL));
251     }
252 
253     @Test
testSwapDefault_forNonBlockableDefaultApps()254     public void testSwapDefault_forNonBlockableDefaultApps() throws Exception {
255         List<String> dialer0 = new ArrayList<>();
256         dialer0.add("dialer");
257 
258         when(mRoleManager.getRoleHoldersAsUser(
259                 ROLE_DIALER,
260                 mUsers.get(0)))
261                 .thenReturn(dialer0);
262 
263         mRoleObserver.init();
264 
265         List<String> newDefault = new ArrayList<>();
266         newDefault.add("phone");
267 
268         ArraySet<Pair<String, Integer>> newDefaultPair = new ArraySet<>();
269         newDefaultPair.add(new Pair("phone", 30));
270         when(mPm.getPackageUid("phone", MATCH_ALL, 0)).thenReturn(30);
271 
272         when(mRoleManager.getRoleHoldersAsUser(
273                 ROLE_DIALER,
274                 mUsers.get(0)))
275                 .thenReturn(newDefault);
276 
277         mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0));
278 
279         verify(mPreferencesHelper, times(1)).updateDefaultApps(
280                 0, new ArraySet<>(dialer0), newDefaultPair);
281     }
282 
283     @Test
testSwapDefault_forTrampolines()284     public void testSwapDefault_forTrampolines() throws Exception {
285         List<String> dialer0 = new ArrayList<>();
286         when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30);
287         when(mPm.getPackageUid("com.browser2", MATCH_ALL, 0)).thenReturn(31);
288         when(mRoleManager.getRoleHoldersAsUser(
289                 ROLE_BROWSER,
290                 mUsers.get(0)))
291                 .thenReturn(asList("com.browser"));
292         mRoleObserver.init();
293         assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30));
294         assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(31));
295         // Default changed
296         when(mRoleManager.getRoleHoldersAsUser(
297                 ROLE_BROWSER,
298                 mUsers.get(0)))
299                 .thenReturn(asList("com.browser2"));
300         mRoleObserver.onRoleHoldersChanged(ROLE_BROWSER, UserHandle.of(0));
301 
302         assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(30));
303         assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(31));
304     }
305 
306     @Test
testSwapDefault_multipleOverlappingApps_forNonBlockableDefaultApps()307     public void testSwapDefault_multipleOverlappingApps_forNonBlockableDefaultApps()
308             throws Exception {
309         List<String> dialer0 = new ArrayList<>();
310         dialer0.add("dialer");
311         dialer0.add("phone");
312 
313         when(mRoleManager.getRoleHoldersAsUser(
314                 ROLE_DIALER,
315                 mUsers.get(0)))
316                 .thenReturn(dialer0);
317 
318         mRoleObserver.init();
319 
320         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0));
321         assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0));
322         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
323 
324         List<String> newDefault = new ArrayList<>();
325         newDefault.add("phone");
326         newDefault.add("emerPhone");
327 
328         when(mRoleManager.getRoleHoldersAsUser(
329                 ROLE_DIALER,
330                 mUsers.get(0)))
331                 .thenReturn(newDefault);
332 
333         ArraySet<String> expectedRemove = new ArraySet<>();
334         expectedRemove.add("dialer");
335 
336         ArraySet<Pair<String, Integer>> expectedAddPair = new ArraySet<>();
337         expectedAddPair.add(new Pair("emerPhone", 30));
338         when(mPm.getPackageUid("emerPhone", MATCH_ALL, 0)).thenReturn(30);
339 
340         mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0));
341 
342         verify(mPreferencesHelper, times(1)).updateDefaultApps(
343                 0, expectedRemove, expectedAddPair);
344 
345         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0));
346         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0));
347         assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
348     }
349 
350     @Test
testSwapDefault_newUser_forNonBlockableDefaultApps()351     public void testSwapDefault_newUser_forNonBlockableDefaultApps() throws Exception {
352         List<String> dialer0 = new ArrayList<>();
353         dialer0.add("dialer");
354 
355         when(mRoleManager.getRoleHoldersAsUser(
356                 ROLE_DIALER,
357                 mUsers.get(0)))
358                 .thenReturn(dialer0);
359 
360         mRoleObserver.init();
361 
362         List<String> dialer10 = new ArrayList<>();
363         dialer10.add("phone");
364 
365         when(mRoleManager.getRoleHoldersAsUser(
366                 ROLE_DIALER,
367                 mUsers.get(1)))
368                 .thenReturn(dialer10);
369 
370         ArraySet<Pair<String, Integer>> expectedAddPair = new ArraySet<>();
371         expectedAddPair.add(new Pair("phone", 30));
372         when(mPm.getPackageUid("phone", MATCH_ALL, 10)).thenReturn(30);
373 
374         mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(10));
375 
376         ArraySet<String> expectedRemove = new ArraySet<>();
377         ArraySet<String> expectedAdd = new ArraySet<>();
378         expectedAdd.add("phone");
379 
380         verify(mPreferencesHelper, times(1)).updateDefaultApps(
381                 10, expectedRemove, expectedAddPair);
382 
383         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 10));
384         assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
385     }
386 
387     @Test
testSwapDefault_newUser_forTrampolines()388     public void testSwapDefault_newUser_forTrampolines() throws Exception {
389         List<String> dialer0 = new ArrayList<>();
390         when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30);
391         when(mPm.getPackageUid("com.browser2", MATCH_ALL, 10)).thenReturn(1031);
392         when(mRoleManager.getRoleHoldersAsUser(
393                 ROLE_BROWSER,
394                 mUsers.get(0)))
395                 .thenReturn(asList("com.browser"));
396         mRoleObserver.init();
397         assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30));
398         assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(1031));
399         // New user
400         when(mRoleManager.getRoleHoldersAsUser(
401                 ROLE_BROWSER,
402                 mUsers.get(1)))
403                 .thenReturn(asList("com.browser2"));
404         mRoleObserver.onRoleHoldersChanged(ROLE_BROWSER, UserHandle.of(10));
405 
406         assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30));
407         assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(1031));
408     }
409 }
410