• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2007 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  
17  package com.android.server.notification;
18  
19  import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
20  import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
21  import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
22  import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
23  import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
24  import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
25  import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
26  import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
27  import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
28  import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
29  import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
30  import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
31  import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
32  import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
33  import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
34  import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
35  import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
36  import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
37  import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
38  import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
39  import static android.service.notification.NotificationListenerService.TRIM_FULL;
40  import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
41  import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
42  import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
43  
44  import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
45  
46  import android.Manifest;
47  import android.annotation.Nullable;
48  import android.app.ActivityManager;
49  import android.app.ActivityManagerInternal;
50  import android.app.ActivityManagerNative;
51  import android.app.AppGlobals;
52  import android.app.AppOpsManager;
53  import android.app.AutomaticZenRule;
54  import android.app.IActivityManager;
55  import android.app.INotificationManager;
56  import android.app.ITransientNotification;
57  import android.app.Notification;
58  import android.app.NotificationManager;
59  import android.app.NotificationManager.Policy;
60  import android.app.PendingIntent;
61  import android.app.StatusBarManager;
62  import android.app.backup.BackupManager;
63  import android.app.usage.UsageEvents;
64  import android.app.usage.UsageStatsManagerInternal;
65  import android.content.BroadcastReceiver;
66  import android.content.ComponentName;
67  import android.content.ContentResolver;
68  import android.content.Context;
69  import android.content.Intent;
70  import android.content.IntentFilter;
71  import android.content.pm.ApplicationInfo;
72  import android.content.pm.IPackageManager;
73  import android.content.pm.PackageInfo;
74  import android.content.pm.PackageManager;
75  import android.content.pm.PackageManager.NameNotFoundException;
76  import android.content.pm.ParceledListSlice;
77  import android.content.pm.UserInfo;
78  import android.content.res.Resources;
79  import android.database.ContentObserver;
80  import android.media.AudioAttributes;
81  import android.media.AudioManager;
82  import android.media.AudioManagerInternal;
83  import android.media.AudioSystem;
84  import android.media.IRingtonePlayer;
85  import android.net.Uri;
86  import android.os.Binder;
87  import android.os.Bundle;
88  import android.os.Environment;
89  import android.os.Handler;
90  import android.os.HandlerThread;
91  import android.os.IBinder;
92  import android.os.IInterface;
93  import android.os.Looper;
94  import android.os.Message;
95  import android.os.Process;
96  import android.os.RemoteException;
97  import android.os.SystemClock;
98  import android.os.SystemProperties;
99  import android.os.UserHandle;
100  import android.os.UserManager;
101  import android.os.Vibrator;
102  import android.provider.Settings;
103  import android.service.notification.Adjustment;
104  import android.service.notification.Condition;
105  import android.service.notification.IConditionProvider;
106  import android.service.notification.INotificationListener;
107  import android.service.notification.IStatusBarNotificationHolder;
108  import android.service.notification.NotificationRankerService;
109  import android.service.notification.NotificationListenerService;
110  import android.service.notification.NotificationRankingUpdate;
111  import android.service.notification.StatusBarNotification;
112  import android.service.notification.ZenModeConfig;
113  import android.telephony.PhoneStateListener;
114  import android.telephony.TelephonyManager;
115  import android.text.TextUtils;
116  import android.util.ArrayMap;
117  import android.util.ArraySet;
118  import android.util.AtomicFile;
119  import android.util.Log;
120  import android.util.Slog;
121  import android.util.SparseArray;
122  import android.util.Xml;
123  import android.view.WindowManager;
124  import android.view.WindowManagerInternal;
125  import android.view.accessibility.AccessibilityEvent;
126  import android.view.accessibility.AccessibilityManager;
127  import android.widget.Toast;
128  
129  import com.android.internal.R;
130  import com.android.internal.annotations.VisibleForTesting;
131  import com.android.internal.statusbar.NotificationVisibility;
132  import com.android.internal.util.FastXmlSerializer;
133  import com.android.internal.util.Preconditions;
134  import com.android.server.DeviceIdleController;
135  import com.android.server.EventLogTags;
136  import com.android.server.LocalServices;
137  import com.android.server.SystemService;
138  import com.android.server.lights.Light;
139  import com.android.server.lights.LightsManager;
140  import com.android.server.notification.ManagedServices.ManagedServiceInfo;
141  import com.android.server.policy.PhoneWindowManager;
142  import com.android.server.statusbar.StatusBarManagerInternal;
143  import com.android.server.notification.ManagedServices.UserProfiles;
144  
145  import libcore.io.IoUtils;
146  
147  import org.json.JSONException;
148  import org.json.JSONObject;
149  import org.xmlpull.v1.XmlPullParser;
150  import org.xmlpull.v1.XmlPullParserException;
151  import org.xmlpull.v1.XmlSerializer;
152  
153  import java.io.ByteArrayInputStream;
154  import java.io.ByteArrayOutputStream;
155  import java.io.File;
156  import java.io.FileDescriptor;
157  import java.io.FileInputStream;
158  import java.io.FileNotFoundException;
159  import java.io.FileOutputStream;
160  import java.io.IOException;
161  import java.io.InputStream;
162  import java.io.OutputStream;
163  import java.io.PrintWriter;
164  import java.nio.charset.StandardCharsets;
165  import java.util.ArrayDeque;
166  import java.util.ArrayList;
167  import java.util.Arrays;
168  import java.util.Iterator;
169  import java.util.List;
170  import java.util.Map;
171  import java.util.Map.Entry;
172  import java.util.Set;
173  import java.util.concurrent.TimeUnit;
174  
175  /** {@hide} */
176  public class NotificationManagerService extends SystemService {
177      static final String TAG = "NotificationService";
178      static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
179      public static final boolean ENABLE_CHILD_NOTIFICATIONS
180              = SystemProperties.getBoolean("debug.child_notifs", true);
181  
182      static final int MAX_PACKAGE_NOTIFICATIONS = 50;
183      static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
184  
185      // message codes
186      static final int MESSAGE_TIMEOUT = 2;
187      static final int MESSAGE_SAVE_POLICY_FILE = 3;
188      static final int MESSAGE_SEND_RANKING_UPDATE = 4;
189      static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
190      static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
191  
192      // ranking thread messages
193      private static final int MESSAGE_RECONSIDER_RANKING = 1000;
194      private static final int MESSAGE_RANKING_SORT = 1001;
195  
196      static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
197      static final int SHORT_DELAY = 2000; // 2 seconds
198  
199      static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
200  
201      static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
202  
203      static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
204  
205      static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
206      static final boolean ENABLE_BLOCKED_TOASTS = true;
207  
208      // When #matchesCallFilter is called from the ringer, wait at most
209      // 3s to resolve the contacts. This timeout is required since
210      // ContactsProvider might take a long time to start up.
211      //
212      // Return STARRED_CONTACT when the timeout is hit in order to avoid
213      // missed calls in ZEN mode "Important".
214      static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
215      static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
216              ValidateNotificationPeople.STARRED_CONTACT;
217  
218      /** notification_enqueue status value for a newly enqueued notification. */
219      private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
220  
221      /** notification_enqueue status value for an existing notification. */
222      private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
223  
224      /** notification_enqueue status value for an ignored notification. */
225      private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
226      private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
227      private String mRankerServicePackageName;
228  
229      private IActivityManager mAm;
230      AudioManager mAudioManager;
231      AudioManagerInternal mAudioManagerInternal;
232      @Nullable StatusBarManagerInternal mStatusBar;
233      Vibrator mVibrator;
234      private WindowManagerInternal mWindowManagerInternal;
235  
236      final IBinder mForegroundToken = new Binder();
237      private Handler mHandler;
238      private final HandlerThread mRankingThread = new HandlerThread("ranker",
239              Process.THREAD_PRIORITY_BACKGROUND);
240  
241      private Light mNotificationLight;
242      Light mAttentionLight;
243      private int mDefaultNotificationColor;
244      private int mDefaultNotificationLedOn;
245  
246      private int mDefaultNotificationLedOff;
247      private long[] mDefaultVibrationPattern;
248  
249      private long[] mFallbackVibrationPattern;
250      private boolean mUseAttentionLight;
251      boolean mSystemReady;
252  
253      private boolean mDisableNotificationEffects;
254      private int mCallState;
255      private String mSoundNotificationKey;
256      private String mVibrateNotificationKey;
257  
258      private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
259              new SparseArray<ArraySet<ManagedServiceInfo>>();
260      private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
261      private int mListenerHints;  // right now, all hints are global
262      private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
263  
264      // for enabling and disabling notification pulse behavior
265      private boolean mScreenOn = true;
266      private boolean mInCall = false;
267      private boolean mNotificationPulseEnabled;
268  
269      // used as a mutex for access to all active notifications & listeners
270      final ArrayList<NotificationRecord> mNotificationList =
271              new ArrayList<NotificationRecord>();
272      final ArrayMap<String, NotificationRecord> mNotificationsByKey =
273              new ArrayMap<String, NotificationRecord>();
274      final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
275      final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
276      final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
277      final PolicyAccess mPolicyAccess = new PolicyAccess();
278  
279      // The last key in this list owns the hardware.
280      ArrayList<String> mLights = new ArrayList<>();
281  
282      private AppOpsManager mAppOps;
283      private UsageStatsManagerInternal mAppUsageStats;
284  
285      private Archive mArchive;
286  
287      // Persistent storage for notification policy
288      private AtomicFile mPolicyFile;
289  
290      private static final int DB_VERSION = 1;
291  
292      private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
293      private static final String ATTR_VERSION = "version";
294  
295      private RankingHelper mRankingHelper;
296  
297      private final UserProfiles mUserProfiles = new UserProfiles();
298      private NotificationListeners mListeners;
299      private NotificationRankers mRankerServices;
300      private ConditionProviders mConditionProviders;
301      private NotificationUsageStats mUsageStats;
302  
303      private static final int MY_UID = Process.myUid();
304      private static final int MY_PID = Process.myPid();
305      private RankingHandler mRankingHandler;
306      private long mLastOverRateLogTime;
307      private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
308      private String mSystemNotificationSound;
309  
310      private static class Archive {
311          final int mBufferSize;
312          final ArrayDeque<StatusBarNotification> mBuffer;
313  
Archive(int size)314          public Archive(int size) {
315              mBufferSize = size;
316              mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
317          }
318  
toString()319          public String toString() {
320              final StringBuilder sb = new StringBuilder();
321              final int N = mBuffer.size();
322              sb.append("Archive (");
323              sb.append(N);
324              sb.append(" notification");
325              sb.append((N==1)?")":"s)");
326              return sb.toString();
327          }
328  
record(StatusBarNotification nr)329          public void record(StatusBarNotification nr) {
330              if (mBuffer.size() == mBufferSize) {
331                  mBuffer.removeFirst();
332              }
333  
334              // We don't want to store the heavy bits of the notification in the archive,
335              // but other clients in the system process might be using the object, so we
336              // store a (lightened) copy.
337              mBuffer.addLast(nr.cloneLight());
338          }
339  
descendingIterator()340          public Iterator<StatusBarNotification> descendingIterator() {
341              return mBuffer.descendingIterator();
342          }
343  
getArray(int count)344          public StatusBarNotification[] getArray(int count) {
345              if (count == 0) count = mBufferSize;
346              final StatusBarNotification[] a
347                      = new StatusBarNotification[Math.min(count, mBuffer.size())];
348              Iterator<StatusBarNotification> iter = descendingIterator();
349              int i=0;
350              while (iter.hasNext() && i < count) {
351                  a[i++] = iter.next();
352              }
353              return a;
354          }
355  
356      }
357  
readPolicyXml(InputStream stream, boolean forRestore)358      private void readPolicyXml(InputStream stream, boolean forRestore)
359              throws XmlPullParserException, NumberFormatException, IOException {
360          final XmlPullParser parser = Xml.newPullParser();
361          parser.setInput(stream, StandardCharsets.UTF_8.name());
362  
363          while (parser.next() != END_DOCUMENT) {
364              mZenModeHelper.readXml(parser, forRestore);
365              mRankingHelper.readXml(parser, forRestore);
366          }
367      }
368  
loadPolicyFile()369      private void loadPolicyFile() {
370          if (DBG) Slog.d(TAG, "loadPolicyFile");
371          synchronized(mPolicyFile) {
372  
373              FileInputStream infile = null;
374              try {
375                  infile = mPolicyFile.openRead();
376                  readPolicyXml(infile, false /*forRestore*/);
377              } catch (FileNotFoundException e) {
378                  // No data yet
379              } catch (IOException e) {
380                  Log.wtf(TAG, "Unable to read notification policy", e);
381              } catch (NumberFormatException e) {
382                  Log.wtf(TAG, "Unable to parse notification policy", e);
383              } catch (XmlPullParserException e) {
384                  Log.wtf(TAG, "Unable to parse notification policy", e);
385              } finally {
386                  IoUtils.closeQuietly(infile);
387              }
388          }
389      }
390  
savePolicyFile()391      public void savePolicyFile() {
392          mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
393          mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
394      }
395  
handleSavePolicyFile()396      private void handleSavePolicyFile() {
397          if (DBG) Slog.d(TAG, "handleSavePolicyFile");
398          synchronized (mPolicyFile) {
399              final FileOutputStream stream;
400              try {
401                  stream = mPolicyFile.startWrite();
402              } catch (IOException e) {
403                  Slog.w(TAG, "Failed to save policy file", e);
404                  return;
405              }
406  
407              try {
408                  writePolicyXml(stream, false /*forBackup*/);
409                  mPolicyFile.finishWrite(stream);
410              } catch (IOException e) {
411                  Slog.w(TAG, "Failed to save policy file, restoring backup", e);
412                  mPolicyFile.failWrite(stream);
413              }
414          }
415          BackupManager.dataChanged(getContext().getPackageName());
416      }
417  
writePolicyXml(OutputStream stream, boolean forBackup)418      private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
419          final XmlSerializer out = new FastXmlSerializer();
420          out.setOutput(stream, StandardCharsets.UTF_8.name());
421          out.startDocument(null, true);
422          out.startTag(null, TAG_NOTIFICATION_POLICY);
423          out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
424          mZenModeHelper.writeXml(out, forBackup);
425          mRankingHelper.writeXml(out, forBackup);
426          out.endTag(null, TAG_NOTIFICATION_POLICY);
427          out.endDocument();
428      }
429  
430      /** Use this when you actually want to post a notification or toast.
431       *
432       * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
433       */
noteNotificationOp(String pkg, int uid)434      private boolean noteNotificationOp(String pkg, int uid) {
435          if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
436                  != AppOpsManager.MODE_ALLOWED) {
437              Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
438              return false;
439          }
440          return true;
441      }
442  
443      /** Use this to check if a package can post a notification or toast. */
checkNotificationOp(String pkg, int uid)444      private boolean checkNotificationOp(String pkg, int uid) {
445          return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
446                  == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
447      }
448  
449      private static final class ToastRecord
450      {
451          final int pid;
452          final String pkg;
453          final ITransientNotification callback;
454          int duration;
455          Binder token;
456  
ToastRecord(int pid, String pkg, ITransientNotification callback, int duration, Binder token)457          ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
458                      Binder token) {
459              this.pid = pid;
460              this.pkg = pkg;
461              this.callback = callback;
462              this.duration = duration;
463              this.token = token;
464          }
465  
update(int duration)466          void update(int duration) {
467              this.duration = duration;
468          }
469  
dump(PrintWriter pw, String prefix, DumpFilter filter)470          void dump(PrintWriter pw, String prefix, DumpFilter filter) {
471              if (filter != null && !filter.matches(pkg)) return;
472              pw.println(prefix + this);
473          }
474  
475          @Override
toString()476          public final String toString()
477          {
478              return "ToastRecord{"
479                  + Integer.toHexString(System.identityHashCode(this))
480                  + " pkg=" + pkg
481                  + " callback=" + callback
482                  + " duration=" + duration;
483          }
484      }
485  
486      private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
487  
488          @Override
489          public void onSetDisabled(int status) {
490              synchronized (mNotificationList) {
491                  mDisableNotificationEffects =
492                          (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
493                  if (disableNotificationEffects(null) != null) {
494                      // cancel whatever's going on
495                      long identity = Binder.clearCallingIdentity();
496                      try {
497                          final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
498                          if (player != null) {
499                              player.stopAsync();
500                          }
501                      } catch (RemoteException e) {
502                      } finally {
503                          Binder.restoreCallingIdentity(identity);
504                      }
505  
506                      identity = Binder.clearCallingIdentity();
507                      try {
508                          mVibrator.cancel();
509                      } finally {
510                          Binder.restoreCallingIdentity(identity);
511                      }
512                  }
513              }
514          }
515  
516          @Override
517          public void onClearAll(int callingUid, int callingPid, int userId) {
518              synchronized (mNotificationList) {
519                  cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
520                          /*includeCurrentProfiles*/ true);
521              }
522          }
523  
524          @Override
525          public void onNotificationClick(int callingUid, int callingPid, String key) {
526              synchronized (mNotificationList) {
527                  NotificationRecord r = mNotificationsByKey.get(key);
528                  if (r == null) {
529                      Log.w(TAG, "No notification with key: " + key);
530                      return;
531                  }
532                  final long now = System.currentTimeMillis();
533                  EventLogTags.writeNotificationClicked(key,
534                          r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
535  
536                  StatusBarNotification sbn = r.sbn;
537                  cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
538                          sbn.getId(), Notification.FLAG_AUTO_CANCEL,
539                          Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
540                          REASON_DELEGATE_CLICK, null);
541              }
542          }
543  
544          @Override
545          public void onNotificationActionClick(int callingUid, int callingPid, String key,
546                  int actionIndex) {
547              synchronized (mNotificationList) {
548                  NotificationRecord r = mNotificationsByKey.get(key);
549                  if (r == null) {
550                      Log.w(TAG, "No notification with key: " + key);
551                      return;
552                  }
553                  final long now = System.currentTimeMillis();
554                  EventLogTags.writeNotificationActionClicked(key, actionIndex,
555                          r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
556                  // TODO: Log action click via UsageStats.
557              }
558          }
559  
560          @Override
561          public void onNotificationClear(int callingUid, int callingPid,
562                  String pkg, String tag, int id, int userId) {
563              cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
564                      Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
565                      true, userId, REASON_DELEGATE_CANCEL, null);
566          }
567  
568          @Override
569          public void onPanelRevealed(boolean clearEffects, int items) {
570              EventLogTags.writeNotificationPanelRevealed(items);
571              if (clearEffects) {
572                  clearEffects();
573              }
574          }
575  
576          @Override
577          public void onPanelHidden() {
578              EventLogTags.writeNotificationPanelHidden();
579          }
580  
581          @Override
582          public void clearEffects() {
583              synchronized (mNotificationList) {
584                  if (DBG) Slog.d(TAG, "clearEffects");
585                  clearSoundLocked();
586                  clearVibrateLocked();
587                  clearLightsLocked();
588              }
589          }
590  
591          @Override
592          public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
593                  int uid, int initialPid, String message, int userId) {
594              Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
595                      + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
596              cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
597                      REASON_DELEGATE_ERROR, null);
598              long ident = Binder.clearCallingIdentity();
599              try {
600                  ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
601                          "Bad notification posted from package " + pkg
602                          + ": " + message);
603              } catch (RemoteException e) {
604              }
605              Binder.restoreCallingIdentity(ident);
606          }
607  
608          @Override
609          public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
610                  NotificationVisibility[] noLongerVisibleKeys) {
611              synchronized (mNotificationList) {
612                  for (NotificationVisibility nv : newlyVisibleKeys) {
613                      NotificationRecord r = mNotificationsByKey.get(nv.key);
614                      if (r == null) continue;
615                      r.setVisibility(true, nv.rank);
616                      nv.recycle();
617                  }
618                  // Note that we might receive this event after notifications
619                  // have already left the system, e.g. after dismissing from the
620                  // shade. Hence not finding notifications in
621                  // mNotificationsByKey is not an exceptional condition.
622                  for (NotificationVisibility nv : noLongerVisibleKeys) {
623                      NotificationRecord r = mNotificationsByKey.get(nv.key);
624                      if (r == null) continue;
625                      r.setVisibility(false, nv.rank);
626                      nv.recycle();
627                  }
628              }
629          }
630  
631          @Override
632          public void onNotificationExpansionChanged(String key,
633                  boolean userAction, boolean expanded) {
634              synchronized (mNotificationList) {
635                  NotificationRecord r = mNotificationsByKey.get(key);
636                  if (r != null) {
637                      r.stats.onExpansionChanged(userAction, expanded);
638                      final long now = System.currentTimeMillis();
639                      EventLogTags.writeNotificationExpansion(key,
640                              userAction ? 1 : 0, expanded ? 1 : 0,
641                              r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
642                  }
643              }
644          }
645      };
646  
clearSoundLocked()647      private void clearSoundLocked() {
648          mSoundNotificationKey = null;
649          long identity = Binder.clearCallingIdentity();
650          try {
651              final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
652              if (player != null) {
653                  player.stopAsync();
654              }
655          } catch (RemoteException e) {
656          } finally {
657              Binder.restoreCallingIdentity(identity);
658          }
659      }
660  
clearVibrateLocked()661      private void clearVibrateLocked() {
662          mVibrateNotificationKey = null;
663          long identity = Binder.clearCallingIdentity();
664          try {
665              mVibrator.cancel();
666          } finally {
667              Binder.restoreCallingIdentity(identity);
668          }
669      }
670  
clearLightsLocked()671      private void clearLightsLocked() {
672          // light
673          mLights.clear();
674          updateLightsLocked();
675      }
676  
677      private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
678          @Override
679          public void onReceive(Context context, Intent intent) {
680              String action = intent.getAction();
681              if (action == null) {
682                  return;
683              }
684  
685              boolean queryRestart = false;
686              boolean queryRemove = false;
687              boolean packageChanged = false;
688              boolean cancelNotifications = true;
689              int reason = REASON_PACKAGE_CHANGED;
690  
691              if (action.equals(Intent.ACTION_PACKAGE_ADDED)
692                      || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
693                      || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
694                      || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
695                      || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
696                      || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
697                      || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
698                  int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
699                          UserHandle.USER_ALL);
700                  String pkgList[] = null;
701                  boolean removingPackage = queryRemove &&
702                          !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
703                  if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
704                  if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
705                      pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
706                  } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
707                      pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
708                      reason = REASON_PACKAGE_SUSPENDED;
709                  } else if (queryRestart) {
710                      pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
711                  } else {
712                      Uri uri = intent.getData();
713                      if (uri == null) {
714                          return;
715                      }
716                      String pkgName = uri.getSchemeSpecificPart();
717                      if (pkgName == null) {
718                          return;
719                      }
720                      if (packageChanged) {
721                          // We cancel notifications for packages which have just been disabled
722                          try {
723                              final IPackageManager pm = AppGlobals.getPackageManager();
724                              final int enabled = pm.getApplicationEnabledSetting(pkgName,
725                                      changeUserId != UserHandle.USER_ALL ? changeUserId :
726                                      UserHandle.USER_SYSTEM);
727                              if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
728                                      || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
729                                  cancelNotifications = false;
730                              }
731                          } catch (IllegalArgumentException e) {
732                              // Package doesn't exist; probably racing with uninstall.
733                              // cancelNotifications is already true, so nothing to do here.
734                              if (DBG) {
735                                  Slog.i(TAG, "Exception trying to look up app enabled setting", e);
736                              }
737                          } catch (RemoteException e) {
738                              // Failed to talk to PackageManagerService Should never happen!
739                          }
740                      }
741                      pkgList = new String[]{pkgName};
742                  }
743  
744                  if (pkgList != null && (pkgList.length > 0)) {
745                      for (String pkgName : pkgList) {
746                          if (cancelNotifications) {
747                              cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
748                                      changeUserId, reason, null);
749                          }
750                      }
751                  }
752                  mListeners.onPackagesChanged(removingPackage, pkgList);
753                  mRankerServices.onPackagesChanged(removingPackage, pkgList);
754                  mConditionProviders.onPackagesChanged(removingPackage, pkgList);
755                  mRankingHelper.onPackagesChanged(removingPackage, pkgList);
756              }
757          }
758      };
759  
760      private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
761          @Override
762          public void onReceive(Context context, Intent intent) {
763              String action = intent.getAction();
764  
765              if (action.equals(Intent.ACTION_SCREEN_ON)) {
766                  // Keep track of screen on/off state, but do not turn off the notification light
767                  // until user passes through the lock screen or views the notification.
768                  mScreenOn = true;
769                  updateNotificationPulse();
770              } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
771                  mScreenOn = false;
772                  updateNotificationPulse();
773              } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
774                  mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
775                          .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
776                  updateNotificationPulse();
777              } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
778                  int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
779                  if (userHandle >= 0) {
780                      cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
781                              REASON_USER_STOPPED, null);
782                  }
783              } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
784                  int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
785                  if (userHandle >= 0) {
786                      cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
787                              REASON_PROFILE_TURNED_OFF, null);
788                  }
789              } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
790                  // turn off LED when user passes through lock screen
791                  mNotificationLight.turnOff();
792                  if (mStatusBar != null) {
793                      mStatusBar.notificationLightOff();
794                  }
795              } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
796                  final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
797                  // reload per-user settings
798                  mSettingsObserver.update(null);
799                  mUserProfiles.updateCache(context);
800                  // Refresh managed services
801                  mConditionProviders.onUserSwitched(user);
802                  mListeners.onUserSwitched(user);
803                  mRankerServices.onUserSwitched(user);
804                  mZenModeHelper.onUserSwitched(user);
805              } else if (action.equals(Intent.ACTION_USER_ADDED)) {
806                  mUserProfiles.updateCache(context);
807              } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
808                  final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
809                  mZenModeHelper.onUserRemoved(user);
810              } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
811                  final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
812                  mConditionProviders.onUserUnlocked(user);
813                  mListeners.onUserUnlocked(user);
814                  mRankerServices.onUserUnlocked(user);
815                  mZenModeHelper.onUserUnlocked(user);
816              }
817          }
818      };
819  
820      private final class SettingsObserver extends ContentObserver {
821          private final Uri NOTIFICATION_LIGHT_PULSE_URI
822                  = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
823          private final Uri NOTIFICATION_SOUND_URI
824                  = Settings.System.getUriFor(Settings.System.NOTIFICATION_SOUND);
825          private final Uri NOTIFICATION_RATE_LIMIT_URI
826                  = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
827  
SettingsObserver(Handler handler)828          SettingsObserver(Handler handler) {
829              super(handler);
830          }
831  
observe()832          void observe() {
833              ContentResolver resolver = getContext().getContentResolver();
834              resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
835                      false, this, UserHandle.USER_ALL);
836              resolver.registerContentObserver(NOTIFICATION_SOUND_URI,
837                      false, this, UserHandle.USER_ALL);
838              resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
839                      false, this, UserHandle.USER_ALL);
840              update(null);
841          }
842  
onChange(boolean selfChange, Uri uri)843          @Override public void onChange(boolean selfChange, Uri uri) {
844              update(uri);
845          }
846  
update(Uri uri)847          public void update(Uri uri) {
848              ContentResolver resolver = getContext().getContentResolver();
849              if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
850                  boolean pulseEnabled = Settings.System.getInt(resolver,
851                              Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
852                  if (mNotificationPulseEnabled != pulseEnabled) {
853                      mNotificationPulseEnabled = pulseEnabled;
854                      updateNotificationPulse();
855                  }
856              }
857              if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
858                  mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
859                              Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
860              }
861              if (uri == null || NOTIFICATION_SOUND_URI.equals(uri)) {
862                  mSystemNotificationSound = Settings.System.getString(resolver,
863                          Settings.System.NOTIFICATION_SOUND);
864              }
865          }
866      }
867  
868      private SettingsObserver mSettingsObserver;
869      private ZenModeHelper mZenModeHelper;
870  
871      private final Runnable mBuzzBeepBlinked = new Runnable() {
872          @Override
873          public void run() {
874              if (mStatusBar != null) {
875                  mStatusBar.buzzBeepBlinked();
876              }
877          }
878      };
879  
getLongArray(Resources r, int resid, int maxlen, long[] def)880      static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
881          int[] ar = r.getIntArray(resid);
882          if (ar == null) {
883              return def;
884          }
885          final int len = ar.length > maxlen ? maxlen : ar.length;
886          long[] out = new long[len];
887          for (int i=0; i<len; i++) {
888              out[i] = ar[i];
889          }
890          return out;
891      }
892  
NotificationManagerService(Context context)893      public NotificationManagerService(Context context) {
894          super(context);
895      }
896  
897      @VisibleForTesting
setAudioManager(AudioManager audioMananger)898      void setAudioManager(AudioManager audioMananger) {
899          mAudioManager = audioMananger;
900      }
901  
902      @VisibleForTesting
setVibrator(Vibrator vibrator)903      void setVibrator(Vibrator vibrator) {
904          mVibrator = vibrator;
905      }
906  
907      @VisibleForTesting
setSystemReady(boolean systemReady)908      void setSystemReady(boolean systemReady) {
909          mSystemReady = systemReady;
910      }
911  
912      @VisibleForTesting
setHandler(Handler handler)913      void setHandler(Handler handler) {
914          mHandler = handler;
915      }
916  
917      @VisibleForTesting
setSystemNotificationSound(String systemNotificationSound)918      void setSystemNotificationSound(String systemNotificationSound) {
919          mSystemNotificationSound = systemNotificationSound;
920      }
921  
922      @Override
onStart()923      public void onStart() {
924          Resources resources = getContext().getResources();
925  
926          mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
927                  Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
928                  DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
929  
930          mAm = ActivityManagerNative.getDefault();
931          mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
932          mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
933          mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
934  
935          // This is the package that contains the AOSP framework update.
936          mRankerServicePackageName = getContext().getPackageManager()
937                  .getServicesSystemSharedLibraryPackageName();
938  
939          mHandler = new WorkerHandler();
940          mRankingThread.start();
941          String[] extractorNames;
942          try {
943              extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
944          } catch (Resources.NotFoundException e) {
945              extractorNames = new String[0];
946          }
947          mUsageStats = new NotificationUsageStats(getContext());
948          mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
949          mRankingHelper = new RankingHelper(getContext(),
950                  mRankingHandler,
951                  mUsageStats,
952                  extractorNames);
953          mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
954          mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
955          mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
956              @Override
957              public void onConfigChanged() {
958                  savePolicyFile();
959              }
960  
961              @Override
962              void onZenModeChanged() {
963                  sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
964                  getContext().sendBroadcastAsUser(
965                          new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
966                                  .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
967                          UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
968                  synchronized(mNotificationList) {
969                      updateInterruptionFilterLocked();
970                  }
971              }
972  
973              @Override
974              void onPolicyChanged() {
975                  sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
976              }
977          });
978          final File systemDir = new File(Environment.getDataDirectory(), "system");
979          mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
980  
981          syncBlockDb();
982  
983          // This is a MangedServices object that keeps track of the listeners.
984          mListeners = new NotificationListeners();
985  
986          // This is a MangedServices object that keeps track of the ranker.
987          mRankerServices = new NotificationRankers();
988          // Find the updatable ranker and register it.
989          mRankerServices.registerRanker();
990  
991          mStatusBar = getLocalService(StatusBarManagerInternal.class);
992          if (mStatusBar != null) {
993              mStatusBar.setNotificationDelegate(mNotificationDelegate);
994          }
995  
996          final LightsManager lights = getLocalService(LightsManager.class);
997          mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
998          mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
999  
1000          mDefaultNotificationColor = resources.getColor(
1001                  R.color.config_defaultNotificationColor);
1002          mDefaultNotificationLedOn = resources.getInteger(
1003                  R.integer.config_defaultNotificationLedOn);
1004          mDefaultNotificationLedOff = resources.getInteger(
1005                  R.integer.config_defaultNotificationLedOff);
1006  
1007          mDefaultVibrationPattern = getLongArray(resources,
1008                  R.array.config_defaultNotificationVibePattern,
1009                  VIBRATE_PATTERN_MAXLEN,
1010                  DEFAULT_VIBRATE_PATTERN);
1011  
1012          mFallbackVibrationPattern = getLongArray(resources,
1013                  R.array.config_notificationFallbackVibePattern,
1014                  VIBRATE_PATTERN_MAXLEN,
1015                  DEFAULT_VIBRATE_PATTERN);
1016  
1017          mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1018  
1019          // Don't start allowing notifications until the setup wizard has run once.
1020          // After that, including subsequent boots, init with notifications turned on.
1021          // This works on the first boot because the setup wizard will toggle this
1022          // flag at least once and we'll go back to 0 after that.
1023          if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1024                      Settings.Global.DEVICE_PROVISIONED, 0)) {
1025              mDisableNotificationEffects = true;
1026          }
1027          mZenModeHelper.initZenMode();
1028          mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1029  
1030          mUserProfiles.updateCache(getContext());
1031          listenForCallState();
1032  
1033          // register for various Intents
1034          IntentFilter filter = new IntentFilter();
1035          filter.addAction(Intent.ACTION_SCREEN_ON);
1036          filter.addAction(Intent.ACTION_SCREEN_OFF);
1037          filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1038          filter.addAction(Intent.ACTION_USER_PRESENT);
1039          filter.addAction(Intent.ACTION_USER_STOPPED);
1040          filter.addAction(Intent.ACTION_USER_SWITCHED);
1041          filter.addAction(Intent.ACTION_USER_ADDED);
1042          filter.addAction(Intent.ACTION_USER_REMOVED);
1043          filter.addAction(Intent.ACTION_USER_UNLOCKED);
1044          filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1045          getContext().registerReceiver(mIntentReceiver, filter);
1046  
1047          IntentFilter pkgFilter = new IntentFilter();
1048          pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1049          pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1050          pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1051          pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1052          pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1053          pkgFilter.addDataScheme("package");
1054          getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1055                  null);
1056  
1057          IntentFilter suspendedPkgFilter = new IntentFilter();
1058          suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1059          getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1060                  suspendedPkgFilter, null, null);
1061  
1062          IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1063          getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1064                  null);
1065  
1066          mSettingsObserver = new SettingsObserver(mHandler);
1067  
1068          mArchive = new Archive(resources.getInteger(
1069                  R.integer.config_notificationServiceArchiveSize));
1070  
1071          publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1072          publishLocalService(NotificationManagerInternal.class, mInternalService);
1073      }
1074  
sendRegisteredOnlyBroadcast(String action)1075      private void sendRegisteredOnlyBroadcast(String action) {
1076          getContext().sendBroadcastAsUser(new Intent(action)
1077                  .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1078      }
1079  
1080      /**
1081       * Make sure the XML config and the the AppOps system agree about blocks.
1082       */
syncBlockDb()1083      private void syncBlockDb() {
1084          loadPolicyFile();
1085  
1086          // sync bans from ranker into app opps
1087          Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1088          for(Entry<Integer, String> ban : packageBans.entrySet()) {
1089              final int uid = ban.getKey();
1090              final String packageName = ban.getValue();
1091              setNotificationsEnabledForPackageImpl(packageName, uid, false);
1092          }
1093  
1094          // sync bans from app opps into ranker
1095          packageBans.clear();
1096          for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1097              final int userId = user.getUserHandle().getIdentifier();
1098              final PackageManager packageManager = getContext().getPackageManager();
1099              List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1100              final int packageCount = packages.size();
1101              for (int p = 0; p < packageCount; p++) {
1102                  final String packageName = packages.get(p).packageName;
1103                  try {
1104                      final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1105                      if (!checkNotificationOp(packageName, uid)) {
1106                          packageBans.put(uid, packageName);
1107                      }
1108                  } catch (NameNotFoundException e) {
1109                      // forget you
1110                  }
1111              }
1112          }
1113          for (Entry<Integer, String> ban : packageBans.entrySet()) {
1114              mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1115          }
1116  
1117          savePolicyFile();
1118      }
1119  
1120      @Override
onBootPhase(int phase)1121      public void onBootPhase(int phase) {
1122          if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1123              // no beeping until we're basically done booting
1124              mSystemReady = true;
1125  
1126              // Grab our optional AudioService
1127              mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1128              mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1129              mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1130              mZenModeHelper.onSystemReady();
1131          } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1132              // This observer will force an update when observe is called, causing us to
1133              // bind to listener services.
1134              mSettingsObserver.observe();
1135              mListeners.onBootPhaseAppsCanStart();
1136              mRankerServices.onBootPhaseAppsCanStart();
1137              mConditionProviders.onBootPhaseAppsCanStart();
1138          }
1139      }
1140  
setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled)1141      void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1142          Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1143  
1144          mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1145                  enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1146  
1147          // Now, cancel any outstanding notifications that are part of a just-disabled app
1148          if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1149              cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1150                      REASON_PACKAGE_BANNED, null);
1151          }
1152      }
1153  
updateListenerHintsLocked()1154      private void updateListenerHintsLocked() {
1155          final int hints = calculateHints();
1156          if (hints == mListenerHints) return;
1157          ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1158          mListenerHints = hints;
1159          scheduleListenerHintsChanged(hints);
1160      }
1161  
updateEffectsSuppressorLocked()1162      private void updateEffectsSuppressorLocked() {
1163          final long updatedSuppressedEffects = calculateSuppressedEffects();
1164          if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1165          final List<ComponentName> suppressors = getSuppressors();
1166          ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1167          mEffectsSuppressors = suppressors;
1168          mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1169          sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1170      }
1171  
getSuppressors()1172      private ArrayList<ComponentName> getSuppressors() {
1173          ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1174          for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1175              ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1176  
1177              for (ManagedServiceInfo info : serviceInfoList) {
1178                  names.add(info.component);
1179              }
1180          }
1181  
1182          return names;
1183      }
1184  
removeDisabledHints(ManagedServiceInfo info)1185      private boolean removeDisabledHints(ManagedServiceInfo info) {
1186          return removeDisabledHints(info, 0);
1187      }
1188  
removeDisabledHints(ManagedServiceInfo info, int hints)1189      private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1190          boolean removed = false;
1191  
1192          for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1193              final int hint = mListenersDisablingEffects.keyAt(i);
1194              final ArraySet<ManagedServiceInfo> listeners =
1195                      mListenersDisablingEffects.valueAt(i);
1196  
1197              if (hints == 0 || (hint & hints) == hint) {
1198                  removed = removed || listeners.remove(info);
1199              }
1200          }
1201  
1202          return removed;
1203      }
1204  
addDisabledHints(ManagedServiceInfo info, int hints)1205      private void addDisabledHints(ManagedServiceInfo info, int hints) {
1206          if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1207              addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1208          }
1209  
1210          if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1211              addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1212          }
1213  
1214          if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1215              addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1216          }
1217      }
1218  
addDisabledHint(ManagedServiceInfo info, int hint)1219      private void addDisabledHint(ManagedServiceInfo info, int hint) {
1220          if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1221              mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1222          }
1223  
1224          ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1225          hintListeners.add(info);
1226      }
1227  
calculateHints()1228      private int calculateHints() {
1229          int hints = 0;
1230          for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1231              int hint = mListenersDisablingEffects.keyAt(i);
1232              ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1233  
1234              if (!serviceInfoList.isEmpty()) {
1235                  hints |= hint;
1236              }
1237          }
1238  
1239          return hints;
1240      }
1241  
calculateSuppressedEffects()1242      private long calculateSuppressedEffects() {
1243          int hints = calculateHints();
1244          long suppressedEffects = 0;
1245  
1246          if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1247              suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1248          }
1249  
1250          if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1251              suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1252          }
1253  
1254          if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1255              suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1256          }
1257  
1258          return suppressedEffects;
1259      }
1260  
updateInterruptionFilterLocked()1261      private void updateInterruptionFilterLocked() {
1262          int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1263          if (interruptionFilter == mInterruptionFilter) return;
1264          mInterruptionFilter = interruptionFilter;
1265          scheduleInterruptionFilterChanged(interruptionFilter);
1266      }
1267  
1268      private final IBinder mService = new INotificationManager.Stub() {
1269          // Toasts
1270          // ============================================================================
1271  
1272          @Override
1273          public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1274          {
1275              if (DBG) {
1276                  Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1277                          + " duration=" + duration);
1278              }
1279  
1280              if (pkg == null || callback == null) {
1281                  Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1282                  return ;
1283              }
1284  
1285              final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1286              final boolean isPackageSuspended =
1287                      isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1288  
1289              if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1290                      || isPackageSuspended)) {
1291                  if (!isSystemToast) {
1292                      Slog.e(TAG, "Suppressing toast from package " + pkg
1293                              + (isPackageSuspended
1294                                      ? " due to package suspended by administrator."
1295                                      : " by user request."));
1296                      return;
1297                  }
1298              }
1299  
1300              synchronized (mToastQueue) {
1301                  int callingPid = Binder.getCallingPid();
1302                  long callingId = Binder.clearCallingIdentity();
1303                  try {
1304                      ToastRecord record;
1305                      int index = indexOfToastLocked(pkg, callback);
1306                      // If it's already in the queue, we update it in place, we don't
1307                      // move it to the end of the queue.
1308                      if (index >= 0) {
1309                          record = mToastQueue.get(index);
1310                          record.update(duration);
1311                      } else {
1312                          // Limit the number of toasts that any given package except the android
1313                          // package can enqueue.  Prevents DOS attacks and deals with leaks.
1314                          if (!isSystemToast) {
1315                              int count = 0;
1316                              final int N = mToastQueue.size();
1317                              for (int i=0; i<N; i++) {
1318                                   final ToastRecord r = mToastQueue.get(i);
1319                                   if (r.pkg.equals(pkg)) {
1320                                       count++;
1321                                       if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1322                                           Slog.e(TAG, "Package has already posted " + count
1323                                                  + " toasts. Not showing more. Package=" + pkg);
1324                                           return;
1325                                       }
1326                                   }
1327                              }
1328                          }
1329  
1330                          Binder token = new Binder();
1331                          mWindowManagerInternal.addWindowToken(token,
1332                                  WindowManager.LayoutParams.TYPE_TOAST);
1333                          record = new ToastRecord(callingPid, pkg, callback, duration, token);
1334                          mToastQueue.add(record);
1335                          index = mToastQueue.size() - 1;
1336                          keepProcessAliveIfNeededLocked(callingPid);
1337                      }
1338                      // If it's at index 0, it's the current toast.  It doesn't matter if it's
1339                      // new or just been updated.  Call back and tell it to show itself.
1340                      // If the callback fails, this will remove it from the list, so don't
1341                      // assume that it's valid after this.
1342                      if (index == 0) {
1343                          showNextToastLocked();
1344                      }
1345                  } finally {
1346                      Binder.restoreCallingIdentity(callingId);
1347                  }
1348              }
1349          }
1350  
1351          @Override
1352          public void cancelToast(String pkg, ITransientNotification callback) {
1353              Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1354  
1355              if (pkg == null || callback == null) {
1356                  Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1357                  return ;
1358              }
1359  
1360              synchronized (mToastQueue) {
1361                  long callingId = Binder.clearCallingIdentity();
1362                  try {
1363                      int index = indexOfToastLocked(pkg, callback);
1364                      if (index >= 0) {
1365                          cancelToastLocked(index);
1366                      } else {
1367                          Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1368                                  + " callback=" + callback);
1369                      }
1370                  } finally {
1371                      Binder.restoreCallingIdentity(callingId);
1372                  }
1373              }
1374          }
1375  
1376          @Override
1377          public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1378                  Notification notification, int[] idOut, int userId) throws RemoteException {
1379              enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1380                      Binder.getCallingPid(), tag, id, notification, idOut, userId);
1381          }
1382  
1383          @Override
1384          public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1385              checkCallerIsSystemOrSameApp(pkg);
1386              userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1387                      Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1388              // Don't allow client applications to cancel foreground service notis or autobundled
1389              // summaries.
1390              cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1391                      (Binder.getCallingUid() == Process.SYSTEM_UID
1392                              ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1393                              | (Binder.getCallingUid() == Process.SYSTEM_UID
1394                              ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1395                      REASON_APP_CANCEL, null);
1396          }
1397  
1398          @Override
1399          public void cancelAllNotifications(String pkg, int userId) {
1400              checkCallerIsSystemOrSameApp(pkg);
1401  
1402              userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1403                      Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1404  
1405              // Calling from user space, don't allow the canceling of actively
1406              // running foreground services.
1407              cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1408                      pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1409                      REASON_APP_CANCEL_ALL, null);
1410          }
1411  
1412          @Override
1413          public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1414              checkCallerIsSystem();
1415  
1416              setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1417              mRankingHelper.setEnabled(pkg, uid, enabled);
1418              savePolicyFile();
1419          }
1420  
1421          /**
1422           * Use this when you just want to know if notifications are OK for this package.
1423           */
1424          @Override
1425          public boolean areNotificationsEnabled(String pkg) {
1426              return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1427          }
1428  
1429          /**
1430           * Use this when you just want to know if notifications are OK for this package.
1431           */
1432          @Override
1433          public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1434              checkCallerIsSystemOrSameApp(pkg);
1435              return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1436                      == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1437          }
1438  
1439          @Override
1440          public void setPriority(String pkg, int uid, int priority) {
1441              checkCallerIsSystem();
1442              mRankingHelper.setPriority(pkg, uid, priority);
1443              savePolicyFile();
1444          }
1445  
1446          @Override
1447          public int getPriority(String pkg, int uid) {
1448              checkCallerIsSystem();
1449              return mRankingHelper.getPriority(pkg, uid);
1450          }
1451  
1452          @Override
1453          public void setVisibilityOverride(String pkg, int uid, int visibility) {
1454              checkCallerIsSystem();
1455              mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1456              savePolicyFile();
1457          }
1458  
1459          @Override
1460          public int getVisibilityOverride(String pkg, int uid) {
1461              checkCallerIsSystem();
1462              return mRankingHelper.getVisibilityOverride(pkg, uid);
1463          }
1464  
1465          @Override
1466          public void setImportance(String pkg, int uid, int importance) {
1467              enforceSystemOrSystemUI("Caller not system or systemui");
1468              setNotificationsEnabledForPackageImpl(pkg, uid,
1469                      importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1470              mRankingHelper.setImportance(pkg, uid, importance);
1471              savePolicyFile();
1472          }
1473  
1474          @Override
1475          public int getPackageImportance(String pkg) {
1476              checkCallerIsSystemOrSameApp(pkg);
1477              return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1478          }
1479  
1480          @Override
1481          public int getImportance(String pkg, int uid) {
1482              enforceSystemOrSystemUI("Caller not system or systemui");
1483              return mRankingHelper.getImportance(pkg, uid);
1484          }
1485  
1486          /**
1487           * System-only API for getting a list of current (i.e. not cleared) notifications.
1488           *
1489           * Requires ACCESS_NOTIFICATIONS which is signature|system.
1490           * @returns A list of all the notifications, in natural order.
1491           */
1492          @Override
1493          public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1494              // enforce() will ensure the calling uid has the correct permission
1495              getContext().enforceCallingOrSelfPermission(
1496                      android.Manifest.permission.ACCESS_NOTIFICATIONS,
1497                      "NotificationManagerService.getActiveNotifications");
1498  
1499              StatusBarNotification[] tmp = null;
1500              int uid = Binder.getCallingUid();
1501  
1502              // noteOp will check to make sure the callingPkg matches the uid
1503              if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1504                      == AppOpsManager.MODE_ALLOWED) {
1505                  synchronized (mNotificationList) {
1506                      tmp = new StatusBarNotification[mNotificationList.size()];
1507                      final int N = mNotificationList.size();
1508                      for (int i=0; i<N; i++) {
1509                          tmp[i] = mNotificationList.get(i).sbn;
1510                      }
1511                  }
1512              }
1513              return tmp;
1514          }
1515  
1516          /**
1517           * Public API for getting a list of current notifications for the calling package/uid.
1518           *
1519           * @returns A list of all the package's notifications, in natural order.
1520           */
1521          @Override
1522          public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1523                  int incomingUserId) {
1524              checkCallerIsSystemOrSameApp(pkg);
1525              int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1526                      Binder.getCallingUid(), incomingUserId, true, false,
1527                      "getAppActiveNotifications", pkg);
1528  
1529              final ArrayList<StatusBarNotification> list
1530                      = new ArrayList<StatusBarNotification>(mNotificationList.size());
1531  
1532              synchronized (mNotificationList) {
1533                  final int N = mNotificationList.size();
1534                  for (int i = 0; i < N; i++) {
1535                      final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1536                      if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1537                              && (sbn.getNotification().flags
1538                              & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1539                          // We could pass back a cloneLight() but clients might get confused and
1540                          // try to send this thing back to notify() again, which would not work
1541                          // very well.
1542                          final StatusBarNotification sbnOut = new StatusBarNotification(
1543                                  sbn.getPackageName(),
1544                                  sbn.getOpPkg(),
1545                                  sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1546                                  0, // hide score from apps
1547                                  sbn.getNotification().clone(),
1548                                  sbn.getUser(), sbn.getPostTime());
1549                          list.add(sbnOut);
1550                      }
1551                  }
1552              }
1553  
1554              return new ParceledListSlice<StatusBarNotification>(list);
1555          }
1556  
1557          /**
1558           * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1559           *
1560           * Requires ACCESS_NOTIFICATIONS which is signature|system.
1561           */
1562          @Override
1563          public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1564              // enforce() will ensure the calling uid has the correct permission
1565              getContext().enforceCallingOrSelfPermission(
1566                      android.Manifest.permission.ACCESS_NOTIFICATIONS,
1567                      "NotificationManagerService.getHistoricalNotifications");
1568  
1569              StatusBarNotification[] tmp = null;
1570              int uid = Binder.getCallingUid();
1571  
1572              // noteOp will check to make sure the callingPkg matches the uid
1573              if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1574                      == AppOpsManager.MODE_ALLOWED) {
1575                  synchronized (mArchive) {
1576                      tmp = mArchive.getArray(count);
1577                  }
1578              }
1579              return tmp;
1580          }
1581  
1582          /**
1583           * Register a listener binder directly with the notification manager.
1584           *
1585           * Only works with system callers. Apps should extend
1586           * {@link android.service.notification.NotificationListenerService}.
1587           */
1588          @Override
1589          public void registerListener(final INotificationListener listener,
1590                  final ComponentName component, final int userid) {
1591              enforceSystemOrSystemUI("INotificationManager.registerListener");
1592              mListeners.registerService(listener, component, userid);
1593          }
1594  
1595          /**
1596           * Remove a listener binder directly
1597           */
1598          @Override
1599          public void unregisterListener(INotificationListener token, int userid) {
1600              mListeners.unregisterService(token, userid);
1601          }
1602  
1603          /**
1604           * Allow an INotificationListener to simulate a "clear all" operation.
1605           *
1606           * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1607           *
1608           * @param token The binder for the listener, to check that the caller is allowed
1609           */
1610          @Override
1611          public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1612              final int callingUid = Binder.getCallingUid();
1613              final int callingPid = Binder.getCallingPid();
1614              long identity = Binder.clearCallingIdentity();
1615              try {
1616                  synchronized (mNotificationList) {
1617                      final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1618                      if (keys != null) {
1619                          final int N = keys.length;
1620                          for (int i = 0; i < N; i++) {
1621                              NotificationRecord r = mNotificationsByKey.get(keys[i]);
1622                              if (r == null) continue;
1623                              final int userId = r.sbn.getUserId();
1624                              if (userId != info.userid && userId != UserHandle.USER_ALL &&
1625                                      !mUserProfiles.isCurrentProfile(userId)) {
1626                                  throw new SecurityException("Disallowed call from listener: "
1627                                          + info.service);
1628                              }
1629                              cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1630                                      r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1631                                      userId);
1632                          }
1633                      } else {
1634                          cancelAllLocked(callingUid, callingPid, info.userid,
1635                                  REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1636                      }
1637                  }
1638              } finally {
1639                  Binder.restoreCallingIdentity(identity);
1640              }
1641          }
1642  
1643          /**
1644           * Handle request from an approved listener to re-enable itself.
1645           *
1646           * @param component The componenet to be re-enabled, caller must match package.
1647           */
1648          @Override
1649          public void requestBindListener(ComponentName component) {
1650              checkCallerIsSystemOrSameApp(component.getPackageName());
1651              long identity = Binder.clearCallingIdentity();
1652              try {
1653                  ManagedServices manager =
1654                          mRankerServices.isComponentEnabledForCurrentProfiles(component)
1655                          ? mRankerServices
1656                          : mListeners;
1657                  manager.setComponentState(component, true);
1658              } finally {
1659                  Binder.restoreCallingIdentity(identity);
1660              }
1661          }
1662  
1663          @Override
1664          public void requestUnbindListener(INotificationListener token) {
1665              long identity = Binder.clearCallingIdentity();
1666              try {
1667                  // allow bound services to disable themselves
1668                  final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1669                  info.getOwner().setComponentState(info.component, false);
1670              } finally {
1671                  Binder.restoreCallingIdentity(identity);
1672              }
1673          }
1674  
1675          @Override
1676          public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1677              long identity = Binder.clearCallingIdentity();
1678              try {
1679                  synchronized (mNotificationList) {
1680                      final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1681                      if (keys != null) {
1682                          final int N = keys.length;
1683                          for (int i = 0; i < N; i++) {
1684                              NotificationRecord r = mNotificationsByKey.get(keys[i]);
1685                              if (r == null) continue;
1686                              final int userId = r.sbn.getUserId();
1687                              if (userId != info.userid && userId != UserHandle.USER_ALL &&
1688                                      !mUserProfiles.isCurrentProfile(userId)) {
1689                                  throw new SecurityException("Disallowed call from listener: "
1690                                          + info.service);
1691                              }
1692                              if (!r.isSeen()) {
1693                                  if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1694                                  mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1695                                          userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1696                                                  : userId,
1697                                          UsageEvents.Event.USER_INTERACTION);
1698                                  r.setSeen();
1699                              }
1700                          }
1701                      }
1702                  }
1703              } finally {
1704                  Binder.restoreCallingIdentity(identity);
1705              }
1706          }
1707  
1708          private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1709                  int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1710              cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1711                      Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1712                      true,
1713                      userId, REASON_LISTENER_CANCEL, info);
1714          }
1715  
1716          /**
1717           * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1718           *
1719           * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1720           *
1721           * @param token The binder for the listener, to check that the caller is allowed
1722           */
1723          @Override
1724          public void cancelNotificationFromListener(INotificationListener token, String pkg,
1725                  String tag, int id) {
1726              final int callingUid = Binder.getCallingUid();
1727              final int callingPid = Binder.getCallingPid();
1728              long identity = Binder.clearCallingIdentity();
1729              try {
1730                  synchronized (mNotificationList) {
1731                      final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1732                      if (info.supportsProfiles()) {
1733                          Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1734                                  + "from " + info.component
1735                                  + " use cancelNotification(key) instead.");
1736                      } else {
1737                          cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1738                                  pkg, tag, id, info.userid);
1739                      }
1740                  }
1741              } finally {
1742                  Binder.restoreCallingIdentity(identity);
1743              }
1744          }
1745  
1746          /**
1747           * Allow an INotificationListener to request the list of outstanding notifications seen by
1748           * the current user. Useful when starting up, after which point the listener callbacks
1749           * should be used.
1750           *
1751           * @param token The binder for the listener, to check that the caller is allowed
1752           * @param keys An array of notification keys to fetch, or null to fetch everything
1753           * @returns The return value will contain the notifications specified in keys, in that
1754           *      order, or if keys is null, all the notifications, in natural order.
1755           */
1756          @Override
1757          public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1758                  INotificationListener token, String[] keys, int trim) {
1759              synchronized (mNotificationList) {
1760                  final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1761                  final boolean getKeys = keys != null;
1762                  final int N = getKeys ? keys.length : mNotificationList.size();
1763                  final ArrayList<StatusBarNotification> list
1764                          = new ArrayList<StatusBarNotification>(N);
1765                  for (int i=0; i<N; i++) {
1766                      final NotificationRecord r = getKeys
1767                              ? mNotificationsByKey.get(keys[i])
1768                              : mNotificationList.get(i);
1769                      if (r == null) continue;
1770                      StatusBarNotification sbn = r.sbn;
1771                      if (!isVisibleToListener(sbn, info)) continue;
1772                      StatusBarNotification sbnToSend =
1773                              (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1774                      list.add(sbnToSend);
1775                  }
1776                  return new ParceledListSlice<StatusBarNotification>(list);
1777              }
1778          }
1779  
1780          @Override
1781          public void requestHintsFromListener(INotificationListener token, int hints) {
1782              final long identity = Binder.clearCallingIdentity();
1783              try {
1784                  synchronized (mNotificationList) {
1785                      final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1786                      final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1787                              | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1788                              | HINT_HOST_DISABLE_CALL_EFFECTS;
1789                      final boolean disableEffects = (hints & disableEffectsMask) != 0;
1790                      if (disableEffects) {
1791                          addDisabledHints(info, hints);
1792                      } else {
1793                          removeDisabledHints(info, hints);
1794                      }
1795                      updateListenerHintsLocked();
1796                      updateEffectsSuppressorLocked();
1797                  }
1798              } finally {
1799                  Binder.restoreCallingIdentity(identity);
1800              }
1801          }
1802  
1803          @Override
1804          public int getHintsFromListener(INotificationListener token) {
1805              synchronized (mNotificationList) {
1806                  return mListenerHints;
1807              }
1808          }
1809  
1810          @Override
1811          public void requestInterruptionFilterFromListener(INotificationListener token,
1812                  int interruptionFilter) throws RemoteException {
1813              final long identity = Binder.clearCallingIdentity();
1814              try {
1815                  synchronized (mNotificationList) {
1816                      final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1817                      mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1818                      updateInterruptionFilterLocked();
1819                  }
1820              } finally {
1821                  Binder.restoreCallingIdentity(identity);
1822              }
1823          }
1824  
1825          @Override
1826          public int getInterruptionFilterFromListener(INotificationListener token)
1827                  throws RemoteException {
1828              synchronized (mNotificationLight) {
1829                  return mInterruptionFilter;
1830              }
1831          }
1832  
1833          @Override
1834          public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1835                  throws RemoteException {
1836              synchronized (mNotificationList) {
1837                  final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1838                  if (info == null) return;
1839                  mListeners.setOnNotificationPostedTrimLocked(info, trim);
1840              }
1841          }
1842  
1843          @Override
1844          public int getZenMode() {
1845              return mZenModeHelper.getZenMode();
1846          }
1847  
1848          @Override
1849          public ZenModeConfig getZenModeConfig() {
1850              enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1851              return mZenModeHelper.getConfig();
1852          }
1853  
1854          @Override
1855          public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1856              enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1857              final long identity = Binder.clearCallingIdentity();
1858              try {
1859                  mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
1860              } finally {
1861                  Binder.restoreCallingIdentity(identity);
1862              }
1863          }
1864  
1865          @Override
1866          public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
1867              enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1868              return mZenModeHelper.getZenRules();
1869          }
1870  
1871          @Override
1872          public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1873              Preconditions.checkNotNull(id, "Id is null");
1874              enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
1875              return mZenModeHelper.getAutomaticZenRule(id);
1876          }
1877  
1878          @Override
1879          public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
1880                  throws RemoteException {
1881              Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1882              Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1883              Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1884              Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1885              enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
1886  
1887              return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1888                      "addAutomaticZenRule");
1889          }
1890  
1891          @Override
1892          public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
1893                  throws RemoteException {
1894              Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1895              Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1896              Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1897              Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1898              enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
1899  
1900              return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
1901                      "updateAutomaticZenRule");
1902          }
1903  
1904          @Override
1905          public boolean removeAutomaticZenRule(String id) throws RemoteException {
1906              Preconditions.checkNotNull(id, "Id is null");
1907              // Verify that they can modify zen rules.
1908              enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1909  
1910              return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
1911          }
1912  
1913          @Override
1914          public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1915              Preconditions.checkNotNull(packageName, "Package name is null");
1916              enforceSystemOrSystemUI("removeAutomaticZenRules");
1917  
1918              return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1919          }
1920  
1921          @Override
1922          public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1923              Preconditions.checkNotNull(owner, "Owner is null");
1924              enforceSystemOrSystemUI("getRuleInstanceCount");
1925  
1926              return mZenModeHelper.getCurrentInstanceCount(owner);
1927          }
1928  
1929          @Override
1930          public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1931              enforcePolicyAccess(pkg, "setInterruptionFilter");
1932              final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1933              if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1934              final long identity = Binder.clearCallingIdentity();
1935              try {
1936                  mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
1937              } finally {
1938                  Binder.restoreCallingIdentity(identity);
1939              }
1940          }
1941  
1942          @Override
1943          public void notifyConditions(final String pkg, IConditionProvider provider,
1944                  final Condition[] conditions) {
1945              final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1946              checkCallerIsSystemOrSameApp(pkg);
1947              mHandler.post(new Runnable() {
1948                  @Override
1949                  public void run() {
1950                      mConditionProviders.notifyConditions(pkg, info, conditions);
1951                  }
1952              });
1953          }
1954  
1955          private void enforceSystemOrSystemUIOrVolume(String message) {
1956              if (mAudioManagerInternal != null) {
1957                  final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1958                  if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1959                      return;
1960                  }
1961              }
1962              enforceSystemOrSystemUI(message);
1963          }
1964  
1965          private void enforceSystemOrSystemUI(String message) {
1966              if (isCallerSystem()) return;
1967              getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1968                      message);
1969          }
1970  
1971          private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1972              try {
1973                  checkCallerIsSystemOrSameApp(pkg);
1974              } catch (SecurityException e) {
1975                  getContext().enforceCallingPermission(
1976                          android.Manifest.permission.STATUS_BAR_SERVICE,
1977                          message);
1978              }
1979          }
1980  
1981          private void enforcePolicyAccess(int uid, String method) {
1982              if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1983                      android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1984                  return;
1985              }
1986              boolean accessAllowed = false;
1987              String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1988              final int packageCount = packages.length;
1989              for (int i = 0; i < packageCount; i++) {
1990                  if (checkPolicyAccess(packages[i])) {
1991                      accessAllowed = true;
1992                  }
1993              }
1994              if (!accessAllowed) {
1995                  Slog.w(TAG, "Notification policy access denied calling " + method);
1996                  throw new SecurityException("Notification policy access denied");
1997              }
1998          }
1999  
2000          private void enforcePolicyAccess(String pkg, String method) {
2001              if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2002                      android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2003                  return;
2004              }
2005              checkCallerIsSameApp(pkg);
2006              if (!checkPolicyAccess(pkg)) {
2007                  Slog.w(TAG, "Notification policy access denied calling " + method);
2008                  throw new SecurityException("Notification policy access denied");
2009              }
2010          }
2011  
2012          private boolean checkPackagePolicyAccess(String pkg) {
2013              return mPolicyAccess.isPackageGranted(pkg);
2014          }
2015  
2016          private boolean checkPolicyAccess(String pkg) {
2017              try {
2018                  int uid = getContext().getPackageManager().getPackageUidAsUser(
2019                          pkg, UserHandle.getCallingUserId());
2020                  if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2021                          android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2022                          -1, true)) {
2023                      return true;
2024                  }
2025              } catch (NameNotFoundException e) {
2026                  return false;
2027              }
2028              return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2029          }
2030  
2031          @Override
2032          protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2033              if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2034                      != PackageManager.PERMISSION_GRANTED) {
2035                  pw.println("Permission Denial: can't dump NotificationManager from pid="
2036                          + Binder.getCallingPid()
2037                          + ", uid=" + Binder.getCallingUid());
2038                  return;
2039              }
2040  
2041              final DumpFilter filter = DumpFilter.parseFromArguments(args);
2042              if (filter != null && filter.stats) {
2043                  dumpJson(pw, filter);
2044              } else {
2045                  dumpImpl(pw, filter);
2046              }
2047          }
2048  
2049          @Override
2050          public ComponentName getEffectsSuppressor() {
2051              enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
2052              return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2053          }
2054  
2055          @Override
2056          public boolean matchesCallFilter(Bundle extras) {
2057              enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2058              return mZenModeHelper.matchesCallFilter(
2059                      Binder.getCallingUserHandle(),
2060                      extras,
2061                      mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2062                      MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2063                      MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2064          }
2065  
2066          @Override
2067          public boolean isSystemConditionProviderEnabled(String path) {
2068              enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
2069              return mConditionProviders.isSystemProviderEnabled(path);
2070          }
2071  
2072          // Backup/restore interface
2073          @Override
2074          public byte[] getBackupPayload(int user) {
2075              if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2076              //TODO: http://b/22388012
2077              if (user != UserHandle.USER_SYSTEM) {
2078                  Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2079                  return null;
2080              }
2081              final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2082              try {
2083                  writePolicyXml(baos, true /*forBackup*/);
2084                  return baos.toByteArray();
2085              } catch (IOException e) {
2086                  Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2087              }
2088              return null;
2089          }
2090  
2091          @Override
2092          public void applyRestore(byte[] payload, int user) {
2093              if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2094                      + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2095              if (payload == null) {
2096                  Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2097                  return;
2098              }
2099              //TODO: http://b/22388012
2100              if (user != UserHandle.USER_SYSTEM) {
2101                  Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2102                  return;
2103              }
2104              final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2105              try {
2106                  readPolicyXml(bais, true /*forRestore*/);
2107                  savePolicyFile();
2108              } catch (NumberFormatException | XmlPullParserException | IOException e) {
2109                  Slog.w(TAG, "applyRestore: error reading payload", e);
2110              }
2111          }
2112  
2113          @Override
2114          public boolean isNotificationPolicyAccessGranted(String pkg) {
2115              return checkPolicyAccess(pkg);
2116          }
2117  
2118          @Override
2119          public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2120              enforceSystemOrSystemUIOrSamePackage(pkg,
2121                      "request policy access status for another package");
2122              return checkPolicyAccess(pkg);
2123          }
2124  
2125          @Override
2126          public String[] getPackagesRequestingNotificationPolicyAccess()
2127                  throws RemoteException {
2128              enforceSystemOrSystemUI("request policy access packages");
2129              final long identity = Binder.clearCallingIdentity();
2130              try {
2131                  return mPolicyAccess.getRequestingPackages();
2132              } finally {
2133                  Binder.restoreCallingIdentity(identity);
2134              }
2135          }
2136  
2137          @Override
2138          public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2139                  throws RemoteException {
2140              enforceSystemOrSystemUI("grant notification policy access");
2141              final long identity = Binder.clearCallingIdentity();
2142              try {
2143                  synchronized (mNotificationList) {
2144                      mPolicyAccess.put(pkg, granted);
2145                  }
2146              } finally {
2147                  Binder.restoreCallingIdentity(identity);
2148              }
2149          }
2150  
2151          @Override
2152          public Policy getNotificationPolicy(String pkg) {
2153              enforcePolicyAccess(pkg, "getNotificationPolicy");
2154              final long identity = Binder.clearCallingIdentity();
2155              try {
2156                  return mZenModeHelper.getNotificationPolicy();
2157              } finally {
2158                  Binder.restoreCallingIdentity(identity);
2159              }
2160          }
2161  
2162          @Override
2163          public void setNotificationPolicy(String pkg, Policy policy) {
2164              enforcePolicyAccess(pkg, "setNotificationPolicy");
2165              final long identity = Binder.clearCallingIdentity();
2166              try {
2167                  mZenModeHelper.setNotificationPolicy(policy);
2168              } finally {
2169                  Binder.restoreCallingIdentity(identity);
2170              }
2171          }
2172  
2173          @Override
2174          public void applyAdjustmentFromRankerService(INotificationListener token,
2175                  Adjustment adjustment) throws RemoteException {
2176              final long identity = Binder.clearCallingIdentity();
2177              try {
2178                  synchronized (mNotificationList) {
2179                      mRankerServices.checkServiceTokenLocked(token);
2180                      applyAdjustmentLocked(adjustment);
2181                  }
2182                  maybeAddAutobundleSummary(adjustment);
2183                  mRankingHandler.requestSort();
2184              } finally {
2185                  Binder.restoreCallingIdentity(identity);
2186              }
2187          }
2188  
2189          @Override
2190          public void applyAdjustmentsFromRankerService(INotificationListener token,
2191                  List<Adjustment> adjustments) throws RemoteException {
2192  
2193              final long identity = Binder.clearCallingIdentity();
2194              try {
2195                  synchronized (mNotificationList) {
2196                      mRankerServices.checkServiceTokenLocked(token);
2197                      for (Adjustment adjustment : adjustments) {
2198                          applyAdjustmentLocked(adjustment);
2199                      }
2200                  }
2201                  for (Adjustment adjustment : adjustments) {
2202                      maybeAddAutobundleSummary(adjustment);
2203                  }
2204                  mRankingHandler.requestSort();
2205              } finally {
2206                  Binder.restoreCallingIdentity(identity);
2207              }
2208          }
2209      };
2210  
applyAdjustmentLocked(Adjustment adjustment)2211      private void applyAdjustmentLocked(Adjustment adjustment) {
2212          maybeClearAutobundleSummaryLocked(adjustment);
2213          NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2214          if (n == null) {
2215              return;
2216          }
2217          if (adjustment.getImportance() != IMPORTANCE_NONE) {
2218              n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2219          }
2220          if (adjustment.getSignals() != null) {
2221              Bundle.setDefusable(adjustment.getSignals(), true);
2222              final String autoGroupKey = adjustment.getSignals().getString(
2223                      Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2224              if (autoGroupKey == null) {
2225                  EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2226              } else {
2227                  EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2228              }
2229              n.sbn.setOverrideGroupKey(autoGroupKey);
2230          }
2231      }
2232  
2233      // Clears the 'fake' auto-bunding summary.
maybeClearAutobundleSummaryLocked(Adjustment adjustment)2234      private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2235          if (adjustment.getSignals() != null) {
2236              Bundle.setDefusable(adjustment.getSignals(), true);
2237              if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2238                  && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2239                  ArrayMap<String, String> summaries =
2240                          mAutobundledSummaries.get(adjustment.getUser());
2241                  if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2242                      // Clear summary.
2243                      final NotificationRecord removed = mNotificationsByKey.get(
2244                              summaries.remove(adjustment.getPackage()));
2245                      if (removed != null) {
2246                          mNotificationList.remove(removed);
2247                          cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2248                      }
2249                  }
2250              }
2251          }
2252      }
2253  
2254      // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
maybeAddAutobundleSummary(Adjustment adjustment)2255      private void maybeAddAutobundleSummary(Adjustment adjustment) {
2256          if (adjustment.getSignals() != null) {
2257              Bundle.setDefusable(adjustment.getSignals(), true);
2258              if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2259                  final String newAutoBundleKey =
2260                          adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2261                  int userId = -1;
2262                  NotificationRecord summaryRecord = null;
2263                  synchronized (mNotificationList) {
2264                      NotificationRecord notificationRecord =
2265                              mNotificationsByKey.get(adjustment.getKey());
2266                      if (notificationRecord == null) {
2267                          // The notification could have been cancelled again already. A successive
2268                          // adjustment will post a summary if needed.
2269                          return;
2270                      }
2271                      final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2272                      userId = adjustedSbn.getUser().getIdentifier();
2273                      ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2274                      if (summaries == null) {
2275                          summaries = new ArrayMap<>();
2276                      }
2277                      mAutobundledSummaries.put(userId, summaries);
2278                      if (!summaries.containsKey(adjustment.getPackage())
2279                              && newAutoBundleKey != null) {
2280                          // Add summary
2281                          final ApplicationInfo appInfo =
2282                                  adjustedSbn.getNotification().extras.getParcelable(
2283                                          Notification.EXTRA_BUILDER_APPLICATION_INFO);
2284                          final Bundle extras = new Bundle();
2285                          extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2286                          final Notification summaryNotification =
2287                                  new Notification.Builder(getContext()).setSmallIcon(
2288                                          adjustedSbn.getNotification().getSmallIcon())
2289                                          .setGroupSummary(true)
2290                                          .setGroup(newAutoBundleKey)
2291                                          .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2292                                          .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2293                                          .setColor(adjustedSbn.getNotification().color)
2294                                          .setLocalOnly(true)
2295                                          .build();
2296                          summaryNotification.extras.putAll(extras);
2297                          Intent appIntent = getContext().getPackageManager()
2298                                  .getLaunchIntentForPackage(adjustment.getPackage());
2299                          if (appIntent != null) {
2300                              summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2301                                      getContext(), 0, appIntent, 0, null,
2302                                      UserHandle.of(userId));
2303                          }
2304                          final StatusBarNotification summarySbn =
2305                                  new StatusBarNotification(adjustedSbn.getPackageName(),
2306                                          adjustedSbn.getOpPkg(),
2307                                          Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2308                                          adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2309                                          summaryNotification, adjustedSbn.getUser(),
2310                                          newAutoBundleKey,
2311                                          System.currentTimeMillis());
2312                          summaryRecord = new NotificationRecord(getContext(), summarySbn);
2313                          summaries.put(adjustment.getPackage(), summarySbn.getKey());
2314                      }
2315                  }
2316                  if (summaryRecord != null) {
2317                      mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2318                  }
2319              }
2320          }
2321      }
2322  
disableNotificationEffects(NotificationRecord record)2323      private String disableNotificationEffects(NotificationRecord record) {
2324          if (mDisableNotificationEffects) {
2325              return "booleanState";
2326          }
2327          if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2328              return "listenerHints";
2329          }
2330          if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2331              return "callState";
2332          }
2333          return null;
2334      };
2335  
dumpJson(PrintWriter pw, DumpFilter filter)2336      private void dumpJson(PrintWriter pw, DumpFilter filter) {
2337          JSONObject dump = new JSONObject();
2338          try {
2339              dump.put("service", "Notification Manager");
2340              dump.put("bans", mRankingHelper.dumpBansJson(filter));
2341              dump.put("ranking", mRankingHelper.dumpJson(filter));
2342              dump.put("stats", mUsageStats.dumpJson(filter));
2343          } catch (JSONException e) {
2344              e.printStackTrace();
2345          }
2346          pw.println(dump);
2347      }
2348  
dumpImpl(PrintWriter pw, DumpFilter filter)2349      void dumpImpl(PrintWriter pw, DumpFilter filter) {
2350          pw.print("Current Notification Manager state");
2351          if (filter.filtered) {
2352              pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2353          }
2354          pw.println(':');
2355          int N;
2356          final boolean zenOnly = filter.filtered && filter.zen;
2357  
2358          if (!zenOnly) {
2359              synchronized (mToastQueue) {
2360                  N = mToastQueue.size();
2361                  if (N > 0) {
2362                      pw.println("  Toast Queue:");
2363                      for (int i=0; i<N; i++) {
2364                          mToastQueue.get(i).dump(pw, "    ", filter);
2365                      }
2366                      pw.println("  ");
2367                  }
2368              }
2369          }
2370  
2371          synchronized (mNotificationList) {
2372              if (!zenOnly) {
2373                  N = mNotificationList.size();
2374                  if (N > 0) {
2375                      pw.println("  Notification List:");
2376                      for (int i=0; i<N; i++) {
2377                          final NotificationRecord nr = mNotificationList.get(i);
2378                          if (filter.filtered && !filter.matches(nr.sbn)) continue;
2379                          nr.dump(pw, "    ", getContext(), filter.redact);
2380                      }
2381                      pw.println("  ");
2382                  }
2383  
2384                  if (!filter.filtered) {
2385                      N = mLights.size();
2386                      if (N > 0) {
2387                          pw.println("  Lights List:");
2388                          for (int i=0; i<N; i++) {
2389                              if (i == N - 1) {
2390                                  pw.print("  > ");
2391                              } else {
2392                                  pw.print("    ");
2393                              }
2394                              pw.println(mLights.get(i));
2395                          }
2396                          pw.println("  ");
2397                      }
2398                      pw.println("  mUseAttentionLight=" + mUseAttentionLight);
2399                      pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2400                      pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
2401                      pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
2402                      pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
2403                      pw.println("  mCallState=" + callStateToString(mCallState));
2404                      pw.println("  mSystemReady=" + mSystemReady);
2405                      pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
2406                  }
2407                  pw.println("  mArchive=" + mArchive.toString());
2408                  Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2409                  int i=0;
2410                  while (iter.hasNext()) {
2411                      final StatusBarNotification sbn = iter.next();
2412                      if (filter != null && !filter.matches(sbn)) continue;
2413                      pw.println("    " + sbn);
2414                      if (++i >= 5) {
2415                          if (iter.hasNext()) pw.println("    ...");
2416                          break;
2417                      }
2418                  }
2419              }
2420  
2421              if (!zenOnly) {
2422                  pw.println("\n  Usage Stats:");
2423                  mUsageStats.dump(pw, "    ", filter);
2424              }
2425  
2426              if (!filter.filtered || zenOnly) {
2427                  pw.println("\n  Zen Mode:");
2428                  pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
2429                  mZenModeHelper.dump(pw, "    ");
2430  
2431                  pw.println("\n  Zen Log:");
2432                  ZenLog.dump(pw, "    ");
2433              }
2434  
2435              if (!zenOnly) {
2436                  pw.println("\n  Ranking Config:");
2437                  mRankingHelper.dump(pw, "    ", filter);
2438  
2439                  pw.println("\n  Notification listeners:");
2440                  mListeners.dump(pw, filter);
2441                  pw.print("    mListenerHints: "); pw.println(mListenerHints);
2442                  pw.print("    mListenersDisablingEffects: (");
2443                  N = mListenersDisablingEffects.size();
2444                  for (int i = 0; i < N; i++) {
2445                      final int hint = mListenersDisablingEffects.keyAt(i);
2446                      if (i > 0) pw.print(';');
2447                      pw.print("hint[" + hint + "]:");
2448  
2449                      final ArraySet<ManagedServiceInfo> listeners =
2450                              mListenersDisablingEffects.valueAt(i);
2451                      final int listenerSize = listeners.size();
2452  
2453                      for (int j = 0; j < listenerSize; j++) {
2454                          if (i > 0) pw.print(',');
2455                          final ManagedServiceInfo listener = listeners.valueAt(i);
2456                          pw.print(listener.component);
2457                      }
2458                  }
2459                  pw.println(')');
2460                  pw.println("\n  mRankerServicePackageName: " + mRankerServicePackageName);
2461                  pw.println("\n  Notification ranker services:");
2462                  mRankerServices.dump(pw, filter);
2463              }
2464              pw.println("\n  Policy access:");
2465              pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
2466  
2467              pw.println("\n  Condition providers:");
2468              mConditionProviders.dump(pw, filter);
2469  
2470              pw.println("\n  Group summaries:");
2471              for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2472                  NotificationRecord r = entry.getValue();
2473                  pw.println("    " + entry.getKey() + " -> " + r.getKey());
2474                  if (mNotificationsByKey.get(r.getKey()) != r) {
2475                      pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2476                      r.dump(pw, "      ", getContext(), filter.redact);
2477                  }
2478              }
2479          }
2480      }
2481  
2482      /**
2483       * The private API only accessible to the system process.
2484       */
2485      private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2486          @Override
2487          public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2488                  String tag, int id, Notification notification, int[] idReceived, int userId) {
2489              enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2490                      idReceived, userId);
2491          }
2492  
2493          @Override
2494          public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2495                  int userId) {
2496              checkCallerIsSystem();
2497              synchronized (mNotificationList) {
2498                  int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2499                  if (i < 0) {
2500                      Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2501                              + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2502                      return;
2503                  }
2504                  NotificationRecord r = mNotificationList.get(i);
2505                  StatusBarNotification sbn = r.sbn;
2506                  // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2507                  // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2508                  // we have to revert to the flags we received initially *and* force remove
2509                  // FLAG_FOREGROUND_SERVICE.
2510                  sbn.getNotification().flags =
2511                          (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2512                  mRankingHelper.sort(mNotificationList);
2513                  mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2514              }
2515          }
2516      };
2517  
enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int[] idOut, int incomingUserId)2518      void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2519              final int callingPid, final String tag, final int id, final Notification notification,
2520              int[] idOut, int incomingUserId) {
2521          if (DBG) {
2522              Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2523                      + " notification=" + notification);
2524          }
2525          checkCallerIsSystemOrSameApp(pkg);
2526          final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2527          final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2528  
2529          final int userId = ActivityManager.handleIncomingUser(callingPid,
2530                  callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2531          final UserHandle user = new UserHandle(userId);
2532  
2533          // Fix the notification as best we can.
2534          try {
2535              final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2536                      pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2537                      (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2538              Notification.addFieldsFromContext(ai, userId, notification);
2539          } catch (NameNotFoundException e) {
2540              Slog.e(TAG, "Cannot create a context for sending app", e);
2541              return;
2542          }
2543  
2544          mUsageStats.registerEnqueuedByApp(pkg);
2545  
2546  
2547          if (pkg == null || notification == null) {
2548              throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2549                      + " id=" + id + " notification=" + notification);
2550          }
2551          final StatusBarNotification n = new StatusBarNotification(
2552                  pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2553                  user);
2554  
2555          // Limit the number of notifications that any given package except the android
2556          // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
2557          if (!isSystemNotification && !isNotificationFromListener) {
2558              synchronized (mNotificationList) {
2559                  if(mNotificationsByKey.get(n.getKey()) != null) {
2560                      // this is an update, rate limit updates only
2561                      final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2562                      if (appEnqueueRate > mMaxPackageEnqueueRate) {
2563                          mUsageStats.registerOverRateQuota(pkg);
2564                          final long now = SystemClock.elapsedRealtime();
2565                          if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2566                              Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2567                                      + ". Shedding events. package=" + pkg);
2568                              mLastOverRateLogTime = now;
2569                          }
2570                          return;
2571                      }
2572                  }
2573  
2574                  int count = 0;
2575                  final int N = mNotificationList.size();
2576                  for (int i=0; i<N; i++) {
2577                      final NotificationRecord r = mNotificationList.get(i);
2578                      if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2579                          if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2580                              break;  // Allow updating existing notification
2581                          }
2582                          count++;
2583                          if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2584                              mUsageStats.registerOverCountQuota(pkg);
2585                              Slog.e(TAG, "Package has already posted " + count
2586                                      + " notifications.  Not showing more.  package=" + pkg);
2587                              return;
2588                          }
2589                      }
2590                  }
2591              }
2592          }
2593  
2594          // Whitelist pending intents.
2595          if (notification.allPendingIntents != null) {
2596              final int intentCount = notification.allPendingIntents.size();
2597              if (intentCount > 0) {
2598                  final ActivityManagerInternal am = LocalServices
2599                          .getService(ActivityManagerInternal.class);
2600                  final long duration = LocalServices.getService(
2601                          DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2602                  for (int i = 0; i < intentCount; i++) {
2603                      PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2604                      if (pendingIntent != null) {
2605                          am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2606                      }
2607                  }
2608              }
2609          }
2610  
2611          // Sanitize inputs
2612          notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2613                  Notification.PRIORITY_MAX);
2614  
2615          // setup local book-keeping
2616          final NotificationRecord r = new NotificationRecord(getContext(), n);
2617          mHandler.post(new EnqueueNotificationRunnable(userId, r));
2618  
2619          idOut[0] = id;
2620      }
2621  
2622      private class EnqueueNotificationRunnable implements Runnable {
2623          private final NotificationRecord r;
2624          private final int userId;
2625  
EnqueueNotificationRunnable(int userId, NotificationRecord r)2626          EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2627              this.userId = userId;
2628              this.r = r;
2629          };
2630  
2631          @Override
run()2632          public void run() {
2633  
2634              synchronized (mNotificationList) {
2635                  final StatusBarNotification n = r.sbn;
2636                  if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2637                  NotificationRecord old = mNotificationsByKey.get(n.getKey());
2638                  if (old != null) {
2639                      // Retain ranking information from previous record
2640                      r.copyRankingInformation(old);
2641                  }
2642  
2643                  final int callingUid = n.getUid();
2644                  final int callingPid = n.getInitialPid();
2645                  final Notification notification = n.getNotification();
2646                  final String pkg = n.getPackageName();
2647                  final int id = n.getId();
2648                  final String tag = n.getTag();
2649                  final boolean isSystemNotification = isUidSystem(callingUid) ||
2650                          ("android".equals(pkg));
2651  
2652                  // Handle grouped notifications and bail out early if we
2653                  // can to avoid extracting signals.
2654                  handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2655  
2656                  // This conditional is a dirty hack to limit the logging done on
2657                  //     behalf of the download manager without affecting other apps.
2658                  if (!pkg.equals("com.android.providers.downloads")
2659                          || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2660                      int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2661                      if (old != null) {
2662                          enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2663                      }
2664                      EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2665                              pkg, id, tag, userId, notification.toString(),
2666                              enqueueStatus);
2667                  }
2668  
2669                  mRankingHelper.extractSignals(r);
2670  
2671                  final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2672  
2673                  // blocked apps
2674                  if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2675                          || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2676                      if (!isSystemNotification) {
2677                          if (isPackageSuspended) {
2678                              Slog.e(TAG, "Suppressing notification from package due to package "
2679                                      + "suspended by administrator.");
2680                              mUsageStats.registerSuspendedByAdmin(r);
2681                          } else {
2682                              Slog.e(TAG, "Suppressing notification from package by user request.");
2683                              mUsageStats.registerBlocked(r);
2684                          }
2685                          return;
2686                      }
2687                  }
2688  
2689                  // tell the ranker service about the notification
2690                  if (mRankerServices.isEnabled()) {
2691                      mRankerServices.onNotificationEnqueued(r);
2692                      // TODO delay the code below here for 100ms or until there is an answer
2693                  }
2694  
2695  
2696                  int index = indexOfNotificationLocked(n.getKey());
2697                  if (index < 0) {
2698                      mNotificationList.add(r);
2699                      mUsageStats.registerPostedByApp(r);
2700                  } else {
2701                      old = mNotificationList.get(index);
2702                      mNotificationList.set(index, r);
2703                      mUsageStats.registerUpdatedByApp(r, old);
2704                      // Make sure we don't lose the foreground service state.
2705                      notification.flags |=
2706                              old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2707                      r.isUpdate = true;
2708                  }
2709  
2710                  mNotificationsByKey.put(n.getKey(), r);
2711  
2712                  // Ensure if this is a foreground service that the proper additional
2713                  // flags are set.
2714                  if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2715                      notification.flags |= Notification.FLAG_ONGOING_EVENT
2716                              | Notification.FLAG_NO_CLEAR;
2717                  }
2718  
2719                  applyZenModeLocked(r);
2720                  mRankingHelper.sort(mNotificationList);
2721  
2722                  if (notification.getSmallIcon() != null) {
2723                      StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2724                      mListeners.notifyPostedLocked(n, oldSbn);
2725                  } else {
2726                      Slog.e(TAG, "Not posting notification without small icon: " + notification);
2727                      if (old != null && !old.isCanceled) {
2728                          mListeners.notifyRemovedLocked(n);
2729                      }
2730                      // ATTENTION: in a future release we will bail out here
2731                      // so that we do not play sounds, show lights, etc. for invalid
2732                      // notifications
2733                      Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2734                              + n.getPackageName());
2735                  }
2736  
2737                  buzzBeepBlinkLocked(r);
2738              }
2739          }
2740      }
2741  
2742      /**
2743       * Ensures that grouped notification receive their special treatment.
2744       *
2745       * <p>Cancels group children if the new notification causes a group to lose
2746       * its summary.</p>
2747       *
2748       * <p>Updates mSummaryByGroupKey.</p>
2749       */
handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, int callingUid, int callingPid)2750      private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2751              int callingUid, int callingPid) {
2752          StatusBarNotification sbn = r.sbn;
2753          Notification n = sbn.getNotification();
2754          if (n.isGroupSummary() && !sbn.isAppGroup())  {
2755              // notifications without a group shouldn't be a summary, otherwise autobundling can
2756              // lead to bugs
2757              n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2758          }
2759  
2760          String group = sbn.getGroupKey();
2761          boolean isSummary = n.isGroupSummary();
2762  
2763          Notification oldN = old != null ? old.sbn.getNotification() : null;
2764          String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2765          boolean oldIsSummary = old != null && oldN.isGroupSummary();
2766  
2767          if (oldIsSummary) {
2768              NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2769              if (removedSummary != old) {
2770                  String removedKey =
2771                          removedSummary != null ? removedSummary.getKey() : "<null>";
2772                  Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2773                          ", removed=" + removedKey);
2774              }
2775          }
2776          if (isSummary) {
2777              mSummaryByGroupKey.put(group, r);
2778          }
2779  
2780          // Clear out group children of the old notification if the update
2781          // causes the group summary to go away. This happens when the old
2782          // notification was a summary and the new one isn't, or when the old
2783          // notification was a summary and its group key changed.
2784          if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2785              cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2786                      REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
2787          }
2788      }
2789  
2790      @VisibleForTesting
buzzBeepBlinkLocked(NotificationRecord record)2791      void buzzBeepBlinkLocked(NotificationRecord record) {
2792          boolean buzz = false;
2793          boolean beep = false;
2794          boolean blink = false;
2795  
2796          final Notification notification = record.sbn.getNotification();
2797          final String key = record.getKey();
2798  
2799          // Should this notification make noise, vibe, or use the LED?
2800          final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2801          final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2802          if (DBG || record.isIntercepted())
2803              Slog.v(TAG,
2804                      "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2805                              " intercept=" + record.isIntercepted()
2806              );
2807  
2808          final int currentUser;
2809          final long token = Binder.clearCallingIdentity();
2810          try {
2811              currentUser = ActivityManager.getCurrentUser();
2812          } finally {
2813              Binder.restoreCallingIdentity(token);
2814          }
2815  
2816          // If we're not supposed to beep, vibrate, etc. then don't.
2817          final String disableEffects = disableNotificationEffects(record);
2818          if (disableEffects != null) {
2819              ZenLog.traceDisableEffects(record, disableEffects);
2820          }
2821  
2822          // Remember if this notification already owns the notification channels.
2823          boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2824          boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2825  
2826          // These are set inside the conditional if the notification is allowed to make noise.
2827          boolean hasValidVibrate = false;
2828          boolean hasValidSound = false;
2829          if (disableEffects == null
2830                  && (record.getUserId() == UserHandle.USER_ALL ||
2831                      record.getUserId() == currentUser ||
2832                      mUserProfiles.isCurrentProfile(record.getUserId()))
2833                  && canInterrupt
2834                  && mSystemReady
2835                  && mAudioManager != null) {
2836              if (DBG) Slog.v(TAG, "Interrupting!");
2837  
2838              // should we use the default notification sound? (indicated either by
2839              // DEFAULT_SOUND or because notification.sound is pointing at
2840              // Settings.System.NOTIFICATION_SOUND)
2841              final boolean useDefaultSound =
2842                     (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2843                             Settings.System.DEFAULT_NOTIFICATION_URI
2844                                     .equals(notification.sound);
2845  
2846              Uri soundUri = null;
2847              if (useDefaultSound) {
2848                  soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2849  
2850                  // check to see if the default notification sound is silent
2851                  hasValidSound = mSystemNotificationSound != null;
2852              } else if (notification.sound != null) {
2853                  soundUri = notification.sound;
2854                  hasValidSound = (soundUri != null);
2855              }
2856  
2857              // Does the notification want to specify its own vibration?
2858              final boolean hasCustomVibrate = notification.vibrate != null;
2859  
2860              // new in 4.2: if there was supposed to be a sound and we're in vibrate
2861              // mode, and no other vibration is specified, we fall back to vibration
2862              final boolean convertSoundToVibration =
2863                      !hasCustomVibrate
2864                              && hasValidSound
2865                              && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
2866  
2867              // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2868              final boolean useDefaultVibrate =
2869                      (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2870  
2871              hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2872                      hasCustomVibrate;
2873  
2874              // We can alert, and we're allowed to alert, but if the developer asked us to only do
2875              // it once, and we already have, then don't.
2876              if (!(record.isUpdate
2877                      && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2878  
2879                  sendAccessibilityEvent(notification, record.sbn.getPackageName());
2880  
2881                  if (hasValidSound) {
2882                      boolean looping =
2883                              (notification.flags & Notification.FLAG_INSISTENT) != 0;
2884                      AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2885                      mSoundNotificationKey = key;
2886                      // do not play notifications if stream volume is 0 (typically because
2887                      // ringer mode is silent) or if there is a user of exclusive audio focus
2888                      if ((mAudioManager.getStreamVolume(
2889                              AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2890                              && !mAudioManager.isAudioFocusExclusive()) {
2891                          final long identity = Binder.clearCallingIdentity();
2892                          try {
2893                              final IRingtonePlayer player =
2894                                      mAudioManager.getRingtonePlayer();
2895                              if (player != null) {
2896                                  if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2897                                          + " with attributes " + audioAttributes);
2898                                  player.playAsync(soundUri, record.sbn.getUser(), looping,
2899                                          audioAttributes);
2900                                  beep = true;
2901                              }
2902                          } catch (RemoteException e) {
2903                          } finally {
2904                              Binder.restoreCallingIdentity(identity);
2905                          }
2906                      }
2907                  }
2908  
2909                  if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2910                          == AudioManager.RINGER_MODE_SILENT)) {
2911                      mVibrateNotificationKey = key;
2912  
2913                      if (useDefaultVibrate || convertSoundToVibration) {
2914                          // Escalate privileges so we can use the vibrator even if the
2915                          // notifying app does not have the VIBRATE permission.
2916                          long identity = Binder.clearCallingIdentity();
2917                          try {
2918                              mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2919                                      useDefaultVibrate ? mDefaultVibrationPattern
2920                                              : mFallbackVibrationPattern,
2921                                      ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2922                                              ? 0: -1, audioAttributesForNotification(notification));
2923                              buzz = true;
2924                          } finally {
2925                              Binder.restoreCallingIdentity(identity);
2926                          }
2927                      } else if (notification.vibrate.length > 1) {
2928                          // If you want your own vibration pattern, you need the VIBRATE
2929                          // permission
2930                          mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2931                                  notification.vibrate,
2932                                  ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2933                                          ? 0: -1, audioAttributesForNotification(notification));
2934                          buzz = true;
2935                      }
2936                  }
2937              }
2938  
2939          }
2940          // If a notification is updated to remove the actively playing sound or vibrate,
2941          // cancel that feedback now
2942          if (wasBeep && !hasValidSound) {
2943              clearSoundLocked();
2944          }
2945          if (wasBuzz && !hasValidVibrate) {
2946              clearVibrateLocked();
2947          }
2948  
2949          // light
2950          // release the light
2951          boolean wasShowLights = mLights.remove(key);
2952          if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2953                  && ((record.getSuppressedVisualEffects()
2954                  & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2955              mLights.add(key);
2956              updateLightsLocked();
2957              if (mUseAttentionLight) {
2958                  mAttentionLight.pulse();
2959              }
2960              blink = true;
2961          } else if (wasShowLights) {
2962              updateLightsLocked();
2963          }
2964          if (buzz || beep || blink) {
2965              if (((record.getSuppressedVisualEffects()
2966                      & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2967                  if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2968              } else {
2969                  EventLogTags.writeNotificationAlert(key,
2970                          buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2971                  mHandler.post(mBuzzBeepBlinked);
2972              }
2973          }
2974      }
2975  
audioAttributesForNotification(Notification n)2976      private static AudioAttributes audioAttributesForNotification(Notification n) {
2977          if (n.audioAttributes != null
2978                  && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2979              // the audio attributes are set and different from the default, use them
2980              return n.audioAttributes;
2981          } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2982              // the stream type is valid, use it
2983              return new AudioAttributes.Builder()
2984                      .setInternalLegacyStreamType(n.audioStreamType)
2985                      .build();
2986          } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2987              return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2988          } else {
2989              Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2990              return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2991          }
2992      }
2993  
showNextToastLocked()2994      void showNextToastLocked() {
2995          ToastRecord record = mToastQueue.get(0);
2996          while (record != null) {
2997              if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2998              try {
2999                  record.callback.show(record.token);
3000                  scheduleTimeoutLocked(record);
3001                  return;
3002              } catch (RemoteException e) {
3003                  Slog.w(TAG, "Object died trying to show notification " + record.callback
3004                          + " in package " + record.pkg);
3005                  // remove it from the list and let the process die
3006                  int index = mToastQueue.indexOf(record);
3007                  if (index >= 0) {
3008                      mToastQueue.remove(index);
3009                  }
3010                  keepProcessAliveIfNeededLocked(record.pid);
3011                  if (mToastQueue.size() > 0) {
3012                      record = mToastQueue.get(0);
3013                  } else {
3014                      record = null;
3015                  }
3016              }
3017          }
3018      }
3019  
cancelToastLocked(int index)3020      void cancelToastLocked(int index) {
3021          ToastRecord record = mToastQueue.get(index);
3022          try {
3023              record.callback.hide();
3024          } catch (RemoteException e) {
3025              Slog.w(TAG, "Object died trying to hide notification " + record.callback
3026                      + " in package " + record.pkg);
3027              // don't worry about this, we're about to remove it from
3028              // the list anyway
3029          }
3030  
3031          ToastRecord lastToast = mToastQueue.remove(index);
3032          mWindowManagerInternal.removeWindowToken(lastToast.token, true);
3033  
3034          keepProcessAliveIfNeededLocked(record.pid);
3035          if (mToastQueue.size() > 0) {
3036              // Show the next one. If the callback fails, this will remove
3037              // it from the list, so don't assume that the list hasn't changed
3038              // after this point.
3039              showNextToastLocked();
3040          }
3041      }
3042  
scheduleTimeoutLocked(ToastRecord r)3043      private void scheduleTimeoutLocked(ToastRecord r)
3044      {
3045          mHandler.removeCallbacksAndMessages(r);
3046          Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3047          long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3048          mHandler.sendMessageDelayed(m, delay);
3049      }
3050  
handleTimeout(ToastRecord record)3051      private void handleTimeout(ToastRecord record)
3052      {
3053          if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3054          synchronized (mToastQueue) {
3055              int index = indexOfToastLocked(record.pkg, record.callback);
3056              if (index >= 0) {
3057                  cancelToastLocked(index);
3058              }
3059          }
3060      }
3061  
3062      // lock on mToastQueue
indexOfToastLocked(String pkg, ITransientNotification callback)3063      int indexOfToastLocked(String pkg, ITransientNotification callback)
3064      {
3065          IBinder cbak = callback.asBinder();
3066          ArrayList<ToastRecord> list = mToastQueue;
3067          int len = list.size();
3068          for (int i=0; i<len; i++) {
3069              ToastRecord r = list.get(i);
3070              if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3071                  return i;
3072              }
3073          }
3074          return -1;
3075      }
3076  
3077      // lock on mToastQueue
keepProcessAliveIfNeededLocked(int pid)3078      void keepProcessAliveIfNeededLocked(int pid)
3079      {
3080          int toastCount = 0; // toasts from this pid
3081          ArrayList<ToastRecord> list = mToastQueue;
3082          int N = list.size();
3083          for (int i=0; i<N; i++) {
3084              ToastRecord r = list.get(i);
3085              if (r.pid == pid) {
3086                  toastCount++;
3087              }
3088          }
3089          try {
3090              mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3091          } catch (RemoteException e) {
3092              // Shouldn't happen.
3093          }
3094      }
3095  
handleRankingReconsideration(Message message)3096      private void handleRankingReconsideration(Message message) {
3097          if (!(message.obj instanceof RankingReconsideration)) return;
3098          RankingReconsideration recon = (RankingReconsideration) message.obj;
3099          recon.run();
3100          boolean changed;
3101          synchronized (mNotificationList) {
3102              final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3103              if (record == null) {
3104                  return;
3105              }
3106              int indexBefore = findNotificationRecordIndexLocked(record);
3107              boolean interceptBefore = record.isIntercepted();
3108              int visibilityBefore = record.getPackageVisibilityOverride();
3109              recon.applyChangesLocked(record);
3110              applyZenModeLocked(record);
3111              mRankingHelper.sort(mNotificationList);
3112              int indexAfter = findNotificationRecordIndexLocked(record);
3113              boolean interceptAfter = record.isIntercepted();
3114              int visibilityAfter = record.getPackageVisibilityOverride();
3115              changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3116                      || visibilityBefore != visibilityAfter;
3117              if (interceptBefore && !interceptAfter) {
3118                  buzzBeepBlinkLocked(record);
3119              }
3120          }
3121          if (changed) {
3122              scheduleSendRankingUpdate();
3123          }
3124      }
3125  
handleRankingSort()3126      private void handleRankingSort() {
3127          synchronized (mNotificationList) {
3128              final int N = mNotificationList.size();
3129              ArrayList<String> orderBefore = new ArrayList<String>(N);
3130              ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3131              int[] visibilities = new int[N];
3132              int[] importances = new int[N];
3133              for (int i = 0; i < N; i++) {
3134                  final NotificationRecord r = mNotificationList.get(i);
3135                  orderBefore.add(r.getKey());
3136                  groupOverrideBefore.add(r.sbn.getGroupKey());
3137                  visibilities[i] = r.getPackageVisibilityOverride();
3138                  importances[i] = r.getImportance();
3139                  mRankingHelper.extractSignals(r);
3140              }
3141              mRankingHelper.sort(mNotificationList);
3142              for (int i = 0; i < N; i++) {
3143                  final NotificationRecord r = mNotificationList.get(i);
3144                  if (!orderBefore.get(i).equals(r.getKey())
3145                          || visibilities[i] != r.getPackageVisibilityOverride()
3146                          || importances[i] != r.getImportance()
3147                          || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3148                      scheduleSendRankingUpdate();
3149                      return;
3150                  }
3151              }
3152          }
3153      }
3154  
recordCallerLocked(NotificationRecord record)3155      private void recordCallerLocked(NotificationRecord record) {
3156          if (mZenModeHelper.isCall(record)) {
3157              mZenModeHelper.recordCaller(record);
3158          }
3159      }
3160  
3161      // let zen mode evaluate this record
applyZenModeLocked(NotificationRecord record)3162      private void applyZenModeLocked(NotificationRecord record) {
3163          record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3164          if (record.isIntercepted()) {
3165              int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3166                      ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3167                      | (mZenModeHelper.shouldSuppressWhenScreenOn()
3168                      ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3169              record.setSuppressedVisualEffects(suppressed);
3170          }
3171      }
3172  
3173      // lock on mNotificationList
findNotificationRecordIndexLocked(NotificationRecord target)3174      private int findNotificationRecordIndexLocked(NotificationRecord target) {
3175          return mRankingHelper.indexOf(mNotificationList, target);
3176      }
3177  
scheduleSendRankingUpdate()3178      private void scheduleSendRankingUpdate() {
3179          if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3180              Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3181              mHandler.sendMessage(m);
3182          }
3183      }
3184  
handleSendRankingUpdate()3185      private void handleSendRankingUpdate() {
3186          synchronized (mNotificationList) {
3187              mListeners.notifyRankingUpdateLocked();
3188          }
3189      }
3190  
scheduleListenerHintsChanged(int state)3191      private void scheduleListenerHintsChanged(int state) {
3192          mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3193          mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3194      }
3195  
scheduleInterruptionFilterChanged(int listenerInterruptionFilter)3196      private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3197          mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3198          mHandler.obtainMessage(
3199                  MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3200                  listenerInterruptionFilter,
3201                  0).sendToTarget();
3202      }
3203  
handleListenerHintsChanged(int hints)3204      private void handleListenerHintsChanged(int hints) {
3205          synchronized (mNotificationList) {
3206              mListeners.notifyListenerHintsChangedLocked(hints);
3207          }
3208      }
3209  
handleListenerInterruptionFilterChanged(int interruptionFilter)3210      private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3211          synchronized (mNotificationList) {
3212              mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3213          }
3214      }
3215  
3216      private final class WorkerHandler extends Handler
3217      {
3218          @Override
handleMessage(Message msg)3219          public void handleMessage(Message msg)
3220          {
3221              switch (msg.what)
3222              {
3223                  case MESSAGE_TIMEOUT:
3224                      handleTimeout((ToastRecord)msg.obj);
3225                      break;
3226                  case MESSAGE_SAVE_POLICY_FILE:
3227                      handleSavePolicyFile();
3228                      break;
3229                  case MESSAGE_SEND_RANKING_UPDATE:
3230                      handleSendRankingUpdate();
3231                      break;
3232                  case MESSAGE_LISTENER_HINTS_CHANGED:
3233                      handleListenerHintsChanged(msg.arg1);
3234                      break;
3235                  case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3236                      handleListenerInterruptionFilterChanged(msg.arg1);
3237                      break;
3238              }
3239          }
3240  
3241      }
3242  
3243      private final class RankingHandlerWorker extends Handler implements RankingHandler
3244      {
RankingHandlerWorker(Looper looper)3245          public RankingHandlerWorker(Looper looper) {
3246              super(looper);
3247          }
3248  
3249          @Override
handleMessage(Message msg)3250          public void handleMessage(Message msg) {
3251              switch (msg.what) {
3252                  case MESSAGE_RECONSIDER_RANKING:
3253                      handleRankingReconsideration(msg);
3254                      break;
3255                  case MESSAGE_RANKING_SORT:
3256                      handleRankingSort();
3257                      break;
3258              }
3259          }
3260  
requestSort()3261          public void requestSort() {
3262              removeMessages(MESSAGE_RANKING_SORT);
3263              sendEmptyMessage(MESSAGE_RANKING_SORT);
3264          }
3265  
requestReconsideration(RankingReconsideration recon)3266          public void requestReconsideration(RankingReconsideration recon) {
3267              Message m = Message.obtain(this,
3268                      NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3269              long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3270              sendMessageDelayed(m, delay);
3271          }
3272      }
3273  
3274      // Notifications
3275      // ============================================================================
clamp(int x, int low, int high)3276      static int clamp(int x, int low, int high) {
3277          return (x < low) ? low : ((x > high) ? high : x);
3278      }
3279  
sendAccessibilityEvent(Notification notification, CharSequence packageName)3280      void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3281          AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3282          if (!manager.isEnabled()) {
3283              return;
3284          }
3285  
3286          AccessibilityEvent event =
3287              AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3288          event.setPackageName(packageName);
3289          event.setClassName(Notification.class.getName());
3290          event.setParcelableData(notification);
3291          CharSequence tickerText = notification.tickerText;
3292          if (!TextUtils.isEmpty(tickerText)) {
3293              event.getText().add(tickerText);
3294          }
3295  
3296          manager.sendAccessibilityEvent(event);
3297      }
3298  
cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason)3299      private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3300  
3301          // Record caller.
3302          recordCallerLocked(r);
3303  
3304          // tell the app
3305          if (sendDelete) {
3306              if (r.getNotification().deleteIntent != null) {
3307                  try {
3308                      r.getNotification().deleteIntent.send();
3309                  } catch (PendingIntent.CanceledException ex) {
3310                      // do nothing - there's no relevant way to recover, and
3311                      //     no reason to let this propagate
3312                      Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3313                  }
3314              }
3315          }
3316  
3317          // status bar
3318          if (r.getNotification().getSmallIcon() != null) {
3319              r.isCanceled = true;
3320              mListeners.notifyRemovedLocked(r.sbn);
3321          }
3322  
3323          final String canceledKey = r.getKey();
3324  
3325          // sound
3326          if (canceledKey.equals(mSoundNotificationKey)) {
3327              mSoundNotificationKey = null;
3328              final long identity = Binder.clearCallingIdentity();
3329              try {
3330                  final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3331                  if (player != null) {
3332                      player.stopAsync();
3333                  }
3334              } catch (RemoteException e) {
3335              } finally {
3336                  Binder.restoreCallingIdentity(identity);
3337              }
3338          }
3339  
3340          // vibrate
3341          if (canceledKey.equals(mVibrateNotificationKey)) {
3342              mVibrateNotificationKey = null;
3343              long identity = Binder.clearCallingIdentity();
3344              try {
3345                  mVibrator.cancel();
3346              }
3347              finally {
3348                  Binder.restoreCallingIdentity(identity);
3349              }
3350          }
3351  
3352          // light
3353          mLights.remove(canceledKey);
3354  
3355          // Record usage stats
3356          // TODO: add unbundling stats?
3357          switch (reason) {
3358              case REASON_DELEGATE_CANCEL:
3359              case REASON_DELEGATE_CANCEL_ALL:
3360              case REASON_LISTENER_CANCEL:
3361              case REASON_LISTENER_CANCEL_ALL:
3362                  mUsageStats.registerDismissedByUser(r);
3363                  break;
3364              case REASON_APP_CANCEL:
3365              case REASON_APP_CANCEL_ALL:
3366                  mUsageStats.registerRemovedByApp(r);
3367                  break;
3368          }
3369  
3370          mNotificationsByKey.remove(r.sbn.getKey());
3371          String groupKey = r.getGroupKey();
3372          NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3373          if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3374              mSummaryByGroupKey.remove(groupKey);
3375          }
3376          final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3377          if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3378              summaries.remove(r.sbn.getPackageName());
3379          }
3380  
3381          // Save it for users of getHistoricalNotifications()
3382          mArchive.record(r.sbn);
3383  
3384          final long now = System.currentTimeMillis();
3385          EventLogTags.writeNotificationCanceled(canceledKey, reason,
3386                  r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3387      }
3388  
3389      /**
3390       * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3391       * and none of the {@code mustNotHaveFlags}.
3392       */
cancelNotification(final int callingUid, final int callingPid, final String pkg, final String tag, final int id, final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, final int userId, final int reason, final ManagedServiceInfo listener)3393      void cancelNotification(final int callingUid, final int callingPid,
3394              final String pkg, final String tag, final int id,
3395              final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3396              final int userId, final int reason, final ManagedServiceInfo listener) {
3397          // In enqueueNotificationInternal notifications are added by scheduling the
3398          // work on the worker handler. Hence, we also schedule the cancel on this
3399          // handler to avoid a scenario where an add notification call followed by a
3400          // remove notification call ends up in not removing the notification.
3401          mHandler.post(new Runnable() {
3402              @Override
3403              public void run() {
3404                  String listenerName = listener == null ? null : listener.component.toShortString();
3405                  if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3406                          userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3407  
3408                  synchronized (mNotificationList) {
3409                      int index = indexOfNotificationLocked(pkg, tag, id, userId);
3410                      if (index >= 0) {
3411                          NotificationRecord r = mNotificationList.get(index);
3412  
3413                          // Ideally we'd do this in the caller of this method. However, that would
3414                          // require the caller to also find the notification.
3415                          if (reason == REASON_DELEGATE_CLICK) {
3416                              mUsageStats.registerClickedByUser(r);
3417                          }
3418  
3419                          if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3420                              return;
3421                          }
3422                          if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3423                              return;
3424                          }
3425  
3426                          mNotificationList.remove(index);
3427  
3428                          cancelNotificationLocked(r, sendDelete, reason);
3429                          cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3430                                  REASON_GROUP_SUMMARY_CANCELED, sendDelete);
3431                          updateLightsLocked();
3432                      }
3433                  }
3434              }
3435          });
3436      }
3437  
3438      /**
3439       * Determine whether the userId applies to the notification in question, either because
3440       * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3441       */
notificationMatchesUserId(NotificationRecord r, int userId)3442      private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3443          return
3444                  // looking for USER_ALL notifications? match everything
3445                     userId == UserHandle.USER_ALL
3446                  // a notification sent to USER_ALL matches any query
3447                  || r.getUserId() == UserHandle.USER_ALL
3448                  // an exact user match
3449                  || r.getUserId() == userId;
3450      }
3451  
3452      /**
3453       * Determine whether the userId applies to the notification in question, either because
3454       * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3455       * because it matches one of the users profiles.
3456       */
notificationMatchesCurrentProfiles(NotificationRecord r, int userId)3457      private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3458          return notificationMatchesUserId(r, userId)
3459                  || mUserProfiles.isCurrentProfile(r.getUserId());
3460      }
3461  
3462      /**
3463       * Cancels all notifications from a given package that have all of the
3464       * {@code mustHaveFlags}.
3465       */
cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason, ManagedServiceInfo listener)3466      boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3467              int mustNotHaveFlags, boolean doit, int userId, int reason,
3468              ManagedServiceInfo listener) {
3469          String listenerName = listener == null ? null : listener.component.toShortString();
3470          EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3471                  pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3472                  listenerName);
3473  
3474          synchronized (mNotificationList) {
3475              final int N = mNotificationList.size();
3476              ArrayList<NotificationRecord> canceledNotifications = null;
3477              for (int i = N-1; i >= 0; --i) {
3478                  NotificationRecord r = mNotificationList.get(i);
3479                  if (!notificationMatchesUserId(r, userId)) {
3480                      continue;
3481                  }
3482                  // Don't remove notifications to all, if there's no package name specified
3483                  if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3484                      continue;
3485                  }
3486                  if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3487                      continue;
3488                  }
3489                  if ((r.getFlags() & mustNotHaveFlags) != 0) {
3490                      continue;
3491                  }
3492                  if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3493                      continue;
3494                  }
3495                  if (canceledNotifications == null) {
3496                      canceledNotifications = new ArrayList<>();
3497                  }
3498                  canceledNotifications.add(r);
3499                  if (!doit) {
3500                      return true;
3501                  }
3502                  mNotificationList.remove(i);
3503                  cancelNotificationLocked(r, false, reason);
3504              }
3505              if (doit && canceledNotifications != null) {
3506                  final int M = canceledNotifications.size();
3507                  for (int i = 0; i < M; i++) {
3508                      cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3509                              listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3510                  }
3511              }
3512              if (canceledNotifications != null) {
3513                  updateLightsLocked();
3514              }
3515              return canceledNotifications != null;
3516          }
3517      }
3518  
cancelAllLocked(int callingUid, int callingPid, int userId, int reason, ManagedServiceInfo listener, boolean includeCurrentProfiles)3519      void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3520              ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3521          String listenerName = listener == null ? null : listener.component.toShortString();
3522          EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3523                  null, userId, 0, 0, reason, listenerName);
3524  
3525          ArrayList<NotificationRecord> canceledNotifications = null;
3526          final int N = mNotificationList.size();
3527          for (int i=N-1; i>=0; i--) {
3528              NotificationRecord r = mNotificationList.get(i);
3529              if (includeCurrentProfiles) {
3530                  if (!notificationMatchesCurrentProfiles(r, userId)) {
3531                      continue;
3532                  }
3533              } else {
3534                  if (!notificationMatchesUserId(r, userId)) {
3535                      continue;
3536                  }
3537              }
3538  
3539              if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3540                              | Notification.FLAG_NO_CLEAR)) == 0) {
3541                  mNotificationList.remove(i);
3542                  cancelNotificationLocked(r, true, reason);
3543                  // Make a note so we can cancel children later.
3544                  if (canceledNotifications == null) {
3545                      canceledNotifications = new ArrayList<>();
3546                  }
3547                  canceledNotifications.add(r);
3548              }
3549          }
3550          int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3551          for (int i = 0; i < M; i++) {
3552              cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3553                      listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3554          }
3555          updateLightsLocked();
3556      }
3557  
3558      // Warning: The caller is responsible for invoking updateLightsLocked().
cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, String listenerName, int reason, boolean sendDelete)3559      private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3560              String listenerName, int reason, boolean sendDelete) {
3561          Notification n = r.getNotification();
3562          if (!n.isGroupSummary()) {
3563              return;
3564          }
3565  
3566          String pkg = r.sbn.getPackageName();
3567          int userId = r.getUserId();
3568  
3569          if (pkg == null) {
3570              if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3571              return;
3572          }
3573  
3574          final int N = mNotificationList.size();
3575          for (int i = N - 1; i >= 0; i--) {
3576              NotificationRecord childR = mNotificationList.get(i);
3577              StatusBarNotification childSbn = childR.sbn;
3578              if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3579                      childR.getGroupKey().equals(r.getGroupKey())
3580                      && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
3581                  EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3582                          childSbn.getTag(), userId, 0, 0, reason, listenerName);
3583                  mNotificationList.remove(i);
3584                  cancelNotificationLocked(childR, sendDelete, reason);
3585              }
3586          }
3587      }
3588  
3589      // lock on mNotificationList
updateLightsLocked()3590      void updateLightsLocked()
3591      {
3592          // handle notification lights
3593          NotificationRecord ledNotification = null;
3594          while (ledNotification == null && !mLights.isEmpty()) {
3595              final String owner = mLights.get(mLights.size() - 1);
3596              ledNotification = mNotificationsByKey.get(owner);
3597              if (ledNotification == null) {
3598                  Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3599                  mLights.remove(owner);
3600              }
3601          }
3602  
3603          // Don't flash while we are in a call or screen is on
3604          if (ledNotification == null || mInCall || mScreenOn) {
3605              mNotificationLight.turnOff();
3606              if (mStatusBar != null) {
3607                  mStatusBar.notificationLightOff();
3608              }
3609          } else {
3610              final Notification ledno = ledNotification.sbn.getNotification();
3611              int ledARGB = ledno.ledARGB;
3612              int ledOnMS = ledno.ledOnMS;
3613              int ledOffMS = ledno.ledOffMS;
3614              if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3615                  ledARGB = mDefaultNotificationColor;
3616                  ledOnMS = mDefaultNotificationLedOn;
3617                  ledOffMS = mDefaultNotificationLedOff;
3618              }
3619              if (mNotificationPulseEnabled) {
3620                  // pulse repeatedly
3621                  mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3622                          ledOnMS, ledOffMS);
3623              }
3624              if (mStatusBar != null) {
3625                  // let SystemUI make an independent decision
3626                  mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3627              }
3628          }
3629      }
3630  
3631      // lock on mNotificationList
indexOfNotificationLocked(String pkg, String tag, int id, int userId)3632      int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3633      {
3634          ArrayList<NotificationRecord> list = mNotificationList;
3635          final int len = list.size();
3636          for (int i=0; i<len; i++) {
3637              NotificationRecord r = list.get(i);
3638              if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3639                      TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3640                  return i;
3641              }
3642          }
3643          return -1;
3644      }
3645  
3646      // lock on mNotificationList
indexOfNotificationLocked(String key)3647      int indexOfNotificationLocked(String key) {
3648          final int N = mNotificationList.size();
3649          for (int i = 0; i < N; i++) {
3650              if (key.equals(mNotificationList.get(i).getKey())) {
3651                  return i;
3652              }
3653          }
3654          return -1;
3655      }
3656  
updateNotificationPulse()3657      private void updateNotificationPulse() {
3658          synchronized (mNotificationList) {
3659              updateLightsLocked();
3660          }
3661      }
3662  
isUidSystem(int uid)3663      private static boolean isUidSystem(int uid) {
3664          final int appid = UserHandle.getAppId(uid);
3665          return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3666      }
3667  
isCallerSystem()3668      private static boolean isCallerSystem() {
3669          return isUidSystem(Binder.getCallingUid());
3670      }
3671  
checkCallerIsSystem()3672      private static void checkCallerIsSystem() {
3673          if (isCallerSystem()) {
3674              return;
3675          }
3676          throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3677      }
3678  
checkCallerIsSystemOrSameApp(String pkg)3679      private static void checkCallerIsSystemOrSameApp(String pkg) {
3680          if (isCallerSystem()) {
3681              return;
3682          }
3683          checkCallerIsSameApp(pkg);
3684      }
3685  
checkCallerIsSameApp(String pkg)3686      private static void checkCallerIsSameApp(String pkg) {
3687          final int uid = Binder.getCallingUid();
3688          try {
3689              ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3690                      pkg, 0, UserHandle.getCallingUserId());
3691              if (ai == null) {
3692                  throw new SecurityException("Unknown package " + pkg);
3693              }
3694              if (!UserHandle.isSameApp(ai.uid, uid)) {
3695                  throw new SecurityException("Calling uid " + uid + " gave package"
3696                          + pkg + " which is owned by uid " + ai.uid);
3697              }
3698          } catch (RemoteException re) {
3699              throw new SecurityException("Unknown package " + pkg + "\n" + re);
3700          }
3701      }
3702  
callStateToString(int state)3703      private static String callStateToString(int state) {
3704          switch (state) {
3705              case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3706              case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3707              case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3708              default: return "CALL_STATE_UNKNOWN_" + state;
3709          }
3710      }
3711  
listenForCallState()3712      private void listenForCallState() {
3713          TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3714              @Override
3715              public void onCallStateChanged(int state, String incomingNumber) {
3716                  if (mCallState == state) return;
3717                  if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3718                  mCallState = state;
3719              }
3720          }, PhoneStateListener.LISTEN_CALL_STATE);
3721      }
3722  
3723      /**
3724       * Generates a NotificationRankingUpdate from 'sbns', considering only
3725       * notifications visible to the given listener.
3726       *
3727       * <p>Caller must hold a lock on mNotificationList.</p>
3728       */
makeRankingUpdateLocked(ManagedServiceInfo info)3729      private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3730          final int N = mNotificationList.size();
3731          ArrayList<String> keys = new ArrayList<String>(N);
3732          ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3733          ArrayList<Integer> importance = new ArrayList<>(N);
3734          Bundle overrideGroupKeys = new Bundle();
3735          Bundle visibilityOverrides = new Bundle();
3736          Bundle suppressedVisualEffects = new Bundle();
3737          Bundle explanation = new Bundle();
3738          for (int i = 0; i < N; i++) {
3739              NotificationRecord record = mNotificationList.get(i);
3740              if (!isVisibleToListener(record.sbn, info)) {
3741                  continue;
3742              }
3743              final String key = record.sbn.getKey();
3744              keys.add(key);
3745              importance.add(record.getImportance());
3746              if (record.getImportanceExplanation() != null) {
3747                  explanation.putCharSequence(key, record.getImportanceExplanation());
3748              }
3749              if (record.isIntercepted()) {
3750                  interceptedKeys.add(key);
3751  
3752              }
3753              suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3754              if (record.getPackageVisibilityOverride()
3755                      != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3756                  visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3757              }
3758              overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3759          }
3760          final int M = keys.size();
3761          String[] keysAr = keys.toArray(new String[M]);
3762          String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3763          int[] importanceAr = new int[M];
3764          for (int i = 0; i < M; i++) {
3765              importanceAr[i] = importance.get(i);
3766          }
3767          return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3768                  suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
3769      }
3770  
isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener)3771      private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3772          if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3773              return false;
3774          }
3775          // TODO: remove this for older listeners.
3776          return true;
3777      }
3778  
isPackageSuspendedForUser(String pkg, int uid)3779      private boolean isPackageSuspendedForUser(String pkg, int uid) {
3780          int userId = UserHandle.getUserId(uid);
3781          try {
3782              return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3783          } catch (RemoteException re) {
3784              throw new SecurityException("Could not talk to package manager service");
3785          } catch (IllegalArgumentException ex) {
3786              // Package not found.
3787              return false;
3788          }
3789      }
3790  
3791      private class TrimCache {
3792          StatusBarNotification heavy;
3793          StatusBarNotification sbnClone;
3794          StatusBarNotification sbnCloneLight;
3795  
TrimCache(StatusBarNotification sbn)3796          TrimCache(StatusBarNotification sbn) {
3797              heavy = sbn;
3798          }
3799  
ForListener(ManagedServiceInfo info)3800          StatusBarNotification ForListener(ManagedServiceInfo info) {
3801              if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3802                  if (sbnCloneLight == null) {
3803                      sbnCloneLight = heavy.cloneLight();
3804                  }
3805                  return sbnCloneLight;
3806              } else {
3807                  if (sbnClone == null) {
3808                      sbnClone = heavy.clone();
3809                  }
3810                  return sbnClone;
3811              }
3812          }
3813      }
3814  
3815      public class NotificationRankers extends ManagedServices {
3816  
NotificationRankers()3817          public NotificationRankers() {
3818              super(getContext(), mHandler, mNotificationList, mUserProfiles);
3819          }
3820  
3821          @Override
getConfig()3822          protected Config getConfig() {
3823              Config c = new Config();
3824              c.caption = "notification ranker service";
3825              c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3826              c.secureSettingName = null;
3827              c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3828              c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3829              c.clientLabel = R.string.notification_ranker_binding_label;
3830              return c;
3831          }
3832  
3833          @Override
asInterface(IBinder binder)3834          protected IInterface asInterface(IBinder binder) {
3835              return INotificationListener.Stub.asInterface(binder);
3836          }
3837  
3838          @Override
checkType(IInterface service)3839          protected boolean checkType(IInterface service) {
3840              return service instanceof INotificationListener;
3841          }
3842  
3843          @Override
onServiceAdded(ManagedServiceInfo info)3844          protected void onServiceAdded(ManagedServiceInfo info) {
3845              mListeners.registerGuestService(info);
3846          }
3847  
3848          @Override
onServiceRemovedLocked(ManagedServiceInfo removed)3849          protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3850              mListeners.unregisterService(removed.service, removed.userid);
3851          }
3852  
onNotificationEnqueued(final NotificationRecord r)3853          public void onNotificationEnqueued(final NotificationRecord r) {
3854              final StatusBarNotification sbn = r.sbn;
3855              TrimCache trimCache = new TrimCache(sbn);
3856  
3857              // mServices is the list inside ManagedServices of all the rankers,
3858              // There should be only one, but it's a list, so while we enforce
3859              // singularity elsewhere, we keep it general here, to avoid surprises.
3860              for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3861                  boolean sbnVisible = isVisibleToListener(sbn, info);
3862                  if (!sbnVisible) {
3863                      continue;
3864                  }
3865  
3866                  final int importance = r.getImportance();
3867                  final boolean fromUser = r.isImportanceFromUser();
3868                  final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
3869                  mHandler.post(new Runnable() {
3870                      @Override
3871                      public void run() {
3872                          notifyEnqueued(info, sbnToPost, importance, fromUser);
3873                      }
3874                  });
3875              }
3876          }
3877  
notifyEnqueued(final ManagedServiceInfo info, final StatusBarNotification sbn, int importance, boolean fromUser)3878          private void notifyEnqueued(final ManagedServiceInfo info,
3879                  final StatusBarNotification sbn, int importance, boolean fromUser) {
3880              final INotificationListener ranker = (INotificationListener) info.service;
3881              StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3882              try {
3883                  ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3884              } catch (RemoteException ex) {
3885                  Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3886              }
3887          }
3888  
isEnabled()3889          public boolean isEnabled() {
3890              return !mServices.isEmpty();
3891          }
3892  
3893          @Override
onUserSwitched(int user)3894          public void onUserSwitched(int user) {
3895              synchronized (mNotificationList) {
3896                  int i = mServices.size()-1;
3897                  while (i --> 0) {
3898                      final ManagedServiceInfo info = mServices.get(i);
3899                      unregisterService(info.service, info.userid);
3900                  }
3901              }
3902              registerRanker();
3903          }
3904  
3905          @Override
onPackagesChanged(boolean removingPackage, String[] pkgList)3906          public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
3907              if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
3908                      + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3909              if (mRankerServicePackageName == null) {
3910                  return;
3911              }
3912  
3913              if (pkgList != null && (pkgList.length > 0) && !removingPackage) {
3914                  for (String pkgName : pkgList) {
3915                      if (mRankerServicePackageName.equals(pkgName)) {
3916                          registerRanker();
3917                      }
3918                  }
3919              }
3920          }
3921  
registerRanker()3922          protected void registerRanker() {
3923              // Find the updatable ranker and register it.
3924              if (mRankerServicePackageName == null) {
3925                  Slog.w(TAG, "could not start ranker service: no package specified!");
3926                  return;
3927              }
3928              Set<ComponentName> rankerComponents = queryPackageForServices(
3929                      mRankerServicePackageName, UserHandle.USER_SYSTEM);
3930              Iterator<ComponentName> iterator = rankerComponents.iterator();
3931              if (iterator.hasNext()) {
3932                  ComponentName rankerComponent = iterator.next();
3933                  if (iterator.hasNext()) {
3934                      Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3935                  } else {
3936                      registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3937                  }
3938              } else {
3939                  Slog.w(TAG, "could not start ranker service: none found");
3940              }
3941          }
3942      }
3943  
3944      public class NotificationListeners extends ManagedServices {
3945  
3946          private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3947  
NotificationListeners()3948          public NotificationListeners() {
3949              super(getContext(), mHandler, mNotificationList, mUserProfiles);
3950          }
3951  
3952          @Override
getConfig()3953          protected Config getConfig() {
3954              Config c = new Config();
3955              c.caption = "notification listener";
3956              c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3957              c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3958              c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3959              c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3960              c.clientLabel = R.string.notification_listener_binding_label;
3961              return c;
3962          }
3963  
3964          @Override
asInterface(IBinder binder)3965          protected IInterface asInterface(IBinder binder) {
3966              return INotificationListener.Stub.asInterface(binder);
3967          }
3968  
3969          @Override
checkType(IInterface service)3970          protected boolean checkType(IInterface service) {
3971              return service instanceof INotificationListener;
3972          }
3973  
3974          @Override
onServiceAdded(ManagedServiceInfo info)3975          public void onServiceAdded(ManagedServiceInfo info) {
3976              final INotificationListener listener = (INotificationListener) info.service;
3977              final NotificationRankingUpdate update;
3978              synchronized (mNotificationList) {
3979                  update = makeRankingUpdateLocked(info);
3980              }
3981              try {
3982                  listener.onListenerConnected(update);
3983              } catch (RemoteException e) {
3984                  // we tried
3985              }
3986          }
3987  
3988          @Override
onServiceRemovedLocked(ManagedServiceInfo removed)3989          protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3990              if (removeDisabledHints(removed)) {
3991                  updateListenerHintsLocked();
3992                  updateEffectsSuppressorLocked();
3993              }
3994              mLightTrimListeners.remove(removed);
3995          }
3996  
setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim)3997          public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3998              if (trim == TRIM_LIGHT) {
3999                  mLightTrimListeners.add(info);
4000              } else {
4001                  mLightTrimListeners.remove(info);
4002              }
4003          }
4004  
getOnNotificationPostedTrim(ManagedServiceInfo info)4005          public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4006              return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
4007          }
4008  
4009          /**
4010           * asynchronously notify all listeners about a new notification
4011           *
4012           * <p>
4013           * Also takes care of removing a notification that has been visible to a listener before,
4014           * but isn't anymore.
4015           */
notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn)4016          public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
4017              // Lazily initialized snapshots of the notification.
4018              TrimCache trimCache = new TrimCache(sbn);
4019  
4020              for (final ManagedServiceInfo info : mServices) {
4021                  boolean sbnVisible = isVisibleToListener(sbn, info);
4022                  boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4023                  // This notification hasn't been and still isn't visible -> ignore.
4024                  if (!oldSbnVisible && !sbnVisible) {
4025                      continue;
4026                  }
4027                  final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4028  
4029                  // This notification became invisible -> remove the old one.
4030                  if (oldSbnVisible && !sbnVisible) {
4031                      final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4032                      mHandler.post(new Runnable() {
4033                          @Override
4034                          public void run() {
4035                              notifyRemoved(info, oldSbnLightClone, update);
4036                          }
4037                      });
4038                      continue;
4039                  }
4040  
4041                  final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4042                  mHandler.post(new Runnable() {
4043                      @Override
4044                      public void run() {
4045                          notifyPosted(info, sbnToPost, update);
4046                      }
4047                  });
4048              }
4049          }
4050  
4051          /**
4052           * asynchronously notify all listeners about a removed notification
4053           */
notifyRemovedLocked(StatusBarNotification sbn)4054          public void notifyRemovedLocked(StatusBarNotification sbn) {
4055              // make a copy in case changes are made to the underlying Notification object
4056              // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4057              // notification
4058              final StatusBarNotification sbnLight = sbn.cloneLight();
4059              for (final ManagedServiceInfo info : mServices) {
4060                  if (!isVisibleToListener(sbn, info)) {
4061                      continue;
4062                  }
4063                  final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4064                  mHandler.post(new Runnable() {
4065                      @Override
4066                      public void run() {
4067                          notifyRemoved(info, sbnLight, update);
4068                      }
4069                  });
4070              }
4071          }
4072  
4073          /**
4074           * asynchronously notify all listeners about a reordering of notifications
4075           */
notifyRankingUpdateLocked()4076          public void notifyRankingUpdateLocked() {
4077              for (final ManagedServiceInfo serviceInfo : mServices) {
4078                  if (!serviceInfo.isEnabledForCurrentProfiles()) {
4079                      continue;
4080                  }
4081                  final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
4082                  mHandler.post(new Runnable() {
4083                      @Override
4084                      public void run() {
4085                          notifyRankingUpdate(serviceInfo, update);
4086                      }
4087                  });
4088              }
4089          }
4090  
notifyListenerHintsChangedLocked(final int hints)4091          public void notifyListenerHintsChangedLocked(final int hints) {
4092              for (final ManagedServiceInfo serviceInfo : mServices) {
4093                  if (!serviceInfo.isEnabledForCurrentProfiles()) {
4094                      continue;
4095                  }
4096                  mHandler.post(new Runnable() {
4097                      @Override
4098                      public void run() {
4099                          notifyListenerHintsChanged(serviceInfo, hints);
4100                      }
4101                  });
4102              }
4103          }
4104  
notifyInterruptionFilterChanged(final int interruptionFilter)4105          public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4106              for (final ManagedServiceInfo serviceInfo : mServices) {
4107                  if (!serviceInfo.isEnabledForCurrentProfiles()) {
4108                      continue;
4109                  }
4110                  mHandler.post(new Runnable() {
4111                      @Override
4112                      public void run() {
4113                          notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4114                      }
4115                  });
4116              }
4117          }
4118  
notifyPosted(final ManagedServiceInfo info, final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate)4119          private void notifyPosted(final ManagedServiceInfo info,
4120                  final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4121              final INotificationListener listener = (INotificationListener)info.service;
4122              StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4123              try {
4124                  listener.onNotificationPosted(sbnHolder, rankingUpdate);
4125              } catch (RemoteException ex) {
4126                  Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4127              }
4128          }
4129  
notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate)4130          private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4131                  NotificationRankingUpdate rankingUpdate) {
4132              if (!info.enabledAndUserMatches(sbn.getUserId())) {
4133                  return;
4134              }
4135              final INotificationListener listener = (INotificationListener) info.service;
4136              StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4137              try {
4138                  listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4139              } catch (RemoteException ex) {
4140                  Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4141              }
4142          }
4143  
notifyRankingUpdate(ManagedServiceInfo info, NotificationRankingUpdate rankingUpdate)4144          private void notifyRankingUpdate(ManagedServiceInfo info,
4145                                           NotificationRankingUpdate rankingUpdate) {
4146              final INotificationListener listener = (INotificationListener) info.service;
4147              try {
4148                  listener.onNotificationRankingUpdate(rankingUpdate);
4149              } catch (RemoteException ex) {
4150                  Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4151              }
4152          }
4153  
notifyListenerHintsChanged(ManagedServiceInfo info, int hints)4154          private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4155              final INotificationListener listener = (INotificationListener) info.service;
4156              try {
4157                  listener.onListenerHintsChanged(hints);
4158              } catch (RemoteException ex) {
4159                  Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4160              }
4161          }
4162  
notifyInterruptionFilterChanged(ManagedServiceInfo info, int interruptionFilter)4163          private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4164                  int interruptionFilter) {
4165              final INotificationListener listener = (INotificationListener) info.service;
4166              try {
4167                  listener.onInterruptionFilterChanged(interruptionFilter);
4168              } catch (RemoteException ex) {
4169                  Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4170              }
4171          }
4172  
isListenerPackage(String packageName)4173          private boolean isListenerPackage(String packageName) {
4174              if (packageName == null) {
4175                  return false;
4176              }
4177              // TODO: clean up locking object later
4178              synchronized (mNotificationList) {
4179                  for (final ManagedServiceInfo serviceInfo : mServices) {
4180                      if (packageName.equals(serviceInfo.component.getPackageName())) {
4181                          return true;
4182                      }
4183                  }
4184              }
4185              return false;
4186          }
4187      }
4188  
4189      public static final class DumpFilter {
4190          public boolean filtered = false;
4191          public String pkgFilter;
4192          public boolean zen;
4193          public long since;
4194          public boolean stats;
4195          public boolean redact = true;
4196  
parseFromArguments(String[] args)4197          public static DumpFilter parseFromArguments(String[] args) {
4198              final DumpFilter filter = new DumpFilter();
4199              for (int ai = 0; ai < args.length; ai++) {
4200                  final String a = args[ai];
4201                  if ("--noredact".equals(a) || "--reveal".equals(a)) {
4202                      filter.redact = false;
4203                  } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4204                      if (ai < args.length-1) {
4205                          ai++;
4206                          filter.pkgFilter = args[ai].trim().toLowerCase();
4207                          if (filter.pkgFilter.isEmpty()) {
4208                              filter.pkgFilter = null;
4209                          } else {
4210                              filter.filtered = true;
4211                          }
4212                      }
4213                  } else if ("--zen".equals(a) || "zen".equals(a)) {
4214                      filter.filtered = true;
4215                      filter.zen = true;
4216                  } else if ("--stats".equals(a)) {
4217                      filter.stats = true;
4218                      if (ai < args.length-1) {
4219                          ai++;
4220                          filter.since = Long.valueOf(args[ai]);
4221                      } else {
4222                          filter.since = 0;
4223                      }
4224                  }
4225              }
4226              return filter;
4227          }
4228  
matches(StatusBarNotification sbn)4229          public boolean matches(StatusBarNotification sbn) {
4230              if (!filtered) return true;
4231              return zen ? true : sbn != null
4232                      && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4233          }
4234  
matches(ComponentName component)4235          public boolean matches(ComponentName component) {
4236              if (!filtered) return true;
4237              return zen ? true : component != null && matches(component.getPackageName());
4238          }
4239  
matches(String pkg)4240          public boolean matches(String pkg) {
4241              if (!filtered) return true;
4242              return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4243          }
4244  
4245          @Override
toString()4246          public String toString() {
4247              return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4248          }
4249      }
4250  
4251      /**
4252       * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4253       * binder without sending large amounts of data over a oneway transaction.
4254       */
4255      private static final class StatusBarNotificationHolder
4256              extends IStatusBarNotificationHolder.Stub {
4257          private StatusBarNotification mValue;
4258  
StatusBarNotificationHolder(StatusBarNotification value)4259          public StatusBarNotificationHolder(StatusBarNotification value) {
4260              mValue = value;
4261          }
4262  
4263          /** Get the held value and clear it. This function should only be called once per holder */
4264          @Override
get()4265          public StatusBarNotification get() {
4266              StatusBarNotification value = mValue;
4267              mValue = null;
4268              return value;
4269          }
4270      }
4271  
4272      private final class PolicyAccess {
4273          private static final String SEPARATOR = ":";
4274          private final String[] PERM = {
4275              android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4276          };
4277  
isPackageGranted(String pkg)4278          public boolean isPackageGranted(String pkg) {
4279              return pkg != null && getGrantedPackages().contains(pkg);
4280          }
4281  
put(String pkg, boolean granted)4282          public void put(String pkg, boolean granted) {
4283              if (pkg == null) return;
4284              final ArraySet<String> pkgs = getGrantedPackages();
4285              boolean changed;
4286              if (granted) {
4287                  changed = pkgs.add(pkg);
4288              } else {
4289                  changed = pkgs.remove(pkg);
4290              }
4291              if (!changed) return;
4292              final String setting = TextUtils.join(SEPARATOR, pkgs);
4293              final int currentUser = ActivityManager.getCurrentUser();
4294              Settings.Secure.putStringForUser(getContext().getContentResolver(),
4295                      Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4296                      setting,
4297                      currentUser);
4298              getContext().sendBroadcastAsUser(new Intent(NotificationManager
4299                      .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4300                  .setPackage(pkg)
4301                  .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4302          }
4303  
getGrantedPackages()4304          public ArraySet<String> getGrantedPackages() {
4305              final ArraySet<String> pkgs = new ArraySet<>();
4306  
4307              long identity = Binder.clearCallingIdentity();
4308              try {
4309                  final String setting = Settings.Secure.getStringForUser(
4310                          getContext().getContentResolver(),
4311                          Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4312                          ActivityManager.getCurrentUser());
4313                  if (setting != null) {
4314                      final String[] tokens = setting.split(SEPARATOR);
4315                      for (int i = 0; i < tokens.length; i++) {
4316                          String token = tokens[i];
4317                          if (token != null) {
4318                              token = token.trim();
4319                          }
4320                          if (TextUtils.isEmpty(token)) {
4321                              continue;
4322                          }
4323                          pkgs.add(token);
4324                      }
4325                  }
4326              } finally {
4327                  Binder.restoreCallingIdentity(identity);
4328              }
4329              return pkgs;
4330          }
4331  
getRequestingPackages()4332          public String[] getRequestingPackages() throws RemoteException {
4333              final ParceledListSlice list = AppGlobals.getPackageManager()
4334                      .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4335                              ActivityManager.getCurrentUser());
4336              final List<PackageInfo> pkgs = list.getList();
4337              if (pkgs == null || pkgs.isEmpty()) return new String[0];
4338              final int N = pkgs.size();
4339              final String[] rt = new String[N];
4340              for (int i = 0; i < N; i++) {
4341                  rt[i] = pkgs.get(i).packageName;
4342              }
4343              return rt;
4344          }
4345      }
4346  }
4347