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