diff --git a/api/current.txt b/api/current.txt index 0cdc8f2ef8061..53b0740315805 100644 --- a/api/current.txt +++ b/api/current.txt @@ -37432,16 +37432,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List getNotificationChannelGroups(java.lang.String); - method public final java.util.List getNotificationChannels(java.lang.String); + method public final java.util.List getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -37454,7 +37454,7 @@ package android.service.notification { method public final void requestUnbind(); method public final void setNotificationsShown(java.lang.String[]); method public final void snoozeNotification(java.lang.String, long); - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index 013a4068cea18..a40634206e83e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -40572,16 +40572,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List getNotificationChannelGroups(java.lang.String); - method public final java.util.List getNotificationChannels(java.lang.String); + method public final java.util.List getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -40598,7 +40598,7 @@ package android.service.notification { method public final void snoozeNotification(java.lang.String, java.lang.String); method public final void snoozeNotification(java.lang.String, long); method public void unregisterAsSystemService() throws android.os.RemoteException; - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index a861e9d39aa76..df84e13b5cd10 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -37611,16 +37611,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List getNotificationChannelGroups(java.lang.String); - method public final java.util.List getNotificationChannels(java.lang.String); + method public final java.util.List getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -37634,7 +37634,7 @@ package android.service.notification { method public final void setNotificationsShown(java.lang.String[]); method public final void snoozeNotification(java.lang.String, java.lang.String); method public final void snoozeNotification(java.lang.String, long); - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index f4e8f3f5687e5..cd9c095890e7f 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.pm.ParceledListSlice; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.service.notification.Adjustment; import android.service.notification.Condition; import android.service.notification.IConditionListener; @@ -101,9 +102,9 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); - void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in NotificationChannel channel); - ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg); - ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg); + void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user, in NotificationChannel channel); + ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user); + ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user); void applyEnqueuedAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index dc1a70d74d7fc..ed44f25996952 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -18,6 +18,7 @@ package android.service.notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; +import android.os.UserHandle; import android.service.notification.IStatusBarNotificationHolder; import android.service.notification.StatusBarNotification; import android.service.notification.NotificationRankingUpdate; @@ -36,8 +37,8 @@ oneway interface INotificationListener void onInterruptionFilterChanged(int interruptionFilter); // companion device managers only - void onNotificationChannelModification(String pkgName, in NotificationChannel channel, int modificationType); - void onNotificationChannelGroupModification(String pkgName, in NotificationChannelGroup group, int modificationType); + void onNotificationChannelModification(String pkgName, in UserHandle user, in NotificationChannel channel, int modificationType); + void onNotificationChannelGroupModification(String pkgName, in UserHandle user, in NotificationChannelGroup group, int modificationType); // rankers only void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 4833be335c882..00bd30456c9ea 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -49,6 +49,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -231,25 +232,25 @@ public abstract class NotificationListenerService extends Service { /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was created. + * {@link #onNotificationChannelModified(String, UserHandle,NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, + * int)}- the provided object was created. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was updated. + * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle,NotificationChannelGroup, int)} + * - the provided object was updated. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was deleted. + * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, + * int)}- the provided object was deleted. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; @@ -432,13 +433,14 @@ public abstract class NotificationListenerService extends Service { * device} in order to receive this callback. * * @param pkg The package the channel belongs to. + * @param user The user on which the change was made. * @param channel The channel that has changed. * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. */ - public void onNotificationChannelModified(String pkg, NotificationChannel channel, - @ChannelOrGroupModificationTypes int modificationType) { + public void onNotificationChannelModified(String pkg, UserHandle user, + NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { // optional } @@ -449,13 +451,14 @@ public abstract class NotificationListenerService extends Service { * device} in order to receive this callback. * * @param pkg The package the group belongs to. + * @param user The user on which the change was made. * @param group The group that has changed. * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. */ - public void onNotificationChannelGroupModified(String pkg, NotificationChannelGroup group, - @ChannelOrGroupModificationTypes int modificationType) { + public void onNotificationChannelGroupModified(String pkg, UserHandle user, + NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { // optional } @@ -661,21 +664,24 @@ public abstract class NotificationListenerService extends Service { /** - * Updates a notification channel for a given package. This should only be used to reflect - * changes a user has made to the channel via the listener's user interface. + * Updates a notification channel for a given package for a given user. This should only be used + * to reflect changes a user has made to the channel via the listener's user interface. * + *

