1 /*
2  * Copyright (C) 2021 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 package com.android.server.notification;
17 
18 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
19 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
20 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
21 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
22 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
23 import static android.content.pm.PackageManager.GET_PERMISSIONS;
24 import static android.content.pm.PackageManager.PERMISSION_DENIED;
25 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.mockito.ArgumentMatchers.anyBoolean;
30 import static org.mockito.ArgumentMatchers.anyInt;
31 import static org.mockito.ArgumentMatchers.anyLong;
32 import static org.mockito.ArgumentMatchers.anyString;
33 import static org.mockito.ArgumentMatchers.eq;
34 import static org.mockito.Mockito.never;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37 
38 import android.Manifest;
39 import android.content.Context;
40 import android.content.pm.ApplicationInfo;
41 import android.content.pm.IPackageManager;
42 import android.content.pm.PackageInfo;
43 import android.content.pm.ParceledListSlice;
44 import android.permission.IPermissionManager;
45 import android.test.suitebuilder.annotation.SmallTest;
46 import android.util.Pair;
47 
48 import androidx.test.runner.AndroidJUnit4;
49 
50 import com.android.server.UiServiceTestCase;
51 
52 import com.google.common.collect.ImmutableList;
53 import com.google.common.collect.ImmutableMap;
54 import com.google.common.collect.ImmutableSet;
55 
56 import org.junit.Before;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 
62 import java.util.Map;
63 import java.util.Set;
64 
65 @SmallTest
66 @RunWith(AndroidJUnit4.class)
67 public class PermissionHelperTest extends UiServiceTestCase {
68 
69     @Mock
70     private Context mContext;
71     @Mock
72     private IPackageManager mPackageManager;
73     @Mock
74     private IPermissionManager mPermManager;
75 
76     private PermissionHelper mPermissionHelper;
77 
78     private static final int USER_FLAG_MASK = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED;
79 
80     @Before
setUp()81     public void setUp() throws Exception {
82         MockitoAnnotations.initMocks(this);
83         mPermissionHelper = new PermissionHelper(mContext, mPackageManager, mPermManager);
84         PackageInfo testPkgInfo = new PackageInfo();
85         testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
86         when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
87                 .thenReturn(testPkgInfo);
88     }
89 
90     @Test
testHasPermission()91     public void testHasPermission() throws Exception {
92         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
93                 .thenReturn(PERMISSION_GRANTED);
94 
95         assertThat(mPermissionHelper.hasPermission(1)).isTrue();
96 
97         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
98                 .thenReturn(PERMISSION_DENIED);
99 
100         assertThat(mPermissionHelper.hasPermission(1)).isFalse();
101     }
102 
103     @Test
testGetAppsRequestingPermission()104     public void testGetAppsRequestingPermission() throws Exception {
105         // App that does not request permission
106         PackageInfo notThis = new PackageInfo();
107         notThis.packageName = "wrong.permission";
108         notThis.requestedPermissions = new String[] {"something else"};
109         // App that does not request any permissions (null check
110         PackageInfo none = new PackageInfo();
111         none.packageName = "no.permissions";
112         // 2 apps that request the permission
113         PackageInfo first = new PackageInfo();
114         first.packageName = "first";
115         first.requestedPermissions =
116                 new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS};
117         ApplicationInfo aiFirst = new ApplicationInfo();
118         aiFirst.uid = 1;
119         first.applicationInfo = aiFirst;
120         PackageInfo second = new PackageInfo();
121         second.packageName = "second";
122         second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
123         ApplicationInfo aiSecond = new ApplicationInfo();
124         aiSecond.uid = 2;
125         second.applicationInfo = aiSecond;
126 
127         Set<Pair<Integer, String>> expected =
128                 ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second"));
129 
130         ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>(
131                 ImmutableList.of(notThis, none, first, second));
132         when(mPackageManager.getInstalledPackages(eq((long) GET_PERMISSIONS), anyInt()))
133                 .thenReturn(infos);
134 
135         Set<Pair<Integer, String>> actual = mPermissionHelper.getAppsRequestingPermission(0);
136 
137         assertThat(actual).containsExactlyElementsIn(expected);
138     }
139 
140     @Test
testHasRequestedPermission_otherPermission()141     public void testHasRequestedPermission_otherPermission() throws Exception {
142         final String permission = "correct";
143 
144         String packageName = "testHasRequestedPermission_otherPermission";
145 
146         PackageInfo info = new PackageInfo();
147         info.packageName = packageName;
148         info.requestedPermissions = new String[]{"something else"};
149 
150         when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info);
151 
152         assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isFalse();
153 
154     }
155 
156     @Test
testHasRequestedPermission_noPermissions()157     public void testHasRequestedPermission_noPermissions() throws Exception {
158         final String permission = "correct";
159 
160         String packageName = "testHasRequestedPermission_noPermissions";
161 
162         PackageInfo info = new PackageInfo();
163         info.packageName = packageName;
164 
165         when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info);
166 
167         assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isFalse();
168     }
169 
170     @Test
testHasRequestedPermission_singlePermissions()171     public void testHasRequestedPermission_singlePermissions() throws Exception {
172         final String permission = "correct";
173 
174         String packageName = "testHasRequestedPermission_twoPermissions";
175 
176         PackageInfo info = new PackageInfo();
177         info.packageName = packageName;
178         info.requestedPermissions =
179                 new String[]{permission};
180 
181         when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info);
182 
183         assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isTrue();
184     }
185 
186     @Test
testHasRequestedPermission_twoPermissions()187     public void testHasRequestedPermission_twoPermissions() throws Exception {
188         final String permission = "correct";
189 
190         String packageName = "testHasRequestedPermission_twoPermissions";
191 
192         PackageInfo info = new PackageInfo();
193         info.packageName = packageName;
194         info.requestedPermissions =
195                 new String[]{"something else", permission};
196 
197         when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info);
198 
199         assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isTrue();
200     }
201 
202     @Test
testGetAppsGrantedPermission_noApps()203     public void testGetAppsGrantedPermission_noApps() throws Exception {
204         int userId = 1;
205         ParceledListSlice<PackageInfo> infos = ParceledListSlice.emptyList();
206         when(mPackageManager.getPackagesHoldingPermissions(
207                 eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId)))
208                 .thenReturn(infos);
209         assertThat(mPermissionHelper.getAppsGrantedPermission(userId)).isNotNull();
210     }
211 
212     @Test
testGetAppsGrantedPermission()213     public void testGetAppsGrantedPermission() throws Exception {
214         int userId = 1;
215         PackageInfo first = new PackageInfo();
216         first.packageName = "first";
217         first.requestedPermissions =
218                 new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS};
219         ApplicationInfo aiFirst = new ApplicationInfo();
220         aiFirst.uid = 1;
221         first.applicationInfo = aiFirst;
222         PackageInfo second = new PackageInfo();
223         second.packageName = "second";
224         second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
225         ApplicationInfo aiSecond = new ApplicationInfo();
226         aiSecond.uid = 2;
227         second.applicationInfo = aiSecond;
228 
229         ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>(
230                 ImmutableList.of(first, second));
231         when(mPackageManager.getPackagesHoldingPermissions(
232                 eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId)))
233                 .thenReturn(infos);
234 
235         Set<Pair<Integer, String>> expected =
236                 ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second"));
237 
238         assertThat(mPermissionHelper.getAppsGrantedPermission(userId))
239                 .containsExactlyElementsIn(expected);
240     }
241 
242     @Test
testSetNotificationPermission_grantUserSet()243     public void testSetNotificationPermission_grantUserSet() throws Exception {
244         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
245                 .thenReturn(PERMISSION_DENIED);
246         mPermissionHelper.setNotificationPermission("pkg", 10, true, true);
247 
248         verify(mPermManager).grantRuntimePermission(
249                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
250         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
251                 USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
252                 FLAG_PERMISSION_USER_SET, true, 10);
253     }
254 
255     @Test
testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()256     public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
257             throws Exception {
258         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
259                 .thenReturn(PERMISSION_DENIED);
260         when(mPermManager.getPermissionFlags(anyString(),
261                 eq(Manifest.permission.POST_NOTIFICATIONS),
262                 anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
263         PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
264                 "pkg", 10, true, false);
265 
266         mPermissionHelper.setNotificationPermission(pkgPerm);
267         verify(mPermManager).grantRuntimePermission(
268                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
269         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
270                 USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
271                 FLAG_PERMISSION_USER_SET, true, 10);
272     }
273 
274     @Test
testSetNotificationPermission_revokeUserSet()275     public void testSetNotificationPermission_revokeUserSet() throws Exception {
276         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
277                 .thenReturn(PERMISSION_GRANTED);
278 
279         mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
280 
281         verify(mPermManager).revokeRuntimePermission(
282                 eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
283         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
284                 USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
285                 FLAG_PERMISSION_USER_SET, true, 10);
286     }
287 
288     @Test
testSetNotificationPermission_grantNotUserSet()289     public void testSetNotificationPermission_grantNotUserSet() throws Exception {
290         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
291                 .thenReturn(PERMISSION_DENIED);
292 
293         mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
294 
295         verify(mPermManager).grantRuntimePermission(
296                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
297         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
298                 USER_FLAG_MASK, 0, true, 10);
299     }
300 
301     @Test
testSetNotificationPermission_revokeNotUserSet()302     public void testSetNotificationPermission_revokeNotUserSet() throws Exception {
303         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
304                 .thenReturn(PERMISSION_GRANTED);
305 
306         mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
307 
308         verify(mPermManager).revokeRuntimePermission(
309                 eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
310         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
311                 USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0,
312                 true, 10);
313     }
314 
315     @Test
testSetNotificationPermission_SystemFixedPermNotSet()316     public void testSetNotificationPermission_SystemFixedPermNotSet() throws Exception {
317         when(mPermManager.getPermissionFlags(anyString(),
318                 eq(Manifest.permission.POST_NOTIFICATIONS),
319                 anyInt())).thenReturn(FLAG_PERMISSION_SYSTEM_FIXED);
320 
321         mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
322         verify(mPermManager, never()).revokeRuntimePermission(
323                 anyString(), anyString(), anyInt(), anyString());
324         verify(mPermManager, never()).updatePermissionFlags(
325                 anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
326     }
327 
328     @Test
testSetNotificationPermission_PolicyFixedPermNotSet()329     public void testSetNotificationPermission_PolicyFixedPermNotSet() throws Exception {
330         when(mPermManager.getPermissionFlags(anyString(),
331                 eq(Manifest.permission.POST_NOTIFICATIONS),
332                 anyInt())).thenReturn(FLAG_PERMISSION_POLICY_FIXED);
333 
334         mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
335         verify(mPermManager, never()).revokeRuntimePermission(
336                 anyString(), anyString(), anyInt(), anyString());
337         verify(mPermManager, never()).updatePermissionFlags(
338                 anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
339     }
340 
341     @Test
testSetNotificationPermission_alreadyGrantedNotRegranted()342     public void testSetNotificationPermission_alreadyGrantedNotRegranted() throws Exception {
343         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
344                 .thenReturn(PERMISSION_GRANTED);
345         mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
346 
347         verify(mPermManager, never()).grantRuntimePermission(
348                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
349     }
350 
351     @Test
testSetNotificationPermission_alreadyRevokedNotRerevoked()352     public void testSetNotificationPermission_alreadyRevokedNotRerevoked() throws Exception {
353         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
354                 .thenReturn(PERMISSION_DENIED);
355         mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
356 
357         verify(mPermManager, never()).revokeRuntimePermission(
358                 eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
359     }
360 
361     @Test
testSetNotificationPermission_doesntRequestNotChanged()362     public void testSetNotificationPermission_doesntRequestNotChanged() throws Exception {
363         int testUid = -1;
364         when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
365                 .thenReturn(PERMISSION_GRANTED);
366         when(mPackageManager.getPackageUid(anyString(), anyInt(), anyInt()))
367                 .thenReturn(testUid);
368         PackageInfo testPkgInfo = new PackageInfo();
369         testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.RECORD_AUDIO };
370         when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
371                 .thenReturn(testPkgInfo);
372         mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
373 
374         verify(mContext, never()).checkPermission(
375                 eq(Manifest.permission.POST_NOTIFICATIONS), eq(-1), eq(testUid));
376         verify(mPermManager, never()).revokeRuntimePermission(
377                 eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
378     }
379 
380     @Test
testIsPermissionFixed()381     public void testIsPermissionFixed() throws Exception {
382         when(mPermManager.getPermissionFlags(anyString(),
383                 eq(Manifest.permission.POST_NOTIFICATIONS),
384                 anyInt())).thenReturn(FLAG_PERMISSION_USER_SET);
385 
386         assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isFalse();
387 
388         when(mPermManager.getPermissionFlags(anyString(),
389                 eq(Manifest.permission.POST_NOTIFICATIONS),
390                 anyInt())).thenReturn(FLAG_PERMISSION_USER_SET|FLAG_PERMISSION_POLICY_FIXED);
391 
392         assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isTrue();
393 
394         when(mPermManager.getPermissionFlags(anyString(),
395                 eq(Manifest.permission.POST_NOTIFICATIONS),
396                 anyInt())).thenReturn(FLAG_PERMISSION_SYSTEM_FIXED);
397 
398         assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isTrue();
399     }
400 
401     @Test
testGetNotificationPermissionValues()402     public void testGetNotificationPermissionValues() throws Exception {
403         int userId = 1;
404         PackageInfo first = new PackageInfo();
405         first.packageName = "first";
406         first.requestedPermissions =
407                 new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS};
408         ApplicationInfo aiFirst = new ApplicationInfo();
409         aiFirst.uid = 1;
410         first.applicationInfo = aiFirst;
411 
412         PackageInfo second = new PackageInfo();
413         second.packageName = "second";
414         second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
415         ApplicationInfo aiSecond = new ApplicationInfo();
416         aiSecond.uid = 2;
417         second.applicationInfo = aiSecond;
418 
419         PackageInfo third = new PackageInfo();
420         third.packageName = "third";
421         third.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
422         ApplicationInfo aiThird = new ApplicationInfo();
423         aiThird.uid = 3;
424         third.applicationInfo = aiThird;
425 
426         ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>(
427                 ImmutableList.of(first, second));
428         when(mPackageManager.getPackagesHoldingPermissions(
429                 eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId)))
430                 .thenReturn(infos);
431         ParceledListSlice<PackageInfo> requesting = new ParceledListSlice<>(
432                 ImmutableList.of(first, second, third));
433         when(mPackageManager.getInstalledPackages(eq((long) GET_PERMISSIONS), anyInt()))
434                 .thenReturn(requesting);
435 
436         // 2 and 3 are user-set permissions
437         when(mPermManager.getPermissionFlags(
438                 "first", Manifest.permission.POST_NOTIFICATIONS, userId)).thenReturn(0);
439         when(mPermManager.getPermissionFlags(
440                 "second", Manifest.permission.POST_NOTIFICATIONS, userId))
441                 .thenReturn(FLAG_PERMISSION_USER_SET);
442         when(mPermManager.getPermissionFlags(
443                 "third", Manifest.permission.POST_NOTIFICATIONS, userId))
444                 .thenReturn(FLAG_PERMISSION_USER_SET);
445 
446         Map<Pair<Integer, String>, Pair<Boolean, Boolean>> expected =
447                 ImmutableMap.of(new Pair(1, "first"), new Pair(true, false),
448                     new Pair(2, "second"), new Pair(true, true),
449                     new Pair(3, "third"), new Pair(false, true));
450 
451         Map<Pair<Integer, String>, Pair<Boolean, Boolean>> actual =
452                 mPermissionHelper.getNotificationPermissionValues(userId);
453 
454         assertThat(actual).containsExactlyEntriesIn(expected);
455     }
456 }
457