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