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