This method will throw a security exception if you don't have access to notifications + * for the given user.

*

The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package the channel belongs to. + * @param user The user the channel belongs to. * @param channel the channel to update. */ - public final void updateNotificationChannel(@NonNull String pkg, + public final void updateNotificationChannel(@NonNull String pkg, @NonNull UserHandle user, @NonNull NotificationChannel channel) { if (!isBound()) return; try { getNotificationInterface().updateNotificationChannelFromPrivilegedListener( - mWrapper, pkg, channel); + mWrapper, pkg, user, channel); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -683,19 +689,22 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns all notification channels belonging to the given package. + * Returns all notification channels belonging to the given package for a given user. * + *

This method will throw a security exception if you don't have access to notifications + * for the given user.

*

The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package to retrieve channels for. */ - public final List getNotificationChannels(@NonNull String pkg) { + public final List getNotificationChannels(@NonNull String pkg, + @NonNull UserHandle user) { if (!isBound()) return null; try { return getNotificationInterface().getNotificationChannelsFromPrivilegedListener( - mWrapper, pkg).getList(); + mWrapper, pkg, user).getList(); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -703,19 +712,22 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns all notification channel groups belonging to the given package. + * Returns all notification channel groups belonging to the given package for a given user. * + *

This method will throw a security exception if you don't have access to notifications + * for the given user.

*

The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package to retrieve channel groups for. */ - public final List getNotificationChannelGroups(@NonNull String pkg) { + public final List getNotificationChannelGroups(@NonNull String pkg, + @NonNull UserHandle user) { if (!isBound()) return null; try { return getNotificationInterface().getNotificationChannelGroupsFromPrivilegedListener( - mWrapper, pkg).getList(); + mWrapper, pkg, user).getList(); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -1252,24 +1264,27 @@ public abstract class NotificationListenerService extends Service { } @Override - public void onNotificationChannelModification(String pkgName, NotificationChannel channel, + public void onNotificationChannelModification(String pkgName, UserHandle user, + NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { SomeArgs args = SomeArgs.obtain(); args.arg1 = pkgName; - args.arg2 = channel; - args.arg3 = modificationType; + args.arg2 = user; + args.arg3 = channel; + args.arg4 = modificationType; mHandler.obtainMessage( MyHandler.MSG_ON_NOTIFICATION_CHANNEL_MODIFIED, args).sendToTarget(); } @Override - public void onNotificationChannelGroupModification(String pkgName, + public void onNotificationChannelGroupModification(String pkgName, UserHandle user, NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { SomeArgs args = SomeArgs.obtain(); args.arg1 = pkgName; - args.arg2 = group; - args.arg3 = modificationType; + args.arg2 = user; + args.arg3 = group; + args.arg4 = modificationType; mHandler.obtainMessage( MyHandler.MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED, args).sendToTarget(); } @@ -1841,17 +1856,19 @@ public abstract class NotificationListenerService extends Service { case MSG_ON_NOTIFICATION_CHANNEL_MODIFIED: { SomeArgs args = (SomeArgs) msg.obj; String pkgName = (String) args.arg1; - NotificationChannel channel = (NotificationChannel) args.arg2; - int modificationType = (int) args.arg3; - onNotificationChannelModified(pkgName, channel, modificationType); + UserHandle user= (UserHandle) args.arg2; + NotificationChannel channel = (NotificationChannel) args.arg3; + int modificationType = (int) args.arg4; + onNotificationChannelModified(pkgName, user, channel, modificationType); } break; case MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED: { SomeArgs args = (SomeArgs) msg.obj; String pkgName = (String) args.arg1; - NotificationChannelGroup group = (NotificationChannelGroup) args.arg2; - int modificationType = (int) args.arg3; - onNotificationChannelGroupModified(pkgName, group, modificationType); + UserHandle user = (UserHandle) args.arg2; + NotificationChannelGroup group = (NotificationChannelGroup) args.arg3; + int modificationType = (int) args.arg4; + onNotificationChannelGroupModified(pkgName, user, group, modificationType); } break; } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f334ba41bdf1c..bac487eb9fbaa 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1322,7 +1322,8 @@ public class NotificationManagerService extends SystemService { if (!fromListener) { mListeners.notifyNotificationChannelChanged( - pkg, modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); + pkg, UserHandle.getUserHandleForUid(uid), + modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); } synchronized (mNotificationLock) { @@ -1647,7 +1648,8 @@ public class NotificationManagerService extends SystemService { Preconditions.checkNotNull(group, "group in list is null"); mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true /* fromTargetApp */); - mListeners.notifyNotificationChannelGroupChanged(pkg, group, + mListeners.notifyNotificationChannelGroupChanged(pkg, + UserHandle.of(UserHandle.getCallingUserId()), group, NOTIFICATION_CHANNEL_OR_GROUP_ADDED); } savePolicyFile(); @@ -1663,6 +1665,7 @@ public class NotificationManagerService extends SystemService { mRankingHelper.createNotificationChannel(pkg, uid, channel, true /* fromTargetApp */); mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(uid), mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false), NOTIFICATION_CHANNEL_OR_GROUP_ADDED); } @@ -1708,6 +1711,7 @@ public class NotificationManagerService extends SystemService { UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(callingUid), mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true), NOTIFICATION_CHANNEL_OR_GROUP_DELETED); savePolicyFile(); @@ -1737,11 +1741,14 @@ public class NotificationManagerService extends SystemService { true, UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); - mListeners.notifyNotificationChannelChanged(pkg, deletedChannel, + mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(callingUid), + deletedChannel, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); } mListeners.notifyNotificationChannelGroupChanged( - pkg, groupToDelete, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); + pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, + NOTIFICATION_CHANNEL_OR_GROUP_DELETED); savePolicyFile(); } } @@ -2691,43 +2698,59 @@ public class NotificationManagerService extends SystemService { @Override public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, - String pkg, NotificationChannel channel) throws RemoteException { + String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { Preconditions.checkNotNull(channel); + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); - } - - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - updateNotificationChannelInt(pkg, uid, channel, true); + verifyPrivilegedListener(token, user); + updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); } @Override public ParceledListSlice getNotificationChannelsFromPrivilegedListener( - INotificationListener token, String pkg) throws RemoteException { - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); - } + INotificationListener token, String pkg, UserHandle user) throws RemoteException { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); + verifyPrivilegedListener(token, user); - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */); + return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), + false /* includeDeleted */); } @Override public ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener( - INotificationListener token, String pkg) throws RemoteException { + INotificationListener token, String pkg, UserHandle user) throws RemoteException { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); + verifyPrivilegedListener(token, user); + + List groups = new ArrayList<>(); + groups.addAll(mRankingHelper.getNotificationChannelGroups( + pkg, getUidForPackageAndUser(pkg, user))); + return new ParceledListSlice<>(groups); + } + + private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); if (!hasCompanionDevice(info)) { throw new SecurityException(info + " does not have access"); } + if (!info.enabledAndUserMatches(user.getIdentifier())) { + throw new SecurityException(info + " does not have access"); + } + } - List groups = new ArrayList<>(); - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - groups.addAll(mRankingHelper.getNotificationChannelGroups(pkg, uid)); - return new ParceledListSlice<>(groups); + private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { + int uid = 0; + long identity = Binder.clearCallingIdentity(); + try { + uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); + } finally { + Binder.restoreCallingIdentity(identity); + } + return uid; } }; @@ -5019,7 +5042,7 @@ public class NotificationManagerService extends SystemService { } } - protected void notifyNotificationChannelChanged(final String pkg, + protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, final NotificationChannel channel, final int modificationType) { if (channel == null) { return; @@ -5034,15 +5057,16 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyNotificationChannelChanged(serviceInfo, pkg, channel, - modificationType); + notifyNotificationChannelChanged( + serviceInfo, pkg, user, channel, modificationType); } }); } } - protected void notifyNotificationChannelGroupChanged(final String pkg, - final NotificationChannelGroup group, final int modificationType) { + protected void notifyNotificationChannelGroupChanged( + final String pkg, final UserHandle user, final NotificationChannelGroup group, + final int modificationType) { if (group == null) { return; } @@ -5056,8 +5080,8 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyNotificationChannelGroupChanged(serviceInfo, pkg, group, - modificationType); + notifyNotificationChannelGroupChanged( + serviceInfo, pkg, user, group, modificationType); } }); } @@ -5118,22 +5142,22 @@ public class NotificationManagerService extends SystemService { } void notifyNotificationChannelChanged(ManagedServiceInfo info, - final String pkg, final NotificationChannel channel, + final String pkg, final UserHandle user, final NotificationChannel channel, final int modificationType) { final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationChannelModification(pkg, channel, modificationType); + listener.onNotificationChannelModification(pkg, user, channel, modificationType); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex); } } private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, - final String pkg, final NotificationChannelGroup group, + final String pkg, final UserHandle user, final NotificationChannelGroup group, final int modificationType) { final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationChannelGroupModification(pkg, group, modificationType); + listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex); } diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java index f666727ec1d19..57ee928f76824 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -49,6 +49,7 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.graphics.Color; import android.os.Binder; +import android.os.Process; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; @@ -460,10 +461,10 @@ public class NotificationManagerServiceTest { mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(channel2), + eq(Process.myUserHandle()), eq(channel2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -481,10 +482,10 @@ public class NotificationManagerServiceTest { mBinderService.createNotificationChannelGroups(PKG, new ParceledListSlice(Arrays.asList(group1, group2))); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(group1), + eq(Process.myUserHandle()), eq(group1), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(group2), + eq(Process.myUserHandle()), eq(group2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -503,7 +504,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -520,7 +521,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId()); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -537,7 +538,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId()); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(ncg), + eq(Process.myUserHandle()), eq(ncg), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -550,12 +551,12 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); mBinderService.updateNotificationChannelFromPrivilegedListener( - null, PKG, mTestNotificationChannel); + null, PKG, Process.myUserHandle(), mTestNotificationChannel); verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any()); verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -568,7 +569,7 @@ public class NotificationManagerServiceTest { try { mBinderService.updateNotificationChannelFromPrivilegedListener( - null, PKG, mTestNotificationChannel); + null, PKG, Process.myUserHandle(), mTestNotificationChannel); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass @@ -577,7 +578,33 @@ public class NotificationManagerServiceTest { verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), + eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); + } + + @Test + @UiThreadTest + public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.updateNotificationChannelFromPrivilegedListener( + null, PKG, UserHandle.ALL, mTestNotificationChannel); + fail("incorrectly allowed a change to a user listener cannot see"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); + + verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -589,7 +616,8 @@ public class NotificationManagerServiceTest { associations.add("a"); when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); - mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); verify(mRankingHelper, times(1)).getNotificationChannels( anyString(), anyInt(), anyBoolean()); @@ -603,7 +631,8 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); try { - mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass @@ -613,6 +642,29 @@ public class NotificationManagerServiceTest { anyString(), anyInt(), anyBoolean()); } + @Test + @UiThreadTest + public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listener getting channels from a user they cannot see"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + @Test @UiThreadTest public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { @@ -621,7 +673,8 @@ public class NotificationManagerServiceTest { associations.add("a"); when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); - mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); verify(mRankingHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt()); } @@ -634,7 +687,29 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); try { - mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listeners that don't have a companion device shouldn't be able to call this"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); + } + + @Test + @UiThreadTest + public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List associations = new ArrayList<>(); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass