/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.notification; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.ParceledListSlice; import android.permission.IPermissionManager; import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import androidx.test.runner.AndroidJUnit4; import com.android.server.UiServiceTestCase; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Map; import java.util.Set; @SmallTest @RunWith(AndroidJUnit4.class) public class PermissionHelperTest extends UiServiceTestCase { @Mock private Context mContext; @Mock private IPackageManager mPackageManager; @Mock private IPermissionManager mPermManager; private PermissionHelper mPermissionHelper; private static final int USER_FLAG_MASK = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mPermissionHelper = new PermissionHelper(mContext, mPackageManager, mPermManager); PackageInfo testPkgInfo = new PackageInfo(); testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS }; when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt())) .thenReturn(testPkgInfo); } @Test public void testHasPermission() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_GRANTED); assertThat(mPermissionHelper.hasPermission(1)).isTrue(); when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_DENIED); assertThat(mPermissionHelper.hasPermission(1)).isFalse(); } @Test public void testGetAppsRequestingPermission() throws Exception { // App that does not request permission PackageInfo notThis = new PackageInfo(); notThis.packageName = "wrong.permission"; notThis.requestedPermissions = new String[] {"something else"}; // App that does not request any permissions (null check PackageInfo none = new PackageInfo(); none.packageName = "no.permissions"; // 2 apps that request the permission PackageInfo first = new PackageInfo(); first.packageName = "first"; first.requestedPermissions = new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiFirst = new ApplicationInfo(); aiFirst.uid = 1; first.applicationInfo = aiFirst; PackageInfo second = new PackageInfo(); second.packageName = "second"; second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiSecond = new ApplicationInfo(); aiSecond.uid = 2; second.applicationInfo = aiSecond; Set> expected = ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second")); ParceledListSlice infos = new ParceledListSlice<>( ImmutableList.of(notThis, none, first, second)); when(mPackageManager.getInstalledPackages(eq((long) GET_PERMISSIONS), anyInt())) .thenReturn(infos); Set> actual = mPermissionHelper.getAppsRequestingPermission(0); assertThat(actual).containsExactlyElementsIn(expected); } @Test public void testHasRequestedPermission_otherPermission() throws Exception { final String permission = "correct"; String packageName = "testHasRequestedPermission_otherPermission"; PackageInfo info = new PackageInfo(); info.packageName = packageName; info.requestedPermissions = new String[]{"something else"}; when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info); assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isFalse(); } @Test public void testHasRequestedPermission_noPermissions() throws Exception { final String permission = "correct"; String packageName = "testHasRequestedPermission_noPermissions"; PackageInfo info = new PackageInfo(); info.packageName = packageName; when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info); assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isFalse(); } @Test public void testHasRequestedPermission_singlePermissions() throws Exception { final String permission = "correct"; String packageName = "testHasRequestedPermission_twoPermissions"; PackageInfo info = new PackageInfo(); info.packageName = packageName; info.requestedPermissions = new String[]{permission}; when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info); assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isTrue(); } @Test public void testHasRequestedPermission_twoPermissions() throws Exception { final String permission = "correct"; String packageName = "testHasRequestedPermission_twoPermissions"; PackageInfo info = new PackageInfo(); info.packageName = packageName; info.requestedPermissions = new String[]{"something else", permission}; when(mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, 0)).thenReturn(info); assertThat(mPermissionHelper.hasRequestedPermission(permission, packageName, 0)).isTrue(); } @Test public void testGetAppsGrantedPermission_noApps() throws Exception { int userId = 1; ParceledListSlice infos = ParceledListSlice.emptyList(); when(mPackageManager.getPackagesHoldingPermissions( eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId))) .thenReturn(infos); assertThat(mPermissionHelper.getAppsGrantedPermission(userId)).isNotNull(); } @Test public void testGetAppsGrantedPermission() throws Exception { int userId = 1; PackageInfo first = new PackageInfo(); first.packageName = "first"; first.requestedPermissions = new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiFirst = new ApplicationInfo(); aiFirst.uid = 1; first.applicationInfo = aiFirst; PackageInfo second = new PackageInfo(); second.packageName = "second"; second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiSecond = new ApplicationInfo(); aiSecond.uid = 2; second.applicationInfo = aiSecond; ParceledListSlice infos = new ParceledListSlice<>( ImmutableList.of(first, second)); when(mPackageManager.getPackagesHoldingPermissions( eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId))) .thenReturn(infos); Set> expected = ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second")); assertThat(mPermissionHelper.getAppsGrantedPermission(userId)) .containsExactlyElementsIn(expected); } @Test public void testSetNotificationPermission_grantUserSet() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_DENIED); mPermissionHelper.setNotificationPermission("pkg", 10, true, true); verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SET, true, 10); } @Test public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_DENIED); when(mPermManager.getPermissionFlags(anyString(), eq(Manifest.permission.POST_NOTIFICATIONS), anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT); PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission( "pkg", 10, true, false); mPermissionHelper.setNotificationPermission(pkgPerm); verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SET, true, 10); } @Test public void testSetNotificationPermission_revokeUserSet() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_GRANTED); mPermissionHelper.setNotificationPermission("pkg", 10, false, true); verify(mPermManager).revokeRuntimePermission( eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString()); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SET, true, 10); } @Test public void testSetNotificationPermission_grantNotUserSet() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_DENIED); mPermissionHelper.setNotificationPermission("pkg", 10, true, false); verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, USER_FLAG_MASK, 0, true, 10); } @Test public void testSetNotificationPermission_revokeNotUserSet() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_GRANTED); mPermissionHelper.setNotificationPermission("pkg", 10, false, false); verify(mPermManager).revokeRuntimePermission( eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString()); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, true, 10); } @Test public void testSetNotificationPermission_SystemFixedPermNotSet() throws Exception { when(mPermManager.getPermissionFlags(anyString(), eq(Manifest.permission.POST_NOTIFICATIONS), anyInt())).thenReturn(FLAG_PERMISSION_SYSTEM_FIXED); mPermissionHelper.setNotificationPermission("pkg", 10, false, true); verify(mPermManager, never()).revokeRuntimePermission( anyString(), anyString(), anyInt(), anyString()); verify(mPermManager, never()).updatePermissionFlags( anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt()); } @Test public void testSetNotificationPermission_PolicyFixedPermNotSet() throws Exception { when(mPermManager.getPermissionFlags(anyString(), eq(Manifest.permission.POST_NOTIFICATIONS), anyInt())).thenReturn(FLAG_PERMISSION_POLICY_FIXED); mPermissionHelper.setNotificationPermission("pkg", 10, false, true); verify(mPermManager, never()).revokeRuntimePermission( anyString(), anyString(), anyInt(), anyString()); verify(mPermManager, never()).updatePermissionFlags( anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt()); } @Test public void testSetNotificationPermission_alreadyGrantedNotRegranted() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_GRANTED); mPermissionHelper.setNotificationPermission("pkg", 10, true, false); verify(mPermManager, never()).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); } @Test public void testSetNotificationPermission_alreadyRevokedNotRerevoked() throws Exception { when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_DENIED); mPermissionHelper.setNotificationPermission("pkg", 10, false, false); verify(mPermManager, never()).revokeRuntimePermission( eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString()); } @Test public void testSetNotificationPermission_doesntRequestNotChanged() throws Exception { int testUid = -1; when(mContext.checkPermission(anyString(), anyInt(), anyInt())) .thenReturn(PERMISSION_GRANTED); when(mPackageManager.getPackageUid(anyString(), anyInt(), anyInt())) .thenReturn(testUid); PackageInfo testPkgInfo = new PackageInfo(); testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.RECORD_AUDIO }; when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt())) .thenReturn(testPkgInfo); mPermissionHelper.setNotificationPermission("pkg", 10, false, false); verify(mContext, never()).checkPermission( eq(Manifest.permission.POST_NOTIFICATIONS), eq(-1), eq(testUid)); verify(mPermManager, never()).revokeRuntimePermission( eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString()); } @Test public void testIsPermissionFixed() throws Exception { when(mPermManager.getPermissionFlags(anyString(), eq(Manifest.permission.POST_NOTIFICATIONS), anyInt())).thenReturn(FLAG_PERMISSION_USER_SET); assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isFalse(); when(mPermManager.getPermissionFlags(anyString(), eq(Manifest.permission.POST_NOTIFICATIONS), anyInt())).thenReturn(FLAG_PERMISSION_USER_SET|FLAG_PERMISSION_POLICY_FIXED); assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isTrue(); when(mPermManager.getPermissionFlags(anyString(), eq(Manifest.permission.POST_NOTIFICATIONS), anyInt())).thenReturn(FLAG_PERMISSION_SYSTEM_FIXED); assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isTrue(); } @Test public void testGetNotificationPermissionValues() throws Exception { int userId = 1; PackageInfo first = new PackageInfo(); first.packageName = "first"; first.requestedPermissions = new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiFirst = new ApplicationInfo(); aiFirst.uid = 1; first.applicationInfo = aiFirst; PackageInfo second = new PackageInfo(); second.packageName = "second"; second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiSecond = new ApplicationInfo(); aiSecond.uid = 2; second.applicationInfo = aiSecond; PackageInfo third = new PackageInfo(); third.packageName = "third"; third.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiThird = new ApplicationInfo(); aiThird.uid = 3; third.applicationInfo = aiThird; ParceledListSlice infos = new ParceledListSlice<>( ImmutableList.of(first, second)); when(mPackageManager.getPackagesHoldingPermissions( eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId))) .thenReturn(infos); ParceledListSlice requesting = new ParceledListSlice<>( ImmutableList.of(first, second, third)); when(mPackageManager.getInstalledPackages(eq((long) GET_PERMISSIONS), anyInt())) .thenReturn(requesting); // 2 and 3 are user-set permissions when(mPermManager.getPermissionFlags( "first", Manifest.permission.POST_NOTIFICATIONS, userId)).thenReturn(0); when(mPermManager.getPermissionFlags( "second", Manifest.permission.POST_NOTIFICATIONS, userId)) .thenReturn(FLAG_PERMISSION_USER_SET); when(mPermManager.getPermissionFlags( "third", Manifest.permission.POST_NOTIFICATIONS, userId)) .thenReturn(FLAG_PERMISSION_USER_SET); Map, Pair> expected = ImmutableMap.of(new Pair(1, "first"), new Pair(true, false), new Pair(2, "second"), new Pair(true, true), new Pair(3, "third"), new Pair(false, true)); Map, Pair> actual = mPermissionHelper.getNotificationPermissionValues(userId); assertThat(actual).containsExactlyEntriesIn(expected); } }