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