diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 211aa07e43515..4d5f67b0637e2 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -92,6 +92,7 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); + void applyEnqueuedAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); void applyAdjustmentsFromAssistant(in INotificationListener token, in List adjustments); void createNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel); diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 51ba8c728fd68..cab390f756284 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -210,7 +210,14 @@ public abstract class NotificationAssistantService extends NotificationListenerS args.recycle(); Adjustment adjustment = onNotificationEnqueued(sbn, importance, user); if (adjustment != null) { - adjustNotification(adjustment); + if (!isBound()) return; + try { + getNotificationInterface().applyEnqueuedAdjustmentFromAssistant( + mWrapper, adjustment); + } catch (android.os.RemoteException ex) { + Log.v(TAG, "Unable to contact notification manager", ex); + throw ex.rethrowFromSystemServer(); + } } } break; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index aaba00ac26803..b08f800416939 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -170,6 +170,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.concurrent.TimeUnit; /** {@hide} */ @@ -225,6 +226,8 @@ public class NotificationManagerService extends SystemService { private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds + private static final long DELAY_FOR_ASSISTANT_TIME = 100; + private IActivityManager mAm; private IPackageManager mPackageManager; AudioManager mAudioManager; @@ -2363,6 +2366,28 @@ public class NotificationManagerService extends SystemService { } } + @Override + public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token, + Adjustment adjustment) throws RemoteException { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mEnqueuedNotifications) { + mNotificationAssistants.checkServiceTokenLocked(token); + int N = mEnqueuedNotifications.size(); + for (int i = 0; i < N; i++) { + final NotificationRecord n = mEnqueuedNotifications.get(i); + if (Objects.equals(adjustment.getKey(), n.getKey()) + && Objects.equals(adjustment.getUser(), n.getUserId())) { + applyAdjustment(n, adjustment); + break; + } + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void applyAdjustmentFromAssistant(INotificationListener token, Adjustment adjustment) throws RemoteException { @@ -2370,7 +2395,8 @@ public class NotificationManagerService extends SystemService { try { synchronized (mNotificationList) { mNotificationAssistants.checkServiceTokenLocked(token); - applyAdjustmentLocked(adjustment); + NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); + applyAdjustment(n, adjustment); } mRankingHandler.requestSort(true); } finally { @@ -2387,7 +2413,8 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationList) { mNotificationAssistants.checkServiceTokenLocked(token); for (Adjustment adjustment : adjustments) { - applyAdjustmentLocked(adjustment); + NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); + applyAdjustment(n, adjustment); } } mRankingHandler.requestSort(true); @@ -2444,8 +2471,7 @@ public class NotificationManagerService extends SystemService { } }; - private void applyAdjustmentLocked(Adjustment adjustment) { - NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); + private void applyAdjustment(NotificationRecord n, Adjustment adjustment) { if (n == null) { return; } @@ -2653,6 +2679,21 @@ public class NotificationManagerService extends SystemService { } } + synchronized (mEnqueuedNotifications) { + if (!zenOnly) { + N = mEnqueuedNotifications.size(); + if (N > 0) { + pw.println(" Enqueued Notification List:"); + for (int i = 0; i < N; i++) { + final NotificationRecord nr = mEnqueuedNotifications.get(i); + if (filter.filtered && !filter.matches(nr.sbn)) continue; + nr.dump(pw, " ", getContext(), filter.redact); + } + pw.println(" "); + } + } + } + if (!zenOnly) { pw.println("\n Usage Stats:"); mUsageStats.dump(pw, " ", filter); @@ -2880,66 +2921,121 @@ public class NotificationManagerService extends SystemService { @Override public void run() { - try { - synchronized (mNotificationList) { - if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) { - // TODO: log to event log - if (DBG) { - Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); - } - mSnoozeHelper.update(userId, r); - savePolicyFile(); - return; + synchronized (mNotificationList) { + if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) { + // TODO: log to event log + if (DBG) { + Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); } + mSnoozeHelper.update(userId, r); + savePolicyFile(); + return; + } - final StatusBarNotification n = r.sbn; - if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); - NotificationRecord old = mNotificationsByKey.get(n.getKey()); + final StatusBarNotification n = r.sbn; + if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); + NotificationRecord old = mNotificationsByKey.get(n.getKey()); + if (old != null) { + // Retain ranking information from previous record + r.copyRankingInformation(old); + } + + final int callingUid = n.getUid(); + final int callingPid = n.getInitialPid(); + final Notification notification = n.getNotification(); + final String pkg = n.getPackageName(); + final int id = n.getId(); + final String tag = n.getTag(); + + // Handle grouped notifications and bail out early if we + // can to avoid extracting signals. + handleGroupedNotificationLocked(r, old, callingUid, callingPid); + + // This conditional is a dirty hack to limit the logging done on + // behalf of the download manager without affecting other apps. + if (!pkg.equals("com.android.providers.downloads") + || Log.isLoggable("DownloadManager", Log.VERBOSE)) { + int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; if (old != null) { - // Retain ranking information from previous record - r.copyRankingInformation(old); + enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } + EventLogTags.writeNotificationEnqueue(callingUid, callingPid, + pkg, id, tag, userId, notification.toString(), + enqueueStatus); + } - final int callingUid = n.getUid(); - final int callingPid = n.getInitialPid(); - final Notification notification = n.getNotification(); - final String pkg = n.getPackageName(); - final int id = n.getId(); - final String tag = n.getTag(); - final boolean isSystemNotification = isUidSystem(callingUid) || - ("android".equals(pkg)); + mRankingHelper.extractSignals(r); - // Handle grouped notifications and bail out early if we - // can to avoid extracting signals. - handleGroupedNotificationLocked(r, old, callingUid, callingPid); + // blocked apps + if (isBlocked(r, mUsageStats)) { + return; + } - // This conditional is a dirty hack to limit the logging done on - // behalf of the download manager without affecting other apps. - if (!pkg.equals("com.android.providers.downloads") - || Log.isLoggable("DownloadManager", Log.VERBOSE)) { - int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; - if (old != null) { - enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; + // tell the assistant service about the notification + if (mNotificationAssistants.isEnabled()) { + mNotificationAssistants.onNotificationEnqueued(r); + mHandler.postDelayed(new PostNotificationRunnable(userId, r.getKey()), + DELAY_FOR_ASSISTANT_TIME); + } else { + mHandler.post(new PostNotificationRunnable(userId, r.getKey())); + } + } + } + + protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) { + final String pkg = r.sbn.getPackageName(); + final int callingUid = r.sbn.getUid(); + + final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); + if (isPackageSuspended) { + Slog.e(TAG, "Suppressing notification from package due to package " + + "suspended by administrator."); + usageStats.registerSuspendedByAdmin(r); + return isPackageSuspended; + } + + final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE + || !r.getChannel().isAllowed() + || !noteNotificationOp(pkg, callingUid); + if (isBlocked) { + Slog.e(TAG, "Suppressing notification from package by user request."); + usageStats.registerBlocked(r); + } + return isBlocked; + } + } + + protected class PostNotificationRunnable implements Runnable { + private final String key; + private final int userId; + + PostNotificationRunnable(int userId, String key) { + this.userId = userId; + this.key = key; + } + + @Override + public void run() { + try { + NotificationRecord r = null; + synchronized (mEnqueuedNotifications) { + int N = mEnqueuedNotifications.size(); + for (int i = 0; i < N; i++) { + final NotificationRecord enqueued = mEnqueuedNotifications.get(i); + if (Objects.equals(key, enqueued.getKey())) { + r = enqueued; + break; } - EventLogTags.writeNotificationEnqueue(callingUid, callingPid, - pkg, id, tag, userId, notification.toString(), - enqueueStatus); } - - mRankingHelper.extractSignals(r); - - // blocked apps - if (isBlocked(r, mUsageStats)) { - return; - } - - // tell the assistant service about the notification - if (mNotificationAssistants.isEnabled()) { - mNotificationAssistants.onNotificationEnqueued(r); - // TODO delay the code below here for 100ms or until there is an answer - } - - + } + if (r == null) { + Slog.e(TAG, "Cannot find enqueued record for key: " + key); + return; + } + synchronized (mNotificationList) { + NotificationRecord old = mNotificationsByKey.get(key); + final StatusBarNotification n = r.sbn; + final Notification notification = n.getNotification(); int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { mNotificationList.add(r); @@ -2998,32 +3094,17 @@ public class NotificationManagerService extends SystemService { } } finally { synchronized (mEnqueuedNotifications) { - mEnqueuedNotifications.remove(r); + int N = mEnqueuedNotifications.size(); + for (int i = 0; i < N; i++) { + final NotificationRecord enqueued = mEnqueuedNotifications.get(i); + if (Objects.equals(key, enqueued.getKey())) { + mEnqueuedNotifications.remove(i); + break; + } + } } } } - - protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) { - final String pkg = r.sbn.getPackageName(); - final int callingUid = r.sbn.getUid(); - - final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); - if (isPackageSuspended) { - Slog.e(TAG, "Suppressing notification from package due to package " - + "suspended by administrator."); - usageStats.registerSuspendedByAdmin(r); - return isPackageSuspended; - } - - final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE - || !r.getChannel().isAllowed() - || !noteNotificationOp(pkg, callingUid); - if (isBlocked) { - Slog.e(TAG, "Suppressing notification from package by user request."); - usageStats.registerBlocked(r); - } - return isBlocked; - } } /** diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index dbd719b9167fe..e8c3d97747d70 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -39,6 +39,7 @@ import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; +import android.text.TextUtils; import android.util.Log; import android.util.Slog; @@ -318,7 +319,7 @@ public final class NotificationRecord { if (notification.actions != null && notification.actions.length > 0) { pw.println(prefix + " actions={"); final int N = notification.actions.length; - for (int i=0; i %s", @@ -350,7 +351,7 @@ public final class NotificationRecord { final int N = Array.getLength(val); pw.print(" (" + N + ")"); if (!redact) { - for (int j=0; j