• 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.app.NotificationManager.IMPORTANCE_LOW;
20 import static android.app.NotificationManager.IMPORTANCE_MIN;
21 import static android.app.NotificationManager.IMPORTANCE_NONE;
22 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
23 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
24 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
25 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
26 import static android.os.UserHandle.USER_NULL;
27 import static android.service.notification.NotificationListenerService
28         .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
29 import static android.service.notification.NotificationListenerService
30         .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
31 import static android.service.notification.NotificationListenerService
32         .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
33 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
34 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
35 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
36 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
37 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
38 import static android.service.notification.NotificationListenerService.REASON_CLICK;
39 import static android.service.notification.NotificationListenerService.REASON_ERROR;
40 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
41 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
42 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
43 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
44 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
45 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
46 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
47 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
48 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
49 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
50 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
51 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
52 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
53 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
54 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
55 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
56 import static android.service.notification.NotificationListenerService.TRIM_FULL;
57 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
58 
59 import static android.view.Display.DEFAULT_DISPLAY;
60 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
61 
62 import android.Manifest;
63 import android.annotation.NonNull;
64 import android.annotation.Nullable;
65 import android.app.ActivityManager;
66 import android.app.ActivityManagerInternal;
67 import android.app.AlarmManager;
68 import android.app.AppGlobals;
69 import android.app.AppOpsManager;
70 import android.app.AutomaticZenRule;
71 import android.app.NotificationChannelGroup;
72 import android.app.backup.BackupManager;
73 import android.app.IActivityManager;
74 import android.app.INotificationManager;
75 import android.app.ITransientNotification;
76 import android.app.Notification;
77 import android.app.NotificationChannel;
78 import android.app.NotificationManager.Policy;
79 import android.app.NotificationManager;
80 import android.app.PendingIntent;
81 import android.app.StatusBarManager;
82 import android.app.usage.UsageEvents;
83 import android.app.usage.UsageStatsManagerInternal;
84 import android.companion.ICompanionDeviceManager;
85 import android.content.BroadcastReceiver;
86 import android.content.ComponentName;
87 import android.content.ContentResolver;
88 import android.content.Context;
89 import android.content.Intent;
90 import android.content.IntentFilter;
91 import android.content.pm.ApplicationInfo;
92 import android.content.pm.IPackageManager;
93 import android.content.pm.PackageManager;
94 import android.content.pm.PackageManager.NameNotFoundException;
95 import android.content.pm.ParceledListSlice;
96 import android.content.res.Resources;
97 import android.database.ContentObserver;
98 import android.media.AudioAttributes;
99 import android.media.AudioManager;
100 import android.media.AudioManagerInternal;
101 import android.media.IRingtonePlayer;
102 import android.net.Uri;
103 import android.os.Binder;
104 import android.os.Build;
105 import android.os.Bundle;
106 import android.os.Environment;
107 import android.os.Handler;
108 import android.os.HandlerThread;
109 import android.os.IBinder;
110 import android.os.IInterface;
111 import android.os.Looper;
112 import android.os.Message;
113 import android.os.Process;
114 import android.os.RemoteException;
115 import android.os.ResultReceiver;
116 import android.os.ServiceManager;
117 import android.os.ShellCallback;
118 import android.os.ShellCommand;
119 import android.os.SystemClock;
120 import android.os.SystemProperties;
121 import android.os.UserHandle;
122 import android.os.Vibrator;
123 import android.os.VibrationEffect;
124 import android.provider.Settings;
125 import android.service.notification.Adjustment;
126 import android.service.notification.Condition;
127 import android.service.notification.IConditionProvider;
128 import android.service.notification.INotificationListener;
129 import android.service.notification.IStatusBarNotificationHolder;
130 import android.service.notification.NotificationAssistantService;
131 import android.service.notification.NotificationListenerService;
132 import android.service.notification.NotificationRankingUpdate;
133 import android.service.notification.NotificationRecordProto;
134 import android.service.notification.NotificationServiceDumpProto;
135 import android.service.notification.NotificationServiceProto;
136 import android.service.notification.SnoozeCriterion;
137 import android.service.notification.StatusBarNotification;
138 import android.service.notification.ZenModeConfig;
139 import android.service.notification.ZenModeProto;
140 import android.telecom.TelecomManager;
141 import android.telephony.PhoneStateListener;
142 import android.telephony.TelephonyManager;
143 import android.text.TextUtils;
144 import android.util.ArrayMap;
145 import android.util.ArraySet;
146 import android.util.AtomicFile;
147 import android.util.Log;
148 import android.util.Slog;
149 import android.util.SparseArray;
150 import android.util.Xml;
151 import android.util.proto.ProtoOutputStream;
152 import android.view.WindowManagerInternal;
153 import android.view.accessibility.AccessibilityEvent;
154 import android.view.accessibility.AccessibilityManager;
155 import android.widget.Toast;
156 
157 import com.android.internal.R;
158 import com.android.internal.annotations.GuardedBy;
159 import com.android.internal.annotations.VisibleForTesting;
160 import com.android.internal.logging.MetricsLogger;
161 import com.android.internal.logging.nano.MetricsProto;
162 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
163 import com.android.internal.os.BackgroundThread;
164 import com.android.internal.statusbar.NotificationVisibility;
165 import com.android.internal.util.ArrayUtils;
166 import com.android.internal.util.DumpUtils;
167 import com.android.internal.util.FastXmlSerializer;
168 import com.android.internal.util.Preconditions;
169 import com.android.internal.util.XmlUtils;
170 import com.android.server.DeviceIdleController;
171 import com.android.server.EventLogTags;
172 import com.android.server.LocalServices;
173 import com.android.server.SystemService;
174 import com.android.server.lights.Light;
175 import com.android.server.lights.LightsManager;
176 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
177 import com.android.server.policy.PhoneWindowManager;
178 import com.android.server.statusbar.StatusBarManagerInternal;
179 import com.android.server.notification.ManagedServices.UserProfiles;
180 
181 import libcore.io.IoUtils;
182 
183 import org.json.JSONException;
184 import org.json.JSONObject;
185 import org.xmlpull.v1.XmlPullParser;
186 import org.xmlpull.v1.XmlPullParserException;
187 import org.xmlpull.v1.XmlSerializer;
188 
189 import java.io.ByteArrayInputStream;
190 import java.io.ByteArrayOutputStream;
191 import java.io.File;
192 import java.io.FileDescriptor;
193 import java.io.FileNotFoundException;
194 import java.io.FileOutputStream;
195 import java.io.IOException;
196 import java.io.InputStream;
197 import java.io.OutputStream;
198 import java.io.PrintWriter;
199 import java.net.URI;
200 import java.nio.charset.StandardCharsets;
201 import java.util.ArrayDeque;
202 import java.util.ArrayList;
203 import java.util.Arrays;
204 import java.util.Iterator;
205 import java.util.List;
206 import java.util.Map.Entry;
207 import java.util.Objects;
208 import java.util.Set;
209 import java.util.concurrent.TimeUnit;
210 
211 /** {@hide} */
212 public class NotificationManagerService extends SystemService {
213     static final String TAG = "NotificationService";
214     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
215     public static final boolean ENABLE_CHILD_NOTIFICATIONS
216             = SystemProperties.getBoolean("debug.child_notifs", true);
217 
218     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
219     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
220 
221     // message codes
222     static final int MESSAGE_TIMEOUT = 2;
223     static final int MESSAGE_SAVE_POLICY_FILE = 3;
224     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
225     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
226     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
227 
228     // ranking thread messages
229     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
230     private static final int MESSAGE_RANKING_SORT = 1001;
231 
232     static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
233     static final int SHORT_DELAY = 2000; // 2 seconds
234 
235     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
236 
237     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
238 
239     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
240 
241     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
242 
243     static final boolean ENABLE_BLOCKED_TOASTS = true;
244 
245     // When #matchesCallFilter is called from the ringer, wait at most
246     // 3s to resolve the contacts. This timeout is required since
247     // ContactsProvider might take a long time to start up.
248     //
249     // Return STARRED_CONTACT when the timeout is hit in order to avoid
250     // missed calls in ZEN mode "Important".
251     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
252     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
253             ValidateNotificationPeople.STARRED_CONTACT;
254 
255     /** notification_enqueue status value for a newly enqueued notification. */
256     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
257 
258     /** notification_enqueue status value for an existing notification. */
259     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
260 
261     /** notification_enqueue status value for an ignored notification. */
262     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
263     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
264 
265     private static final long DELAY_FOR_ASSISTANT_TIME = 100;
266 
267     private static final String ACTION_NOTIFICATION_TIMEOUT =
268             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
269     private static final int REQUEST_CODE_TIMEOUT = 1;
270     private static final String SCHEME_TIMEOUT = "timeout";
271     private static final String EXTRA_KEY = "key";
272 
273     private IActivityManager mAm;
274     private ActivityManager mActivityManager;
275     private IPackageManager mPackageManager;
276     private PackageManager mPackageManagerClient;
277     AudioManager mAudioManager;
278     AudioManagerInternal mAudioManagerInternal;
279     @Nullable StatusBarManagerInternal mStatusBar;
280     Vibrator mVibrator;
281     private WindowManagerInternal mWindowManagerInternal;
282     private AlarmManager mAlarmManager;
283     private ICompanionDeviceManager mCompanionManager;
284     private AccessibilityManager mAccessibilityManager;
285 
286     final IBinder mForegroundToken = new Binder();
287     private WorkerHandler mHandler;
288     private final HandlerThread mRankingThread = new HandlerThread("ranker",
289             Process.THREAD_PRIORITY_BACKGROUND);
290 
291     private Light mNotificationLight;
292     Light mAttentionLight;
293 
294     private long[] mFallbackVibrationPattern;
295     private boolean mUseAttentionLight;
296     boolean mSystemReady;
297 
298     private boolean mDisableNotificationEffects;
299     private int mCallState;
300     private String mSoundNotificationKey;
301     private String mVibrateNotificationKey;
302 
303     private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
304             new SparseArray<>();
305     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
306     private int mListenerHints;  // right now, all hints are global
307     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
308 
309     // for enabling and disabling notification pulse behavior
310     private boolean mScreenOn = true;
311     protected boolean mInCall = false;
312     private boolean mNotificationPulseEnabled;
313 
314     private Uri mInCallNotificationUri;
315     private AudioAttributes mInCallNotificationAudioAttributes;
316     private float mInCallNotificationVolume;
317 
318     // used as a mutex for access to all active notifications & listeners
319     final Object mNotificationLock = new Object();
320     @GuardedBy("mNotificationLock")
321     final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
322     @GuardedBy("mNotificationLock")
323     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
324     @GuardedBy("mNotificationLock")
325     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
326     @GuardedBy("mNotificationLock")
327     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
328     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
329     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
330 
331     // The last key in this list owns the hardware.
332     ArrayList<String> mLights = new ArrayList<>();
333 
334     private AppOpsManager mAppOps;
335     private UsageStatsManagerInternal mAppUsageStats;
336 
337     private Archive mArchive;
338 
339     // Persistent storage for notification policy
340     private AtomicFile mPolicyFile;
341 
342     private static final int DB_VERSION = 1;
343 
344     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
345     private static final String ATTR_VERSION = "version";
346 
347     private RankingHelper mRankingHelper;
348 
349     private final UserProfiles mUserProfiles = new UserProfiles();
350     private NotificationListeners mListeners;
351     private NotificationAssistants mAssistants;
352     private ConditionProviders mConditionProviders;
353     private NotificationUsageStats mUsageStats;
354 
355     private static final int MY_UID = Process.myUid();
356     private static final int MY_PID = Process.myPid();
357     private static final IBinder WHITELIST_TOKEN = new Binder();
358     private RankingHandler mRankingHandler;
359     private long mLastOverRateLogTime;
360     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
361 
362     private SnoozeHelper mSnoozeHelper;
363     private GroupHelper mGroupHelper;
364     private boolean mIsTelevision;
365 
366     private static class Archive {
367         final int mBufferSize;
368         final ArrayDeque<StatusBarNotification> mBuffer;
369 
Archive(int size)370         public Archive(int size) {
371             mBufferSize = size;
372             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
373         }
374 
toString()375         public String toString() {
376             final StringBuilder sb = new StringBuilder();
377             final int N = mBuffer.size();
378             sb.append("Archive (");
379             sb.append(N);
380             sb.append(" notification");
381             sb.append((N==1)?")":"s)");
382             return sb.toString();
383         }
384 
record(StatusBarNotification nr)385         public void record(StatusBarNotification nr) {
386             if (mBuffer.size() == mBufferSize) {
387                 mBuffer.removeFirst();
388             }
389 
390             // We don't want to store the heavy bits of the notification in the archive,
391             // but other clients in the system process might be using the object, so we
392             // store a (lightened) copy.
393             mBuffer.addLast(nr.cloneLight());
394         }
395 
descendingIterator()396         public Iterator<StatusBarNotification> descendingIterator() {
397             return mBuffer.descendingIterator();
398         }
399 
getArray(int count)400         public StatusBarNotification[] getArray(int count) {
401             if (count == 0) count = mBufferSize;
402             final StatusBarNotification[] a
403                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
404             Iterator<StatusBarNotification> iter = descendingIterator();
405             int i=0;
406             while (iter.hasNext() && i < count) {
407                 a[i++] = iter.next();
408             }
409             return a;
410         }
411 
412     }
413 
readDefaultApprovedServices(int userId)414     protected void readDefaultApprovedServices(int userId) {
415         String defaultListenerAccess = getContext().getResources().getString(
416                 com.android.internal.R.string.config_defaultListenerAccessPackages);
417         if (defaultListenerAccess != null) {
418             for (String whitelisted :
419                     defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
420                 // Gather all notification listener components for candidate pkgs.
421                 Set<ComponentName> approvedListeners =
422                         mListeners.queryPackageForServices(whitelisted,
423                                 PackageManager.MATCH_DIRECT_BOOT_AWARE
424                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
425                 for (ComponentName cn : approvedListeners) {
426                     try {
427                         getBinderService().setNotificationListenerAccessGrantedForUser(cn,
428                                     userId, true);
429                     } catch (RemoteException e) {
430                         e.printStackTrace();
431                     }
432                 }
433             }
434         }
435         String defaultDndAccess = getContext().getResources().getString(
436                 com.android.internal.R.string.config_defaultDndAccessPackages);
437         if (defaultListenerAccess != null) {
438             for (String whitelisted :
439                     defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
440                 try {
441                     getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
442                 } catch (RemoteException e) {
443                     e.printStackTrace();
444                 }
445             }
446         }
447     }
448 
readPolicyXml(InputStream stream, boolean forRestore)449     void readPolicyXml(InputStream stream, boolean forRestore)
450             throws XmlPullParserException, NumberFormatException, IOException {
451         final XmlPullParser parser = Xml.newPullParser();
452         parser.setInput(stream, StandardCharsets.UTF_8.name());
453         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
454         boolean migratedManagedServices = false;
455         int outerDepth = parser.getDepth();
456         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
457             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
458                 mZenModeHelper.readXml(parser, forRestore);
459             } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
460                 mRankingHelper.readXml(parser, forRestore);
461             }
462             // No non-system managed services are allowed on low ram devices
463             if (!ActivityManager.isLowRamDeviceStatic()) {
464                 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
465                     mListeners.readXml(parser);
466                     migratedManagedServices = true;
467                 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
468                     mAssistants.readXml(parser);
469                     migratedManagedServices = true;
470                 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
471                     mConditionProviders.readXml(parser);
472                     migratedManagedServices = true;
473                 }
474             }
475         }
476 
477         if (!migratedManagedServices) {
478             mListeners.migrateToXml();
479             mAssistants.migrateToXml();
480             mConditionProviders.migrateToXml();
481             savePolicyFile();
482         }
483     }
484 
loadPolicyFile()485     private void loadPolicyFile() {
486         if (DBG) Slog.d(TAG, "loadPolicyFile");
487         synchronized (mPolicyFile) {
488 
489             InputStream infile = null;
490             try {
491                 infile = mPolicyFile.openRead();
492                 readPolicyXml(infile, false /*forRestore*/);
493             } catch (FileNotFoundException e) {
494                 // No data yet
495                 // Load default managed services approvals
496                 readDefaultApprovedServices(UserHandle.USER_SYSTEM);
497             } catch (IOException e) {
498                 Log.wtf(TAG, "Unable to read notification policy", e);
499             } catch (NumberFormatException e) {
500                 Log.wtf(TAG, "Unable to parse notification policy", e);
501             } catch (XmlPullParserException e) {
502                 Log.wtf(TAG, "Unable to parse notification policy", e);
503             } finally {
504                 IoUtils.closeQuietly(infile);
505             }
506         }
507     }
508 
savePolicyFile()509     public void savePolicyFile() {
510         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
511         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
512     }
513 
handleSavePolicyFile()514     private void handleSavePolicyFile() {
515         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
516         synchronized (mPolicyFile) {
517             final FileOutputStream stream;
518             try {
519                 stream = mPolicyFile.startWrite();
520             } catch (IOException e) {
521                 Slog.w(TAG, "Failed to save policy file", e);
522                 return;
523             }
524 
525             try {
526                 writePolicyXml(stream, false /*forBackup*/);
527                 mPolicyFile.finishWrite(stream);
528             } catch (IOException e) {
529                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
530                 mPolicyFile.failWrite(stream);
531             }
532         }
533         BackupManager.dataChanged(getContext().getPackageName());
534     }
535 
writePolicyXml(OutputStream stream, boolean forBackup)536     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
537         final XmlSerializer out = new FastXmlSerializer();
538         out.setOutput(stream, StandardCharsets.UTF_8.name());
539         out.startDocument(null, true);
540         out.startTag(null, TAG_NOTIFICATION_POLICY);
541         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
542         mZenModeHelper.writeXml(out, forBackup);
543         mRankingHelper.writeXml(out, forBackup);
544         mListeners.writeXml(out, forBackup);
545         mAssistants.writeXml(out, forBackup);
546         mConditionProviders.writeXml(out, forBackup);
547         out.endTag(null, TAG_NOTIFICATION_POLICY);
548         out.endDocument();
549     }
550 
551     /** Use this to check if a package can post a notification or toast. */
checkNotificationOp(String pkg, int uid)552     private boolean checkNotificationOp(String pkg, int uid) {
553         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
554                 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
555     }
556 
557     private static final class ToastRecord
558     {
559         final int pid;
560         final String pkg;
561         ITransientNotification callback;
562         int duration;
563         Binder token;
564 
ToastRecord(int pid, String pkg, ITransientNotification callback, int duration, Binder token)565         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
566                     Binder token) {
567             this.pid = pid;
568             this.pkg = pkg;
569             this.callback = callback;
570             this.duration = duration;
571             this.token = token;
572         }
573 
update(int duration)574         void update(int duration) {
575             this.duration = duration;
576         }
577 
update(ITransientNotification callback)578         void update(ITransientNotification callback) {
579             this.callback = callback;
580         }
581 
dump(PrintWriter pw, String prefix, DumpFilter filter)582         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
583             if (filter != null && !filter.matches(pkg)) return;
584             pw.println(prefix + this);
585         }
586 
587         @Override
toString()588         public final String toString()
589         {
590             return "ToastRecord{"
591                 + Integer.toHexString(System.identityHashCode(this))
592                 + " pkg=" + pkg
593                 + " callback=" + callback
594                 + " duration=" + duration;
595         }
596     }
597 
598     @VisibleForTesting
599     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
600 
601         @Override
602         public void onSetDisabled(int status) {
603             synchronized (mNotificationLock) {
604                 mDisableNotificationEffects =
605                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
606                 if (disableNotificationEffects(null) != null) {
607                     // cancel whatever's going on
608                     long identity = Binder.clearCallingIdentity();
609                     try {
610                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
611                         if (player != null) {
612                             player.stopAsync();
613                         }
614                     } catch (RemoteException e) {
615                     } finally {
616                         Binder.restoreCallingIdentity(identity);
617                     }
618 
619                     identity = Binder.clearCallingIdentity();
620                     try {
621                         mVibrator.cancel();
622                     } finally {
623                         Binder.restoreCallingIdentity(identity);
624                     }
625                 }
626             }
627         }
628 
629         @Override
630         public void onClearAll(int callingUid, int callingPid, int userId) {
631             synchronized (mNotificationLock) {
632                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
633                         /*includeCurrentProfiles*/ true);
634             }
635         }
636 
637         @Override
638         public void onNotificationClick(int callingUid, int callingPid, String key) {
639             synchronized (mNotificationLock) {
640                 NotificationRecord r = mNotificationsByKey.get(key);
641                 if (r == null) {
642                     Log.w(TAG, "No notification with key: " + key);
643                     return;
644                 }
645                 final long now = System.currentTimeMillis();
646                 MetricsLogger.action(r.getLogMaker(now)
647                         .setCategory(MetricsEvent.NOTIFICATION_ITEM)
648                         .setType(MetricsEvent.TYPE_ACTION));
649                 EventLogTags.writeNotificationClicked(key,
650                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
651 
652                 StatusBarNotification sbn = r.sbn;
653                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
654                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
655                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
656                         REASON_CLICK, null);
657             }
658         }
659 
660         @Override
661         public void onNotificationActionClick(int callingUid, int callingPid, String key,
662                 int actionIndex) {
663             synchronized (mNotificationLock) {
664                 NotificationRecord r = mNotificationsByKey.get(key);
665                 if (r == null) {
666                     Log.w(TAG, "No notification with key: " + key);
667                     return;
668                 }
669                 final long now = System.currentTimeMillis();
670                 MetricsLogger.action(r.getLogMaker(now)
671                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
672                         .setType(MetricsEvent.TYPE_ACTION)
673                         .setSubtype(actionIndex));
674                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
675                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
676                 // TODO: Log action click via UsageStats.
677             }
678         }
679 
680         @Override
681         public void onNotificationClear(int callingUid, int callingPid,
682                 String pkg, String tag, int id, int userId) {
683             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
684                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
685                     true, userId, REASON_CANCEL, null);
686         }
687 
688         @Override
689         public void onPanelRevealed(boolean clearEffects, int items) {
690             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
691             MetricsLogger.histogram(getContext(), "note_load", items);
692             EventLogTags.writeNotificationPanelRevealed(items);
693             if (clearEffects) {
694                 clearEffects();
695             }
696         }
697 
698         @Override
699         public void onPanelHidden() {
700             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
701             EventLogTags.writeNotificationPanelHidden();
702         }
703 
704         @Override
705         public void clearEffects() {
706             synchronized (mNotificationLock) {
707                 if (DBG) Slog.d(TAG, "clearEffects");
708                 clearSoundLocked();
709                 clearVibrateLocked();
710                 clearLightsLocked();
711             }
712         }
713 
714         @Override
715         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
716                 int uid, int initialPid, String message, int userId) {
717             final boolean fgService;
718             synchronized (mNotificationLock) {
719                 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
720                 fgService = r != null
721                         && (r.getNotification().flags&Notification.FLAG_FOREGROUND_SERVICE) != 0;
722             }
723             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
724                     REASON_ERROR, null);
725             if (fgService) {
726                 // Still crash for foreground services, preventing the not-crash behaviour abused
727                 // by apps to give us a garbage notification and silently start a fg service.
728                 Binder.withCleanCallingIdentity(
729                         () -> mAm.crashApplication(uid, initialPid, pkg, -1,
730                             "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
731                                 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
732                                 + message, true /* force */));
733             }
734         }
735 
736         @Override
737         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
738                 NotificationVisibility[] noLongerVisibleKeys) {
739             synchronized (mNotificationLock) {
740                 for (NotificationVisibility nv : newlyVisibleKeys) {
741                     NotificationRecord r = mNotificationsByKey.get(nv.key);
742                     if (r == null) continue;
743                     r.setVisibility(true, nv.rank);
744                     nv.recycle();
745                 }
746                 // Note that we might receive this event after notifications
747                 // have already left the system, e.g. after dismissing from the
748                 // shade. Hence not finding notifications in
749                 // mNotificationsByKey is not an exceptional condition.
750                 for (NotificationVisibility nv : noLongerVisibleKeys) {
751                     NotificationRecord r = mNotificationsByKey.get(nv.key);
752                     if (r == null) continue;
753                     r.setVisibility(false, nv.rank);
754                     nv.recycle();
755                 }
756             }
757         }
758 
759         @Override
760         public void onNotificationExpansionChanged(String key,
761                 boolean userAction, boolean expanded) {
762             synchronized (mNotificationLock) {
763                 NotificationRecord r = mNotificationsByKey.get(key);
764                 if (r != null) {
765                     r.stats.onExpansionChanged(userAction, expanded);
766                     final long now = System.currentTimeMillis();
767                     if (userAction) {
768                         MetricsLogger.action(r.getLogMaker(now)
769                                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
770                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
771                                         : MetricsEvent.TYPE_COLLAPSE));
772                     }
773                     EventLogTags.writeNotificationExpansion(key,
774                             userAction ? 1 : 0, expanded ? 1 : 0,
775                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
776                 }
777             }
778         }
779     };
780 
781     @GuardedBy("mNotificationLock")
clearSoundLocked()782     private void clearSoundLocked() {
783         mSoundNotificationKey = null;
784         long identity = Binder.clearCallingIdentity();
785         try {
786             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
787             if (player != null) {
788                 player.stopAsync();
789             }
790         } catch (RemoteException e) {
791         } finally {
792             Binder.restoreCallingIdentity(identity);
793         }
794     }
795 
796     @GuardedBy("mNotificationLock")
clearVibrateLocked()797     private void clearVibrateLocked() {
798         mVibrateNotificationKey = null;
799         long identity = Binder.clearCallingIdentity();
800         try {
801             mVibrator.cancel();
802         } finally {
803             Binder.restoreCallingIdentity(identity);
804         }
805     }
806 
807     @GuardedBy("mNotificationLock")
clearLightsLocked()808     private void clearLightsLocked() {
809         // light
810         mLights.clear();
811         updateLightsLocked();
812     }
813 
814     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
815         @Override
816         public void onReceive(Context context, Intent intent) {
817             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
818                 mZenModeHelper.updateDefaultZenRules();
819                 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
820             }
821         }
822     };
823 
824     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
825         @Override
826         public void onReceive(Context context, Intent intent) {
827             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
828                 try {
829                     String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
830                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
831                     int restoredFromSdkInt = intent.getIntExtra(
832                             Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
833                     mListeners.onSettingRestored(
834                             element, newValue, restoredFromSdkInt, getSendingUserId());
835                     mConditionProviders.onSettingRestored(
836                             element, newValue, restoredFromSdkInt, getSendingUserId());
837                 } catch (Exception e) {
838                     Slog.wtf(TAG, "Cannot restore managed services from settings", e);
839                 }
840             }
841         }
842     };
843 
844     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
845         @Override
846         public void onReceive(Context context, Intent intent) {
847             String action = intent.getAction();
848             if (action == null) {
849                 return;
850             }
851             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
852                 final NotificationRecord record;
853                 synchronized (mNotificationLock) {
854                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
855                 }
856                 if (record != null) {
857                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
858                             record.sbn.getPackageName(), record.sbn.getTag(),
859                             record.sbn.getId(), 0,
860                             Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
861                             REASON_TIMEOUT, null);
862                 }
863             }
864         }
865     };
866 
867     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
868         @Override
869         public void onReceive(Context context, Intent intent) {
870             String action = intent.getAction();
871             if (action == null) {
872                 return;
873             }
874 
875             boolean queryRestart = false;
876             boolean queryRemove = false;
877             boolean packageChanged = false;
878             boolean cancelNotifications = true;
879             int reason = REASON_PACKAGE_CHANGED;
880 
881             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
882                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
883                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
884                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
885                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
886                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
887                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
888                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
889                         UserHandle.USER_ALL);
890                 String pkgList[] = null;
891                 int uidList[] = null;
892                 boolean removingPackage = queryRemove &&
893                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
894                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
895                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
896                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
897                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
898                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
899                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
900                     reason = REASON_PACKAGE_SUSPENDED;
901                 } else if (queryRestart) {
902                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
903                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
904                 } else {
905                     Uri uri = intent.getData();
906                     if (uri == null) {
907                         return;
908                     }
909                     String pkgName = uri.getSchemeSpecificPart();
910                     if (pkgName == null) {
911                         return;
912                     }
913                     if (packageChanged) {
914                         // We cancel notifications for packages which have just been disabled
915                         try {
916                             final int enabled = mPackageManager.getApplicationEnabledSetting(
917                                     pkgName,
918                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
919                                             UserHandle.USER_SYSTEM);
920                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
921                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
922                                 cancelNotifications = false;
923                             }
924                         } catch (IllegalArgumentException e) {
925                             // Package doesn't exist; probably racing with uninstall.
926                             // cancelNotifications is already true, so nothing to do here.
927                             if (DBG) {
928                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
929                             }
930                         } catch (RemoteException e) {
931                             // Failed to talk to PackageManagerService Should never happen!
932                         }
933                     }
934                     pkgList = new String[]{pkgName};
935                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
936                 }
937                 if (pkgList != null && (pkgList.length > 0)) {
938                     for (String pkgName : pkgList) {
939                         if (cancelNotifications) {
940                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
941                                     !queryRestart, changeUserId, reason, null);
942                         }
943                     }
944                 }
945                 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
946                 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
947                 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
948                 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
949                 savePolicyFile();
950             }
951         }
952     };
953 
954     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
955         @Override
956         public void onReceive(Context context, Intent intent) {
957             String action = intent.getAction();
958 
959             if (action.equals(Intent.ACTION_SCREEN_ON)) {
960                 // Keep track of screen on/off state, but do not turn off the notification light
961                 // until user passes through the lock screen or views the notification.
962                 mScreenOn = true;
963                 updateNotificationPulse();
964             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
965                 mScreenOn = false;
966                 updateNotificationPulse();
967             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
968                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
969                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
970                 updateNotificationPulse();
971             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
972                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
973                 if (userHandle >= 0) {
974                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
975                             REASON_USER_STOPPED, null);
976                 }
977             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
978                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
979                 if (userHandle >= 0) {
980                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
981                             REASON_PROFILE_TURNED_OFF, null);
982                 }
983             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
984                 // turn off LED when user passes through lock screen
985                 mNotificationLight.turnOff();
986             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
987                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
988                 // reload per-user settings
989                 mSettingsObserver.update(null);
990                 mUserProfiles.updateCache(context);
991                 // Refresh managed services
992                 mConditionProviders.onUserSwitched(user);
993                 mListeners.onUserSwitched(user);
994                 mAssistants.onUserSwitched(user);
995                 mZenModeHelper.onUserSwitched(user);
996             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
997                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
998                 if (userId != USER_NULL) {
999                     mUserProfiles.updateCache(context);
1000                     if (!mUserProfiles.isManagedProfile(userId)) {
1001                         readDefaultApprovedServices(userId);
1002                     }
1003                 }
1004             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
1005                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1006                 mZenModeHelper.onUserRemoved(user);
1007                 mRankingHelper.onUserRemoved(user);
1008                 mListeners.onUserRemoved(user);
1009                 mConditionProviders.onUserRemoved(user);
1010                 mAssistants.onUserRemoved(user);
1011                 savePolicyFile();
1012             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1013                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1014                 mConditionProviders.onUserUnlocked(user);
1015                 mListeners.onUserUnlocked(user);
1016                 mAssistants.onUserUnlocked(user);
1017                 mZenModeHelper.onUserUnlocked(user);
1018             }
1019         }
1020     };
1021 
1022     private final class SettingsObserver extends ContentObserver {
1023         private final Uri NOTIFICATION_BADGING_URI
1024                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
1025         private final Uri NOTIFICATION_LIGHT_PULSE_URI
1026                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
1027         private final Uri NOTIFICATION_RATE_LIMIT_URI
1028                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
1029 
SettingsObserver(Handler handler)1030         SettingsObserver(Handler handler) {
1031             super(handler);
1032         }
1033 
observe()1034         void observe() {
1035             ContentResolver resolver = getContext().getContentResolver();
1036             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1037                     false, this, UserHandle.USER_ALL);
1038             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
1039                     false, this, UserHandle.USER_ALL);
1040             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1041                     false, this, UserHandle.USER_ALL);
1042             update(null);
1043         }
1044 
onChange(boolean selfChange, Uri uri)1045         @Override public void onChange(boolean selfChange, Uri uri) {
1046             update(uri);
1047         }
1048 
update(Uri uri)1049         public void update(Uri uri) {
1050             ContentResolver resolver = getContext().getContentResolver();
1051             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
1052                 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1053                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
1054                 if (mNotificationPulseEnabled != pulseEnabled) {
1055                     mNotificationPulseEnabled = pulseEnabled;
1056                     updateNotificationPulse();
1057                 }
1058             }
1059             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1060                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1061                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1062             }
1063             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1064                 mRankingHelper.updateBadgingEnabled();
1065             }
1066         }
1067     }
1068 
1069     private SettingsObserver mSettingsObserver;
1070     protected ZenModeHelper mZenModeHelper;
1071 
getLongArray(Resources r, int resid, int maxlen, long[] def)1072     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1073         int[] ar = r.getIntArray(resid);
1074         if (ar == null) {
1075             return def;
1076         }
1077         final int len = ar.length > maxlen ? maxlen : ar.length;
1078         long[] out = new long[len];
1079         for (int i=0; i<len; i++) {
1080             out[i] = ar[i];
1081         }
1082         return out;
1083     }
1084 
NotificationManagerService(Context context)1085     public NotificationManagerService(Context context) {
1086         super(context);
1087         Notification.processWhitelistToken = WHITELIST_TOKEN;
1088     }
1089 
1090     // TODO - replace these methods with a single VisibleForTesting constructor
1091     @VisibleForTesting
setAudioManager(AudioManager audioMananger)1092     void setAudioManager(AudioManager audioMananger) {
1093         mAudioManager = audioMananger;
1094     }
1095 
1096     @VisibleForTesting
setVibrator(Vibrator vibrator)1097     void setVibrator(Vibrator vibrator) {
1098         mVibrator = vibrator;
1099     }
1100 
1101     @VisibleForTesting
setLights(Light light)1102     void setLights(Light light) {
1103         mNotificationLight = light;
1104         mAttentionLight = light;
1105         mNotificationPulseEnabled = true;
1106     }
1107 
1108     @VisibleForTesting
setScreenOn(boolean on)1109     void setScreenOn(boolean on) {
1110         mScreenOn = on;
1111     }
1112 
1113     @VisibleForTesting
getNotificationRecordCount()1114     int getNotificationRecordCount() {
1115         synchronized (mNotificationLock) {
1116             int count = mNotificationList.size() + mNotificationsByKey.size()
1117                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1118             // subtract duplicates
1119             for (NotificationRecord posted : mNotificationList) {
1120                 if (mNotificationsByKey.containsKey(posted.getKey())) {
1121                     count--;
1122                 }
1123                 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1124                     count--;
1125                 }
1126             }
1127 
1128             return count;
1129         }
1130     }
1131 
clearNotifications()1132     void clearNotifications() {
1133         mEnqueuedNotifications.clear();
1134         mNotificationList.clear();
1135         mNotificationsByKey.clear();
1136         mSummaryByGroupKey.clear();
1137     }
1138 
1139     @VisibleForTesting
addNotification(NotificationRecord r)1140     void addNotification(NotificationRecord r) {
1141         mNotificationList.add(r);
1142         mNotificationsByKey.put(r.sbn.getKey(), r);
1143         if (r.sbn.isGroup()) {
1144             mSummaryByGroupKey.put(r.getGroupKey(), r);
1145         }
1146     }
1147 
1148     @VisibleForTesting
addEnqueuedNotification(NotificationRecord r)1149     void addEnqueuedNotification(NotificationRecord r) {
1150         mEnqueuedNotifications.add(r);
1151     }
1152 
1153     @VisibleForTesting
getNotificationRecord(String key)1154     NotificationRecord getNotificationRecord(String key) {
1155         return mNotificationsByKey.get(key);
1156     }
1157 
1158 
1159     @VisibleForTesting
setSystemReady(boolean systemReady)1160     void setSystemReady(boolean systemReady) {
1161         mSystemReady = systemReady;
1162     }
1163 
1164     @VisibleForTesting
setHandler(WorkerHandler handler)1165     void setHandler(WorkerHandler handler) {
1166         mHandler = handler;
1167     }
1168 
1169     @VisibleForTesting
setFallbackVibrationPattern(long[] vibrationPattern)1170     void setFallbackVibrationPattern(long[] vibrationPattern) {
1171         mFallbackVibrationPattern = vibrationPattern;
1172     }
1173 
1174     @VisibleForTesting
setPackageManager(IPackageManager packageManager)1175     void setPackageManager(IPackageManager packageManager) {
1176         mPackageManager = packageManager;
1177     }
1178 
1179     @VisibleForTesting
setRankingHelper(RankingHelper rankingHelper)1180     void setRankingHelper(RankingHelper rankingHelper) {
1181         mRankingHelper = rankingHelper;
1182     }
1183 
1184     @VisibleForTesting
setRankingHandler(RankingHandler rankingHandler)1185     void setRankingHandler(RankingHandler rankingHandler) {
1186         mRankingHandler = rankingHandler;
1187     }
1188 
1189     @VisibleForTesting
setIsTelevision(boolean isTelevision)1190     void setIsTelevision(boolean isTelevision) {
1191         mIsTelevision = isTelevision;
1192     }
1193 
1194     @VisibleForTesting
setUsageStats(NotificationUsageStats us)1195     void setUsageStats(NotificationUsageStats us) {
1196         mUsageStats = us;
1197     }
1198 
1199     @VisibleForTesting
setAccessibilityManager(AccessibilityManager am)1200     void setAccessibilityManager(AccessibilityManager am) {
1201         mAccessibilityManager = am;
1202     }
1203 
1204     // TODO: All tests should use this init instead of the one-off setters above.
1205     @VisibleForTesting
init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient, LightsManager lightsManager, NotificationListeners notificationListeners, NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, NotificationUsageStats usageStats, AtomicFile policyFile, ActivityManager activityManager, GroupHelper groupHelper)1206     void init(Looper looper, IPackageManager packageManager,
1207             PackageManager packageManagerClient,
1208             LightsManager lightsManager, NotificationListeners notificationListeners,
1209             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
1210             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1211             NotificationUsageStats usageStats, AtomicFile policyFile,
1212             ActivityManager activityManager, GroupHelper groupHelper) {
1213         Resources resources = getContext().getResources();
1214         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1215                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1216                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1217 
1218         mAccessibilityManager =
1219                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
1220         mAm = ActivityManager.getService();
1221         mPackageManager = packageManager;
1222         mPackageManagerClient = packageManagerClient;
1223         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1224         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1225         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1226         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1227         mCompanionManager = companionManager;
1228         mActivityManager = activityManager;
1229 
1230         mHandler = new WorkerHandler(looper);
1231         mRankingThread.start();
1232         String[] extractorNames;
1233         try {
1234             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1235         } catch (Resources.NotFoundException e) {
1236             extractorNames = new String[0];
1237         }
1238         mUsageStats = usageStats;
1239         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1240         mRankingHelper = new RankingHelper(getContext(),
1241                 mPackageManagerClient,
1242                 mRankingHandler,
1243                 mUsageStats,
1244                 extractorNames);
1245         mConditionProviders = conditionProviders;
1246         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1247         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1248             @Override
1249             public void onConfigChanged() {
1250                 savePolicyFile();
1251             }
1252 
1253             @Override
1254             void onZenModeChanged() {
1255                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1256                 getContext().sendBroadcastAsUser(
1257                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1258                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1259                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1260                 synchronized (mNotificationLock) {
1261                     updateInterruptionFilterLocked();
1262                 }
1263             }
1264 
1265             @Override
1266             void onPolicyChanged() {
1267                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1268             }
1269         });
1270         mSnoozeHelper = snoozeHelper;
1271         mGroupHelper = groupHelper;
1272 
1273         // This is a ManagedServices object that keeps track of the listeners.
1274         mListeners = notificationListeners;
1275 
1276         // This is a MangedServices object that keeps track of the assistant.
1277         mAssistants = notificationAssistants;
1278 
1279         mPolicyFile = policyFile;
1280         loadPolicyFile();
1281 
1282         mStatusBar = getLocalService(StatusBarManagerInternal.class);
1283         if (mStatusBar != null) {
1284             mStatusBar.setNotificationDelegate(mNotificationDelegate);
1285         }
1286 
1287         mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1288         mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1289 
1290         mFallbackVibrationPattern = getLongArray(resources,
1291                 R.array.config_notificationFallbackVibePattern,
1292                 VIBRATE_PATTERN_MAXLEN,
1293                 DEFAULT_VIBRATE_PATTERN);
1294         mInCallNotificationUri = Uri.parse("file://" +
1295                 resources.getString(R.string.config_inCallNotificationSound));
1296         mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1297                 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1298                 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1299                 .build();
1300         mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1301 
1302         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1303 
1304         // Don't start allowing notifications until the setup wizard has run once.
1305         // After that, including subsequent boots, init with notifications turned on.
1306         // This works on the first boot because the setup wizard will toggle this
1307         // flag at least once and we'll go back to 0 after that.
1308         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1309                     Settings.Global.DEVICE_PROVISIONED, 0)) {
1310             mDisableNotificationEffects = true;
1311         }
1312         mZenModeHelper.initZenMode();
1313         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1314 
1315         mUserProfiles.updateCache(getContext());
1316         listenForCallState();
1317 
1318         mSettingsObserver = new SettingsObserver(mHandler);
1319 
1320         mArchive = new Archive(resources.getInteger(
1321                 R.integer.config_notificationServiceArchiveSize));
1322 
1323         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1324                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1325     }
1326 
1327     @Override
onStart()1328     public void onStart() {
1329         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1330             @Override
1331             public void repost(int userId, NotificationRecord r) {
1332                 try {
1333                     if (DBG) {
1334                         Slog.d(TAG, "Reposting " + r.getKey());
1335                     }
1336                     enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1337                             r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1338                             r.sbn.getNotification(), userId);
1339                 } catch (Exception e) {
1340                     Slog.e(TAG, "Cannot un-snooze notification", e);
1341                 }
1342             }
1343         }, mUserProfiles);
1344 
1345         final File systemDir = new File(Environment.getDataDirectory(), "system");
1346 
1347         init(Looper.myLooper(),
1348                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1349                 getLocalService(LightsManager.class),
1350                 new NotificationListeners(AppGlobals.getPackageManager()),
1351                 new NotificationAssistants(AppGlobals.getPackageManager()),
1352                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1353                 null, snoozeHelper, new NotificationUsageStats(getContext()),
1354                 new AtomicFile(new File(systemDir, "notification_policy.xml")),
1355                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1356                 getGroupHelper());
1357 
1358         // register for various Intents
1359         IntentFilter filter = new IntentFilter();
1360         filter.addAction(Intent.ACTION_SCREEN_ON);
1361         filter.addAction(Intent.ACTION_SCREEN_OFF);
1362         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1363         filter.addAction(Intent.ACTION_USER_PRESENT);
1364         filter.addAction(Intent.ACTION_USER_STOPPED);
1365         filter.addAction(Intent.ACTION_USER_SWITCHED);
1366         filter.addAction(Intent.ACTION_USER_ADDED);
1367         filter.addAction(Intent.ACTION_USER_REMOVED);
1368         filter.addAction(Intent.ACTION_USER_UNLOCKED);
1369         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1370         getContext().registerReceiver(mIntentReceiver, filter);
1371 
1372         IntentFilter pkgFilter = new IntentFilter();
1373         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1374         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1375         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1376         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1377         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1378         pkgFilter.addDataScheme("package");
1379         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1380                 null);
1381 
1382         IntentFilter suspendedPkgFilter = new IntentFilter();
1383         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1384         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1385                 suspendedPkgFilter, null, null);
1386 
1387         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1388         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1389                 null);
1390 
1391         IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1392         timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1393         getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1394 
1395         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1396         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1397 
1398         IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1399         getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1400 
1401         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1402         publishLocalService(NotificationManagerInternal.class, mInternalService);
1403     }
1404 
getGroupHelper()1405     private GroupHelper getGroupHelper() {
1406         return new GroupHelper(new GroupHelper.Callback() {
1407             @Override
1408             public void addAutoGroup(String key) {
1409                 synchronized (mNotificationLock) {
1410                     addAutogroupKeyLocked(key);
1411                 }
1412             }
1413 
1414             @Override
1415             public void removeAutoGroup(String key) {
1416                 synchronized (mNotificationLock) {
1417                     removeAutogroupKeyLocked(key);
1418                 }
1419             }
1420 
1421             @Override
1422             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1423                 createAutoGroupSummary(userId, pkg, triggeringKey);
1424             }
1425 
1426             @Override
1427             public void removeAutoGroupSummary(int userId, String pkg) {
1428                 synchronized (mNotificationLock) {
1429                     clearAutogroupSummaryLocked(userId, pkg);
1430                 }
1431             }
1432         });
1433     }
1434 
1435     private void sendRegisteredOnlyBroadcast(String action) {
1436         getContext().sendBroadcastAsUser(new Intent(action)
1437                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1438     }
1439 
1440     @Override
1441     public void onBootPhase(int phase) {
1442         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1443             // no beeping until we're basically done booting
1444             mSystemReady = true;
1445 
1446             // Grab our optional AudioService
1447             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1448             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1449             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1450             mZenModeHelper.onSystemReady();
1451         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1452             // This observer will force an update when observe is called, causing us to
1453             // bind to listener services.
1454             mSettingsObserver.observe();
1455             mListeners.onBootPhaseAppsCanStart();
1456             mAssistants.onBootPhaseAppsCanStart();
1457             mConditionProviders.onBootPhaseAppsCanStart();
1458         }
1459     }
1460 
1461     @GuardedBy("mNotificationLock")
1462     private void updateListenerHintsLocked() {
1463         final int hints = calculateHints();
1464         if (hints == mListenerHints) return;
1465         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1466         mListenerHints = hints;
1467         scheduleListenerHintsChanged(hints);
1468     }
1469 
1470     @GuardedBy("mNotificationLock")
1471     private void updateEffectsSuppressorLocked() {
1472         final long updatedSuppressedEffects = calculateSuppressedEffects();
1473         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1474         final List<ComponentName> suppressors = getSuppressors();
1475         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1476         mEffectsSuppressors = suppressors;
1477         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1478         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1479     }
1480 
1481     private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1482             boolean fromListener) {
1483         if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1484             // cancel
1485             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1486                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
1487                     null);
1488             if (isUidSystemOrPhone(uid)) {
1489                 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1490                 int N = profileIds.length;
1491                 for (int i = 0; i < N; i++) {
1492                     int profileId = profileIds[i];
1493                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1494                             profileId, REASON_CHANNEL_BANNED,
1495                             null);
1496                 }
1497             }
1498         }
1499         mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
1500 
1501         if (!fromListener) {
1502             final NotificationChannel modifiedChannel =
1503                     mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1504             mListeners.notifyNotificationChannelChanged(
1505                     pkg, UserHandle.getUserHandleForUid(uid),
1506                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1507         }
1508 
1509         savePolicyFile();
1510     }
1511 
1512     private ArrayList<ComponentName> getSuppressors() {
1513         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1514         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1515             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1516 
1517             for (ManagedServiceInfo info : serviceInfoList) {
1518                 names.add(info.component);
1519             }
1520         }
1521 
1522         return names;
1523     }
1524 
1525     private boolean removeDisabledHints(ManagedServiceInfo info) {
1526         return removeDisabledHints(info, 0);
1527     }
1528 
1529     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1530         boolean removed = false;
1531 
1532         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1533             final int hint = mListenersDisablingEffects.keyAt(i);
1534             final ArraySet<ManagedServiceInfo> listeners =
1535                     mListenersDisablingEffects.valueAt(i);
1536 
1537             if (hints == 0 || (hint & hints) == hint) {
1538                 removed = removed || listeners.remove(info);
1539             }
1540         }
1541 
1542         return removed;
1543     }
1544 
1545     private void addDisabledHints(ManagedServiceInfo info, int hints) {
1546         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1547             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1548         }
1549 
1550         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1551             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1552         }
1553 
1554         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1555             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1556         }
1557     }
1558 
1559     private void addDisabledHint(ManagedServiceInfo info, int hint) {
1560         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1561             mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1562         }
1563 
1564         ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1565         hintListeners.add(info);
1566     }
1567 
1568     private int calculateHints() {
1569         int hints = 0;
1570         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1571             int hint = mListenersDisablingEffects.keyAt(i);
1572             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1573 
1574             if (!serviceInfoList.isEmpty()) {
1575                 hints |= hint;
1576             }
1577         }
1578 
1579         return hints;
1580     }
1581 
1582     private long calculateSuppressedEffects() {
1583         int hints = calculateHints();
1584         long suppressedEffects = 0;
1585 
1586         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1587             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1588         }
1589 
1590         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1591             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1592         }
1593 
1594         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1595             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1596         }
1597 
1598         return suppressedEffects;
1599     }
1600 
1601     @GuardedBy("mNotificationLock")
1602     private void updateInterruptionFilterLocked() {
1603         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1604         if (interruptionFilter == mInterruptionFilter) return;
1605         mInterruptionFilter = interruptionFilter;
1606         scheduleInterruptionFilterChanged(interruptionFilter);
1607     }
1608 
1609     @VisibleForTesting
1610     INotificationManager getBinderService() {
1611         return INotificationManager.Stub.asInterface(mService);
1612     }
1613 
1614     @VisibleForTesting
1615     NotificationManagerInternal getInternalService() {
1616         return mInternalService;
1617     }
1618 
1619     private final IBinder mService = new INotificationManager.Stub() {
1620         // Toasts
1621         // ============================================================================
1622 
1623         @Override
1624         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1625         {
1626             if (DBG) {
1627                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1628                         + " duration=" + duration);
1629             }
1630 
1631             if (pkg == null || callback == null) {
1632                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1633                 return ;
1634             }
1635             final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1636             final boolean isPackageSuspended =
1637                     isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1638 
1639             if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1640                     (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1641                             || isPackageSuspended)) {
1642                 Slog.e(TAG, "Suppressing toast from package " + pkg
1643                         + (isPackageSuspended
1644                                 ? " due to package suspended by administrator."
1645                                 : " by user request."));
1646                 return;
1647             }
1648 
1649             synchronized (mToastQueue) {
1650                 int callingPid = Binder.getCallingPid();
1651                 long callingId = Binder.clearCallingIdentity();
1652                 try {
1653                     ToastRecord record;
1654                     int index;
1655                     // All packages aside from the android package can enqueue one toast at a time
1656                     if (!isSystemToast) {
1657                         index = indexOfToastPackageLocked(pkg);
1658                     } else {
1659                         index = indexOfToastLocked(pkg, callback);
1660                     }
1661 
1662                     // If the package already has a toast, we update its toast
1663                     // in the queue, we don't move it to the end of the queue.
1664                     if (index >= 0) {
1665                         record = mToastQueue.get(index);
1666                         record.update(duration);
1667                         record.update(callback);
1668                     } else {
1669                         Binder token = new Binder();
1670                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1671                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
1672                         mToastQueue.add(record);
1673                         index = mToastQueue.size() - 1;
1674                     }
1675                     keepProcessAliveIfNeededLocked(callingPid);
1676                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
1677                     // new or just been updated.  Call back and tell it to show itself.
1678                     // If the callback fails, this will remove it from the list, so don't
1679                     // assume that it's valid after this.
1680                     if (index == 0) {
1681                         showNextToastLocked();
1682                     }
1683                 } finally {
1684                     Binder.restoreCallingIdentity(callingId);
1685                 }
1686             }
1687         }
1688 
1689         @Override
1690         public void cancelToast(String pkg, ITransientNotification callback) {
1691             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1692 
1693             if (pkg == null || callback == null) {
1694                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1695                 return ;
1696             }
1697 
1698             synchronized (mToastQueue) {
1699                 long callingId = Binder.clearCallingIdentity();
1700                 try {
1701                     int index = indexOfToastLocked(pkg, callback);
1702                     if (index >= 0) {
1703                         cancelToastLocked(index);
1704                     } else {
1705                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1706                                 + " callback=" + callback);
1707                     }
1708                 } finally {
1709                     Binder.restoreCallingIdentity(callingId);
1710                 }
1711             }
1712         }
1713 
1714         @Override
1715         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1716                 Notification notification, int userId) throws RemoteException {
1717             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1718                     Binder.getCallingPid(), tag, id, notification, userId);
1719         }
1720 
1721         @Override
1722         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1723             checkCallerIsSystemOrSameApp(pkg);
1724             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1725                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1726             // Don't allow client applications to cancel foreground service notis or autobundled
1727             // summaries.
1728             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1729                     (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
1730             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1731                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
1732         }
1733 
1734         @Override
1735         public void cancelAllNotifications(String pkg, int userId) {
1736             checkCallerIsSystemOrSameApp(pkg);
1737 
1738             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1739                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1740 
1741             // Calling from user space, don't allow the canceling of actively
1742             // running foreground services.
1743             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1744                     pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1745                     REASON_APP_CANCEL_ALL, null);
1746         }
1747 
1748         @Override
1749         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1750             checkCallerIsSystem();
1751 
1752             mRankingHelper.setEnabled(pkg, uid, enabled);
1753             // Now, cancel any outstanding notifications that are part of a just-disabled app
1754             if (!enabled) {
1755                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1756                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1757             }
1758             savePolicyFile();
1759         }
1760 
1761         /**
1762          * Use this when you just want to know if notifications are OK for this package.
1763          */
1764         @Override
1765         public boolean areNotificationsEnabled(String pkg) {
1766             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1767         }
1768 
1769         /**
1770          * Use this when you just want to know if notifications are OK for this package.
1771          */
1772         @Override
1773         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1774             checkCallerIsSystemOrSameApp(pkg);
1775             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
1776                 getContext().enforceCallingPermission(
1777                         android.Manifest.permission.INTERACT_ACROSS_USERS,
1778                         "canNotifyAsPackage for uid " + uid);
1779             }
1780 
1781             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1782         }
1783 
1784         @Override
1785         public int getPackageImportance(String pkg) {
1786             checkCallerIsSystemOrSameApp(pkg);
1787             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1788         }
1789 
1790         @Override
1791         public boolean canShowBadge(String pkg, int uid) {
1792             checkCallerIsSystem();
1793             return mRankingHelper.canShowBadge(pkg, uid);
1794         }
1795 
1796         @Override
1797         public void setShowBadge(String pkg, int uid, boolean showBadge) {
1798             checkCallerIsSystem();
1799             mRankingHelper.setShowBadge(pkg, uid, showBadge);
1800             savePolicyFile();
1801         }
1802 
1803         @Override
1804         public void createNotificationChannelGroups(String pkg,
1805                 ParceledListSlice channelGroupList) throws RemoteException {
1806             checkCallerIsSystemOrSameApp(pkg);
1807             List<NotificationChannelGroup> groups = channelGroupList.getList();
1808             final int groupSize = groups.size();
1809             for (int i = 0; i < groupSize; i++) {
1810                 final NotificationChannelGroup group = groups.get(i);
1811                 Preconditions.checkNotNull(group, "group in list is null");
1812                 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1813                         true /* fromTargetApp */);
1814                 mListeners.notifyNotificationChannelGroupChanged(pkg,
1815                         UserHandle.of(UserHandle.getCallingUserId()), group,
1816                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1817             }
1818             savePolicyFile();
1819         }
1820 
1821         private void createNotificationChannelsImpl(String pkg, int uid,
1822                 ParceledListSlice channelsList) {
1823             List<NotificationChannel> channels = channelsList.getList();
1824             final int channelsSize = channels.size();
1825             for (int i = 0; i < channelsSize; i++) {
1826                 final NotificationChannel channel = channels.get(i);
1827                 Preconditions.checkNotNull(channel, "channel in list is null");
1828                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1829                         true /* fromTargetApp */);
1830                 mListeners.notifyNotificationChannelChanged(pkg,
1831                         UserHandle.getUserHandleForUid(uid),
1832                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1833                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1834             }
1835             savePolicyFile();
1836         }
1837 
1838         @Override
1839         public void createNotificationChannels(String pkg,
1840                 ParceledListSlice channelsList) throws RemoteException {
1841             checkCallerIsSystemOrSameApp(pkg);
1842             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1843         }
1844 
1845         @Override
1846         public void createNotificationChannelsForPackage(String pkg, int uid,
1847                 ParceledListSlice channelsList) throws RemoteException {
1848             checkCallerIsSystem();
1849             createNotificationChannelsImpl(pkg, uid, channelsList);
1850         }
1851 
1852         @Override
1853         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1854             checkCallerIsSystemOrSameApp(pkg);
1855             return mRankingHelper.getNotificationChannel(
1856                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1857         }
1858 
1859         @Override
1860         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1861                 String channelId, boolean includeDeleted) {
1862             checkCallerIsSystem();
1863             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1864         }
1865 
1866         @Override
1867         public void deleteNotificationChannel(String pkg, String channelId) {
1868             checkCallerIsSystemOrSameApp(pkg);
1869             final int callingUid = Binder.getCallingUid();
1870             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1871                 throw new IllegalArgumentException("Cannot delete default channel");
1872             }
1873             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1874                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1875             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1876             mListeners.notifyNotificationChannelChanged(pkg,
1877                     UserHandle.getUserHandleForUid(callingUid),
1878                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1879                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1880             savePolicyFile();
1881         }
1882 
1883         @Override
1884         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1885                 String pkg) {
1886             checkCallerIsSystemOrSameApp(pkg);
1887             return new ParceledListSlice<>(new ArrayList(
1888                     mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1889         }
1890 
1891         @Override
1892         public void deleteNotificationChannelGroup(String pkg, String groupId) {
1893             checkCallerIsSystemOrSameApp(pkg);
1894 
1895             final int callingUid = Binder.getCallingUid();
1896             NotificationChannelGroup groupToDelete =
1897                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1898             if (groupToDelete != null) {
1899                 List<NotificationChannel> deletedChannels =
1900                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1901                 for (int i = 0; i < deletedChannels.size(); i++) {
1902                     final NotificationChannel deletedChannel = deletedChannels.get(i);
1903                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1904                             true,
1905                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1906                             null);
1907                     mListeners.notifyNotificationChannelChanged(pkg,
1908                             UserHandle.getUserHandleForUid(callingUid),
1909                             deletedChannel,
1910                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1911                 }
1912                 mListeners.notifyNotificationChannelGroupChanged(
1913                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1914                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1915                 savePolicyFile();
1916             }
1917         }
1918 
1919         @Override
1920         public void updateNotificationChannelForPackage(String pkg, int uid,
1921                 NotificationChannel channel) {
1922             enforceSystemOrSystemUI("Caller not system or systemui");
1923             Preconditions.checkNotNull(channel);
1924             updateNotificationChannelInt(pkg, uid, channel, false);
1925         }
1926 
1927         @Override
1928         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1929                 int uid, boolean includeDeleted) {
1930             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1931             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1932         }
1933 
1934         @Override
1935         public int getNumNotificationChannelsForPackage(String pkg, int uid,
1936                 boolean includeDeleted) {
1937             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1938             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1939                     .getList().size();
1940         }
1941 
1942         @Override
1943         public boolean onlyHasDefaultChannel(String pkg, int uid) {
1944             enforceSystemOrSystemUI("onlyHasDefaultChannel");
1945             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1946         }
1947 
1948         @Override
1949         public int getDeletedChannelCount(String pkg, int uid) {
1950             enforceSystemOrSystemUI("getDeletedChannelCount");
1951             return mRankingHelper.getDeletedChannelCount(pkg, uid);
1952         }
1953 
1954         @Override
1955         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1956                 String pkg, int uid, boolean includeDeleted) {
1957             checkCallerIsSystem();
1958             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1959         }
1960 
1961         @Override
1962         public NotificationChannelGroup getNotificationChannelGroupForPackage(
1963                 String groupId, String pkg, int uid) {
1964             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1965             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1966         }
1967 
1968         @Override
1969         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1970             checkCallerIsSystemOrSameApp(pkg);
1971             return mRankingHelper.getNotificationChannels(
1972                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
1973         }
1974 
1975         @Override
1976         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1977             checkCallerIsSystem();
1978 
1979             // Cancel posted notifications
1980             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1981                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1982 
1983             final String[] packages = new String[] {packageName};
1984             final int[] uids = new int[] {uid};
1985 
1986             // Listener & assistant
1987             mListeners.onPackagesChanged(true, packages, uids);
1988             mAssistants.onPackagesChanged(true, packages, uids);
1989 
1990             // Zen
1991             mConditionProviders.onPackagesChanged(true, packages, uids);
1992 
1993             // Reset notification preferences
1994             if (!fromApp) {
1995                 mRankingHelper.onPackagesChanged(
1996                         true, UserHandle.getCallingUserId(), packages, uids);
1997             }
1998 
1999             savePolicyFile();
2000         }
2001 
2002 
2003         /**
2004          * System-only API for getting a list of current (i.e. not cleared) notifications.
2005          *
2006          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2007          * @returns A list of all the notifications, in natural order.
2008          */
2009         @Override
2010         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2011             // enforce() will ensure the calling uid has the correct permission
2012             getContext().enforceCallingOrSelfPermission(
2013                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2014                     "NotificationManagerService.getActiveNotifications");
2015 
2016             StatusBarNotification[] tmp = null;
2017             int uid = Binder.getCallingUid();
2018 
2019             // noteOp will check to make sure the callingPkg matches the uid
2020             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2021                     == AppOpsManager.MODE_ALLOWED) {
2022                 synchronized (mNotificationLock) {
2023                     tmp = new StatusBarNotification[mNotificationList.size()];
2024                     final int N = mNotificationList.size();
2025                     for (int i=0; i<N; i++) {
2026                         tmp[i] = mNotificationList.get(i).sbn;
2027                     }
2028                 }
2029             }
2030             return tmp;
2031         }
2032 
2033         /**
2034          * Public API for getting a list of current notifications for the calling package/uid.
2035          *
2036          * Note that since notification posting is done asynchronously, this will not return
2037          * notifications that are in the process of being posted.
2038          *
2039          * @returns A list of all the package's notifications, in natural order.
2040          */
2041         @Override
2042         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2043                 int incomingUserId) {
2044             checkCallerIsSystemOrSameApp(pkg);
2045             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2046                     Binder.getCallingUid(), incomingUserId, true, false,
2047                     "getAppActiveNotifications", pkg);
2048             synchronized (mNotificationLock) {
2049                 final ArrayMap<String, StatusBarNotification> map
2050                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2051                 final int N = mNotificationList.size();
2052                 for (int i = 0; i < N; i++) {
2053                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2054                             mNotificationList.get(i).sbn);
2055                     if (sbn != null) {
2056                         map.put(sbn.getKey(), sbn);
2057                     }
2058                 }
2059                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2060                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2061                     if (sbn != null) {
2062                         map.put(sbn.getKey(), sbn);
2063                     }
2064                 }
2065                 final int M = mEnqueuedNotifications.size();
2066                 for (int i = 0; i < M; i++) {
2067                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2068                             mEnqueuedNotifications.get(i).sbn);
2069                     if (sbn != null) {
2070                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
2071                     }
2072                 }
2073                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2074                 list.addAll(map.values());
2075                 return new ParceledListSlice<StatusBarNotification>(list);
2076             }
2077         }
2078 
2079         private StatusBarNotification sanitizeSbn(String pkg, int userId,
2080                 StatusBarNotification sbn) {
2081             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
2082                 // We could pass back a cloneLight() but clients might get confused and
2083                 // try to send this thing back to notify() again, which would not work
2084                 // very well.
2085                 return new StatusBarNotification(
2086                         sbn.getPackageName(),
2087                         sbn.getOpPkg(),
2088                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2089                         sbn.getNotification().clone(),
2090                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2091             }
2092             return null;
2093         }
2094 
2095         /**
2096          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2097          *
2098          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2099          */
2100         @Override
2101         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2102             // enforce() will ensure the calling uid has the correct permission
2103             getContext().enforceCallingOrSelfPermission(
2104                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2105                     "NotificationManagerService.getHistoricalNotifications");
2106 
2107             StatusBarNotification[] tmp = null;
2108             int uid = Binder.getCallingUid();
2109 
2110             // noteOp will check to make sure the callingPkg matches the uid
2111             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2112                     == AppOpsManager.MODE_ALLOWED) {
2113                 synchronized (mArchive) {
2114                     tmp = mArchive.getArray(count);
2115                 }
2116             }
2117             return tmp;
2118         }
2119 
2120         /**
2121          * Register a listener binder directly with the notification manager.
2122          *
2123          * Only works with system callers. Apps should extend
2124          * {@link android.service.notification.NotificationListenerService}.
2125          */
2126         @Override
2127         public void registerListener(final INotificationListener listener,
2128                 final ComponentName component, final int userid) {
2129             enforceSystemOrSystemUI("INotificationManager.registerListener");
2130             mListeners.registerService(listener, component, userid);
2131         }
2132 
2133         /**
2134          * Remove a listener binder directly
2135          */
2136         @Override
2137         public void unregisterListener(INotificationListener token, int userid) {
2138             mListeners.unregisterService(token, userid);
2139         }
2140 
2141         /**
2142          * Allow an INotificationListener to simulate a "clear all" operation.
2143          *
2144          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2145          *
2146          * @param token The binder for the listener, to check that the caller is allowed
2147          */
2148         @Override
2149         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2150             final int callingUid = Binder.getCallingUid();
2151             final int callingPid = Binder.getCallingPid();
2152             long identity = Binder.clearCallingIdentity();
2153             try {
2154                 synchronized (mNotificationLock) {
2155                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2156                     if (keys != null) {
2157                         final int N = keys.length;
2158                         for (int i = 0; i < N; i++) {
2159                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2160                             if (r == null) continue;
2161                             final int userId = r.sbn.getUserId();
2162                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2163                                     !mUserProfiles.isCurrentProfile(userId)) {
2164                                 throw new SecurityException("Disallowed call from listener: "
2165                                         + info.service);
2166                             }
2167                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2168                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2169                                     userId);
2170                         }
2171                     } else {
2172                         cancelAllLocked(callingUid, callingPid, info.userid,
2173                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2174                     }
2175                 }
2176             } finally {
2177                 Binder.restoreCallingIdentity(identity);
2178             }
2179         }
2180 
2181         /**
2182          * Handle request from an approved listener to re-enable itself.
2183          *
2184          * @param component The componenet to be re-enabled, caller must match package.
2185          */
2186         @Override
2187         public void requestBindListener(ComponentName component) {
2188             checkCallerIsSystemOrSameApp(component.getPackageName());
2189             long identity = Binder.clearCallingIdentity();
2190             try {
2191                 ManagedServices manager =
2192                         mAssistants.isComponentEnabledForCurrentProfiles(component)
2193                         ? mAssistants
2194                         : mListeners;
2195                 manager.setComponentState(component, true);
2196             } finally {
2197                 Binder.restoreCallingIdentity(identity);
2198             }
2199         }
2200 
2201         @Override
2202         public void requestUnbindListener(INotificationListener token) {
2203             long identity = Binder.clearCallingIdentity();
2204             try {
2205                 // allow bound services to disable themselves
2206                 synchronized (mNotificationLock) {
2207                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2208                     info.getOwner().setComponentState(info.component, false);
2209                 }
2210             } finally {
2211                 Binder.restoreCallingIdentity(identity);
2212             }
2213         }
2214 
2215         @Override
2216         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2217             long identity = Binder.clearCallingIdentity();
2218             try {
2219                 synchronized (mNotificationLock) {
2220                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2221                     if (keys != null) {
2222                         final int N = keys.length;
2223                         for (int i = 0; i < N; i++) {
2224                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2225                             if (r == null) continue;
2226                             final int userId = r.sbn.getUserId();
2227                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2228                                     !mUserProfiles.isCurrentProfile(userId)) {
2229                                 throw new SecurityException("Disallowed call from listener: "
2230                                         + info.service);
2231                             }
2232                             if (!r.isSeen()) {
2233                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2234                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2235                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2236                                                 : userId,
2237                                         UsageEvents.Event.USER_INTERACTION);
2238                                 r.setSeen();
2239                             }
2240                         }
2241                     }
2242                 }
2243             } finally {
2244                 Binder.restoreCallingIdentity(identity);
2245             }
2246         }
2247 
2248         /**
2249          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2250          *
2251          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2252          *
2253          * @param info The binder for the listener, to check that the caller is allowed
2254          */
2255         @GuardedBy("mNotificationLock")
2256         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2257                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2258             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2259                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2260                     true,
2261                     userId, REASON_LISTENER_CANCEL, info);
2262         }
2263 
2264         /**
2265          * Allow an INotificationListener to snooze a single notification until a context.
2266          *
2267          * @param token The binder for the listener, to check that the caller is allowed
2268          */
2269         @Override
2270         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2271                 String key, String snoozeCriterionId) {
2272             long identity = Binder.clearCallingIdentity();
2273             try {
2274                 synchronized (mNotificationLock) {
2275                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2276                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2277                 }
2278             } finally {
2279                 Binder.restoreCallingIdentity(identity);
2280             }
2281         }
2282 
2283         /**
2284          * Allow an INotificationListener to snooze a single notification until a time.
2285          *
2286          * @param token The binder for the listener, to check that the caller is allowed
2287          */
2288         @Override
2289         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2290                 long duration) {
2291             long identity = Binder.clearCallingIdentity();
2292             try {
2293                 synchronized (mNotificationLock) {
2294                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2295                     snoozeNotificationInt(key, duration, null, info);
2296                 }
2297             } finally {
2298                 Binder.restoreCallingIdentity(identity);
2299             }
2300         }
2301 
2302         /**
2303          * Allows the notification assistant to un-snooze a single notification.
2304          *
2305          * @param token The binder for the assistant, to check that the caller is allowed
2306          */
2307         @Override
2308         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2309             long identity = Binder.clearCallingIdentity();
2310             try {
2311                 synchronized (mNotificationLock) {
2312                     final ManagedServiceInfo info =
2313                             mAssistants.checkServiceTokenLocked(token);
2314                     unsnoozeNotificationInt(key, info);
2315                 }
2316             } finally {
2317                 Binder.restoreCallingIdentity(identity);
2318             }
2319         }
2320 
2321         /**
2322          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2323          *
2324          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2325          *
2326          * @param token The binder for the listener, to check that the caller is allowed
2327          */
2328         @Override
2329         public void cancelNotificationFromListener(INotificationListener token, String pkg,
2330                 String tag, int id) {
2331             final int callingUid = Binder.getCallingUid();
2332             final int callingPid = Binder.getCallingPid();
2333             long identity = Binder.clearCallingIdentity();
2334             try {
2335                 synchronized (mNotificationLock) {
2336                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2337                     if (info.supportsProfiles()) {
2338                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2339                                 + "from " + info.component
2340                                 + " use cancelNotification(key) instead.");
2341                     } else {
2342                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2343                                 pkg, tag, id, info.userid);
2344                     }
2345                 }
2346             } finally {
2347                 Binder.restoreCallingIdentity(identity);
2348             }
2349         }
2350 
2351         /**
2352          * Allow an INotificationListener to request the list of outstanding notifications seen by
2353          * the current user. Useful when starting up, after which point the listener callbacks
2354          * should be used.
2355          *
2356          * @param token The binder for the listener, to check that the caller is allowed
2357          * @param keys An array of notification keys to fetch, or null to fetch everything
2358          * @returns The return value will contain the notifications specified in keys, in that
2359          *      order, or if keys is null, all the notifications, in natural order.
2360          */
2361         @Override
2362         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2363                 INotificationListener token, String[] keys, int trim) {
2364             synchronized (mNotificationLock) {
2365                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2366                 final boolean getKeys = keys != null;
2367                 final int N = getKeys ? keys.length : mNotificationList.size();
2368                 final ArrayList<StatusBarNotification> list
2369                         = new ArrayList<StatusBarNotification>(N);
2370                 for (int i=0; i<N; i++) {
2371                     final NotificationRecord r = getKeys
2372                             ? mNotificationsByKey.get(keys[i])
2373                             : mNotificationList.get(i);
2374                     if (r == null) continue;
2375                     StatusBarNotification sbn = r.sbn;
2376                     if (!isVisibleToListener(sbn, info)) continue;
2377                     StatusBarNotification sbnToSend =
2378                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2379                     list.add(sbnToSend);
2380                 }
2381                 return new ParceledListSlice<StatusBarNotification>(list);
2382             }
2383         }
2384 
2385         /**
2386          * Allow an INotificationListener to request the list of outstanding snoozed notifications
2387          * seen by the current user. Useful when starting up, after which point the listener
2388          * callbacks should be used.
2389          *
2390          * @param token The binder for the listener, to check that the caller is allowed
2391          * @returns The return value will contain the notifications specified in keys, in that
2392          *      order, or if keys is null, all the notifications, in natural order.
2393          */
2394         @Override
2395         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2396                 INotificationListener token, int trim) {
2397             synchronized (mNotificationLock) {
2398                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2399                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2400                 final int N = snoozedRecords.size();
2401                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2402                 for (int i=0; i < N; i++) {
2403                     final NotificationRecord r = snoozedRecords.get(i);
2404                     if (r == null) continue;
2405                     StatusBarNotification sbn = r.sbn;
2406                     if (!isVisibleToListener(sbn, info)) continue;
2407                     StatusBarNotification sbnToSend =
2408                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2409                     list.add(sbnToSend);
2410                 }
2411                 return new ParceledListSlice<>(list);
2412             }
2413         }
2414 
2415         @Override
2416         public void requestHintsFromListener(INotificationListener token, int hints) {
2417             final long identity = Binder.clearCallingIdentity();
2418             try {
2419                 synchronized (mNotificationLock) {
2420                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2421                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2422                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2423                             | HINT_HOST_DISABLE_CALL_EFFECTS;
2424                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
2425                     if (disableEffects) {
2426                         addDisabledHints(info, hints);
2427                     } else {
2428                         removeDisabledHints(info, hints);
2429                     }
2430                     updateListenerHintsLocked();
2431                     updateEffectsSuppressorLocked();
2432                 }
2433             } finally {
2434                 Binder.restoreCallingIdentity(identity);
2435             }
2436         }
2437 
2438         @Override
2439         public int getHintsFromListener(INotificationListener token) {
2440             synchronized (mNotificationLock) {
2441                 return mListenerHints;
2442             }
2443         }
2444 
2445         @Override
2446         public void requestInterruptionFilterFromListener(INotificationListener token,
2447                 int interruptionFilter) throws RemoteException {
2448             final long identity = Binder.clearCallingIdentity();
2449             try {
2450                 synchronized (mNotificationLock) {
2451                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2452                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2453                     updateInterruptionFilterLocked();
2454                 }
2455             } finally {
2456                 Binder.restoreCallingIdentity(identity);
2457             }
2458         }
2459 
2460         @Override
2461         public int getInterruptionFilterFromListener(INotificationListener token)
2462                 throws RemoteException {
2463             synchronized (mNotificationLight) {
2464                 return mInterruptionFilter;
2465             }
2466         }
2467 
2468         @Override
2469         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2470                 throws RemoteException {
2471             synchronized (mNotificationLock) {
2472                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2473                 if (info == null) return;
2474                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2475             }
2476         }
2477 
2478         @Override
2479         public int getZenMode() {
2480             return mZenModeHelper.getZenMode();
2481         }
2482 
2483         @Override
2484         public ZenModeConfig getZenModeConfig() {
2485             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2486             return mZenModeHelper.getConfig();
2487         }
2488 
2489         @Override
2490         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2491             enforceSystemOrSystemUI("INotificationManager.setZenMode");
2492             final long identity = Binder.clearCallingIdentity();
2493             try {
2494                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2495             } finally {
2496                 Binder.restoreCallingIdentity(identity);
2497             }
2498         }
2499 
2500         @Override
2501         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2502             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2503             return mZenModeHelper.getZenRules();
2504         }
2505 
2506         @Override
2507         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2508             Preconditions.checkNotNull(id, "Id is null");
2509             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2510             return mZenModeHelper.getAutomaticZenRule(id);
2511         }
2512 
2513         @Override
2514         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2515                 throws RemoteException {
2516             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2517             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2518             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2519             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2520             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2521 
2522             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2523                     "addAutomaticZenRule");
2524         }
2525 
2526         @Override
2527         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2528                 throws RemoteException {
2529             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2530             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2531             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2532             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2533             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2534 
2535             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2536                     "updateAutomaticZenRule");
2537         }
2538 
2539         @Override
2540         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2541             Preconditions.checkNotNull(id, "Id is null");
2542             // Verify that they can modify zen rules.
2543             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2544 
2545             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2546         }
2547 
2548         @Override
2549         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2550             Preconditions.checkNotNull(packageName, "Package name is null");
2551             enforceSystemOrSystemUI("removeAutomaticZenRules");
2552 
2553             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2554         }
2555 
2556         @Override
2557         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2558             Preconditions.checkNotNull(owner, "Owner is null");
2559             enforceSystemOrSystemUI("getRuleInstanceCount");
2560 
2561             return mZenModeHelper.getCurrentInstanceCount(owner);
2562         }
2563 
2564         @Override
2565         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2566             enforcePolicyAccess(pkg, "setInterruptionFilter");
2567             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2568             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2569             final long identity = Binder.clearCallingIdentity();
2570             try {
2571                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2572             } finally {
2573                 Binder.restoreCallingIdentity(identity);
2574             }
2575         }
2576 
2577         @Override
2578         public void notifyConditions(final String pkg, IConditionProvider provider,
2579                 final Condition[] conditions) {
2580             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2581             checkCallerIsSystemOrSameApp(pkg);
2582             mHandler.post(new Runnable() {
2583                 @Override
2584                 public void run() {
2585                     mConditionProviders.notifyConditions(pkg, info, conditions);
2586                 }
2587             });
2588         }
2589 
2590         @Override
2591         public void requestUnbindProvider(IConditionProvider provider) {
2592             long identity = Binder.clearCallingIdentity();
2593             try {
2594                 // allow bound services to disable themselves
2595                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2596                 info.getOwner().setComponentState(info.component, false);
2597             } finally {
2598                 Binder.restoreCallingIdentity(identity);
2599             }
2600         }
2601 
2602         @Override
2603         public void requestBindProvider(ComponentName component) {
2604             checkCallerIsSystemOrSameApp(component.getPackageName());
2605             long identity = Binder.clearCallingIdentity();
2606             try {
2607                 mConditionProviders.setComponentState(component, true);
2608             } finally {
2609                 Binder.restoreCallingIdentity(identity);
2610             }
2611         }
2612 
2613         private void enforceSystemOrSystemUI(String message) {
2614             if (isCallerSystemOrPhone()) return;
2615             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2616                     message);
2617         }
2618 
2619         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2620             try {
2621                 checkCallerIsSystemOrSameApp(pkg);
2622             } catch (SecurityException e) {
2623                 getContext().enforceCallingPermission(
2624                         android.Manifest.permission.STATUS_BAR_SERVICE,
2625                         message);
2626             }
2627         }
2628 
2629         private void enforcePolicyAccess(int uid, String method) {
2630             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2631                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2632                 return;
2633             }
2634             boolean accessAllowed = false;
2635             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2636             final int packageCount = packages.length;
2637             for (int i = 0; i < packageCount; i++) {
2638                 if (mConditionProviders.isPackageOrComponentAllowed(
2639                         packages[i], UserHandle.getUserId(uid))) {
2640                     accessAllowed = true;
2641                 }
2642             }
2643             if (!accessAllowed) {
2644                 Slog.w(TAG, "Notification policy access denied calling " + method);
2645                 throw new SecurityException("Notification policy access denied");
2646             }
2647         }
2648 
2649         private void enforcePolicyAccess(String pkg, String method) {
2650             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2651                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2652                 return;
2653             }
2654             checkCallerIsSameApp(pkg);
2655             if (!checkPolicyAccess(pkg)) {
2656                 Slog.w(TAG, "Notification policy access denied calling " + method);
2657                 throw new SecurityException("Notification policy access denied");
2658             }
2659         }
2660 
2661         private boolean checkPackagePolicyAccess(String pkg) {
2662             return mConditionProviders.isPackageOrComponentAllowed(
2663                     pkg, getCallingUserHandle().getIdentifier());
2664         }
2665 
2666         private boolean checkPolicyAccess(String pkg) {
2667             try {
2668                 int uid = getContext().getPackageManager().getPackageUidAsUser(
2669                         pkg, UserHandle.getCallingUserId());
2670                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2671                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2672                         -1, true)) {
2673                     return true;
2674                 }
2675             } catch (NameNotFoundException e) {
2676                 return false;
2677             }
2678             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2679         }
2680 
2681         @Override
2682         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2683             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2684             final DumpFilter filter = DumpFilter.parseFromArguments(args);
2685             if (filter != null && filter.stats) {
2686                 dumpJson(pw, filter);
2687             } else if (filter != null && filter.proto) {
2688                 dumpProto(fd, filter);
2689             } else {
2690                 dumpImpl(pw, filter);
2691             }
2692         }
2693 
2694         @Override
2695         public ComponentName getEffectsSuppressor() {
2696             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2697         }
2698 
2699         @Override
2700         public boolean matchesCallFilter(Bundle extras) {
2701             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2702             return mZenModeHelper.matchesCallFilter(
2703                     Binder.getCallingUserHandle(),
2704                     extras,
2705                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2706                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2707                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2708         }
2709 
2710         @Override
2711         public boolean isSystemConditionProviderEnabled(String path) {
2712             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2713             return mConditionProviders.isSystemProviderEnabled(path);
2714         }
2715 
2716         // Backup/restore interface
2717         @Override
2718         public byte[] getBackupPayload(int user) {
2719             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2720             //TODO: http://b/22388012
2721             if (user != UserHandle.USER_SYSTEM) {
2722                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2723                 return null;
2724             }
2725             synchronized(mPolicyFile) {
2726                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2727                 try {
2728                     writePolicyXml(baos, true /*forBackup*/);
2729                     return baos.toByteArray();
2730                 } catch (IOException e) {
2731                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2732                 }
2733             }
2734             return null;
2735         }
2736 
2737         @Override
2738         public void applyRestore(byte[] payload, int user) {
2739             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2740                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2741             if (payload == null) {
2742                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2743                 return;
2744             }
2745             //TODO: http://b/22388012
2746             if (user != UserHandle.USER_SYSTEM) {
2747                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2748                 return;
2749             }
2750             synchronized(mPolicyFile) {
2751                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2752                 try {
2753                     readPolicyXml(bais, true /*forRestore*/);
2754                     savePolicyFile();
2755                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2756                     Slog.w(TAG, "applyRestore: error reading payload", e);
2757                 }
2758             }
2759         }
2760 
2761         @Override
2762         public boolean isNotificationPolicyAccessGranted(String pkg) {
2763             return checkPolicyAccess(pkg);
2764         }
2765 
2766         @Override
2767         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2768             enforceSystemOrSystemUIOrSamePackage(pkg,
2769                     "request policy access status for another package");
2770             return checkPolicyAccess(pkg);
2771         }
2772 
2773         @Override
2774         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2775                 throws RemoteException {
2776             setNotificationPolicyAccessGrantedForUser(
2777                     pkg, getCallingUserHandle().getIdentifier(), granted);
2778         }
2779 
2780         @Override
2781         public void setNotificationPolicyAccessGrantedForUser(
2782                 String pkg, int userId, boolean granted) {
2783             checkCallerIsSystemOrShell();
2784             final long identity = Binder.clearCallingIdentity();
2785             try {
2786                 if (!mActivityManager.isLowRamDevice()) {
2787                     mConditionProviders.setPackageOrComponentEnabled(
2788                             pkg, userId, true, granted);
2789 
2790                     getContext().sendBroadcastAsUser(new Intent(
2791                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2792                                     .setPackage(pkg)
2793                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2794                             UserHandle.of(userId), null);
2795                     savePolicyFile();
2796                 }
2797             } finally {
2798                 Binder.restoreCallingIdentity(identity);
2799             }
2800         }
2801 
2802         @Override
2803         public Policy getNotificationPolicy(String pkg) {
2804             enforcePolicyAccess(pkg, "getNotificationPolicy");
2805             final long identity = Binder.clearCallingIdentity();
2806             try {
2807                 return mZenModeHelper.getNotificationPolicy();
2808             } finally {
2809                 Binder.restoreCallingIdentity(identity);
2810             }
2811         }
2812 
2813         @Override
2814         public void setNotificationPolicy(String pkg, Policy policy) {
2815             enforcePolicyAccess(pkg, "setNotificationPolicy");
2816             final long identity = Binder.clearCallingIdentity();
2817             try {
2818                 mZenModeHelper.setNotificationPolicy(policy);
2819             } finally {
2820                 Binder.restoreCallingIdentity(identity);
2821             }
2822         }
2823 
2824         @Override
2825         public List<String> getEnabledNotificationListenerPackages() {
2826             checkCallerIsSystem();
2827             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2828         }
2829 
2830         @Override
2831         public List<ComponentName> getEnabledNotificationListeners(int userId) {
2832             checkCallerIsSystem();
2833             return mListeners.getAllowedComponents(userId);
2834         }
2835 
2836         @Override
2837         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2838             Preconditions.checkNotNull(listener);
2839             checkCallerIsSystemOrSameApp(listener.getPackageName());
2840             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2841                     getCallingUserHandle().getIdentifier());
2842         }
2843 
2844         @Override
2845         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2846                 int userId) {
2847             Preconditions.checkNotNull(listener);
2848             checkCallerIsSystem();
2849             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2850                     userId);
2851         }
2852 
2853         @Override
2854         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2855             Preconditions.checkNotNull(assistant);
2856             checkCallerIsSystemOrSameApp(assistant.getPackageName());
2857             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
2858                     getCallingUserHandle().getIdentifier());
2859         }
2860 
2861         @Override
2862         public void setNotificationListenerAccessGranted(ComponentName listener,
2863                 boolean granted) throws RemoteException {
2864             setNotificationListenerAccessGrantedForUser(
2865                     listener, getCallingUserHandle().getIdentifier(), granted);
2866         }
2867 
2868         @Override
2869         public void setNotificationAssistantAccessGranted(ComponentName assistant,
2870                 boolean granted) throws RemoteException {
2871             setNotificationAssistantAccessGrantedForUser(
2872                     assistant, getCallingUserHandle().getIdentifier(), granted);
2873         }
2874 
2875         @Override
2876         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
2877                 boolean granted) throws RemoteException {
2878             Preconditions.checkNotNull(listener);
2879             checkCallerIsSystemOrShell();
2880             final long identity = Binder.clearCallingIdentity();
2881             try {
2882                 if (!mActivityManager.isLowRamDevice()) {
2883                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
2884                             userId, false, granted);
2885                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
2886                             userId, true, granted);
2887 
2888                     getContext().sendBroadcastAsUser(new Intent(
2889                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2890                                     .setPackage(listener.getPackageName())
2891                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2892                             UserHandle.of(userId), null);
2893 
2894                     savePolicyFile();
2895                 }
2896             } finally {
2897                 Binder.restoreCallingIdentity(identity);
2898             }
2899         }
2900 
2901         @Override
2902         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
2903                 int userId, boolean granted) throws RemoteException {
2904             Preconditions.checkNotNull(assistant);
2905             checkCallerIsSystemOrShell();
2906             final long identity = Binder.clearCallingIdentity();
2907             try {
2908                 if (!mActivityManager.isLowRamDevice()) {
2909                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
2910                             userId, false, granted);
2911                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
2912                             userId, true, granted);
2913 
2914                     getContext().sendBroadcastAsUser(new Intent(
2915                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2916                                     .setPackage(assistant.getPackageName())
2917                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2918                             UserHandle.of(userId), null);
2919 
2920                     savePolicyFile();
2921                 }
2922             } finally {
2923                 Binder.restoreCallingIdentity(identity);
2924             }
2925         }
2926 
2927         @Override
2928         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2929                 Adjustment adjustment) throws RemoteException {
2930             final long identity = Binder.clearCallingIdentity();
2931             try {
2932                 synchronized (mNotificationLock) {
2933                     mAssistants.checkServiceTokenLocked(token);
2934                     int N = mEnqueuedNotifications.size();
2935                     for (int i = 0; i < N; i++) {
2936                         final NotificationRecord n = mEnqueuedNotifications.get(i);
2937                         if (Objects.equals(adjustment.getKey(), n.getKey())
2938                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2939                             applyAdjustment(n, adjustment);
2940                             break;
2941                         }
2942                     }
2943                 }
2944             } finally {
2945                 Binder.restoreCallingIdentity(identity);
2946             }
2947         }
2948 
2949         @Override
2950         public void applyAdjustmentFromAssistant(INotificationListener token,
2951                 Adjustment adjustment) throws RemoteException {
2952             final long identity = Binder.clearCallingIdentity();
2953             try {
2954                 synchronized (mNotificationLock) {
2955                     mAssistants.checkServiceTokenLocked(token);
2956                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2957                     applyAdjustment(n, adjustment);
2958                 }
2959                 mRankingHandler.requestSort();
2960             } finally {
2961                 Binder.restoreCallingIdentity(identity);
2962             }
2963         }
2964 
2965         @Override
2966         public void applyAdjustmentsFromAssistant(INotificationListener token,
2967                 List<Adjustment> adjustments) throws RemoteException {
2968 
2969             final long identity = Binder.clearCallingIdentity();
2970             try {
2971                 synchronized (mNotificationLock) {
2972                     mAssistants.checkServiceTokenLocked(token);
2973                     for (Adjustment adjustment : adjustments) {
2974                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2975                         applyAdjustment(n, adjustment);
2976                     }
2977                 }
2978                 mRankingHandler.requestSort();
2979             } finally {
2980                 Binder.restoreCallingIdentity(identity);
2981             }
2982         }
2983 
2984         @Override
2985         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2986                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2987             Preconditions.checkNotNull(channel);
2988             Preconditions.checkNotNull(pkg);
2989             Preconditions.checkNotNull(user);
2990 
2991             verifyPrivilegedListener(token, user);
2992             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2993         }
2994 
2995         @Override
2996         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2997                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2998             Preconditions.checkNotNull(pkg);
2999             Preconditions.checkNotNull(user);
3000             verifyPrivilegedListener(token, user);
3001 
3002             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3003                     false /* includeDeleted */);
3004         }
3005 
3006         @Override
3007         public ParceledListSlice<NotificationChannelGroup>
3008                 getNotificationChannelGroupsFromPrivilegedListener(
3009                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3010             Preconditions.checkNotNull(pkg);
3011             Preconditions.checkNotNull(user);
3012             verifyPrivilegedListener(token, user);
3013 
3014             List<NotificationChannelGroup> groups = new ArrayList<>();
3015             groups.addAll(mRankingHelper.getNotificationChannelGroups(
3016                     pkg, getUidForPackageAndUser(pkg, user)));
3017             return new ParceledListSlice<>(groups);
3018         }
3019 
3020         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
3021             ManagedServiceInfo info;
3022             synchronized (mNotificationLock) {
3023                 info = mListeners.checkServiceTokenLocked(token);
3024             }
3025             if (!hasCompanionDevice(info)) {
3026                 throw new SecurityException(info + " does not have access");
3027             }
3028             if (!info.enabledAndUserMatches(user.getIdentifier())) {
3029                 throw new SecurityException(info + " does not have access");
3030             }
3031         }
3032 
3033         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3034             int uid = 0;
3035             long identity = Binder.clearCallingIdentity();
3036             try {
3037                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3038             } finally {
3039                 Binder.restoreCallingIdentity(identity);
3040             }
3041             return uid;
3042         }
3043 
3044         @Override
3045         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3046                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3047                 throws RemoteException {
3048             new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3049         }
3050     };
3051 
3052     private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3053         if (r == null) {
3054             return;
3055         }
3056         if (adjustment.getSignals() != null) {
3057             Bundle.setDefusable(adjustment.getSignals(), true);
3058             r.addAdjustment(adjustment);
3059         }
3060     }
3061 
3062     @GuardedBy("mNotificationLock")
3063     void addAutogroupKeyLocked(String key) {
3064         NotificationRecord r = mNotificationsByKey.get(key);
3065         if (r == null) {
3066             return;
3067         }
3068         if (r.sbn.getOverrideGroupKey() == null) {
3069             addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3070             EventLogTags.writeNotificationAutogrouped(key);
3071             mRankingHandler.requestSort();
3072         }
3073     }
3074 
3075     @GuardedBy("mNotificationLock")
3076     void removeAutogroupKeyLocked(String key) {
3077         NotificationRecord r = mNotificationsByKey.get(key);
3078         if (r == null) {
3079             return;
3080         }
3081         if (r.sbn.getOverrideGroupKey() != null) {
3082             addAutoGroupAdjustment(r, null);
3083             EventLogTags.writeNotificationUnautogrouped(key);
3084             mRankingHandler.requestSort();
3085         }
3086     }
3087 
3088     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3089         Bundle signals = new Bundle();
3090         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3091         Adjustment adjustment =
3092                 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3093         r.addAdjustment(adjustment);
3094     }
3095 
3096     // Clears the 'fake' auto-group summary.
3097     @GuardedBy("mNotificationLock")
3098     private void clearAutogroupSummaryLocked(int userId, String pkg) {
3099         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3100         if (summaries != null && summaries.containsKey(pkg)) {
3101             // Clear summary.
3102             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
3103             if (removed != null) {
3104                 boolean wasPosted = removeFromNotificationListsLocked(removed);
3105                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
3106             }
3107         }
3108     }
3109 
3110     @GuardedBy("mNotificationLock")
3111     private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3112         ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3113         return summaries != null && summaries.containsKey(sbn.getPackageName());
3114     }
3115 
3116     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
3117     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3118         NotificationRecord summaryRecord = null;
3119         synchronized (mNotificationLock) {
3120             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3121             if (notificationRecord == null) {
3122                 // The notification could have been cancelled again already. A successive
3123                 // adjustment will post a summary if needed.
3124                 return;
3125             }
3126             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3127             userId = adjustedSbn.getUser().getIdentifier();
3128             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3129             if (summaries == null) {
3130                 summaries = new ArrayMap<>();
3131             }
3132             mAutobundledSummaries.put(userId, summaries);
3133             if (!summaries.containsKey(pkg)) {
3134                 // Add summary
3135                 final ApplicationInfo appInfo =
3136                        adjustedSbn.getNotification().extras.getParcelable(
3137                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
3138                 final Bundle extras = new Bundle();
3139                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
3140                 final String channelId = notificationRecord.getChannel().getId();
3141                 final Notification summaryNotification =
3142                         new Notification.Builder(getContext(), channelId)
3143                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
3144                                 .setGroupSummary(true)
3145                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
3146                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
3147                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3148                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3149                                 .setColor(adjustedSbn.getNotification().color)
3150                                 .setLocalOnly(true)
3151                                 .build();
3152                 summaryNotification.extras.putAll(extras);
3153                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3154                 if (appIntent != null) {
3155                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3156                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3157                 }
3158                 final StatusBarNotification summarySbn =
3159                         new StatusBarNotification(adjustedSbn.getPackageName(),
3160                                 adjustedSbn.getOpPkg(),
3161                                 Integer.MAX_VALUE,
3162                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3163                                 adjustedSbn.getInitialPid(), summaryNotification,
3164                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3165                                 System.currentTimeMillis());
3166                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
3167                         notificationRecord.getChannel());
3168                 summaries.put(pkg, summarySbn.getKey());
3169             }
3170         }
3171         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
3172                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
3173             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
3174         }
3175     }
3176 
3177     private String disableNotificationEffects(NotificationRecord record) {
3178         if (mDisableNotificationEffects) {
3179             return "booleanState";
3180         }
3181         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3182             return "listenerHints";
3183         }
3184         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3185             return "callState";
3186         }
3187         return null;
3188     };
3189 
3190     private void dumpJson(PrintWriter pw, DumpFilter filter) {
3191         JSONObject dump = new JSONObject();
3192         try {
3193             dump.put("service", "Notification Manager");
3194             dump.put("bans", mRankingHelper.dumpBansJson(filter));
3195             dump.put("ranking", mRankingHelper.dumpJson(filter));
3196             dump.put("stats", mUsageStats.dumpJson(filter));
3197             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
3198         } catch (JSONException e) {
3199             e.printStackTrace();
3200         }
3201         pw.println(dump);
3202     }
3203 
3204     private void dumpProto(FileDescriptor fd, DumpFilter filter) {
3205         final ProtoOutputStream proto = new ProtoOutputStream(fd);
3206         synchronized (mNotificationLock) {
3207             long records = proto.start(NotificationServiceDumpProto.RECORDS);
3208             int N = mNotificationList.size();
3209             if (N > 0) {
3210                 for (int i = 0; i < N; i++) {
3211                     final NotificationRecord nr = mNotificationList.get(i);
3212                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3213                     nr.dump(proto, filter.redact);
3214                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
3215                 }
3216             }
3217             N = mEnqueuedNotifications.size();
3218             if (N > 0) {
3219                 for (int i = 0; i < N; i++) {
3220                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
3221                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3222                     nr.dump(proto, filter.redact);
3223                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
3224                 }
3225             }
3226             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3227             N = snoozed.size();
3228             if (N > 0) {
3229                 for (int i = 0; i < N; i++) {
3230                     final NotificationRecord nr = snoozed.get(i);
3231                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3232                     nr.dump(proto, filter.redact);
3233                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
3234                 }
3235             }
3236             proto.end(records);
3237         }
3238 
3239         long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3240         mZenModeHelper.dump(proto);
3241         for (ComponentName suppressor : mEffectsSuppressors) {
3242             proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3243         }
3244         proto.end(zenLog);
3245 
3246         proto.flush();
3247     }
3248 
3249     void dumpImpl(PrintWriter pw, DumpFilter filter) {
3250         pw.print("Current Notification Manager state");
3251         if (filter.filtered) {
3252             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
3253         }
3254         pw.println(':');
3255         int N;
3256         final boolean zenOnly = filter.filtered && filter.zen;
3257 
3258         if (!zenOnly) {
3259             synchronized (mToastQueue) {
3260                 N = mToastQueue.size();
3261                 if (N > 0) {
3262                     pw.println("  Toast Queue:");
3263                     for (int i=0; i<N; i++) {
3264                         mToastQueue.get(i).dump(pw, "    ", filter);
3265                     }
3266                     pw.println("  ");
3267                 }
3268             }
3269         }
3270 
3271         synchronized (mNotificationLock) {
3272             if (!zenOnly) {
3273                 N = mNotificationList.size();
3274                 if (N > 0) {
3275                     pw.println("  Notification List:");
3276                     for (int i=0; i<N; i++) {
3277                         final NotificationRecord nr = mNotificationList.get(i);
3278                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
3279                         nr.dump(pw, "    ", getContext(), filter.redact);
3280                     }
3281                     pw.println("  ");
3282                 }
3283 
3284                 if (!filter.filtered) {
3285                     N = mLights.size();
3286                     if (N > 0) {
3287                         pw.println("  Lights List:");
3288                         for (int i=0; i<N; i++) {
3289                             if (i == N - 1) {
3290                                 pw.print("  > ");
3291                             } else {
3292                                 pw.print("    ");
3293                             }
3294                             pw.println(mLights.get(i));
3295                         }
3296                         pw.println("  ");
3297                     }
3298                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
3299                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3300                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
3301                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
3302                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
3303                     pw.println("  mCallState=" + callStateToString(mCallState));
3304                     pw.println("  mSystemReady=" + mSystemReady);
3305                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3306                 }
3307                 pw.println("  mArchive=" + mArchive.toString());
3308                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3309                 int j=0;
3310                 while (iter.hasNext()) {
3311                     final StatusBarNotification sbn = iter.next();
3312                     if (filter != null && !filter.matches(sbn)) continue;
3313                     pw.println("    " + sbn);
3314                     if (++j >= 5) {
3315                         if (iter.hasNext()) pw.println("    ...");
3316                         break;
3317                     }
3318                 }
3319 
3320                 if (!zenOnly) {
3321                     N = mEnqueuedNotifications.size();
3322                     if (N > 0) {
3323                         pw.println("  Enqueued Notification List:");
3324                         for (int i = 0; i < N; i++) {
3325                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
3326                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
3327                             nr.dump(pw, "    ", getContext(), filter.redact);
3328                         }
3329                         pw.println("  ");
3330                     }
3331 
3332                     mSnoozeHelper.dump(pw, filter);
3333                 }
3334             }
3335 
3336             if (!zenOnly) {
3337                 pw.println("\n  Ranking Config:");
3338                 mRankingHelper.dump(pw, "    ", filter);
3339 
3340                 pw.println("\n  Notification listeners:");
3341                 mListeners.dump(pw, filter);
3342                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
3343                 pw.print("    mListenersDisablingEffects: (");
3344                 N = mListenersDisablingEffects.size();
3345                 for (int i = 0; i < N; i++) {
3346                     final int hint = mListenersDisablingEffects.keyAt(i);
3347                     if (i > 0) pw.print(';');
3348                     pw.print("hint[" + hint + "]:");
3349 
3350                     final ArraySet<ManagedServiceInfo> listeners =
3351                             mListenersDisablingEffects.valueAt(i);
3352                     final int listenerSize = listeners.size();
3353 
3354                     for (int j = 0; j < listenerSize; j++) {
3355                         if (i > 0) pw.print(',');
3356                         final ManagedServiceInfo listener = listeners.valueAt(i);
3357                         pw.print(listener.component);
3358                     }
3359                 }
3360                 pw.println(')');
3361                 pw.println("\n  Notification assistant services:");
3362                 mAssistants.dump(pw, filter);
3363             }
3364 
3365             if (!filter.filtered || zenOnly) {
3366                 pw.println("\n  Zen Mode:");
3367                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3368                 mZenModeHelper.dump(pw, "    ");
3369 
3370                 pw.println("\n  Zen Log:");
3371                 ZenLog.dump(pw, "    ");
3372             }
3373 
3374             pw.println("\n  Condition providers:");
3375             mConditionProviders.dump(pw, filter);
3376 
3377             pw.println("\n  Group summaries:");
3378             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3379                 NotificationRecord r = entry.getValue();
3380                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
3381                 if (mNotificationsByKey.get(r.getKey()) != r) {
3382                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3383                     r.dump(pw, "      ", getContext(), filter.redact);
3384                 }
3385             }
3386 
3387             if (!zenOnly) {
3388                 pw.println("\n  Usage Stats:");
3389                 mUsageStats.dump(pw, "    ", filter);
3390             }
3391         }
3392     }
3393 
3394     /**
3395      * The private API only accessible to the system process.
3396      */
3397     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3398         @Override
3399         public NotificationChannel getNotificationChannel(String pkg, int uid, String
3400                 channelId) {
3401             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3402         }
3403 
3404         @Override
3405         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3406                 String tag, int id, Notification notification, int userId) {
3407             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3408                     userId);
3409         }
3410 
3411         @Override
3412         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3413                 int userId) {
3414             checkCallerIsSystem();
3415             mHandler.post(new Runnable() {
3416                 @Override
3417                 public void run() {
3418                     synchronized (mNotificationLock) {
3419                         removeForegroundServiceFlagByListLocked(
3420                                 mEnqueuedNotifications, pkg, notificationId, userId);
3421                         removeForegroundServiceFlagByListLocked(
3422                                 mNotificationList, pkg, notificationId, userId);
3423                     }
3424                 }
3425             });
3426         }
3427 
3428         @GuardedBy("mNotificationLock")
3429         private void removeForegroundServiceFlagByListLocked(
3430                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3431                 int userId) {
3432             NotificationRecord r = findNotificationByListLocked(
3433                     notificationList, pkg, null, notificationId, userId);
3434             if (r == null) {
3435                 return;
3436             }
3437             StatusBarNotification sbn = r.sbn;
3438             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3439             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3440             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3441             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3442             sbn.getNotification().flags =
3443                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3444             mRankingHelper.sort(mNotificationList);
3445             mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3446         }
3447     };
3448 
3449     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3450             final int callingPid, final String tag, final int id, final Notification notification,
3451             int incomingUserId) {
3452         if (DBG) {
3453             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3454                     + " notification=" + notification);
3455         }
3456         checkCallerIsSystemOrSameApp(pkg);
3457 
3458         final int userId = ActivityManager.handleIncomingUser(callingPid,
3459                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3460         final UserHandle user = new UserHandle(userId);
3461 
3462         if (pkg == null || notification == null) {
3463             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3464                     + " id=" + id + " notification=" + notification);
3465         }
3466 
3467         // The system can post notifications for any package, let us resolve that.
3468         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3469 
3470         // Fix the notification as best we can.
3471         try {
3472             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3473                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3474                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3475             Notification.addFieldsFromContext(ai, notification);
3476 
3477             int canColorize = mPackageManagerClient.checkPermission(
3478                     android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3479             if (canColorize == PERMISSION_GRANTED) {
3480                 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3481             } else {
3482                 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3483             }
3484 
3485         } catch (NameNotFoundException e) {
3486             Slog.e(TAG, "Cannot create a context for sending app", e);
3487             return;
3488         }
3489 
3490         mUsageStats.registerEnqueuedByApp(pkg);
3491 
3492         // setup local book-keeping
3493         String channelId = notification.getChannelId();
3494         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3495             channelId = (new Notification.TvExtender(notification)).getChannelId();
3496         }
3497         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3498                 notificationUid, channelId, false /* includeDeleted */);
3499         if (channel == null) {
3500             final String noChannelStr = "No Channel found for "
3501                     + "pkg=" + pkg
3502                     + ", channelId=" + channelId
3503                     + ", id=" + id
3504                     + ", tag=" + tag
3505                     + ", opPkg=" + opPkg
3506                     + ", callingUid=" + callingUid
3507                     + ", userId=" + userId
3508                     + ", incomingUserId=" + incomingUserId
3509                     + ", notificationUid=" + notificationUid
3510                     + ", notification=" + notification;
3511             Log.e(TAG, noChannelStr);
3512             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3513                     "Failed to post notification on channel \"" + channelId + "\"\n" +
3514                     "See log for more details");
3515             return;
3516         }
3517 
3518         final StatusBarNotification n = new StatusBarNotification(
3519                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3520                 user, null, System.currentTimeMillis());
3521         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3522 
3523         if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3524                 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3525                 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3526             // Increase the importance of foreground service notifications unless the user had an
3527             // opinion otherwise
3528             if (TextUtils.isEmpty(channelId)
3529                     || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3530                 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3531             } else {
3532                 channel.setImportance(IMPORTANCE_LOW);
3533                 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3534                 r.updateNotificationChannel(channel);
3535             }
3536         }
3537 
3538         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3539                 r.sbn.getOverrideGroupKey() != null)) {
3540             return;
3541         }
3542 
3543         // Whitelist pending intents.
3544         if (notification.allPendingIntents != null) {
3545             final int intentCount = notification.allPendingIntents.size();
3546             if (intentCount > 0) {
3547                 final ActivityManagerInternal am = LocalServices
3548                         .getService(ActivityManagerInternal.class);
3549                 final long duration = LocalServices.getService(
3550                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3551                 for (int i = 0; i < intentCount; i++) {
3552                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3553                     if (pendingIntent != null) {
3554                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3555                                 WHITELIST_TOKEN, duration);
3556                     }
3557                 }
3558             }
3559         }
3560 
3561         mHandler.post(new EnqueueNotificationRunnable(userId, r));
3562     }
3563 
3564     private void doChannelWarningToast(CharSequence toastText) {
3565         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3566         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3567                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3568         if (warningEnabled) {
3569             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3570                     Toast.LENGTH_SHORT);
3571             toast.show();
3572         }
3573     }
3574 
3575     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3576         // The system can post notifications on behalf of any package it wants
3577         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3578             try {
3579                 return getContext().getPackageManager()
3580                         .getPackageUidAsUser(opPackageName, userId);
3581             } catch (NameNotFoundException e) {
3582                 /* ignore */
3583             }
3584         }
3585         return callingUid;
3586     }
3587 
3588     /**
3589      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3590      *
3591      * Has side effects.
3592      */
3593     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3594             NotificationRecord r, boolean isAutogroup) {
3595         final String pkg = r.sbn.getPackageName();
3596         final String dialerPackage =
3597                 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
3598         final boolean isSystemNotification =
3599                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg))
3600                 || TextUtils.equals(pkg, dialerPackage);
3601         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3602 
3603         // Limit the number of notifications that any given package except the android
3604         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3605         if (!isSystemNotification && !isNotificationFromListener) {
3606             synchronized (mNotificationLock) {
3607                 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3608                     // Ephemeral apps have some special constraints for notifications.
3609                     // They are not allowed to create new notifications however they are allowed to
3610                     // update notifications created by the system (e.g. a foreground service
3611                     // notification).
3612                     throw new SecurityException("Instant app " + pkg
3613                             + " cannot create notifications");
3614                 }
3615 
3616                 // rate limit updates that aren't completed progress notifications
3617                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
3618                         && !r.getNotification().hasCompletedProgress()
3619                         && !isAutogroup) {
3620 
3621                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3622                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
3623                         mUsageStats.registerOverRateQuota(pkg);
3624                         final long now = SystemClock.elapsedRealtime();
3625                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3626                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3627                                     + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
3628                             mLastOverRateLogTime = now;
3629                         }
3630                         return false;
3631                     }
3632                 }
3633 
3634                 // limit the number of outstanding notificationrecords an app can have
3635                 int count = getNotificationCountLocked(pkg, userId, id, tag);
3636                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3637                     mUsageStats.registerOverCountQuota(pkg);
3638                     Slog.e(TAG, "Package has already posted or enqueued " + count
3639                             + " notifications.  Not showing more.  package=" + pkg);
3640                     return false;
3641                 }
3642             }
3643         }
3644 
3645         // snoozed apps
3646         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3647             MetricsLogger.action(r.getLogMaker()
3648                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3649                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3650             if (DBG) {
3651                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3652             }
3653             mSnoozeHelper.update(userId, r);
3654             savePolicyFile();
3655             return false;
3656         }
3657 
3658 
3659         // blocked apps
3660         if (isBlocked(r, mUsageStats)) {
3661             return false;
3662         }
3663 
3664         return true;
3665     }
3666 
3667     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3668             String excludedTag) {
3669         int count = 0;
3670         final int N = mNotificationList.size();
3671         for (int i = 0; i < N; i++) {
3672             final NotificationRecord existing = mNotificationList.get(i);
3673             if (existing.sbn.getPackageName().equals(pkg)
3674                     && existing.sbn.getUserId() == userId) {
3675                 if (existing.sbn.getId() == excludedId
3676                         && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3677                     continue;
3678                 }
3679                 count++;
3680             }
3681         }
3682         final int M = mEnqueuedNotifications.size();
3683         for (int i = 0; i < M; i++) {
3684             final NotificationRecord existing = mEnqueuedNotifications.get(i);
3685             if (existing.sbn.getPackageName().equals(pkg)
3686                     && existing.sbn.getUserId() == userId) {
3687                 count++;
3688             }
3689         }
3690         return count;
3691     }
3692 
3693     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3694         final String pkg = r.sbn.getPackageName();
3695         final int callingUid = r.sbn.getUid();
3696 
3697         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3698         if (isPackageSuspended) {
3699             Slog.e(TAG, "Suppressing notification from package due to package "
3700                     + "suspended by administrator.");
3701             usageStats.registerSuspendedByAdmin(r);
3702             return isPackageSuspended;
3703         }
3704 
3705         final boolean isBlocked =
3706                 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3707                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3708         if (isBlocked) {
3709             Slog.e(TAG, "Suppressing notification from package by user request.");
3710             usageStats.registerBlocked(r);
3711         }
3712         return isBlocked;
3713     }
3714 
3715     protected class SnoozeNotificationRunnable implements Runnable {
3716         private final String mKey;
3717         private final long mDuration;
3718         private final String mSnoozeCriterionId;
3719 
3720         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3721             mKey = key;
3722             mDuration = duration;
3723             mSnoozeCriterionId = snoozeCriterionId;
3724         }
3725 
3726         @Override
3727         public void run() {
3728             synchronized (mNotificationLock) {
3729                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3730                 if (r != null) {
3731                     snoozeLocked(r);
3732                 }
3733             }
3734         }
3735 
3736         @GuardedBy("mNotificationLock")
3737         void snoozeLocked(NotificationRecord r) {
3738             if (r.sbn.isGroup()) {
3739                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3740                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3741                 if (r.getNotification().isGroupSummary()) {
3742                     // snooze summary and all children
3743                     for (int i = 0; i < groupNotifications.size(); i++) {
3744                         snoozeNotificationLocked(groupNotifications.get(i));
3745                     }
3746                 } else {
3747                     // if there is a valid summary for this group, and we are snoozing the only
3748                     // child, also snooze the summary
3749                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3750                         if (groupNotifications.size() != 2) {
3751                             snoozeNotificationLocked(r);
3752                         } else {
3753                             // snooze summary and the one child
3754                             for (int i = 0; i < groupNotifications.size(); i++) {
3755                                 snoozeNotificationLocked(groupNotifications.get(i));
3756                             }
3757                         }
3758                     } else {
3759                         snoozeNotificationLocked(r);
3760                     }
3761                 }
3762             } else {
3763                 // just snooze the one notification
3764                 snoozeNotificationLocked(r);
3765             }
3766         }
3767 
3768         @GuardedBy("mNotificationLock")
3769         void snoozeNotificationLocked(NotificationRecord r) {
3770             MetricsLogger.action(r.getLogMaker()
3771                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3772                     .setType(MetricsEvent.TYPE_CLOSE)
3773                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
3774                             mDuration)
3775                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3776                             mSnoozeCriterionId == null ? 0 : 1));
3777             boolean wasPosted = removeFromNotificationListsLocked(r);
3778             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
3779             updateLightsLocked();
3780             if (mSnoozeCriterionId != null) {
3781                 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3782                 mSnoozeHelper.snooze(r);
3783             } else {
3784                 mSnoozeHelper.snooze(r, mDuration);
3785             }
3786             savePolicyFile();
3787         }
3788     }
3789 
3790     protected class EnqueueNotificationRunnable implements Runnable {
3791         private final NotificationRecord r;
3792         private final int userId;
3793 
3794         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3795             this.userId = userId;
3796             this.r = r;
3797         };
3798 
3799         @Override
3800         public void run() {
3801             synchronized (mNotificationLock) {
3802                 mEnqueuedNotifications.add(r);
3803                 scheduleTimeoutLocked(r);
3804 
3805                 final StatusBarNotification n = r.sbn;
3806                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3807                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3808                 if (old != null) {
3809                     // Retain ranking information from previous record
3810                     r.copyRankingInformation(old);
3811                 }
3812 
3813                 final int callingUid = n.getUid();
3814                 final int callingPid = n.getInitialPid();
3815                 final Notification notification = n.getNotification();
3816                 final String pkg = n.getPackageName();
3817                 final int id = n.getId();
3818                 final String tag = n.getTag();
3819 
3820                 // Handle grouped notifications and bail out early if we
3821                 // can to avoid extracting signals.
3822                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3823 
3824                 // if this is a group child, unsnooze parent summary
3825                 if (n.isGroup() && notification.isGroupChild()) {
3826                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3827                 }
3828 
3829                 // This conditional is a dirty hack to limit the logging done on
3830                 //     behalf of the download manager without affecting other apps.
3831                 if (!pkg.equals("com.android.providers.downloads")
3832                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3833                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3834                     if (old != null) {
3835                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3836                     }
3837                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3838                             pkg, id, tag, userId, notification.toString(),
3839                             enqueueStatus);
3840                 }
3841 
3842                 mRankingHelper.extractSignals(r);
3843 
3844                 // tell the assistant service about the notification
3845                 if (mAssistants.isEnabled()) {
3846                     mAssistants.onNotificationEnqueued(r);
3847                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3848                             DELAY_FOR_ASSISTANT_TIME);
3849                 } else {
3850                     mHandler.post(new PostNotificationRunnable(r.getKey()));
3851                 }
3852             }
3853         }
3854     }
3855 
3856     protected class PostNotificationRunnable implements Runnable {
3857         private final String key;
3858 
3859         PostNotificationRunnable(String key) {
3860             this.key = key;
3861         }
3862 
3863         @Override
3864         public void run() {
3865             synchronized (mNotificationLock) {
3866                 try {
3867                     NotificationRecord r = null;
3868                     int N = mEnqueuedNotifications.size();
3869                     for (int i = 0; i < N; i++) {
3870                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3871                         if (Objects.equals(key, enqueued.getKey())) {
3872                             r = enqueued;
3873                             break;
3874                         }
3875                     }
3876                     if (r == null) {
3877                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3878                         return;
3879                     }
3880                     NotificationRecord old = mNotificationsByKey.get(key);
3881                     final StatusBarNotification n = r.sbn;
3882                     final Notification notification = n.getNotification();
3883                     int index = indexOfNotificationLocked(n.getKey());
3884                     if (index < 0) {
3885                         mNotificationList.add(r);
3886                         mUsageStats.registerPostedByApp(r);
3887                     } else {
3888                         old = mNotificationList.get(index);
3889                         mNotificationList.set(index, r);
3890                         mUsageStats.registerUpdatedByApp(r, old);
3891                         // Make sure we don't lose the foreground service state.
3892                         notification.flags |=
3893                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3894                         r.isUpdate = true;
3895                     }
3896 
3897                     mNotificationsByKey.put(n.getKey(), r);
3898 
3899                     // Ensure if this is a foreground service that the proper additional
3900                     // flags are set.
3901                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3902                         notification.flags |= Notification.FLAG_ONGOING_EVENT
3903                                 | Notification.FLAG_NO_CLEAR;
3904                     }
3905 
3906                     applyZenModeLocked(r);
3907                     mRankingHelper.sort(mNotificationList);
3908 
3909                     if (notification.getSmallIcon() != null) {
3910                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3911                         mListeners.notifyPostedLocked(n, oldSbn);
3912                         if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
3913                             mHandler.post(new Runnable() {
3914                                 @Override
3915                                 public void run() {
3916                                     mGroupHelper.onNotificationPosted(
3917                                             n, hasAutoGroupSummaryLocked(n));
3918                                 }
3919                             });
3920                         }
3921                     } else {
3922                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
3923                         if (old != null && !old.isCanceled) {
3924                             mListeners.notifyRemovedLocked(n,
3925                                     NotificationListenerService.REASON_ERROR);
3926                             mHandler.post(new Runnable() {
3927                                 @Override
3928                                 public void run() {
3929                                     mGroupHelper.onNotificationRemoved(n);
3930                                 }
3931                             });
3932                         }
3933                         // ATTENTION: in a future release we will bail out here
3934                         // so that we do not play sounds, show lights, etc. for invalid
3935                         // notifications
3936                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3937                                 + n.getPackageName());
3938                     }
3939 
3940                     buzzBeepBlinkLocked(r);
3941                 } finally {
3942                     int N = mEnqueuedNotifications.size();
3943                     for (int i = 0; i < N; i++) {
3944                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3945                         if (Objects.equals(key, enqueued.getKey())) {
3946                             mEnqueuedNotifications.remove(i);
3947                             break;
3948                         }
3949                     }
3950                 }
3951             }
3952         }
3953     }
3954 
3955     /**
3956      * Ensures that grouped notification receive their special treatment.
3957      *
3958      * <p>Cancels group children if the new notification causes a group to lose
3959      * its summary.</p>
3960      *
3961      * <p>Updates mSummaryByGroupKey.</p>
3962      */
3963     @GuardedBy("mNotificationLock")
3964     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3965             int callingUid, int callingPid) {
3966         StatusBarNotification sbn = r.sbn;
3967         Notification n = sbn.getNotification();
3968         if (n.isGroupSummary() && !sbn.isAppGroup())  {
3969             // notifications without a group shouldn't be a summary, otherwise autobundling can
3970             // lead to bugs
3971             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3972         }
3973 
3974         String group = sbn.getGroupKey();
3975         boolean isSummary = n.isGroupSummary();
3976 
3977         Notification oldN = old != null ? old.sbn.getNotification() : null;
3978         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3979         boolean oldIsSummary = old != null && oldN.isGroupSummary();
3980 
3981         if (oldIsSummary) {
3982             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3983             if (removedSummary != old) {
3984                 String removedKey =
3985                         removedSummary != null ? removedSummary.getKey() : "<null>";
3986                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3987                         ", removed=" + removedKey);
3988             }
3989         }
3990         if (isSummary) {
3991             mSummaryByGroupKey.put(group, r);
3992         }
3993 
3994         // Clear out group children of the old notification if the update
3995         // causes the group summary to go away. This happens when the old
3996         // notification was a summary and the new one isn't, or when the old
3997         // notification was a summary and its group key changed.
3998         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3999             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4000                     null);
4001         }
4002     }
4003 
4004     @VisibleForTesting
4005     @GuardedBy("mNotificationLock")
4006     void scheduleTimeoutLocked(NotificationRecord record) {
4007         if (record.getNotification().getTimeoutAfter() > 0) {
4008             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4009                     REQUEST_CODE_TIMEOUT,
4010                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
4011                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4012                                     .appendPath(record.getKey()).build())
4013                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4014                             .putExtra(EXTRA_KEY, record.getKey()),
4015                     PendingIntent.FLAG_UPDATE_CURRENT);
4016             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4017                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
4018         }
4019     }
4020 
4021     @VisibleForTesting
4022     @GuardedBy("mNotificationLock")
4023     void buzzBeepBlinkLocked(NotificationRecord record) {
4024         boolean buzz = false;
4025         boolean beep = false;
4026         boolean blink = false;
4027 
4028         final Notification notification = record.sbn.getNotification();
4029         final String key = record.getKey();
4030 
4031         // Should this notification make noise, vibe, or use the LED?
4032         final boolean aboveThreshold =
4033                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
4034 
4035         // Remember if this notification already owns the notification channels.
4036         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4037         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
4038         // These are set inside the conditional if the notification is allowed to make noise.
4039         boolean hasValidVibrate = false;
4040         boolean hasValidSound = false;
4041         boolean sentAccessibilityEvent = false;
4042         // If the notification will appear in the status bar, it should send an accessibility
4043         // event
4044         if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4045             sendAccessibilityEvent(notification, record.sbn.getPackageName());
4046             sentAccessibilityEvent = true;
4047         }
4048 
4049         if (aboveThreshold && isNotificationForCurrentUser(record)) {
4050 
4051             if (mSystemReady && mAudioManager != null) {
4052                 Uri soundUri = record.getSound();
4053                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4054                 long[] vibration = record.getVibration();
4055                 // Demote sound to vibration if vibration missing & phone in vibration mode.
4056                 if (vibration == null
4057                         && hasValidSound
4058                         && (mAudioManager.getRingerModeInternal()
4059                         == AudioManager.RINGER_MODE_VIBRATE)
4060                         && mAudioManager.getStreamVolume(
4061                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
4062                     vibration = mFallbackVibrationPattern;
4063                 }
4064                 hasValidVibrate = vibration != null;
4065 
4066                 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
4067                 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
4068                     if (!sentAccessibilityEvent) {
4069                         sendAccessibilityEvent(notification, record.sbn.getPackageName());
4070                         sentAccessibilityEvent = true;
4071                     }
4072                     if (DBG) Slog.v(TAG, "Interrupting!");
4073                     if (hasValidSound) {
4074                         mSoundNotificationKey = key;
4075                         if (mInCall) {
4076                             playInCallNotification();
4077                             beep = true;
4078                         } else {
4079                             beep = playSound(record, soundUri);
4080                         }
4081                     }
4082 
4083                     final boolean ringerModeSilent =
4084                             mAudioManager.getRingerModeInternal()
4085                                     == AudioManager.RINGER_MODE_SILENT;
4086                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4087                         mVibrateNotificationKey = key;
4088 
4089                         buzz = playVibration(record, vibration, hasValidSound);
4090                     }
4091                 }
4092             }
4093         }
4094         // If a notification is updated to remove the actively playing sound or vibrate,
4095         // cancel that feedback now
4096         if (wasBeep && !hasValidSound) {
4097             clearSoundLocked();
4098         }
4099         if (wasBuzz && !hasValidVibrate) {
4100             clearVibrateLocked();
4101         }
4102 
4103         // light
4104         // release the light
4105         boolean wasShowLights = mLights.remove(key);
4106         if (record.getLight() != null && aboveThreshold
4107                 && ((record.getSuppressedVisualEffects()
4108                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
4109             mLights.add(key);
4110             updateLightsLocked();
4111             if (mUseAttentionLight) {
4112                 mAttentionLight.pulse();
4113             }
4114             blink = true;
4115         } else if (wasShowLights) {
4116             updateLightsLocked();
4117         }
4118         if (buzz || beep || blink) {
4119             MetricsLogger.action(record.getLogMaker()
4120                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4121                     .setType(MetricsEvent.TYPE_OPEN)
4122                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4123             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
4124         }
4125     }
4126 
4127     @GuardedBy("mNotificationLock")
4128     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
4129         // Suppressed because it's a silent update
4130         final Notification notification = record.getNotification();
4131         if(record.isUpdate
4132                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4133             return true;
4134         }
4135 
4136         // muted by listener
4137         final String disableEffects = disableNotificationEffects(record);
4138         if (disableEffects != null) {
4139             ZenLog.traceDisableEffects(record, disableEffects);
4140             return true;
4141         }
4142 
4143         // suppressed due to DND
4144         if (record.isIntercepted()) {
4145             return true;
4146         }
4147 
4148         // Suppressed because another notification in its group handles alerting
4149         if (record.sbn.isGroup()) {
4150             return notification.suppressAlertingDueToGrouping();
4151         }
4152 
4153         // Suppressed for being too recently noisy
4154         final String pkg = record.sbn.getPackageName();
4155         if (mUsageStats.isAlertRateLimited(pkg)) {
4156             Slog.e(TAG, "Muting recently noisy " + record.getKey());
4157             return true;
4158         }
4159 
4160         return false;
4161     }
4162 
4163     private boolean playSound(final NotificationRecord record, Uri soundUri) {
4164         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4165         // do not play notifications if there is a user of exclusive audio focus
4166         // or the device is in vibrate mode
4167         if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
4168                 != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
4169                 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
4170             final long identity = Binder.clearCallingIdentity();
4171             try {
4172                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4173                 if (player != null) {
4174                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4175                             + " with attributes " + record.getAudioAttributes());
4176                     player.playAsync(soundUri, record.sbn.getUser(), looping,
4177                             record.getAudioAttributes());
4178                     return true;
4179                 }
4180             } catch (RemoteException e) {
4181             } finally {
4182                 Binder.restoreCallingIdentity(identity);
4183             }
4184         }
4185         return false;
4186     }
4187 
4188     private boolean playVibration(final NotificationRecord record, long[] vibration,
4189             boolean delayVibForSound) {
4190         // Escalate privileges so we can use the vibrator even if the
4191         // notifying app does not have the VIBRATE permission.
4192         long identity = Binder.clearCallingIdentity();
4193         try {
4194             final VibrationEffect effect;
4195             try {
4196                 final boolean insistent =
4197                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4198                 effect = VibrationEffect.createWaveform(
4199                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
4200             } catch (IllegalArgumentException e) {
4201                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4202                         Arrays.toString(vibration));
4203                 return false;
4204             }
4205             if (delayVibForSound) {
4206                 new Thread(() -> {
4207                     // delay the vibration by the same amount as the notification sound
4208                     final int waitMs = mAudioManager.getFocusRampTimeMs(
4209                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4210                             record.getAudioAttributes());
4211                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4212                     try {
4213                         Thread.sleep(waitMs);
4214                     } catch (InterruptedException e) { }
4215                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4216                             effect, record.getAudioAttributes());
4217                 }).start();
4218             } else {
4219                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4220                         effect, record.getAudioAttributes());
4221             }
4222             return true;
4223         } finally{
4224             Binder.restoreCallingIdentity(identity);
4225         }
4226     }
4227 
4228     private boolean isNotificationForCurrentUser(NotificationRecord record) {
4229         final int currentUser;
4230         final long token = Binder.clearCallingIdentity();
4231         try {
4232             currentUser = ActivityManager.getCurrentUser();
4233         } finally {
4234             Binder.restoreCallingIdentity(token);
4235         }
4236         return (record.getUserId() == UserHandle.USER_ALL ||
4237                 record.getUserId() == currentUser ||
4238                 mUserProfiles.isCurrentProfile(record.getUserId()));
4239     }
4240 
4241     protected void playInCallNotification() {
4242         new Thread() {
4243             @Override
4244             public void run() {
4245                 final long identity = Binder.clearCallingIdentity();
4246                 try {
4247                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4248                     if (player != null) {
4249                         player.play(new Binder(), mInCallNotificationUri,
4250                                 mInCallNotificationAudioAttributes,
4251                                 mInCallNotificationVolume, false);
4252                     }
4253                 } catch (RemoteException e) {
4254                 } finally {
4255                     Binder.restoreCallingIdentity(identity);
4256                 }
4257             }
4258         }.start();
4259     }
4260 
4261     @GuardedBy("mToastQueue")
4262     void showNextToastLocked() {
4263         ToastRecord record = mToastQueue.get(0);
4264         while (record != null) {
4265             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4266             try {
4267                 record.callback.show(record.token);
4268                 scheduleTimeoutLocked(record);
4269                 return;
4270             } catch (RemoteException e) {
4271                 Slog.w(TAG, "Object died trying to show notification " + record.callback
4272                         + " in package " + record.pkg);
4273                 // remove it from the list and let the process die
4274                 int index = mToastQueue.indexOf(record);
4275                 if (index >= 0) {
4276                     mToastQueue.remove(index);
4277                 }
4278                 keepProcessAliveIfNeededLocked(record.pid);
4279                 if (mToastQueue.size() > 0) {
4280                     record = mToastQueue.get(0);
4281                 } else {
4282                     record = null;
4283                 }
4284             }
4285         }
4286     }
4287 
4288     @GuardedBy("mToastQueue")
4289     void cancelToastLocked(int index) {
4290         ToastRecord record = mToastQueue.get(index);
4291         try {
4292             record.callback.hide();
4293         } catch (RemoteException e) {
4294             Slog.w(TAG, "Object died trying to hide notification " + record.callback
4295                     + " in package " + record.pkg);
4296             // don't worry about this, we're about to remove it from
4297             // the list anyway
4298         }
4299 
4300         ToastRecord lastToast = mToastQueue.remove(index);
4301         mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
4302 
4303         keepProcessAliveIfNeededLocked(record.pid);
4304         if (mToastQueue.size() > 0) {
4305             // Show the next one. If the callback fails, this will remove
4306             // it from the list, so don't assume that the list hasn't changed
4307             // after this point.
4308             showNextToastLocked();
4309         }
4310     }
4311 
4312     @GuardedBy("mToastQueue")
4313     private void scheduleTimeoutLocked(ToastRecord r)
4314     {
4315         mHandler.removeCallbacksAndMessages(r);
4316         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4317         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4318         mHandler.sendMessageDelayed(m, delay);
4319     }
4320 
4321     private void handleTimeout(ToastRecord record)
4322     {
4323         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4324         synchronized (mToastQueue) {
4325             int index = indexOfToastLocked(record.pkg, record.callback);
4326             if (index >= 0) {
4327                 cancelToastLocked(index);
4328             }
4329         }
4330     }
4331 
4332     @GuardedBy("mToastQueue")
4333     int indexOfToastLocked(String pkg, ITransientNotification callback)
4334     {
4335         IBinder cbak = callback.asBinder();
4336         ArrayList<ToastRecord> list = mToastQueue;
4337         int len = list.size();
4338         for (int i=0; i<len; i++) {
4339             ToastRecord r = list.get(i);
4340             if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4341                 return i;
4342             }
4343         }
4344         return -1;
4345     }
4346 
4347     @GuardedBy("mToastQueue")
4348     int indexOfToastPackageLocked(String pkg)
4349     {
4350         ArrayList<ToastRecord> list = mToastQueue;
4351         int len = list.size();
4352         for (int i=0; i<len; i++) {
4353             ToastRecord r = list.get(i);
4354             if (r.pkg.equals(pkg)) {
4355                 return i;
4356             }
4357         }
4358         return -1;
4359     }
4360 
4361     @GuardedBy("mToastQueue")
4362     void keepProcessAliveIfNeededLocked(int pid)
4363     {
4364         int toastCount = 0; // toasts from this pid
4365         ArrayList<ToastRecord> list = mToastQueue;
4366         int N = list.size();
4367         for (int i=0; i<N; i++) {
4368             ToastRecord r = list.get(i);
4369             if (r.pid == pid) {
4370                 toastCount++;
4371             }
4372         }
4373         try {
4374             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4375         } catch (RemoteException e) {
4376             // Shouldn't happen.
4377         }
4378     }
4379 
4380     private void handleRankingReconsideration(Message message) {
4381         if (!(message.obj instanceof RankingReconsideration)) return;
4382         RankingReconsideration recon = (RankingReconsideration) message.obj;
4383         recon.run();
4384         boolean changed;
4385         synchronized (mNotificationLock) {
4386             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4387             if (record == null) {
4388                 return;
4389             }
4390             int indexBefore = findNotificationRecordIndexLocked(record);
4391             boolean interceptBefore = record.isIntercepted();
4392             float contactAffinityBefore = record.getContactAffinity();
4393             int visibilityBefore = record.getPackageVisibilityOverride();
4394             recon.applyChangesLocked(record);
4395             applyZenModeLocked(record);
4396             mRankingHelper.sort(mNotificationList);
4397             int indexAfter = findNotificationRecordIndexLocked(record);
4398             boolean interceptAfter = record.isIntercepted();
4399             float contactAffinityAfter = record.getContactAffinity();
4400             int visibilityAfter = record.getPackageVisibilityOverride();
4401             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4402                     || visibilityBefore != visibilityAfter;
4403             if (interceptBefore && !interceptAfter
4404                     && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4405                 buzzBeepBlinkLocked(record);
4406             }
4407         }
4408         if (changed) {
4409             mHandler.scheduleSendRankingUpdate();
4410         }
4411     }
4412 
4413     void handleRankingSort() {
4414         if (mRankingHelper == null) return;
4415         synchronized (mNotificationLock) {
4416             final int N = mNotificationList.size();
4417             // Any field that can change via one of the extractors needs to be added here.
4418             ArrayList<String> orderBefore = new ArrayList<>(N);
4419             int[] visibilities = new int[N];
4420             boolean[] showBadges = new boolean[N];
4421             ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4422             ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4423             ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4424             ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
4425             for (int i = 0; i < N; i++) {
4426                 final NotificationRecord r = mNotificationList.get(i);
4427                 orderBefore.add(r.getKey());
4428                 visibilities[i] = r.getPackageVisibilityOverride();
4429                 showBadges[i] = r.canShowBadge();
4430                 channelBefore.add(r.getChannel());
4431                 groupKeyBefore.add(r.getGroupKey());
4432                 overridePeopleBefore.add(r.getPeopleOverride());
4433                 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
4434                 mRankingHelper.extractSignals(r);
4435             }
4436             mRankingHelper.sort(mNotificationList);
4437             for (int i = 0; i < N; i++) {
4438                 final NotificationRecord r = mNotificationList.get(i);
4439                 if (!orderBefore.get(i).equals(r.getKey())
4440                         || visibilities[i] != r.getPackageVisibilityOverride()
4441                         || showBadges[i] != r.canShowBadge()
4442                         || !Objects.equals(channelBefore.get(i), r.getChannel())
4443                         || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4444                         || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
4445                         || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
4446                     mHandler.scheduleSendRankingUpdate();
4447                     return;
4448                 }
4449             }
4450         }
4451     }
4452 
4453     @GuardedBy("mNotificationLock")
4454     private void recordCallerLocked(NotificationRecord record) {
4455         if (mZenModeHelper.isCall(record)) {
4456             mZenModeHelper.recordCaller(record);
4457         }
4458     }
4459 
4460     // let zen mode evaluate this record
4461     @GuardedBy("mNotificationLock")
4462     private void applyZenModeLocked(NotificationRecord record) {
4463         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4464         if (record.isIntercepted()) {
4465             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4466                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4467                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
4468                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4469             record.setSuppressedVisualEffects(suppressed);
4470         } else {
4471             record.setSuppressedVisualEffects(0);
4472         }
4473     }
4474 
4475     @GuardedBy("mNotificationLock")
4476     private int findNotificationRecordIndexLocked(NotificationRecord target) {
4477         return mRankingHelper.indexOf(mNotificationList, target);
4478     }
4479 
4480     private void handleSendRankingUpdate() {
4481         synchronized (mNotificationLock) {
4482             mListeners.notifyRankingUpdateLocked();
4483         }
4484     }
4485 
4486     private void scheduleListenerHintsChanged(int state) {
4487         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4488         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4489     }
4490 
4491     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4492         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4493         mHandler.obtainMessage(
4494                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4495                 listenerInterruptionFilter,
4496                 0).sendToTarget();
4497     }
4498 
4499     private void handleListenerHintsChanged(int hints) {
4500         synchronized (mNotificationLock) {
4501             mListeners.notifyListenerHintsChangedLocked(hints);
4502         }
4503     }
4504 
4505     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4506         synchronized (mNotificationLock) {
4507             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4508         }
4509     }
4510 
4511     protected class WorkerHandler extends Handler
4512     {
4513         public WorkerHandler(Looper looper) {
4514             super(looper);
4515         }
4516 
4517         @Override
4518         public void handleMessage(Message msg)
4519         {
4520             switch (msg.what)
4521             {
4522                 case MESSAGE_TIMEOUT:
4523                     handleTimeout((ToastRecord)msg.obj);
4524                     break;
4525                 case MESSAGE_SAVE_POLICY_FILE:
4526                     handleSavePolicyFile();
4527                     break;
4528                 case MESSAGE_SEND_RANKING_UPDATE:
4529                     handleSendRankingUpdate();
4530                     break;
4531                 case MESSAGE_LISTENER_HINTS_CHANGED:
4532                     handleListenerHintsChanged(msg.arg1);
4533                     break;
4534                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4535                     handleListenerInterruptionFilterChanged(msg.arg1);
4536                     break;
4537             }
4538         }
4539 
4540         protected void scheduleSendRankingUpdate() {
4541             if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4542                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4543                 sendMessage(m);
4544             }
4545         }
4546 
4547     }
4548 
4549     private final class RankingHandlerWorker extends Handler implements RankingHandler
4550     {
4551         public RankingHandlerWorker(Looper looper) {
4552             super(looper);
4553         }
4554 
4555         @Override
4556         public void handleMessage(Message msg) {
4557             switch (msg.what) {
4558                 case MESSAGE_RECONSIDER_RANKING:
4559                     handleRankingReconsideration(msg);
4560                     break;
4561                 case MESSAGE_RANKING_SORT:
4562                     handleRankingSort();
4563                     break;
4564             }
4565         }
4566 
4567         public void requestSort() {
4568             removeMessages(MESSAGE_RANKING_SORT);
4569             Message msg = Message.obtain();
4570             msg.what = MESSAGE_RANKING_SORT;
4571             sendMessage(msg);
4572         }
4573 
4574         public void requestReconsideration(RankingReconsideration recon) {
4575             Message m = Message.obtain(this,
4576                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4577             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4578             sendMessageDelayed(m, delay);
4579         }
4580     }
4581 
4582     // Notifications
4583     // ============================================================================
4584     static int clamp(int x, int low, int high) {
4585         return (x < low) ? low : ((x > high) ? high : x);
4586     }
4587 
4588     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4589         if (!mAccessibilityManager.isEnabled()) {
4590             return;
4591         }
4592 
4593         AccessibilityEvent event =
4594             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4595         event.setPackageName(packageName);
4596         event.setClassName(Notification.class.getName());
4597         event.setParcelableData(notification);
4598         CharSequence tickerText = notification.tickerText;
4599         if (!TextUtils.isEmpty(tickerText)) {
4600             event.getText().add(tickerText);
4601         }
4602 
4603         mAccessibilityManager.sendAccessibilityEvent(event);
4604     }
4605 
4606     /**
4607      * Removes all NotificationsRecords with the same key as the given notification record
4608      * from both lists. Do not call this method while iterating over either list.
4609      */
4610     @GuardedBy("mNotificationLock")
4611     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4612         // Remove from both lists, either list could have a separate Record for what is
4613         // effectively the same notification.
4614         boolean wasPosted = false;
4615         NotificationRecord recordInList = null;
4616         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4617                 != null) {
4618             mNotificationList.remove(recordInList);
4619             mNotificationsByKey.remove(recordInList.sbn.getKey());
4620             wasPosted = true;
4621         }
4622         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4623                 != null) {
4624             mEnqueuedNotifications.remove(recordInList);
4625         }
4626         return wasPosted;
4627     }
4628 
4629     @GuardedBy("mNotificationLock")
4630     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4631             boolean wasPosted, String listenerName) {
4632         final String canceledKey = r.getKey();
4633 
4634         // Record caller.
4635         recordCallerLocked(r);
4636 
4637         // tell the app
4638         if (sendDelete) {
4639             if (r.getNotification().deleteIntent != null) {
4640                 try {
4641                     r.getNotification().deleteIntent.send();
4642                 } catch (PendingIntent.CanceledException ex) {
4643                     // do nothing - there's no relevant way to recover, and
4644                     //     no reason to let this propagate
4645                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4646                 }
4647             }
4648         }
4649 
4650         // Only cancel these if this notification actually got to be posted.
4651         if (wasPosted) {
4652             // status bar
4653             if (r.getNotification().getSmallIcon() != null) {
4654                 if (reason != REASON_SNOOZED) {
4655                     r.isCanceled = true;
4656                 }
4657                 mListeners.notifyRemovedLocked(r.sbn, reason);
4658                 mHandler.post(new Runnable() {
4659                     @Override
4660                     public void run() {
4661                         mGroupHelper.onNotificationRemoved(r.sbn);
4662                     }
4663                 });
4664             }
4665 
4666             // sound
4667             if (canceledKey.equals(mSoundNotificationKey)) {
4668                 mSoundNotificationKey = null;
4669                 final long identity = Binder.clearCallingIdentity();
4670                 try {
4671                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4672                     if (player != null) {
4673                         player.stopAsync();
4674                     }
4675                 } catch (RemoteException e) {
4676                 } finally {
4677                     Binder.restoreCallingIdentity(identity);
4678                 }
4679             }
4680 
4681             // vibrate
4682             if (canceledKey.equals(mVibrateNotificationKey)) {
4683                 mVibrateNotificationKey = null;
4684                 long identity = Binder.clearCallingIdentity();
4685                 try {
4686                     mVibrator.cancel();
4687                 }
4688                 finally {
4689                     Binder.restoreCallingIdentity(identity);
4690                 }
4691             }
4692 
4693             // light
4694             mLights.remove(canceledKey);
4695         }
4696 
4697         // Record usage stats
4698         // TODO: add unbundling stats?
4699         switch (reason) {
4700             case REASON_CANCEL:
4701             case REASON_CANCEL_ALL:
4702             case REASON_LISTENER_CANCEL:
4703             case REASON_LISTENER_CANCEL_ALL:
4704                 mUsageStats.registerDismissedByUser(r);
4705                 break;
4706             case REASON_APP_CANCEL:
4707             case REASON_APP_CANCEL_ALL:
4708                 mUsageStats.registerRemovedByApp(r);
4709                 break;
4710         }
4711 
4712         String groupKey = r.getGroupKey();
4713         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4714         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4715             mSummaryByGroupKey.remove(groupKey);
4716         }
4717         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4718         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4719             summaries.remove(r.sbn.getPackageName());
4720         }
4721 
4722         // Save it for users of getHistoricalNotifications()
4723         mArchive.record(r.sbn);
4724 
4725         final long now = System.currentTimeMillis();
4726         MetricsLogger.action(r.getLogMaker(now)
4727                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4728                 .setType(MetricsEvent.TYPE_DISMISS)
4729                 .setSubtype(reason));
4730         EventLogTags.writeNotificationCanceled(canceledKey, reason,
4731                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
4732     }
4733 
4734     /**
4735      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4736      * and none of the {@code mustNotHaveFlags}.
4737      */
4738     void cancelNotification(final int callingUid, final int callingPid,
4739             final String pkg, final String tag, final int id,
4740             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4741             final int userId, final int reason, final ManagedServiceInfo listener) {
4742         // In enqueueNotificationInternal notifications are added by scheduling the
4743         // work on the worker handler. Hence, we also schedule the cancel on this
4744         // handler to avoid a scenario where an add notification call followed by a
4745         // remove notification call ends up in not removing the notification.
4746         mHandler.post(new Runnable() {
4747             @Override
4748             public void run() {
4749                 String listenerName = listener == null ? null : listener.component.toShortString();
4750                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4751                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4752 
4753                 synchronized (mNotificationLock) {
4754                     // If the notification is currently enqueued, repost this runnable so it has a
4755                     // chance to notify listeners
4756                     if ((findNotificationByListLocked(
4757                             mEnqueuedNotifications, pkg, tag, id, userId)) != null) {
4758                         mHandler.post(this);
4759                     }
4760                     // Look for the notification in the posted list, since we already checked enq
4761                     NotificationRecord r = findNotificationByListLocked(
4762                             mNotificationList, pkg, tag, id, userId);
4763                     if (r != null) {
4764                         // The notification was found, check if it should be removed.
4765 
4766                         // Ideally we'd do this in the caller of this method. However, that would
4767                         // require the caller to also find the notification.
4768                         if (reason == REASON_CLICK) {
4769                             mUsageStats.registerClickedByUser(r);
4770                         }
4771 
4772                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4773                             return;
4774                         }
4775                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4776                             return;
4777                         }
4778 
4779                         // Cancel the notification.
4780                         boolean wasPosted = removeFromNotificationListsLocked(r);
4781                         cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4782                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4783                                 sendDelete, null);
4784                         updateLightsLocked();
4785                     } else {
4786                         // No notification was found, assume that it is snoozed and cancel it.
4787                         if (reason != REASON_SNOOZED) {
4788                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4789                             if (wasSnoozed) {
4790                                 savePolicyFile();
4791                             }
4792                         }
4793                     }
4794                 }
4795             }
4796         });
4797     }
4798 
4799     /**
4800      * Determine whether the userId applies to the notification in question, either because
4801      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4802      */
4803     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4804         return
4805                 // looking for USER_ALL notifications? match everything
4806                    userId == UserHandle.USER_ALL
4807                 // a notification sent to USER_ALL matches any query
4808                 || r.getUserId() == UserHandle.USER_ALL
4809                 // an exact user match
4810                 || r.getUserId() == userId;
4811     }
4812 
4813     /**
4814      * Determine whether the userId applies to the notification in question, either because
4815      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4816      * because it matches one of the users profiles.
4817      */
4818     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4819         return notificationMatchesUserId(r, userId)
4820                 || mUserProfiles.isCurrentProfile(r.getUserId());
4821     }
4822 
4823     /**
4824      * Cancels all notifications from a given package that have all of the
4825      * {@code mustHaveFlags}.
4826      */
4827     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4828             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4829             ManagedServiceInfo listener) {
4830         mHandler.post(new Runnable() {
4831             @Override
4832             public void run() {
4833                 String listenerName = listener == null ? null : listener.component.toShortString();
4834                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4835                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4836                         listenerName);
4837 
4838                 // Why does this parameter exist? Do we actually want to execute the above if doit
4839                 // is false?
4840                 if (!doit) {
4841                     return;
4842                 }
4843 
4844                 synchronized (mNotificationLock) {
4845                     FlagChecker flagChecker = (int flags) -> {
4846                         if ((flags & mustHaveFlags) != mustHaveFlags) {
4847                             return false;
4848                         }
4849                         if ((flags & mustNotHaveFlags) != 0) {
4850                             return false;
4851                         }
4852                         return true;
4853                     };
4854                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4855                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4856                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4857                             listenerName, true /* wasPosted */);
4858                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4859                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4860                             flagChecker, false /*includeCurrentProfiles*/, userId,
4861                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4862                     mSnoozeHelper.cancel(userId, pkg);
4863                 }
4864             }
4865         });
4866     }
4867 
4868     private interface FlagChecker {
4869         // Returns false if these flags do not pass the defined flag test.
4870         public boolean apply(int flags);
4871     }
4872 
4873     @GuardedBy("mNotificationLock")
4874     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4875             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4876             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4877             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4878         ArrayList<NotificationRecord> canceledNotifications = null;
4879         for (int i = notificationList.size() - 1; i >= 0; --i) {
4880             NotificationRecord r = notificationList.get(i);
4881             if (includeCurrentProfiles) {
4882                 if (!notificationMatchesCurrentProfiles(r, userId)) {
4883                     continue;
4884                 }
4885             } else if (!notificationMatchesUserId(r, userId)) {
4886                 continue;
4887             }
4888             // Don't remove notifications to all, if there's no package name specified
4889             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4890                 continue;
4891             }
4892             if (!flagChecker.apply(r.getFlags())) {
4893                 continue;
4894             }
4895             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4896                 continue;
4897             }
4898             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4899                 continue;
4900             }
4901             if (canceledNotifications == null) {
4902                 canceledNotifications = new ArrayList<>();
4903             }
4904             notificationList.remove(i);
4905             mNotificationsByKey.remove(r.getKey());
4906             canceledNotifications.add(r);
4907             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4908         }
4909         if (canceledNotifications != null) {
4910             final int M = canceledNotifications.size();
4911             for (int i = 0; i < M; i++) {
4912                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4913                         listenerName, false /* sendDelete */, flagChecker);
4914             }
4915             updateLightsLocked();
4916         }
4917     }
4918 
4919     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4920             ManagedServiceInfo listener) {
4921         String listenerName = listener == null ? null : listener.component.toShortString();
4922         if (duration <= 0 && snoozeCriterionId == null || key == null) {
4923             return;
4924         }
4925 
4926         if (DBG) {
4927             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4928                     snoozeCriterionId, listenerName));
4929         }
4930         // Needs to post so that it can cancel notifications not yet enqueued.
4931         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4932     }
4933 
4934     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4935         String listenerName = listener == null ? null : listener.component.toShortString();
4936         if (DBG) {
4937             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4938         }
4939         mSnoozeHelper.repost(key);
4940         savePolicyFile();
4941     }
4942 
4943     @GuardedBy("mNotificationLock")
4944     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4945             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4946         mHandler.post(new Runnable() {
4947             @Override
4948             public void run() {
4949                 synchronized (mNotificationLock) {
4950                     String listenerName =
4951                             listener == null ? null : listener.component.toShortString();
4952                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4953                             null, userId, 0, 0, reason, listenerName);
4954 
4955                     FlagChecker flagChecker = (int flags) -> {
4956                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4957                                 != 0) {
4958                             return false;
4959                         }
4960                         return true;
4961                     };
4962 
4963                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4964                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4965                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4966                             listenerName, true);
4967                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4968                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4969                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4970                             reason, listenerName, false);
4971                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4972                 }
4973             }
4974         });
4975     }
4976 
4977     // Warning: The caller is responsible for invoking updateLightsLocked().
4978     @GuardedBy("mNotificationLock")
4979     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4980             String listenerName, boolean sendDelete, FlagChecker flagChecker) {
4981         Notification n = r.getNotification();
4982         if (!n.isGroupSummary()) {
4983             return;
4984         }
4985 
4986         String pkg = r.sbn.getPackageName();
4987 
4988         if (pkg == null) {
4989             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4990             return;
4991         }
4992 
4993         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4994                 sendDelete, true, flagChecker);
4995         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4996                 listenerName, sendDelete, false, flagChecker);
4997     }
4998 
4999     @GuardedBy("mNotificationLock")
5000     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5001             NotificationRecord parentNotification, int callingUid, int callingPid,
5002             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
5003         final String pkg = parentNotification.sbn.getPackageName();
5004         final int userId = parentNotification.getUserId();
5005         final int reason = REASON_GROUP_SUMMARY_CANCELED;
5006         for (int i = notificationList.size() - 1; i >= 0; i--) {
5007             final NotificationRecord childR = notificationList.get(i);
5008             final StatusBarNotification childSbn = childR.sbn;
5009             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
5010                     childR.getGroupKey().equals(parentNotification.getGroupKey())
5011                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5012                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
5013                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5014                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
5015                 notificationList.remove(i);
5016                 mNotificationsByKey.remove(childR.getKey());
5017                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5018             }
5019         }
5020     }
5021 
5022     @GuardedBy("mNotificationLock")
5023     void updateLightsLocked()
5024     {
5025         // handle notification lights
5026         NotificationRecord ledNotification = null;
5027         while (ledNotification == null && !mLights.isEmpty()) {
5028             final String owner = mLights.get(mLights.size() - 1);
5029             ledNotification = mNotificationsByKey.get(owner);
5030             if (ledNotification == null) {
5031                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5032                 mLights.remove(owner);
5033             }
5034         }
5035 
5036         // Don't flash while we are in a call or screen is on
5037         if (ledNotification == null || mInCall || mScreenOn) {
5038             mNotificationLight.turnOff();
5039         } else {
5040             NotificationRecord.Light light = ledNotification.getLight();
5041             if (light != null && mNotificationPulseEnabled) {
5042                 // pulse repeatedly
5043                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5044                         light.onMs, light.offMs);
5045             }
5046         }
5047     }
5048 
5049     @GuardedBy("mNotificationLock")
5050     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5051             String groupKey, int userId) {
5052         List<NotificationRecord> records = new ArrayList<>();
5053         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5054         records.addAll(
5055                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5056         return records;
5057     }
5058 
5059 
5060     @GuardedBy("mNotificationLock")
5061     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5062             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5063         List<NotificationRecord> records = new ArrayList<>();
5064         final int len = list.size();
5065         for (int i = 0; i < len; i++) {
5066             NotificationRecord r = list.get(i);
5067             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5068                     && r.sbn.getPackageName().equals(pkg)) {
5069                 records.add(r);
5070             }
5071         }
5072         return records;
5073     }
5074 
5075     // Searches both enqueued and posted notifications by key.
5076     // TODO: need to combine a bunch of these getters with slightly different behavior.
5077     // TODO: Should enqueuing just add to mNotificationsByKey instead?
5078     @GuardedBy("mNotificationLock")
5079     private NotificationRecord findNotificationByKeyLocked(String key) {
5080         NotificationRecord r;
5081         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5082             return r;
5083         }
5084         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5085             return r;
5086         }
5087         return null;
5088     }
5089 
5090     @GuardedBy("mNotificationLock")
5091     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5092         NotificationRecord r;
5093         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5094             return r;
5095         }
5096         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5097                 != null) {
5098             return r;
5099         }
5100         return null;
5101     }
5102 
5103     @GuardedBy("mNotificationLock")
5104     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5105             String pkg, String tag, int id, int userId) {
5106         final int len = list.size();
5107         for (int i = 0; i < len; i++) {
5108             NotificationRecord r = list.get(i);
5109             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5110                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5111                 return r;
5112             }
5113         }
5114         return null;
5115     }
5116 
5117     @GuardedBy("mNotificationLock")
5118     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5119             String key) {
5120         final int N = list.size();
5121         for (int i = 0; i < N; i++) {
5122             if (key.equals(list.get(i).getKey())) {
5123                 return list.get(i);
5124             }
5125         }
5126         return null;
5127     }
5128 
5129     @GuardedBy("mNotificationLock")
5130     int indexOfNotificationLocked(String key) {
5131         final int N = mNotificationList.size();
5132         for (int i = 0; i < N; i++) {
5133             if (key.equals(mNotificationList.get(i).getKey())) {
5134                 return i;
5135             }
5136         }
5137         return -1;
5138     }
5139 
5140     private void updateNotificationPulse() {
5141         synchronized (mNotificationLock) {
5142             updateLightsLocked();
5143         }
5144     }
5145 
5146     protected boolean isCallingUidSystem() {
5147         final int uid = Binder.getCallingUid();
5148         return uid == Process.SYSTEM_UID;
5149     }
5150 
5151     protected boolean isUidSystemOrPhone(int uid) {
5152         final int appid = UserHandle.getAppId(uid);
5153         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5154     }
5155 
5156     // TODO: Most calls should probably move to isCallerSystem.
5157     protected boolean isCallerSystemOrPhone() {
5158         return isUidSystemOrPhone(Binder.getCallingUid());
5159     }
5160 
5161     private void checkCallerIsSystemOrShell() {
5162         if (Binder.getCallingUid() == Process.SHELL_UID) {
5163             return;
5164         }
5165         checkCallerIsSystem();
5166     }
5167 
5168     private void checkCallerIsSystem() {
5169         if (isCallerSystemOrPhone()) {
5170             return;
5171         }
5172         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5173     }
5174 
5175     private void checkCallerIsSystemOrSameApp(String pkg) {
5176         if (isCallerSystemOrPhone()) {
5177             return;
5178         }
5179         checkCallerIsSameApp(pkg);
5180     }
5181 
5182     private boolean isCallerInstantApp(String pkg) {
5183         // System is always allowed to act for ephemeral apps.
5184         if (isCallerSystemOrPhone()) {
5185             return false;
5186         }
5187 
5188         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5189 
5190         try {
5191             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5192                     UserHandle.getCallingUserId());
5193             if (ai == null) {
5194                 throw new SecurityException("Unknown package " + pkg);
5195             }
5196             return ai.isInstantApp();
5197         } catch (RemoteException re) {
5198             throw new SecurityException("Unknown package " + pkg, re);
5199         }
5200 
5201     }
5202 
5203     private void checkCallerIsSameApp(String pkg) {
5204         final int uid = Binder.getCallingUid();
5205         try {
5206             ApplicationInfo ai = mPackageManager.getApplicationInfo(
5207                     pkg, 0, UserHandle.getCallingUserId());
5208             if (ai == null) {
5209                 throw new SecurityException("Unknown package " + pkg);
5210             }
5211             if (!UserHandle.isSameApp(ai.uid, uid)) {
5212                 throw new SecurityException("Calling uid " + uid + " gave package "
5213                         + pkg + " which is owned by uid " + ai.uid);
5214             }
5215         } catch (RemoteException re) {
5216             throw new SecurityException("Unknown package " + pkg + "\n" + re);
5217         }
5218     }
5219 
5220     private static String callStateToString(int state) {
5221         switch (state) {
5222             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5223             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5224             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5225             default: return "CALL_STATE_UNKNOWN_" + state;
5226         }
5227     }
5228 
5229     private void listenForCallState() {
5230         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5231             @Override
5232             public void onCallStateChanged(int state, String incomingNumber) {
5233                 if (mCallState == state) return;
5234                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5235                 mCallState = state;
5236             }
5237         }, PhoneStateListener.LISTEN_CALL_STATE);
5238     }
5239 
5240     /**
5241      * Generates a NotificationRankingUpdate from 'sbns', considering only
5242      * notifications visible to the given listener.
5243      */
5244     @GuardedBy("mNotificationLock")
5245     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5246         final int N = mNotificationList.size();
5247         ArrayList<String> keys = new ArrayList<String>(N);
5248         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5249         ArrayList<Integer> importance = new ArrayList<>(N);
5250         Bundle overrideGroupKeys = new Bundle();
5251         Bundle visibilityOverrides = new Bundle();
5252         Bundle suppressedVisualEffects = new Bundle();
5253         Bundle explanation = new Bundle();
5254         Bundle channels = new Bundle();
5255         Bundle overridePeople = new Bundle();
5256         Bundle snoozeCriteria = new Bundle();
5257         Bundle showBadge = new Bundle();
5258         for (int i = 0; i < N; i++) {
5259             NotificationRecord record = mNotificationList.get(i);
5260             if (!isVisibleToListener(record.sbn, info)) {
5261                 continue;
5262             }
5263             final String key = record.sbn.getKey();
5264             keys.add(key);
5265             importance.add(record.getImportance());
5266             if (record.getImportanceExplanation() != null) {
5267                 explanation.putCharSequence(key, record.getImportanceExplanation());
5268             }
5269             if (record.isIntercepted()) {
5270                 interceptedKeys.add(key);
5271 
5272             }
5273             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5274             if (record.getPackageVisibilityOverride()
5275                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5276                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5277             }
5278             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5279             channels.putParcelable(key, record.getChannel());
5280             overridePeople.putStringArrayList(key, record.getPeopleOverride());
5281             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5282             showBadge.putBoolean(key, record.canShowBadge());
5283         }
5284         final int M = keys.size();
5285         String[] keysAr = keys.toArray(new String[M]);
5286         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5287         int[] importanceAr = new int[M];
5288         for (int i = 0; i < M; i++) {
5289             importanceAr[i] = importance.get(i);
5290         }
5291         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5292                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5293                 channels, overridePeople, snoozeCriteria, showBadge);
5294     }
5295 
5296     boolean hasCompanionDevice(ManagedServiceInfo info) {
5297         if (mCompanionManager == null) {
5298             mCompanionManager = getCompanionManager();
5299         }
5300         // Companion mgr doesn't exist on all device types
5301         if (mCompanionManager == null) {
5302             return false;
5303         }
5304         long identity = Binder.clearCallingIdentity();
5305         try {
5306             List<String> associations = mCompanionManager.getAssociations(
5307                     info.component.getPackageName(), info.userid);
5308             if (!ArrayUtils.isEmpty(associations)) {
5309                 return true;
5310             }
5311         } catch (SecurityException se) {
5312             // Not a privileged listener
5313         } catch (RemoteException re) {
5314             Slog.e(TAG, "Cannot reach companion device service", re);
5315         } catch (Exception e) {
5316             Slog.e(TAG, "Cannot verify listener " + info, e);
5317         } finally {
5318             Binder.restoreCallingIdentity(identity);
5319         }
5320         return false;
5321     }
5322 
5323     protected ICompanionDeviceManager getCompanionManager() {
5324         return ICompanionDeviceManager.Stub.asInterface(
5325                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5326     }
5327 
5328     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5329         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5330             return false;
5331         }
5332         // TODO: remove this for older listeners.
5333         return true;
5334     }
5335 
5336     private boolean isPackageSuspendedForUser(String pkg, int uid) {
5337         int userId = UserHandle.getUserId(uid);
5338         try {
5339             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5340         } catch (RemoteException re) {
5341             throw new SecurityException("Could not talk to package manager service");
5342         } catch (IllegalArgumentException ex) {
5343             // Package not found.
5344             return false;
5345         }
5346     }
5347 
5348     private class TrimCache {
5349         StatusBarNotification heavy;
5350         StatusBarNotification sbnClone;
5351         StatusBarNotification sbnCloneLight;
5352 
5353         TrimCache(StatusBarNotification sbn) {
5354             heavy = sbn;
5355         }
5356 
5357         StatusBarNotification ForListener(ManagedServiceInfo info) {
5358             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5359                 if (sbnCloneLight == null) {
5360                     sbnCloneLight = heavy.cloneLight();
5361                 }
5362                 return sbnCloneLight;
5363             } else {
5364                 if (sbnClone == null) {
5365                     sbnClone = heavy.clone();
5366                 }
5367                 return sbnClone;
5368             }
5369         }
5370     }
5371 
5372     public class NotificationAssistants extends ManagedServices {
5373         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
5374 
5375         public NotificationAssistants(IPackageManager pm) {
5376             super(getContext(), mNotificationLock, mUserProfiles, pm);
5377         }
5378 
5379         @Override
5380         protected Config getConfig() {
5381             Config c = new Config();
5382             c.caption = "notification assistant service";
5383             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5384             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
5385             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5386             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5387             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5388             c.clientLabel = R.string.notification_ranker_binding_label;
5389             return c;
5390         }
5391 
5392         @Override
5393         protected IInterface asInterface(IBinder binder) {
5394             return INotificationListener.Stub.asInterface(binder);
5395         }
5396 
5397         @Override
5398         protected boolean checkType(IInterface service) {
5399             return service instanceof INotificationListener;
5400         }
5401 
5402         @Override
5403         protected void onServiceAdded(ManagedServiceInfo info) {
5404             mListeners.registerGuestService(info);
5405         }
5406 
5407         @Override
5408         @GuardedBy("mNotificationLock")
5409         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5410             mListeners.unregisterService(removed.service, removed.userid);
5411         }
5412 
5413         public void onNotificationEnqueued(final NotificationRecord r) {
5414             final StatusBarNotification sbn = r.sbn;
5415             TrimCache trimCache = new TrimCache(sbn);
5416 
5417             // There should be only one, but it's a list, so while we enforce
5418             // singularity elsewhere, we keep it general here, to avoid surprises.
5419             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5420                 boolean sbnVisible = isVisibleToListener(sbn, info);
5421                 if (!sbnVisible) {
5422                     continue;
5423                 }
5424 
5425                 final int importance = r.getImportance();
5426                 final boolean fromUser = r.isImportanceFromUser();
5427                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5428                 mHandler.post(new Runnable() {
5429                     @Override
5430                     public void run() {
5431                         notifyEnqueued(info, sbnToPost);
5432                     }
5433                 });
5434             }
5435         }
5436 
5437         private void notifyEnqueued(final ManagedServiceInfo info,
5438                 final StatusBarNotification sbn) {
5439             final INotificationListener assistant = (INotificationListener) info.service;
5440             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5441             try {
5442                 assistant.onNotificationEnqueued(sbnHolder);
5443             } catch (RemoteException ex) {
5444                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5445             }
5446         }
5447 
5448         /**
5449          * asynchronously notify the assistant that a notification has been snoozed until a
5450          * context
5451          */
5452         @GuardedBy("mNotificationLock")
5453         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5454                 final String snoozeCriterionId) {
5455             TrimCache trimCache = new TrimCache(sbn);
5456             for (final ManagedServiceInfo info : getServices()) {
5457                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5458                 mHandler.post(new Runnable() {
5459                     @Override
5460                     public void run() {
5461                         final INotificationListener assistant =
5462                                 (INotificationListener) info.service;
5463                         StatusBarNotificationHolder sbnHolder
5464                                 = new StatusBarNotificationHolder(sbnToPost);
5465                         try {
5466                             assistant.onNotificationSnoozedUntilContext(
5467                                     sbnHolder, snoozeCriterionId);
5468                         } catch (RemoteException ex) {
5469                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5470                         }
5471                     }
5472                 });
5473             }
5474         }
5475 
5476         public boolean isEnabled() {
5477             return !getServices().isEmpty();
5478         }
5479     }
5480 
5481     public class NotificationListeners extends ManagedServices {
5482         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
5483 
5484         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5485 
5486         public NotificationListeners(IPackageManager pm) {
5487             super(getContext(), mNotificationLock, mUserProfiles, pm);
5488 
5489         }
5490 
5491         @Override
5492         protected Config getConfig() {
5493             Config c = new Config();
5494             c.caption = "notification listener";
5495             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5496             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
5497             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5498             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5499             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5500             c.clientLabel = R.string.notification_listener_binding_label;
5501             return c;
5502         }
5503 
5504         @Override
5505         protected IInterface asInterface(IBinder binder) {
5506             return INotificationListener.Stub.asInterface(binder);
5507         }
5508 
5509         @Override
5510         protected boolean checkType(IInterface service) {
5511             return service instanceof INotificationListener;
5512         }
5513 
5514         @Override
5515         public void onServiceAdded(ManagedServiceInfo info) {
5516             final INotificationListener listener = (INotificationListener) info.service;
5517             final NotificationRankingUpdate update;
5518             synchronized (mNotificationLock) {
5519                 update = makeRankingUpdateLocked(info);
5520             }
5521             try {
5522                 listener.onListenerConnected(update);
5523             } catch (RemoteException e) {
5524                 // we tried
5525             }
5526         }
5527 
5528         @Override
5529         @GuardedBy("mNotificationLock")
5530         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5531             if (removeDisabledHints(removed)) {
5532                 updateListenerHintsLocked();
5533                 updateEffectsSuppressorLocked();
5534             }
5535             mLightTrimListeners.remove(removed);
5536         }
5537 
5538         @GuardedBy("mNotificationLock")
5539         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5540             if (trim == TRIM_LIGHT) {
5541                 mLightTrimListeners.add(info);
5542             } else {
5543                 mLightTrimListeners.remove(info);
5544             }
5545         }
5546 
5547         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5548             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5549         }
5550 
5551         /**
5552          * asynchronously notify all listeners about a new notification
5553          *
5554          * <p>
5555          * Also takes care of removing a notification that has been visible to a listener before,
5556          * but isn't anymore.
5557          */
5558         @GuardedBy("mNotificationLock")
5559         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5560             // Lazily initialized snapshots of the notification.
5561             TrimCache trimCache = new TrimCache(sbn);
5562 
5563             for (final ManagedServiceInfo info : getServices()) {
5564                 boolean sbnVisible = isVisibleToListener(sbn, info);
5565                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5566                 // This notification hasn't been and still isn't visible -> ignore.
5567                 if (!oldSbnVisible && !sbnVisible) {
5568                     continue;
5569                 }
5570                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5571 
5572                 // This notification became invisible -> remove the old one.
5573                 if (oldSbnVisible && !sbnVisible) {
5574                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5575                     mHandler.post(new Runnable() {
5576                         @Override
5577                         public void run() {
5578                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5579                         }
5580                     });
5581                     continue;
5582                 }
5583 
5584                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5585                 mHandler.post(new Runnable() {
5586                     @Override
5587                     public void run() {
5588                         notifyPosted(info, sbnToPost, update);
5589                     }
5590                 });
5591             }
5592         }
5593 
5594         /**
5595          * asynchronously notify all listeners about a removed notification
5596          */
5597         @GuardedBy("mNotificationLock")
5598         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5599             // make a copy in case changes are made to the underlying Notification object
5600             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5601             // notification
5602             final StatusBarNotification sbnLight = sbn.cloneLight();
5603             for (final ManagedServiceInfo info : getServices()) {
5604                 if (!isVisibleToListener(sbn, info)) {
5605                     continue;
5606                 }
5607                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5608                 mHandler.post(new Runnable() {
5609                     @Override
5610                     public void run() {
5611                         notifyRemoved(info, sbnLight, update, reason);
5612                     }
5613                 });
5614             }
5615         }
5616 
5617         /**
5618          * asynchronously notify all listeners about a reordering of notifications
5619          */
5620         @GuardedBy("mNotificationLock")
5621         public void notifyRankingUpdateLocked() {
5622             for (final ManagedServiceInfo serviceInfo : getServices()) {
5623                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5624                     continue;
5625                 }
5626                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5627                 mHandler.post(new Runnable() {
5628                     @Override
5629                     public void run() {
5630                         notifyRankingUpdate(serviceInfo, update);
5631                     }
5632                 });
5633             }
5634         }
5635 
5636         @GuardedBy("mNotificationLock")
5637         public void notifyListenerHintsChangedLocked(final int hints) {
5638             for (final ManagedServiceInfo serviceInfo : getServices()) {
5639                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5640                     continue;
5641                 }
5642                 mHandler.post(new Runnable() {
5643                     @Override
5644                     public void run() {
5645                         notifyListenerHintsChanged(serviceInfo, hints);
5646                     }
5647                 });
5648             }
5649         }
5650 
5651         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5652             for (final ManagedServiceInfo serviceInfo : getServices()) {
5653                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5654                     continue;
5655                 }
5656                 mHandler.post(new Runnable() {
5657                     @Override
5658                     public void run() {
5659                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5660                     }
5661                 });
5662             }
5663         }
5664 
5665         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5666                 final NotificationChannel channel, final int modificationType) {
5667             if (channel == null) {
5668                 return;
5669             }
5670             for (final ManagedServiceInfo serviceInfo : getServices()) {
5671                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5672                     continue;
5673                 }
5674 
5675                 BackgroundThread.getHandler().post(() -> {
5676                     if (hasCompanionDevice(serviceInfo)) {
5677                         notifyNotificationChannelChanged(
5678                                 serviceInfo, pkg, user, channel, modificationType);
5679                     }
5680                 });
5681             }
5682         }
5683 
5684         protected void notifyNotificationChannelGroupChanged(
5685                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5686                 final int modificationType) {
5687             if (group == null) {
5688                 return;
5689             }
5690             for (final ManagedServiceInfo serviceInfo : getServices()) {
5691                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5692                     continue;
5693                 }
5694 
5695                 BackgroundThread.getHandler().post(() -> {
5696                     if (hasCompanionDevice(serviceInfo)) {
5697                         notifyNotificationChannelGroupChanged(
5698                                 serviceInfo, pkg, user, group, modificationType);
5699                     }
5700                 });
5701             }
5702         }
5703 
5704         private void notifyPosted(final ManagedServiceInfo info,
5705                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5706             final INotificationListener listener = (INotificationListener) info.service;
5707             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5708             try {
5709                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5710             } catch (RemoteException ex) {
5711                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5712             }
5713         }
5714 
5715         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5716                 NotificationRankingUpdate rankingUpdate, int reason) {
5717             if (!info.enabledAndUserMatches(sbn.getUserId())) {
5718                 return;
5719             }
5720             final INotificationListener listener = (INotificationListener) info.service;
5721             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5722             try {
5723                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5724             } catch (RemoteException ex) {
5725                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5726             }
5727         }
5728 
5729         private void notifyRankingUpdate(ManagedServiceInfo info,
5730                                          NotificationRankingUpdate rankingUpdate) {
5731             final INotificationListener listener = (INotificationListener) info.service;
5732             try {
5733                 listener.onNotificationRankingUpdate(rankingUpdate);
5734             } catch (RemoteException ex) {
5735                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5736             }
5737         }
5738 
5739         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5740             final INotificationListener listener = (INotificationListener) info.service;
5741             try {
5742                 listener.onListenerHintsChanged(hints);
5743             } catch (RemoteException ex) {
5744                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5745             }
5746         }
5747 
5748         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5749                 int interruptionFilter) {
5750             final INotificationListener listener = (INotificationListener) info.service;
5751             try {
5752                 listener.onInterruptionFilterChanged(interruptionFilter);
5753             } catch (RemoteException ex) {
5754                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5755             }
5756         }
5757 
5758         void notifyNotificationChannelChanged(ManagedServiceInfo info,
5759                 final String pkg, final UserHandle user, final NotificationChannel channel,
5760                 final int modificationType) {
5761             final INotificationListener listener = (INotificationListener) info.service;
5762             try {
5763                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5764             } catch (RemoteException ex) {
5765                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5766             }
5767         }
5768 
5769         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5770                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5771                 final int modificationType) {
5772             final INotificationListener listener = (INotificationListener) info.service;
5773             try {
5774                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5775             } catch (RemoteException ex) {
5776                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5777             }
5778         }
5779 
5780         public boolean isListenerPackage(String packageName) {
5781             if (packageName == null) {
5782                 return false;
5783             }
5784             // TODO: clean up locking object later
5785             synchronized (mNotificationLock) {
5786                 for (final ManagedServiceInfo serviceInfo : getServices()) {
5787                     if (packageName.equals(serviceInfo.component.getPackageName())) {
5788                         return true;
5789                     }
5790                 }
5791             }
5792             return false;
5793         }
5794     }
5795 
5796     public static final class DumpFilter {
5797         public boolean filtered = false;
5798         public String pkgFilter;
5799         public boolean zen;
5800         public long since;
5801         public boolean stats;
5802         public boolean redact = true;
5803         public boolean proto = false;
5804 
5805         public static DumpFilter parseFromArguments(String[] args) {
5806             final DumpFilter filter = new DumpFilter();
5807             for (int ai = 0; ai < args.length; ai++) {
5808                 final String a = args[ai];
5809                 if ("--proto".equals(args[0])) {
5810                     filter.proto = true;
5811                 }
5812                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5813                     filter.redact = false;
5814                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5815                     if (ai < args.length-1) {
5816                         ai++;
5817                         filter.pkgFilter = args[ai].trim().toLowerCase();
5818                         if (filter.pkgFilter.isEmpty()) {
5819                             filter.pkgFilter = null;
5820                         } else {
5821                             filter.filtered = true;
5822                         }
5823                     }
5824                 } else if ("--zen".equals(a) || "zen".equals(a)) {
5825                     filter.filtered = true;
5826                     filter.zen = true;
5827                 } else if ("--stats".equals(a)) {
5828                     filter.stats = true;
5829                     if (ai < args.length-1) {
5830                         ai++;
5831                         filter.since = Long.parseLong(args[ai]);
5832                     } else {
5833                         filter.since = 0;
5834                     }
5835                 }
5836             }
5837             return filter;
5838         }
5839 
5840         public boolean matches(StatusBarNotification sbn) {
5841             if (!filtered) return true;
5842             return zen ? true : sbn != null
5843                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5844         }
5845 
5846         public boolean matches(ComponentName component) {
5847             if (!filtered) return true;
5848             return zen ? true : component != null && matches(component.getPackageName());
5849         }
5850 
5851         public boolean matches(String pkg) {
5852             if (!filtered) return true;
5853             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5854         }
5855 
5856         @Override
5857         public String toString() {
5858             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5859         }
5860     }
5861 
5862     /**
5863      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5864      * binder without sending large amounts of data over a oneway transaction.
5865      */
5866     private static final class StatusBarNotificationHolder
5867             extends IStatusBarNotificationHolder.Stub {
5868         private StatusBarNotification mValue;
5869 
5870         public StatusBarNotificationHolder(StatusBarNotification value) {
5871             mValue = value;
5872         }
5873 
5874         /** Get the held value and clear it. This function should only be called once per holder */
5875         @Override
5876         public StatusBarNotification get() {
5877             StatusBarNotification value = mValue;
5878             mValue = null;
5879             return value;
5880         }
5881     }
5882 
5883     private class ShellCmd extends ShellCommand {
5884         public static final String USAGE = "help\n"
5885                 + "allow_listener COMPONENT [user_id]\n"
5886                 + "disallow_listener COMPONENT [user_id]\n"
5887                 + "set_assistant COMPONENT\n"
5888                 + "remove_assistant COMPONENT\n"
5889                 + "allow_dnd PACKAGE\n"
5890                 + "disallow_dnd PACKAGE";
5891 
5892         @Override
5893         public int onCommand(String cmd) {
5894             if (cmd == null) {
5895                 return handleDefaultCommands(cmd);
5896             }
5897             final PrintWriter pw = getOutPrintWriter();
5898             try {
5899                 switch (cmd) {
5900                     case "allow_dnd": {
5901                         getBinderService().setNotificationPolicyAccessGranted(
5902                                 getNextArgRequired(), true);
5903                     }
5904                     break;
5905 
5906                     case "disallow_dnd": {
5907                         getBinderService().setNotificationPolicyAccessGranted(
5908                                 getNextArgRequired(), false);
5909                     }
5910                     break;
5911                     case "allow_listener": {
5912                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5913                         if (cn == null) {
5914                             pw.println("Invalid listener - must be a ComponentName");
5915                             return -1;
5916                         }
5917                         String userId = getNextArg();
5918                         if (userId == null) {
5919                             getBinderService().setNotificationListenerAccessGranted(cn, true);
5920                         } else {
5921                             getBinderService().setNotificationListenerAccessGrantedForUser(
5922                                     cn, Integer.parseInt(userId), true);
5923                         }
5924                     }
5925                     break;
5926                     case "disallow_listener": {
5927                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5928                         if (cn == null) {
5929                             pw.println("Invalid listener - must be a ComponentName");
5930                             return -1;
5931                         }
5932                         String userId = getNextArg();
5933                         if (userId == null) {
5934                             getBinderService().setNotificationListenerAccessGranted(cn, false);
5935                         } else {
5936                             getBinderService().setNotificationListenerAccessGrantedForUser(
5937                                     cn, Integer.parseInt(userId), false);
5938                         }
5939                     }
5940                     break;
5941                     case "allow_assistant": {
5942                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5943                         if (cn == null) {
5944                             pw.println("Invalid assistant - must be a ComponentName");
5945                             return -1;
5946                         }
5947                         getBinderService().setNotificationAssistantAccessGranted(cn, true);
5948                     }
5949                     break;
5950                     case "disallow_assistant": {
5951                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5952                         if (cn == null) {
5953                             pw.println("Invalid assistant - must be a ComponentName");
5954                             return -1;
5955                         }
5956                         getBinderService().setNotificationAssistantAccessGranted(cn, false);
5957                     }
5958                     break;
5959 
5960                     default:
5961                         return handleDefaultCommands(cmd);
5962                 }
5963             } catch (Exception e) {
5964                 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
5965                 Slog.e(TAG, "Error running shell command", e);
5966             }
5967             return 0;
5968         }
5969 
5970         @Override
5971         public void onHelp() {
5972             getOutPrintWriter().println(USAGE);
5973         }
5974     }
5975 }
5976