• 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