Loading services/core/java/com/android/server/notification/NotificationManagerService.java +2 −7 Original line number Diff line number Diff line Loading @@ -2288,6 +2288,7 @@ public class NotificationManagerService extends SystemService { mPermissionHelper, mNotificationChannelLogger, mAppOps, mUgmInternal, new SysUiStatsEvent.BuilderFactory(), mShowReviewPermissionsNotification); mPreferencesHelper.updateFixedImportance(mUm.getUsers()); Loading Loading @@ -5728,13 +5729,7 @@ public class NotificationManagerService extends SystemService { final Uri originalSoundUri = (originalChannel != null) ? originalChannel.getSound() : null; if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) { Binder.withCleanCallingIdentity(() -> { mUgmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(soundUri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(soundUri, UserHandle.getUserId(sourceUid))); }); PermissionHelper.grantUriPermission(mUgmInternal, soundUri, sourceUid); } } Loading services/core/java/com/android/server/notification/NotificationRecord.java +4 −9 Original line number Diff line number Diff line Loading @@ -1369,19 +1369,16 @@ public final class NotificationRecord { * {@link SecurityException} depending on target SDK of enqueuing app. */ private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; if (mGrantableUris != null && mGrantableUris.contains(uri)) { return; // already verified this URI } // We can't grant Uri permissions from system final int sourceUid = getSbn().getUid(); if (sourceUid == android.os.Process.SYSTEM_UID) return; final long ident = Binder.clearCallingIdentity(); try { // This will throw SecurityException if caller can't grant mUgmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); PermissionHelper.grantUriPermission(mUgmInternal, uri, sourceUid); if (mGrantableUris == null) { mGrantableUris = new ArraySet<>(); Loading @@ -1401,8 +1398,6 @@ public final class NotificationRecord { } } } } finally { Binder.restoreCallingIdentity(ident); } } Loading services/core/java/com/android/server/notification/PermissionHelper.java +19 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,17 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.net.Uri; import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.ArrayMap; import android.util.Pair; Loading @@ -36,6 +41,7 @@ import android.util.Slog; import com.android.internal.util.ArrayUtils; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.uri.UriGrantsManagerInternal; import java.util.Collections; import java.util.HashSet; Loading Loading @@ -266,6 +272,19 @@ public final class PermissionHelper { return false; } static void grantUriPermission(final UriGrantsManagerInternal ugmInternal, Uri uri, int sourceUid) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; Binder.withCleanCallingIdentity(() -> { // This will throw a SecurityException if the caller can't grant. ugmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); }); } public static class PackagePermission { public final String packageName; public final @UserIdInt int userId; Loading services/core/java/com/android/server/notification/PreferencesHelper.java +9 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.notification.PermissionHelper.PackagePermission; import com.android.server.uri.UriGrantsManagerInternal; import org.json.JSONArray; import org.json.JSONException; Loading Loading @@ -182,6 +183,7 @@ public class PreferencesHelper implements RankingConfig { private final PermissionHelper mPermissionHelper; private final NotificationChannelLogger mNotificationChannelLogger; private final AppOpsManager mAppOps; private final UriGrantsManagerInternal mUgmInternal; private SparseBooleanArray mBadgingEnabled; private SparseBooleanArray mBubblesEnabled; Loading @@ -198,6 +200,7 @@ public class PreferencesHelper implements RankingConfig { ZenModeHelper zenHelper, PermissionHelper permHelper, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, UriGrantsManagerInternal ugmInternal, SysUiStatsEvent.BuilderFactory statsEventBuilderFactory, boolean showReviewPermissionsNotification) { mContext = context; Loading @@ -208,6 +211,7 @@ public class PreferencesHelper implements RankingConfig { mNotificationChannelLogger = notificationChannelLogger; mAppOps = appOpsManager; mStatsEventBuilderFactory = statsEventBuilderFactory; mUgmInternal = ugmInternal; mShowReviewPermissionsNotification = showReviewPermissionsNotification; XML_VERSION = 4; Loading Loading @@ -1008,6 +1012,11 @@ public class PreferencesHelper implements RankingConfig { } clearLockedFieldsLocked(channel); // Verify that the app has permission to read the sound Uri // Only check for new channels, as regular apps can only set sound // before creating. See: {@link NotificationChannel#setSound} PermissionHelper.grantUriPermission(mUgmInternal, channel.getSound(), uid); channel.setImportanceLockedByCriticalDeviceFunction( r.defaultAppLockedImportance || r.fixedImportance); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +36 −1 Original line number Diff line number Diff line Loading @@ -3256,6 +3256,41 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), anyInt(), eq(Process.myUserHandle().getIdentifier())); mBinderService.updateNotificationChannelFromPrivilegedListener( null, mPkg, Process.myUserHandle(), updatedNotificationChannel); verify(mPreferencesHelper, times(1)).updateNotificationChannel( anyString(), anyInt(), any(), anyBoolean()); verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @Test public void testUpdateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); when(mCompanionMgr.getAssociations(mPkg, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean())) .thenReturn(mTestNotificationChannel); // Missing Uri permissions for the old channel sound final Uri oldSoundUri = Settings.System.DEFAULT_NOTIFICATION_URI; doThrow(new SecurityException("no access")).when(mUgmInternal) .checkGrantUriPermission(eq(Process.myUid()), any(), eq(oldSoundUri), anyInt(), eq(Process.myUserHandle().getIdentifier())); // Has Uri permissions for the old channel sound final Uri newSoundUri = Uri.parse("content://media/test/sound/uri"); final NotificationChannel updatedNotificationChannel = new NotificationChannel( TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); updatedNotificationChannel.setSound(newSoundUri, updatedNotificationChannel.getAudioAttributes()); mBinderService.updateNotificationChannelFromPrivilegedListener( null, PKG, Process.myUserHandle(), updatedNotificationChannel); Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +2 −7 Original line number Diff line number Diff line Loading @@ -2288,6 +2288,7 @@ public class NotificationManagerService extends SystemService { mPermissionHelper, mNotificationChannelLogger, mAppOps, mUgmInternal, new SysUiStatsEvent.BuilderFactory(), mShowReviewPermissionsNotification); mPreferencesHelper.updateFixedImportance(mUm.getUsers()); Loading Loading @@ -5728,13 +5729,7 @@ public class NotificationManagerService extends SystemService { final Uri originalSoundUri = (originalChannel != null) ? originalChannel.getSound() : null; if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) { Binder.withCleanCallingIdentity(() -> { mUgmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(soundUri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(soundUri, UserHandle.getUserId(sourceUid))); }); PermissionHelper.grantUriPermission(mUgmInternal, soundUri, sourceUid); } } Loading
services/core/java/com/android/server/notification/NotificationRecord.java +4 −9 Original line number Diff line number Diff line Loading @@ -1369,19 +1369,16 @@ public final class NotificationRecord { * {@link SecurityException} depending on target SDK of enqueuing app. */ private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; if (mGrantableUris != null && mGrantableUris.contains(uri)) { return; // already verified this URI } // We can't grant Uri permissions from system final int sourceUid = getSbn().getUid(); if (sourceUid == android.os.Process.SYSTEM_UID) return; final long ident = Binder.clearCallingIdentity(); try { // This will throw SecurityException if caller can't grant mUgmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); PermissionHelper.grantUriPermission(mUgmInternal, uri, sourceUid); if (mGrantableUris == null) { mGrantableUris = new ArraySet<>(); Loading @@ -1401,8 +1398,6 @@ public final class NotificationRecord { } } } } finally { Binder.restoreCallingIdentity(ident); } } Loading
services/core/java/com/android/server/notification/PermissionHelper.java +19 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,17 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.net.Uri; import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.ArrayMap; import android.util.Pair; Loading @@ -36,6 +41,7 @@ import android.util.Slog; import com.android.internal.util.ArrayUtils; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.uri.UriGrantsManagerInternal; import java.util.Collections; import java.util.HashSet; Loading Loading @@ -266,6 +272,19 @@ public final class PermissionHelper { return false; } static void grantUriPermission(final UriGrantsManagerInternal ugmInternal, Uri uri, int sourceUid) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; Binder.withCleanCallingIdentity(() -> { // This will throw a SecurityException if the caller can't grant. ugmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); }); } public static class PackagePermission { public final String packageName; public final @UserIdInt int userId; Loading
services/core/java/com/android/server/notification/PreferencesHelper.java +9 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.notification.PermissionHelper.PackagePermission; import com.android.server.uri.UriGrantsManagerInternal; import org.json.JSONArray; import org.json.JSONException; Loading Loading @@ -182,6 +183,7 @@ public class PreferencesHelper implements RankingConfig { private final PermissionHelper mPermissionHelper; private final NotificationChannelLogger mNotificationChannelLogger; private final AppOpsManager mAppOps; private final UriGrantsManagerInternal mUgmInternal; private SparseBooleanArray mBadgingEnabled; private SparseBooleanArray mBubblesEnabled; Loading @@ -198,6 +200,7 @@ public class PreferencesHelper implements RankingConfig { ZenModeHelper zenHelper, PermissionHelper permHelper, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, UriGrantsManagerInternal ugmInternal, SysUiStatsEvent.BuilderFactory statsEventBuilderFactory, boolean showReviewPermissionsNotification) { mContext = context; Loading @@ -208,6 +211,7 @@ public class PreferencesHelper implements RankingConfig { mNotificationChannelLogger = notificationChannelLogger; mAppOps = appOpsManager; mStatsEventBuilderFactory = statsEventBuilderFactory; mUgmInternal = ugmInternal; mShowReviewPermissionsNotification = showReviewPermissionsNotification; XML_VERSION = 4; Loading Loading @@ -1008,6 +1012,11 @@ public class PreferencesHelper implements RankingConfig { } clearLockedFieldsLocked(channel); // Verify that the app has permission to read the sound Uri // Only check for new channels, as regular apps can only set sound // before creating. See: {@link NotificationChannel#setSound} PermissionHelper.grantUriPermission(mUgmInternal, channel.getSound(), uid); channel.setImportanceLockedByCriticalDeviceFunction( r.defaultAppLockedImportance || r.fixedImportance); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +36 −1 Original line number Diff line number Diff line Loading @@ -3256,6 +3256,41 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), anyInt(), eq(Process.myUserHandle().getIdentifier())); mBinderService.updateNotificationChannelFromPrivilegedListener( null, mPkg, Process.myUserHandle(), updatedNotificationChannel); verify(mPreferencesHelper, times(1)).updateNotificationChannel( anyString(), anyInt(), any(), anyBoolean()); verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @Test public void testUpdateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); when(mCompanionMgr.getAssociations(mPkg, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean())) .thenReturn(mTestNotificationChannel); // Missing Uri permissions for the old channel sound final Uri oldSoundUri = Settings.System.DEFAULT_NOTIFICATION_URI; doThrow(new SecurityException("no access")).when(mUgmInternal) .checkGrantUriPermission(eq(Process.myUid()), any(), eq(oldSoundUri), anyInt(), eq(Process.myUserHandle().getIdentifier())); // Has Uri permissions for the old channel sound final Uri newSoundUri = Uri.parse("content://media/test/sound/uri"); final NotificationChannel updatedNotificationChannel = new NotificationChannel( TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); updatedNotificationChannel.setSound(newSoundUri, updatedNotificationChannel.getAudioAttributes()); mBinderService.updateNotificationChannelFromPrivilegedListener( null, PKG, Process.myUserHandle(), updatedNotificationChannel); Loading