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