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.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS;
20 import static android.Manifest.permission.RECEIVE_SENSITIVE_NOTIFICATIONS;
21 import static android.Manifest.permission.STATUS_BAR_SERVICE;
22 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
23 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
24 import static android.app.AppOpsManager.MODE_ALLOWED;
25 import static android.app.AppOpsManager.MODE_DEFAULT;
26 import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
27 import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
28 import static android.app.Flags.lifetimeExtensionRefactor;
29 import static android.app.Flags.sortSectionByTime;
30 import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
31 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
32 import static android.app.Notification.EXTRA_LARGE_ICON_BIG;
33 import static android.app.Notification.EXTRA_SUB_TEXT;
34 import static android.app.Notification.EXTRA_TEXT;
35 import static android.app.Notification.EXTRA_TEXT_LINES;
36 import static android.app.Notification.EXTRA_TITLE_BIG;
37 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
38 import static android.app.Notification.FLAG_AUTO_CANCEL;
39 import static android.app.Notification.FLAG_BUBBLE;
40 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
41 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
42 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
43 import static android.app.Notification.FLAG_NO_CLEAR;
44 import static android.app.Notification.FLAG_NO_DISMISS;
45 import static android.app.Notification.FLAG_ONGOING_EVENT;
46 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
47 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
48 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
49 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
50 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
51 import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED;
52 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
53 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL;
54 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
55 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
56 import static android.app.NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED;
57 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
58 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED;
59 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
60 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
61 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
62 import static android.app.NotificationManager.EXTRA_NOTIFICATION_POLICY;
63 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
64 import static android.app.NotificationManager.IMPORTANCE_LOW;
65 import static android.app.NotificationManager.IMPORTANCE_MIN;
66 import static android.app.NotificationManager.IMPORTANCE_NONE;
67 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
68 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
69 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
70 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
71 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
72 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
73 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
74 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
78 import static android.app.NotificationManager.zenModeFromInterruptionFilter;
79 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED;
80 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED;
81 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
82 import static android.content.Context.BIND_AUTO_CREATE;
83 import static android.content.Context.BIND_FOREGROUND_SERVICE;
84 import static android.content.Context.BIND_NOT_PERCEPTIBLE;
85 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
86 import static android.content.pm.PackageManager.FEATURE_TELECOM;
87 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
88 import static android.content.pm.PackageManager.MATCH_ALL;
89 import static android.content.pm.PackageManager.MATCH_ANY_USER;
90 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
91 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
92 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
93 import static android.os.Flags.allowPrivateProfile;
94 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
95 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
96 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
97 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
98 import static android.os.UserHandle.USER_ALL;
99 import static android.os.UserHandle.USER_NULL;
100 import static android.os.UserHandle.USER_SYSTEM;
101 import static android.service.notification.Flags.callstyleCallbackApi;
102 import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners;
103 import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle;
104 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
105 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
106 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
107 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
108 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
109 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
110 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
111 import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES;
112 import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES;
113 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
114 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
115 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
116 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
117 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
118 import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
119 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
120 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
121 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
122 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_REMOVED;
123 import static android.service.notification.NotificationListenerService.REASON_CLEAR_DATA;
124 import static android.service.notification.NotificationListenerService.REASON_CLICK;
125 import static android.service.notification.NotificationListenerService.REASON_ERROR;
126 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
127 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
128 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
129 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
130 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
131 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
132 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
133 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
134 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
135 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
136 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
137 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
138 import static android.service.notification.NotificationListenerService.Ranking.RANKING_DEMOTED;
139 import static android.service.notification.NotificationListenerService.Ranking.RANKING_PROMOTED;
140 import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED;
141 import static android.service.notification.NotificationListenerService.TRIM_FULL;
142 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
143 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
144 import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
145 
146 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
147 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
148 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
149 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
150 import static com.android.internal.util.Preconditions.checkArgument;
151 import static com.android.internal.util.Preconditions.checkNotNull;
152 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
153 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
154 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
155 import static com.android.server.notification.Flags.expireBitmaps;
156 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER;
157 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
158 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
159 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
160 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
161 
162 import android.Manifest;
163 import android.Manifest.permission;
164 import android.annotation.DurationMillisLong;
165 import android.annotation.ElapsedRealtimeLong;
166 import android.annotation.EnforcePermission;
167 import android.annotation.FlaggedApi;
168 import android.annotation.MainThread;
169 import android.annotation.NonNull;
170 import android.annotation.Nullable;
171 import android.annotation.RequiresPermission;
172 import android.annotation.UserIdInt;
173 import android.annotation.WorkerThread;
174 import android.app.ActivityManager;
175 import android.app.ActivityManagerInternal;
176 import android.app.ActivityManagerInternal.ServiceNotificationPolicy;
177 import android.app.ActivityTaskManager;
178 import android.app.AlarmManager;
179 import android.app.AppGlobals;
180 import android.app.AppOpsManager;
181 import android.app.AutomaticZenRule;
182 import android.app.IActivityManager;
183 import android.app.ICallNotificationEventCallback;
184 import android.app.INotificationManager;
185 import android.app.ITransientNotification;
186 import android.app.ITransientNotificationCallback;
187 import android.app.IUriGrantsManager;
188 import android.app.Notification;
189 import android.app.Notification.MessagingStyle;
190 import android.app.NotificationChannel;
191 import android.app.NotificationChannelGroup;
192 import android.app.NotificationHistory;
193 import android.app.NotificationHistory.HistoricalNotification;
194 import android.app.NotificationManager;
195 import android.app.NotificationManager.Policy;
196 import android.app.PendingIntent;
197 import android.app.Person;
198 import android.app.RemoteServiceException.BadForegroundServiceNotificationException;
199 import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException;
200 import android.app.StatsManager;
201 import android.app.UriGrantsManager;
202 import android.app.admin.DevicePolicyManagerInternal;
203 import android.app.backup.BackupManager;
204 import android.app.compat.CompatChanges;
205 import android.app.role.OnRoleHoldersChangedListener;
206 import android.app.role.RoleManager;
207 import android.app.usage.UsageEvents;
208 import android.app.usage.UsageStatsManagerInternal;
209 import android.companion.AssociationInfo;
210 import android.companion.AssociationRequest;
211 import android.companion.ICompanionDeviceManager;
212 import android.compat.annotation.ChangeId;
213 import android.compat.annotation.EnabledAfter;
214 import android.compat.annotation.EnabledSince;
215 import android.compat.annotation.LoggingOnly;
216 import android.content.AttributionSource;
217 import android.content.BroadcastReceiver;
218 import android.content.ComponentName;
219 import android.content.ContentProvider;
220 import android.content.ContentResolver;
221 import android.content.Context;
222 import android.content.Intent;
223 import android.content.IntentFilter;
224 import android.content.pm.ApplicationInfo;
225 import android.content.pm.IPackageManager;
226 import android.content.pm.LauncherApps;
227 import android.content.pm.ModuleInfo;
228 import android.content.pm.PackageInfo;
229 import android.content.pm.PackageManager;
230 import android.content.pm.PackageManager.NameNotFoundException;
231 import android.content.pm.PackageManagerInternal;
232 import android.content.pm.ParceledListSlice;
233 import android.content.pm.ServiceInfo;
234 import android.content.pm.ShortcutInfo;
235 import android.content.pm.ShortcutServiceInternal;
236 import android.content.pm.UserInfo;
237 import android.content.pm.VersionedPackage;
238 import android.content.res.Resources;
239 import android.database.ContentObserver;
240 import android.graphics.drawable.Icon;
241 import android.metrics.LogMaker;
242 import android.net.Uri;
243 import android.os.Binder;
244 import android.os.Build;
245 import android.os.Bundle;
246 import android.os.DeadObjectException;
247 import android.os.DeviceIdleManager;
248 import android.os.Environment;
249 import android.os.Handler;
250 import android.os.HandlerThread;
251 import android.os.IBinder;
252 import android.os.IInterface;
253 import android.os.Looper;
254 import android.os.Message;
255 import android.os.ParcelFileDescriptor;
256 import android.os.PowerManager;
257 import android.os.PowerManager.WakeLock;
258 import android.os.Process;
259 import android.os.RemoteCallbackList;
260 import android.os.RemoteException;
261 import android.os.ResultReceiver;
262 import android.os.ServiceManager;
263 import android.os.ShellCallback;
264 import android.os.SystemClock;
265 import android.os.SystemProperties;
266 import android.os.Trace;
267 import android.os.UserHandle;
268 import android.os.UserManager;
269 import android.os.WorkSource;
270 import android.permission.PermissionManager;
271 import android.provider.Settings;
272 import android.provider.Settings.Secure;
273 import android.service.notification.Adjustment;
274 import android.service.notification.Condition;
275 import android.service.notification.ConversationChannelWrapper;
276 import android.service.notification.DeviceEffectsApplier;
277 import android.service.notification.IConditionProvider;
278 import android.service.notification.INotificationListener;
279 import android.service.notification.IStatusBarNotificationHolder;
280 import android.service.notification.ListenersDisablingEffectsProto;
281 import android.service.notification.NotificationAssistantService;
282 import android.service.notification.NotificationListenerFilter;
283 import android.service.notification.NotificationListenerService;
284 import android.service.notification.NotificationRankingUpdate;
285 import android.service.notification.NotificationRecordProto;
286 import android.service.notification.NotificationServiceDumpProto;
287 import android.service.notification.NotificationStats;
288 import android.service.notification.StatusBarNotification;
289 import android.service.notification.ZenDeviceEffects;
290 import android.service.notification.ZenModeConfig;
291 import android.service.notification.ZenModeProto;
292 import android.service.notification.ZenPolicy;
293 import android.telecom.TelecomManager;
294 import android.telephony.TelephonyManager;
295 import android.text.TextUtils;
296 import android.text.format.DateUtils;
297 import android.util.ArrayMap;
298 import android.util.ArraySet;
299 import android.util.AtomicFile;
300 import android.util.IntArray;
301 import android.util.Log;
302 import android.util.Pair;
303 import android.util.Slog;
304 import android.util.SparseArray;
305 import android.util.SparseBooleanArray;
306 import android.util.StatsEvent;
307 import android.util.Xml;
308 import android.util.proto.ProtoOutputStream;
309 import android.view.Display;
310 import android.view.accessibility.AccessibilityManager;
311 import android.widget.RemoteViews;
312 import android.widget.Toast;
313 
314 import com.android.internal.R;
315 import com.android.internal.annotations.GuardedBy;
316 import com.android.internal.annotations.VisibleForTesting;
317 import com.android.internal.compat.IPlatformCompat;
318 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
319 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
320 import com.android.internal.logging.InstanceId;
321 import com.android.internal.logging.InstanceIdSequence;
322 import com.android.internal.logging.MetricsLogger;
323 import com.android.internal.logging.nano.MetricsProto;
324 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
325 import com.android.internal.messages.nano.SystemMessageProto;
326 import com.android.internal.notification.SystemNotificationChannels;
327 import com.android.internal.os.BackgroundThread;
328 import com.android.internal.os.SomeArgs;
329 import com.android.internal.statusbar.NotificationVisibility;
330 import com.android.internal.util.ArrayUtils;
331 import com.android.internal.util.CollectionUtils;
332 import com.android.internal.util.ConcurrentUtils;
333 import com.android.internal.util.DumpUtils;
334 import com.android.internal.util.FrameworkStatsLog;
335 import com.android.internal.util.Preconditions;
336 import com.android.internal.util.XmlUtils;
337 import com.android.internal.util.function.TriPredicate;
338 import com.android.internal.widget.LockPatternUtils;
339 import com.android.modules.utils.TypedXmlPullParser;
340 import com.android.modules.utils.TypedXmlSerializer;
341 import com.android.server.DeviceIdleInternal;
342 import com.android.server.EventLogTags;
343 import com.android.server.IoThread;
344 import com.android.server.LocalServices;
345 import com.android.server.SystemService;
346 import com.android.server.job.JobSchedulerInternal;
347 import com.android.server.lights.LightsManager;
348 import com.android.server.notification.GroupHelper.NotificationAttributes;
349 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
350 import com.android.server.notification.ManagedServices.UserProfiles;
351 import com.android.server.notification.toast.CustomToastRecord;
352 import com.android.server.notification.toast.TextToastRecord;
353 import com.android.server.notification.toast.ToastRecord;
354 import com.android.server.pm.PackageManagerService;
355 import com.android.server.pm.UserManagerInternal;
356 import com.android.server.policy.PermissionPolicyInternal;
357 import com.android.server.statusbar.StatusBarManagerInternal;
358 import com.android.server.uri.UriGrantsManagerInternal;
359 import com.android.server.utils.Slogf;
360 import com.android.server.utils.quota.MultiRateLimiter;
361 import com.android.server.wm.ActivityTaskManagerInternal;
362 import com.android.server.wm.BackgroundActivityStartCallback;
363 import com.android.server.wm.WindowManagerInternal;
364 
365 import libcore.io.IoUtils;
366 
367 import org.json.JSONException;
368 import org.json.JSONObject;
369 import org.xmlpull.v1.XmlPullParserException;
370 
371 import java.io.ByteArrayInputStream;
372 import java.io.ByteArrayOutputStream;
373 import java.io.File;
374 import java.io.FileDescriptor;
375 import java.io.FileNotFoundException;
376 import java.io.FileOutputStream;
377 import java.io.IOException;
378 import java.io.InputStream;
379 import java.io.OutputStream;
380 import java.io.PrintWriter;
381 import java.nio.charset.StandardCharsets;
382 import java.time.Clock;
383 import java.time.Duration;
384 import java.util.ArrayList;
385 import java.util.Arrays;
386 import java.util.Collection;
387 import java.util.HashSet;
388 import java.util.Iterator;
389 import java.util.LinkedList;
390 import java.util.List;
391 import java.util.Map;
392 import java.util.Map.Entry;
393 import java.util.Objects;
394 import java.util.Set;
395 import java.util.concurrent.Executor;
396 import java.util.concurrent.TimeUnit;
397 import java.util.function.BiConsumer;
398 import java.util.stream.Collectors;
399 
400 /** {@hide} */
401 public class NotificationManagerService extends SystemService {
402     public static final String TAG = "NotificationService";
403     public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
404     public static final boolean ENABLE_CHILD_NOTIFICATIONS
405             = SystemProperties.getBoolean("debug.child_notifs", true);
406 
407     // pullStats report request: undecorated remote view stats
408     public static final int REPORT_REMOTE_VIEWS = 0x01;
409 
410     static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
411             "debug.notification.interruptiveness", false);
412 
413     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
414     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
415 
416     // To limit bad UX of seeing a toast many seconds after if was triggered.
417     static final int MAX_PACKAGE_TOASTS = 5;
418 
419     // message codes
420     static final int MESSAGE_DURATION_REACHED = 2;
421     // 3: removed to a different handler
422     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
423     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
424     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
425     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
426     static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
427 
428     static final Duration BITMAP_DURATION = Duration.ofHours(24);
429 
430     // ranking thread messages
431     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
432     private static final int MESSAGE_RANKING_SORT = 1001;
433 
434     static final int LONG_DELAY = TOAST_WINDOW_TIMEOUT - TOAST_WINDOW_ANIM_BUFFER; // 3.5 seconds
435     static final int SHORT_DELAY = 2000; // 2 seconds
436 
437     // 1 second past the ANR timeout.
438     static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
439 
440     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
441 
442     /**
443      *  The threshold, in milliseconds, to determine whether a notification has been
444      * cleared too quickly.
445      */
446     private static final int NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS = 5000;
447 
448     static final int INVALID_UID = -1;
449     static final String ROOT_PKG = "root";
450 
451     static final String[] ALLOWED_ADJUSTMENTS = new String[] {
452             Adjustment.KEY_PEOPLE,
453             Adjustment.KEY_SNOOZE_CRITERIA,
454             Adjustment.KEY_USER_SENTIMENT,
455             Adjustment.KEY_CONTEXTUAL_ACTIONS,
456             Adjustment.KEY_TEXT_REPLIES,
457             Adjustment.KEY_IMPORTANCE,
458             Adjustment.KEY_IMPORTANCE_PROPOSAL,
459             Adjustment.KEY_SENSITIVE_CONTENT,
460             Adjustment.KEY_RANKING_SCORE,
461             Adjustment.KEY_NOT_CONVERSATION
462     };
463 
464     static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
465             RoleManager.ROLE_DIALER,
466             RoleManager.ROLE_EMERGENCY
467     };
468 
469     // Used for rate limiting toasts by package.
470     static final String TOAST_QUOTA_TAG = "toast_quota_tag";
471 
472     // This constant defines rate limits applied to showing toasts. The numbers are set in a way
473     // such that an aggressive toast showing strategy would result in a roughly 1.5x longer wait
474     // time (before the package is allowed to show toasts again) each time the toast rate limit is
475     // reached. It's meant to protect the user against apps spamming them with toasts (either
476     // accidentally or on purpose).
477     private static final MultiRateLimiter.RateLimit[] TOAST_RATE_LIMITS = {
478             MultiRateLimiter.RateLimit.create(3, Duration.ofSeconds(20)),
479             MultiRateLimiter.RateLimit.create(5, Duration.ofSeconds(42)),
480             MultiRateLimiter.RateLimit.create(6, Duration.ofSeconds(68)),
481     };
482 
483     // When #matchesCallFilter is called from the ringer, wait at most
484     // 3s to resolve the contacts. This timeout is required since
485     // ContactsProvider might take a long time to start up.
486     //
487     // Return STARRED_CONTACT when the timeout is hit in order to avoid
488     // missed calls in ZEN mode "Important".
489     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
490     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
491             ValidateNotificationPeople.STARRED_CONTACT;
492 
493     /** notification_enqueue status value for a newly enqueued notification. */
494     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
495 
496     /** notification_enqueue status value for an existing notification. */
497     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
498 
499     /** notification_enqueue status value for an ignored notification. */
500     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
501     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
502 
503     private static final long DELAY_FOR_ASSISTANT_TIME = 200;
504 
505     private static final String ACTION_NOTIFICATION_TIMEOUT =
506             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
507     private static final int REQUEST_CODE_TIMEOUT = 1;
508     private static final String SCHEME_TIMEOUT = "timeout";
509     private static final String EXTRA_KEY = "key";
510 
511     private static final int NOTIFICATION_INSTANCE_ID_MAX = (1 << 13);
512 
513     // States for the review permissions notification
514     static final int REVIEW_NOTIF_STATE_UNKNOWN = -1;
515     static final int REVIEW_NOTIF_STATE_SHOULD_SHOW = 0;
516     static final int REVIEW_NOTIF_STATE_USER_INTERACTED = 1;
517     static final int REVIEW_NOTIF_STATE_DISMISSED = 2;
518     static final int REVIEW_NOTIF_STATE_RESHOWN = 3;
519 
520     // Action strings for review permissions notification
521     static final String REVIEW_NOTIF_ACTION_REMIND = "REVIEW_NOTIF_ACTION_REMIND";
522     static final String REVIEW_NOTIF_ACTION_DISMISS = "REVIEW_NOTIF_ACTION_DISMISS";
523     static final String REVIEW_NOTIF_ACTION_CANCELED = "REVIEW_NOTIF_ACTION_CANCELED";
524 
525     /**
526      * Apps that post custom toasts in the background will have those blocked. Apps can
527      * still post toasts created with
528      * {@link Toast#makeText(Context, CharSequence, int)} and its variants while
529      * in the background.
530      */
531     @ChangeId
532     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
533     private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L;
534 
535     /**
536      * Activity starts coming from broadcast receivers or services in response to notification and
537      * notification action clicks will be blocked for UX and performance reasons. Instead start the
538      * activity directly from the PendingIntent.
539      */
540     @ChangeId
541     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
542     private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L;
543 
544     /**
545      * Activity starts coming from broadcast receivers or services in response to notification and
546      * notification action clicks will be blocked for UX and performance reasons for previously
547      * exempt role holders (browser).
548      */
549     @ChangeId
550     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
551     private static final long NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES = 227752274L;
552 
553     /**
554      * Whether a notification listeners can understand new, more specific, cancellation reasons.
555      */
556     @ChangeId
557     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
558     private static final long NOTIFICATION_CANCELLATION_REASONS = 175319604L;
559 
560     /**
561      * Rate limit showing toasts, on a per package basis.
562      *
563      * It limits the number of {@link Toast#show()} calls to prevent overburdening
564      * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed
565      * in a certain time frame will result in the toast being discarded.
566      */
567     @ChangeId
568     @LoggingOnly
569     private static final long RATE_LIMIT_TOASTS = 174840628L;
570 
571     /**
572      * Whether listeners understand the more specific reason provided for notification
573      * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL.
574      */
575     @ChangeId
576     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
577     private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
578 
579     /**
580      * NO_CLEAR flag will be set for any media notification.
581      */
582     @ChangeId
583     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
584     static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L;
585 
586     /**
587      * App calls to {@link NotificationManager#setInterruptionFilter} and
588      * {@link NotificationManager#setNotificationPolicy} manage DND through the
589      * creation and activation of an implicit {@link AutomaticZenRule}.
590      */
591     @ChangeId
592     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
593     static final long MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES = 308670109L;
594 
595     private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
596 
597     static final long NOTIFICATION_TTL = Duration.ofDays(3).toMillis();
598 
599     static final long NOTIFICATION_MAX_AGE_AT_POST = Duration.ofDays(14).toMillis();
600 
601     private IActivityManager mAm;
602     private ActivityTaskManagerInternal mAtm;
603     private ActivityManager mActivityManager;
604     private ActivityManagerInternal mAmi;
605     @VisibleForTesting
606     IPackageManager mPackageManager;
607     private PackageManager mPackageManagerClient;
608     PackageManagerInternal mPackageManagerInternal;
609     private PermissionManager mPermissionManager;
610     private PermissionPolicyInternal mPermissionPolicyInternal;
611 
612     // Can be null for wear
613     @Nullable StatusBarManagerInternal mStatusBar;
614     private WindowManagerInternal mWindowManagerInternal;
615     private AlarmManager mAlarmManager;
616     @VisibleForTesting
617     ICompanionDeviceManager mCompanionManager;
618     private AccessibilityManager mAccessibilityManager;
619     private DeviceIdleManager mDeviceIdleManager;
620     private IUriGrantsManager mUgm;
621     private UriGrantsManagerInternal mUgmInternal;
622     private volatile RoleObserver mRoleObserver;
623     private UserManager mUm;
624     private UserManagerInternal mUmInternal;
625     private IPlatformCompat mPlatformCompat;
626     private ShortcutHelper mShortcutHelper;
627     private PermissionHelper mPermissionHelper;
628     private UsageStatsManagerInternal mUsageStatsManagerInternal;
629     private TelecomManager mTelecomManager;
630     private PowerManager mPowerManager;
631     private PostNotificationTrackerFactory mPostNotificationTrackerFactory;
632 
633     private LockPatternUtils mLockUtils;
634 
635     final IBinder mForegroundToken = new Binder();
636     @VisibleForTesting
637     WorkerHandler mHandler;
638     private final HandlerThread mRankingThread = new HandlerThread("ranker",
639             Process.THREAD_PRIORITY_BACKGROUND);
640 
641     private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
642             new SparseArray<>();
643     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
644     private int mListenerHints;  // right now, all hints are global
645     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
646 
647     private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
648 
649     // used as a mutex for access to all active notifications & listeners
650     final Object mNotificationLock = new Object();
651     @GuardedBy("mNotificationLock")
652     final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
653     @GuardedBy("mNotificationLock")
654     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
655     @GuardedBy("mNotificationLock")
656     final ArrayMap<String, InlineReplyUriRecord> mInlineReplyRecordsByKey = new ArrayMap<>();
657     @GuardedBy("mNotificationLock")
658     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
659     @GuardedBy("mNotificationLock")
660     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
661     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
662     // set of uids for which toast rate limiting is disabled
663     @GuardedBy("mToastQueue")
664     private final Set<Integer> mToastRateLimitingDisabledUids = new ArraySet<>();
665     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
666 
667     // True if the toast that's on top of the queue is being shown at the moment.
668     @GuardedBy("mToastQueue")
669     private boolean mIsCurrentToastShown = false;
670 
671     // Used for rate limiting toasts by package.
672     private MultiRateLimiter mToastRateLimiter;
673 
674     private AppOpsManager mAppOps;
675     private UsageStatsManagerInternal mAppUsageStats;
676     private DevicePolicyManagerInternal mDpm;
677     private StatsManager mStatsManager;
678     private StatsPullAtomCallbackImpl mPullAtomCallback;
679 
680     private Archive mArchive;
681 
682     // Persistent storage for notification policy
683     private AtomicFile mPolicyFile;
684 
685     private static final int DB_VERSION = 1;
686 
687 
688     private static final String ADSERVICES_MODULE_PKG_NAME =
689             "com.android.adservices";
690 
691     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
692     private static final String ATTR_VERSION = "version";
693 
694     private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
695             "allow-secure-notifications-on-lockscreen";
696     private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
697 
698     @VisibleForTesting
699     RankingHelper mRankingHelper;
700     @VisibleForTesting
701     PreferencesHelper mPreferencesHelper;
702 
703     private final UserProfiles mUserProfiles = new UserProfiles();
704     private NotificationListeners mListeners;
705     @VisibleForTesting
706     NotificationAssistants mAssistants;
707     private ConditionProviders mConditionProviders;
708     private NotificationUsageStats mUsageStats;
709     private boolean mLockScreenAllowSecureNotifications = true;
710     final ArrayMap<String, ArrayMap<Integer,
711             RemoteCallbackList<ICallNotificationEventCallback>>>
712             mCallNotificationEventCallbacks = new ArrayMap<>();
713 
714     private static final int MY_UID = Process.myUid();
715     private static final int MY_PID = Process.myPid();
716     static final IBinder ALLOWLIST_TOKEN = new Binder();
717     protected RankingHandler mRankingHandler;
718     private long mLastOverRateLogTime;
719     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
720 
721     private NotificationHistoryManager mHistoryManager;
722     protected SnoozeHelper mSnoozeHelper;
723     private TimeToLiveHelper mTtlHelper;
724     private GroupHelper mGroupHelper;
725     private int mAutoGroupAtCount;
726     private boolean mIsTelevision;
727     protected NotificationAttentionHelper mAttentionHelper;
728 
729     private int mWarnRemoteViewsSizeBytes;
730     private int mStripRemoteViewsSizeBytes;
731 
732     @VisibleForTesting
733     protected boolean mShowReviewPermissionsNotification;
734 
735     private MetricsLogger mMetricsLogger;
736     private NotificationChannelLogger mNotificationChannelLogger;
737     private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
738 
739     private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
740     private NotificationRecordLogger mNotificationRecordLogger;
741     private InstanceIdSequence mNotificationInstanceIdSequence;
742     private Set<String> mMsgPkgsAllowedAsConvos = new HashSet();
743     private String mDefaultSearchSelectorPkg;
744 
745     // Broadcast intent receiver for notification permissions review-related intents
746     private ReviewNotificationPermissionsReceiver mReviewNotificationPermissionsReceiver;
747 
748     private AppOpsManager.OnOpChangedListener mAppOpsListener;
749 
750     private ModuleInfo mAdservicesModuleInfo;
751 
752     static class Archive {
753         final SparseArray<Boolean> mEnabled;
754         final int mBufferSize;
755         final Object mBufferLock = new Object();
756         @GuardedBy("mBufferLock")
757         final LinkedList<Pair<StatusBarNotification, Integer>> mBuffer;
758 
Archive(int size)759         public Archive(int size) {
760             mBufferSize = size;
761             mBuffer = new LinkedList<>();
762             mEnabled = new SparseArray<>();
763         }
764 
toString()765         public String toString() {
766             final StringBuilder sb = new StringBuilder();
767             final int N = mBuffer.size();
768             sb.append("Archive (");
769             sb.append(N);
770             sb.append(" notification");
771             sb.append((N == 1) ? ")" : "s)");
772             return sb.toString();
773         }
774 
record(StatusBarNotification sbn, int reason)775         public void record(StatusBarNotification sbn, int reason) {
776             if (!mEnabled.get(sbn.getNormalizedUserId(), false)) {
777                 return;
778             }
779             synchronized (mBufferLock) {
780                 if (mBuffer.size() == mBufferSize) {
781                     mBuffer.removeFirst();
782                 }
783 
784                 // We don't want to store the heavy bits of the notification in the archive,
785                 // but other clients in the system process might be using the object, so we
786                 // store a (lightened) copy.
787                 mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason));
788             }
789         }
790 
descendingIterator()791         public Iterator<Pair<StatusBarNotification, Integer>> descendingIterator() {
792             return mBuffer.descendingIterator();
793         }
794 
getArray(UserManager um, int count, boolean includeSnoozed)795         public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) {
796             ArrayList<Integer> currentUsers = new ArrayList<>();
797             currentUsers.add(USER_ALL);
798             Binder.withCleanCallingIdentity(() -> {
799                 for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) {
800                     currentUsers.add(user);
801                 }
802             });
803             synchronized (mBufferLock) {
804                 if (count == 0) count = mBufferSize;
805                 List<StatusBarNotification> a = new ArrayList();
806                 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator();
807                 int i = 0;
808                 while (iter.hasNext() && i < count) {
809                     Pair<StatusBarNotification, Integer> pair = iter.next();
810                     if (pair.second != REASON_SNOOZED || includeSnoozed) {
811                         if (currentUsers.contains(pair.first.getUserId())) {
812                             i++;
813                             a.add(pair.first);
814                         }
815                     }
816                 }
817                 return a.toArray(new StatusBarNotification[a.size()]);
818             }
819         }
820 
updateHistoryEnabled(@serIdInt int userId, boolean enabled)821         public void updateHistoryEnabled(@UserIdInt int userId, boolean enabled) {
822             mEnabled.put(userId, enabled);
823 
824             if (!enabled) {
825                 synchronized (mBufferLock) {
826                     for (int i = mBuffer.size() - 1; i >= 0; i--) {
827                         if (userId == mBuffer.get(i).first.getNormalizedUserId()) {
828                             mBuffer.remove(i);
829                         }
830                     }
831                 }
832             }
833         }
834 
835         // Remove notifications with the specified user & channel ID.
removeChannelNotifications(String pkg, @UserIdInt int userId, String channelId)836         public void removeChannelNotifications(String pkg, @UserIdInt int userId,
837                 String channelId) {
838             synchronized (mBufferLock) {
839                 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator();
840                 while (bufferIter.hasNext()) {
841                     final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
842                     if (pair.first != null
843                             && userId == pair.first.getNormalizedUserId()
844                             && pkg != null && pkg.equals(pair.first.getPackageName())
845                             && pair.first.getNotification() != null
846                             && Objects.equals(channelId,
847                             pair.first.getNotification().getChannelId())) {
848                         bufferIter.remove();
849                     }
850                 }
851             }
852         }
853 
854         // Removes all notifications with the specified user & package.
removePackageNotifications(String pkg, @UserIdInt int userId)855         public void removePackageNotifications(String pkg, @UserIdInt int userId) {
856             synchronized (mBufferLock) {
857                 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator();
858                 while (bufferIter.hasNext()) {
859                     final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
860                     if (pair.first != null
861                             && userId == pair.first.getNormalizedUserId()
862                             && pkg != null && pkg.equals(pair.first.getPackageName())
863                             && pair.first.getNotification() != null) {
864                         bufferIter.remove();
865                     }
866                 }
867             }
868         }
869 
dumpImpl(PrintWriter pw, @NonNull DumpFilter filter)870         void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
871             synchronized (mBufferLock) {
872                 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator();
873                 int i = 0;
874                 while (iter.hasNext()) {
875                     final StatusBarNotification sbn = iter.next().first;
876                     if (filter != null && !filter.matches(sbn)) continue;
877                     pw.println("    " + sbn);
878                     if (++i >= 5) {
879                         if (iter.hasNext()) pw.println("    ...");
880                         break;
881                     }
882                 }
883             }
884         }
885     }
886 
loadDefaultApprovedServices(int userId)887     void loadDefaultApprovedServices(int userId) {
888         mListeners.loadDefaultsFromConfig();
889 
890         mConditionProviders.loadDefaultsFromConfig();
891 
892         mAssistants.loadDefaultsFromConfig();
893     }
894 
allowDefaultApprovedServices(int userId)895     protected void allowDefaultApprovedServices(int userId) {
896         ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents();
897         for (int i = 0; i < defaultListeners.size(); i++) {
898             ComponentName cn = defaultListeners.valueAt(i);
899             allowNotificationListener(userId, cn);
900         }
901 
902         allowDndPackages(userId);
903 
904         setDefaultAssistantForUser(userId);
905     }
906 
907     @VisibleForTesting
allowDndPackages(int userId)908     void allowDndPackages(int userId) {
909         ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages();
910         for (int i = 0; i < defaultDnds.size(); i++) {
911             allowDndPackage(userId, defaultDnds.valueAt(i));
912         }
913         if (!isDNDMigrationDone(userId)) {
914             setDNDMigrationDone(userId);
915         }
916     }
917 
918     @VisibleForTesting
isDNDMigrationDone(int userId)919     boolean isDNDMigrationDone(int userId) {
920         return Secure.getIntForUser(getContext().getContentResolver(),
921                 Secure.DND_CONFIGS_MIGRATED, 0, userId) == 1;
922     }
923 
924     @VisibleForTesting
setDNDMigrationDone(int userId)925     void setDNDMigrationDone(int userId) {
926         Secure.putIntForUser(getContext().getContentResolver(),
927                 Secure.DND_CONFIGS_MIGRATED, 1, userId);
928     }
929 
migrateDefaultNAS()930     protected void migrateDefaultNAS() {
931         final List<UserInfo> activeUsers = mUm.getUsers();
932         for (UserInfo userInfo : activeUsers) {
933             int userId = userInfo.getUserHandle().getIdentifier();
934             if (isNASMigrationDone(userId) || isProfileUser(userInfo)) {
935                 continue;
936             }
937             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
938             if (allowedComponents.size() == 0) { // user set to none
939                 Slog.d(TAG, "NAS Migration: user set to none, disable new NAS setting");
940                 setNASMigrationDone(userId);
941                 mAssistants.clearDefaults();
942             } else {
943                 Slog.d(TAG, "Reset NAS setting and migrate to new default");
944                 resetAssistantUserSet(userId);
945                 // migrate to new default and set migration done
946                 mAssistants.resetDefaultAssistantsIfNecessary();
947             }
948         }
949     }
950 
951     @VisibleForTesting
setNASMigrationDone(int baseUserId)952     void setNASMigrationDone(int baseUserId) {
953         for (int profileId : mUm.getProfileIds(baseUserId, false)) {
954             Secure.putIntForUser(getContext().getContentResolver(),
955                     Secure.NAS_SETTINGS_UPDATED, 1, profileId);
956         }
957     }
958 
959     @VisibleForTesting
isNASMigrationDone(int userId)960     boolean isNASMigrationDone(int userId) {
961         return (Secure.getIntForUser(getContext().getContentResolver(),
962                 Secure.NAS_SETTINGS_UPDATED, 0, userId) == 1);
963     }
964 
isProfileUser(UserInfo userInfo)965     boolean isProfileUser(UserInfo userInfo) {
966         if (privateSpaceFlagsEnabled()) {
967             return userInfo.isProfile() && hasParent(userInfo);
968         }
969         return userInfo.isManagedProfile() || userInfo.isCloneProfile();
970     }
971 
hasParent(UserInfo profile)972     boolean hasParent(UserInfo profile) {
973         return mUmInternal.getProfileParentId(profile.id) != profile.id;
974     }
975 
setDefaultAssistantForUser(int userId)976     protected void setDefaultAssistantForUser(int userId) {
977         ArraySet<ComponentName> defaults = mAssistants.getDefaultComponents();
978         // We should have only one default assistant by default
979         // allowAssistant should execute once in practice
980         for (int i = 0; i < defaults.size(); i++) {
981             ComponentName cn = defaults.valueAt(i);
982             if (allowAssistant(userId, cn)) return;
983         }
984     }
985 
986     /**
987      * This method will update the flags and/or the icon of the summary.
988      * It will set it to FLAG_ONGOING_EVENT if any of its group members
989      * has the same flag. It will delete the flag otherwise.
990      * It will update the summary notification icon if the group children's
991      * icons are different.
992      * @param userId user id of the autogroup summary
993      * @param pkg package of the autogroup summary
994      * @param summaryAttr the new flags and/or icon & color for this summary
995      * @param isAppForeground true if the app is currently in the foreground.
996      */
997     @GuardedBy("mNotificationLock")
updateAutobundledSummaryLocked(int userId, String pkg, NotificationAttributes summaryAttr, boolean isAppForeground)998     protected void updateAutobundledSummaryLocked(int userId, String pkg,
999             NotificationAttributes summaryAttr, boolean isAppForeground) {
1000         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
1001         if (summaries == null) {
1002             return;
1003         }
1004         String summaryKey = summaries.get(pkg);
1005         if (summaryKey == null) {
1006             return;
1007         }
1008         NotificationRecord summary = mNotificationsByKey.get(summaryKey);
1009         if (summary == null) {
1010             return;
1011         }
1012         int oldFlags = summary.getSbn().getNotification().flags;
1013 
1014         boolean attributesUpdated =
1015                 !summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon())
1016                 || summaryAttr.iconColor != summary.getSbn().getNotification().color
1017                 || summaryAttr.visibility != summary.getSbn().getNotification().visibility;
1018 
1019         if (oldFlags != summaryAttr.flags || attributesUpdated) {
1020             summary.getSbn().getNotification().flags =
1021                     summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags;
1022             summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon);
1023             summary.getSbn().getNotification().color = summaryAttr.iconColor;
1024             summary.getSbn().getNotification().visibility = summaryAttr.visibility;
1025             mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
1026                     mPostNotificationTrackerFactory.newTracker(null)));
1027         }
1028     }
1029 
allowDndPackage(int userId, String packageName)1030     private void allowDndPackage(int userId, String packageName) {
1031         try {
1032             getBinderService().setNotificationPolicyAccessGrantedForUser(packageName, userId, true);
1033         } catch (RemoteException e) {
1034             e.printStackTrace();
1035         }
1036     }
1037 
allowNotificationListener(int userId, ComponentName cn)1038     private void allowNotificationListener(int userId, ComponentName cn) {
1039 
1040         try {
1041             getBinderService().setNotificationListenerAccessGrantedForUser(cn,
1042                         userId, true, true);
1043         } catch (RemoteException e) {
1044             e.printStackTrace();
1045         }
1046     }
1047 
allowAssistant(int userId, ComponentName candidate)1048     private boolean allowAssistant(int userId, ComponentName candidate) {
1049         Set<ComponentName> validAssistants =
1050                 mAssistants.queryPackageForServices(
1051                         null,
1052                         MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
1053         if (candidate != null && validAssistants.contains(candidate)) {
1054             setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true, false);
1055             return true;
1056         }
1057         return false;
1058     }
1059 
readPolicyXml(InputStream stream, boolean forRestore, int userId)1060     void readPolicyXml(InputStream stream, boolean forRestore, int userId)
1061             throws XmlPullParserException, NumberFormatException, IOException {
1062         final TypedXmlPullParser parser;
1063         if (forRestore) {
1064             parser = Xml.newFastPullParser();
1065             parser.setInput(stream, StandardCharsets.UTF_8.name());
1066         } else {
1067             parser = Xml.resolvePullParser(stream);
1068         }
1069         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
1070         boolean migratedManagedServices = false;
1071         UserInfo userInfo = mUmInternal.getUserInfo(userId);
1072         boolean ineligibleForManagedServices = forRestore && isProfileUser(userInfo);
1073         int outerDepth = parser.getDepth();
1074         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1075             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
1076                 mZenModeHelper.readXml(parser, forRestore, userId);
1077             } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
1078                 mPreferencesHelper.readXml(parser, forRestore, userId);
1079             }
1080             if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
1081                 if (ineligibleForManagedServices) {
1082                     continue;
1083                 }
1084                 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
1085                 migratedManagedServices = true;
1086             } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
1087                 if (ineligibleForManagedServices) {
1088                     continue;
1089                 }
1090                 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
1091                 migratedManagedServices = true;
1092             } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
1093                 if (ineligibleForManagedServices) {
1094                     continue;
1095                 }
1096                 mConditionProviders.readXml(
1097                         parser, mAllowedManagedServicePackages, forRestore, userId);
1098                 migratedManagedServices = true;
1099             } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
1100                 mSnoozeHelper.readXml(parser, System.currentTimeMillis());
1101             }
1102             if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
1103                 if (forRestore && userId != USER_SYSTEM) {
1104                     continue;
1105                 }
1106                 mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null,
1107                         LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true);
1108             }
1109         }
1110 
1111         if (!migratedManagedServices) {
1112             mListeners.migrateToXml();
1113             mAssistants.migrateToXml();
1114             mConditionProviders.migrateToXml();
1115             handleSavePolicyFile();
1116         }
1117 
1118         mAssistants.resetDefaultAssistantsIfNecessary();
1119         mPreferencesHelper.syncChannelsBypassingDnd();
1120     }
1121 
1122     @VisibleForTesting
resetDefaultDndIfNecessary()1123     void resetDefaultDndIfNecessary() {
1124         boolean removed = false;
1125         final List<UserInfo> activeUsers = mUm.getAliveUsers();
1126         for (UserInfo userInfo : activeUsers) {
1127             int userId = userInfo.getUserHandle().getIdentifier();
1128             if (isDNDMigrationDone(userId)) {
1129                 continue;
1130             }
1131             removed |= mConditionProviders.removeDefaultFromConfig(userId);
1132             mConditionProviders.resetDefaultFromConfig();
1133             allowDndPackages(userId);
1134         }
1135         if (removed) {
1136             handleSavePolicyFile();
1137         }
1138     }
1139 
1140     @VisibleForTesting
loadPolicyFile()1141     protected void loadPolicyFile() {
1142         if (DBG) Slog.d(TAG, "loadPolicyFile");
1143         synchronized (mPolicyFile) {
1144             InputStream infile = null;
1145             try {
1146                 infile = mPolicyFile.openRead();
1147                 readPolicyXml(infile, false /*forRestore*/, USER_ALL);
1148 
1149                 // We re-load the default dnd packages to allow the newly added and denined.
1150                 final boolean isWatch = mPackageManagerClient.hasSystemFeature(
1151                         PackageManager.FEATURE_WATCH);
1152                 if (isWatch) {
1153                     resetDefaultDndIfNecessary();
1154                 }
1155             } catch (FileNotFoundException e) {
1156                 // No data yet
1157                 // Load default managed services approvals
1158                 loadDefaultApprovedServices(USER_SYSTEM);
1159                 allowDefaultApprovedServices(USER_SYSTEM);
1160             } catch (IOException e) {
1161                 Log.wtf(TAG, "Unable to read notification policy", e);
1162             } catch (NumberFormatException e) {
1163                 Log.wtf(TAG, "Unable to parse notification policy", e);
1164             } catch (XmlPullParserException e) {
1165                 Log.wtf(TAG, "Unable to parse notification policy", e);
1166             } finally {
1167                 IoUtils.closeQuietly(infile);
1168             }
1169         }
1170     }
1171 
1172     @VisibleForTesting
handleSavePolicyFile()1173     protected void handleSavePolicyFile() {
1174         if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
1175             IoThread.getHandler().postDelayed(mSavePolicyFile, 250);
1176         }
1177     }
1178 
privateSpaceFlagsEnabled()1179     protected static boolean privateSpaceFlagsEnabled() {
1180         return allowPrivateProfile() && android.multiuser.Flags.enablePrivateSpaceFeatures();
1181     }
1182 
1183     private final class SavePolicyFileRunnable implements Runnable {
1184         @Override
run()1185         public void run() {
1186             if (DBG) Slog.d(TAG, "handleSavePolicyFile");
1187             synchronized (mPolicyFile) {
1188                 final FileOutputStream stream;
1189                 try {
1190                     stream = mPolicyFile.startWrite();
1191                 } catch (IOException e) {
1192                     Slog.w(TAG, "Failed to save policy file", e);
1193                     return;
1194                 }
1195 
1196                 try {
1197                     writePolicyXml(stream, false /*forBackup*/, USER_ALL);
1198                     mPolicyFile.finishWrite(stream);
1199                 } catch (IOException e) {
1200                     Slog.w(TAG, "Failed to save policy file, restoring backup", e);
1201                     mPolicyFile.failWrite(stream);
1202                 }
1203             }
1204             BackupManager.dataChanged(getContext().getPackageName());
1205         }
1206     }
1207 
writePolicyXml(OutputStream stream, boolean forBackup, int userId)1208     private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
1209             throws IOException {
1210         final TypedXmlSerializer out;
1211         if (forBackup) {
1212             out = Xml.newFastSerializer();
1213             out.setOutput(stream, StandardCharsets.UTF_8.name());
1214         } else {
1215             out = Xml.resolveSerializer(stream);
1216         }
1217         out.startDocument(null, true);
1218         out.startTag(null, TAG_NOTIFICATION_POLICY);
1219         out.attributeInt(null, ATTR_VERSION, DB_VERSION);
1220         mZenModeHelper.writeXml(out, forBackup, null, userId);
1221         mPreferencesHelper.writeXml(out, forBackup, userId);
1222         mListeners.writeXml(out, forBackup, userId);
1223         mAssistants.writeXml(out, forBackup, userId);
1224         mSnoozeHelper.writeXml(out);
1225         mConditionProviders.writeXml(out, forBackup, userId);
1226         if (!forBackup || userId == USER_SYSTEM) {
1227             writeSecureNotificationsPolicy(out);
1228         }
1229         out.endTag(null, TAG_NOTIFICATION_POLICY);
1230         out.endDocument();
1231     }
1232 
1233     @VisibleForTesting
1234     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
1235 
1236         @Override
1237         public void prepareForPossibleShutdown() {
1238             mHistoryManager.triggerWriteToDisk();
1239         }
1240 
1241         @Override
1242         public void onSetDisabled(int status) {
1243             synchronized (mNotificationLock) {
1244                 mAttentionHelper.updateDisableNotificationEffectsLocked(status);
1245             }
1246         }
1247 
1248         @Override
1249         public void onClearAll(int callingUid, int callingPid, int userId) {
1250             synchronized (mNotificationLock) {
1251                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
1252                         /*includeCurrentProfiles*/ true, FLAG_ONGOING_EVENT | FLAG_NO_CLEAR);
1253             }
1254         }
1255 
1256         @Override
1257         public void onNotificationClick(int callingUid, int callingPid, String key,
1258                 NotificationVisibility nv) {
1259             exitIdle();
1260             synchronized (mNotificationLock) {
1261                 NotificationRecord r = mNotificationsByKey.get(key);
1262                 if (r == null) {
1263                     Slog.w(TAG, "No notification with key: " + key);
1264                     return;
1265                 }
1266                 final long now = System.currentTimeMillis();
1267                 MetricsLogger.action(r.getItemLogMaker()
1268                         .setType(MetricsEvent.TYPE_ACTION)
1269                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
1270                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
1271                 mNotificationRecordLogger.log(
1272                         NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, r);
1273                 EventLogTags.writeNotificationClicked(key,
1274                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
1275                         nv.rank, nv.count);
1276 
1277                 StatusBarNotification sbn = r.getSbn();
1278                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
1279                         sbn.getId(), FLAG_AUTO_CANCEL,
1280                         FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_BUBBLE,
1281                         false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null);
1282                 nv.recycle();
1283                 reportUserInteraction(r);
1284                 mAssistants.notifyAssistantNotificationClicked(r);
1285             }
1286         }
1287 
1288         @Override
1289         public void onNotificationActionClick(int callingUid, int callingPid, String key,
1290                 int actionIndex, Notification.Action action, NotificationVisibility nv,
1291                 boolean generatedByAssistant) {
1292             exitIdle();
1293             synchronized (mNotificationLock) {
1294                 NotificationRecord r = mNotificationsByKey.get(key);
1295                 if (r == null) {
1296                     Slog.w(TAG, "No notification with key: " + key);
1297                     return;
1298                 }
1299                 final long now = System.currentTimeMillis();
1300                 MetricsLogger.action(r.getLogMaker(now)
1301                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
1302                         .setType(MetricsEvent.TYPE_ACTION)
1303                         .setSubtype(actionIndex)
1304                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
1305                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)
1306                         .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART,
1307                                 action.isContextual() ? 1 : 0)
1308                         .addTaggedData(
1309                                 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1310                                 generatedByAssistant ? 1 : 0)
1311                         .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
1312                                 nv.location.toMetricsEventEnum()));
1313                 mNotificationRecordLogger.log(
1314                         NotificationRecordLogger.NotificationEvent.fromAction(actionIndex,
1315                                 generatedByAssistant, action.isContextual()), r);
1316                 EventLogTags.writeNotificationActionClicked(key,
1317                         action.actionIntent.getTarget().toString(),
1318                         action.actionIntent.getIntent().toString(), actionIndex,
1319                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
1320                         nv.rank, nv.count);
1321                 nv.recycle();
1322                 reportUserInteraction(r);
1323                 mAssistants.notifyAssistantActionClicked(r, action, generatedByAssistant);
1324                 // Notifications that have been interacted with should no longer be lifetime
1325                 // extended.
1326                 if (lifetimeExtensionRefactor()) {
1327                     // This cancellation should only work if
1328                     // the notification still has FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY
1329                     // We wait for 200 milliseconds before posting the cancel, to allow the app
1330                     // time to update the notification in response instead.
1331                     // If that update goes through, the notification won't have the lifetime
1332                     // extended flag, and this cancellation will be dropped.
1333                     mHandler.scheduleCancelNotification(
1334                             new CancelNotificationRunnable(
1335                                     callingUid,
1336                                     callingPid,
1337                                     r.getSbn().getPackageName(),
1338                                     r.getSbn().getTag(),
1339                                     r.getSbn().getId(),
1340                                     FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY /*=mustHaveFlags*/,
1341                                     FLAG_NO_DISMISS /*=mustNotHaveFlags*/,
1342                                     false /*=sendDelete*/,
1343                                     r.getUserId(),
1344                                     REASON_CLICK,
1345                                     -1 /*=rank*/,
1346                                     -1 /*=count*/,
1347                                     null /*=listener*/,
1348                                     SystemClock.elapsedRealtime()),
1349                             200);
1350                 }
1351             }
1352         }
1353 
1354         @Override
1355         public void onNotificationClear(int callingUid, int callingPid,
1356                 String pkg, int userId, String key,
1357                 @NotificationStats.DismissalSurface int dismissalSurface,
1358                 @NotificationStats.DismissalSentiment int dismissalSentiment,
1359                 NotificationVisibility nv) {
1360             String tag = null;
1361             int id = 0;
1362             synchronized (mNotificationLock) {
1363                 NotificationRecord r = mNotificationsByKey.get(key);
1364                 if (r != null) {
1365                     r.recordDismissalSurface(dismissalSurface);
1366                     r.recordDismissalSentiment(dismissalSentiment);
1367                     tag = r.getSbn().getTag();
1368                     id = r.getSbn().getId();
1369                 }
1370             }
1371 
1372             int mustNotHaveFlags = FLAG_NO_DISMISS;
1373             cancelNotification(callingUid, callingPid, pkg, tag, id,
1374                     /* mustHaveFlags= */ 0,
1375                     /* mustNotHaveFlags= */ mustNotHaveFlags,
1376                     /* sendDelete= */ true,
1377                     userId, REASON_CANCEL, nv.rank, nv.count, /* listener= */ null);
1378             nv.recycle();
1379         }
1380 
1381         @Override
1382         public void onPanelRevealed(boolean clearEffects, int items) {
1383             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
1384             MetricsLogger.histogram(getContext(), "note_load", items);
1385             mNotificationRecordLogger.log(
1386                     NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN);
1387             EventLogTags.writeNotificationPanelRevealed(items);
1388             if (clearEffects) {
1389                 clearEffects();
1390             }
1391             mAssistants.onPanelRevealed(items);
1392         }
1393 
1394         @Override
1395         public void onPanelHidden() {
1396             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
1397             mNotificationRecordLogger.log(
1398                     NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE);
1399             EventLogTags.writeNotificationPanelHidden();
1400             mAssistants.onPanelHidden();
1401         }
1402 
1403         @Override
1404         public void clearEffects() {
1405             synchronized (mNotificationLock) {
1406                 if (DBG) Slog.d(TAG, "clearEffects");
1407                 mAttentionHelper.clearAttentionEffects();
1408             }
1409         }
1410 
1411         @Override
1412         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
1413                 int id, int uid, int initialPid, String message, int userId) {
1414             final boolean fgService;
1415             final boolean uiJob;
1416             synchronized (mNotificationLock) {
1417                 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
1418                 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
1419                 uiJob = r != null && (r.getNotification().flags & FLAG_USER_INITIATED_JOB) != 0;
1420             }
1421             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
1422                     REASON_ERROR, null);
1423             if (fgService || uiJob) {
1424                 // Still crash for foreground services or user-initiated jobs, preventing the
1425                 // not-crash behaviour abused by apps to give us a garbage notification and
1426                 // silently start a fg service or user-initiated job.
1427                 final int exceptionTypeId = fgService
1428                         ? BadForegroundServiceNotificationException.TYPE_ID
1429                         : BadUserInitiatedJobNotificationException.TYPE_ID;
1430                 Binder.withCleanCallingIdentity(
1431                         () -> mAm.crashApplicationWithType(uid, initialPid, pkg, -1,
1432                             "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
1433                                 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
1434                                 + message, true /* force */, exceptionTypeId));
1435             }
1436         }
1437 
1438         @Override
1439         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
1440                 NotificationVisibility[] noLongerVisibleKeys) {
1441             synchronized (mNotificationLock) {
1442                 for (NotificationVisibility nv : newlyVisibleKeys) {
1443                     NotificationRecord r = mNotificationsByKey.get(nv.key);
1444                     if (r == null) continue;
1445                     if (!r.isSeen()) {
1446                         // Report to usage stats that notification was made visible
1447                         if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
1448                         reportSeen(r);
1449                     }
1450                     r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger);
1451                     mAssistants.notifyAssistantVisibilityChangedLocked(r, true);
1452                     boolean isHun = (nv.location
1453                             == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
1454                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
1455                     // the NotificationRecord to ensure the expansion state is up-to-date.
1456                     if (isHun || r.hasBeenVisiblyExpanded()) {
1457                         logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
1458                     }
1459                     maybeRecordInterruptionLocked(r);
1460                     nv.recycle();
1461                 }
1462                 // Note that we might receive this event after notifications
1463                 // have already left the system, e.g. after dismissing from the
1464                 // shade. Hence not finding notifications in
1465                 // mNotificationsByKey is not an exceptional condition.
1466                 for (NotificationVisibility nv : noLongerVisibleKeys) {
1467                     NotificationRecord r = mNotificationsByKey.get(nv.key);
1468                     if (r == null) continue;
1469                     r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger);
1470                     mAssistants.notifyAssistantVisibilityChangedLocked(r, false);
1471                     nv.recycle();
1472                 }
1473             }
1474         }
1475 
1476         @Override
1477         public void onNotificationExpansionChanged(String key,
1478                 boolean userAction, boolean expanded, int notificationLocation) {
1479             synchronized (mNotificationLock) {
1480                 NotificationRecord r = mNotificationsByKey.get(key);
1481                 if (r != null) {
1482                     r.stats.onExpansionChanged(userAction, expanded);
1483                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
1484                     // the NotificationRecord to ensure the expansion state is up-to-date.
1485                     if (r.hasBeenVisiblyExpanded()) {
1486                         logSmartSuggestionsVisible(r, notificationLocation);
1487                     }
1488                     if (userAction) {
1489                         MetricsLogger.action(r.getItemLogMaker()
1490                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
1491                                         : MetricsEvent.TYPE_COLLAPSE));
1492                         mNotificationRecordLogger.log(
1493                                 NotificationRecordLogger.NotificationEvent.fromExpanded(expanded,
1494                                         userAction),
1495                                 r);
1496                     }
1497                     if (expanded && userAction) {
1498                         r.recordExpanded();
1499                         reportUserInteraction(r);
1500                     }
1501                     mAssistants.notifyAssistantExpansionChangedLocked(
1502                             r.getSbn(), r.getNotificationType(), userAction, expanded);
1503                 }
1504             }
1505         }
1506 
1507         @Override
1508         public void onNotificationDirectReplied(String key) {
1509             exitIdle();
1510             String packageName = null;
1511             final int packageImportance;
1512             synchronized (mNotificationLock) {
1513                 NotificationRecord r = mNotificationsByKey.get(key);
1514                 if (r != null) {
1515                     packageName = r.getSbn().getPackageName();
1516                 }
1517             }
1518             if (lifetimeExtensionRefactor() && packageName != null) {
1519                 packageImportance = getPackageImportanceWithIdentity(packageName);
1520             } else {
1521                 packageImportance = IMPORTANCE_NONE;
1522             }
1523             synchronized (mNotificationLock) {
1524                 NotificationRecord r = mNotificationsByKey.get(key);
1525                 if (r != null) {
1526                     // If the notification is already marked as lifetime extended before we record
1527                     // the new direct reply, there must have been a previous lifetime extension
1528                     // event, and the app has already cancelled the notification, or does not
1529                     // respond to direct replies with updates. So we need to update System UI
1530                     // immediately.
1531                     if (lifetimeExtensionRefactor()) {
1532                         maybeNotifySystemUiListenerLifetimeExtendedLocked(r,
1533                                 r.getSbn().getPackageName(), packageImportance);
1534                     }
1535 
1536                     r.recordDirectReplied();
1537                     mMetricsLogger.write(r.getLogMaker()
1538                             .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
1539                             .setType(MetricsEvent.TYPE_ACTION));
1540                     mNotificationRecordLogger.log(
1541                             NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
1542                             r);
1543                     reportUserInteraction(r);
1544                     mAssistants.notifyAssistantNotificationDirectReplyLocked(r);
1545                 }
1546             }
1547         }
1548 
1549         @Override
1550         public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
1551                 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
1552             synchronized (mNotificationLock) {
1553                 NotificationRecord r = mNotificationsByKey.get(key);
1554                 if (r != null) {
1555                     r.setNumSmartRepliesAdded(smartReplyCount);
1556                     r.setNumSmartActionsAdded(smartActionCount);
1557                     r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
1558                     r.setEditChoicesBeforeSending(editBeforeSending);
1559                 }
1560             }
1561         }
1562 
1563         @Override
1564         public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
1565                 int notificationLocation, boolean modifiedBeforeSending) {
1566             String packageName = null;
1567             final int packageImportance;
1568             synchronized (mNotificationLock) {
1569                 NotificationRecord r = mNotificationsByKey.get(key);
1570                 if (r != null) {
1571                     packageName = r.getSbn().getPackageName();
1572                 }
1573             }
1574             if (lifetimeExtensionRefactor() && packageName != null) {
1575                 packageImportance = getPackageImportanceWithIdentity(packageName);
1576             } else {
1577                 packageImportance = IMPORTANCE_NONE;
1578             }
1579             synchronized (mNotificationLock) {
1580                 NotificationRecord r = mNotificationsByKey.get(key);
1581                 if (r != null) {
1582                     // If the notification is already marked as lifetime extended before we record
1583                     // the new direct reply, there must have been a previous lifetime extension
1584                     // event, and the app has already cancelled the notification, or does not
1585                     // respond to direct replies with updates. So we need to update System UI
1586                     // immediately.
1587                     if (lifetimeExtensionRefactor()) {
1588                         maybeNotifySystemUiListenerLifetimeExtendedLocked(r,
1589                                 r.getSbn().getPackageName(), packageImportance);
1590                     }
1591                     r.recordSmartReplied();
1592                     LogMaker logMaker = r.getLogMaker()
1593                             .setCategory(MetricsEvent.SMART_REPLY_ACTION)
1594                             .setSubtype(replyIndex)
1595                             .addTaggedData(
1596                                     MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1597                                     r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1598                             .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
1599                                     notificationLocation)
1600                             .addTaggedData(
1601                                     MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1602                                     r.getEditChoicesBeforeSending() ? 1 : 0)
1603                             .addTaggedData(
1604                                     MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
1605                                     modifiedBeforeSending ? 1 : 0);
1606                     mMetricsLogger.write(logMaker);
1607                     mNotificationRecordLogger.log(
1608                             NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
1609                             r);
1610                     // Treat clicking on a smart reply as a user interaction.
1611                     reportUserInteraction(r);
1612                     mAssistants.notifyAssistantSuggestedReplySent(
1613                             r.getSbn(), r.getNotificationType(), reply,
1614                             r.getSuggestionsGeneratedByAssistant());
1615                 }
1616             }
1617         }
1618 
1619         @Override
1620         public void onNotificationSettingsViewed(String key) {
1621             synchronized (mNotificationLock) {
1622                 NotificationRecord r = mNotificationsByKey.get(key);
1623                 if (r != null) {
1624                     r.recordViewedSettings();
1625                 }
1626             }
1627         }
1628 
1629         @Override
1630         public void onNotificationBubbleChanged(String key, boolean isBubble, int bubbleFlags) {
1631             synchronized (mNotificationLock) {
1632                 NotificationRecord r = mNotificationsByKey.get(key);
1633                 if (r != null) {
1634                     if (!isBubble) {
1635                         // This happens if the user has dismissed the bubble but the notification
1636                         // is still active in the shade, enqueuing would create a bubble since
1637                         // the notification is technically allowed. Flip the flag so that
1638                         // apps querying noMan will know that their notification is not showing
1639                         // as a bubble.
1640                         r.getNotification().flags &= ~FLAG_BUBBLE;
1641                         r.setFlagBubbleRemoved(true);
1642                     } else {
1643                         // Enqueue will trigger resort & if the flag is allowed to be true it'll
1644                         // be applied there.
1645                         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
1646                         r.setFlagBubbleRemoved(false);
1647                         if (r.getNotification().getBubbleMetadata() != null) {
1648                             r.getNotification().getBubbleMetadata().setFlags(bubbleFlags);
1649                         }
1650                         // Force isAppForeground true here, because for sysui's purposes we
1651                         // want to adjust the flag behaviour.
1652                         mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(),
1653                                 r, true /* isAppForeground*/,
1654                                 mPostNotificationTrackerFactory.newTracker(null)));
1655                     }
1656                 }
1657             }
1658         }
1659 
1660         @Override
1661         public void onBubbleMetadataFlagChanged(String key, int flags) {
1662             synchronized (mNotificationLock) {
1663                 NotificationRecord r = mNotificationsByKey.get(key);
1664                 if (r != null) {
1665                     Notification.BubbleMetadata data = r.getNotification().getBubbleMetadata();
1666                     if (data == null) {
1667                         // No data, do nothing
1668                         return;
1669                     }
1670 
1671                     if (flags != data.getFlags()) {
1672                         int changedFlags = data.getFlags() ^ flags;
1673                         if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) {
1674                             // Suppress notification flag changed, clear any effects
1675                             mAttentionHelper.clearEffectsLocked(key);
1676                         }
1677                         data.setFlags(flags);
1678                         // Shouldn't alert again just because of a flag change.
1679                         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
1680                         // Force isAppForeground true here, because for sysui's purposes we
1681                         // want to be able to adjust the flag behaviour.
1682                         mHandler.post(
1683                                 new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r,
1684                                         /* foreground= */ true,
1685                                         mPostNotificationTrackerFactory.newTracker(null)));
1686                     }
1687                 }
1688             }
1689         }
1690 
1691         /**
1692          * Grant permission to read the specified URI to the package specified in the
1693          * NotificationRecord associated with the given key. The callingUid represents the UID of
1694          * SystemUI from which this method is being called.
1695          *
1696          * For this to work, SystemUI must have permission to read the URI when running under the
1697          * user associated with the NotificationRecord, and this grant will fail when trying
1698          * to grant URI permissions across users.
1699          */
1700         @Override
1701         public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
1702                 String packageName, int callingUid) {
1703             synchronized (mNotificationLock) {
1704                 InlineReplyUriRecord r = mInlineReplyRecordsByKey.get(key);
1705                 if (r == null) {
1706                     InlineReplyUriRecord newRecord = new InlineReplyUriRecord(
1707                             mUgmInternal.newUriPermissionOwner("INLINE_REPLY:" + key),
1708                             user,
1709                             packageName,
1710                             key);
1711                     r = newRecord;
1712                     mInlineReplyRecordsByKey.put(key, r);
1713                 }
1714                 IBinder owner = r.getPermissionOwner();
1715                 int uid = callingUid;
1716                 int userId = r.getUserId();
1717                 if (UserHandle.getUserId(uid) != userId) {
1718                     try {
1719                         final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
1720                         if (pkgs == null) {
1721                             Log.e(TAG, "Cannot grant uri permission to unknown UID: "
1722                                     + callingUid);
1723                         }
1724                         final String pkg = pkgs[0]; // Get the SystemUI package
1725                         // Find the UID for SystemUI for the correct user
1726                         uid =  mPackageManager.getPackageUid(pkg, 0, userId);
1727                     } catch (RemoteException re) {
1728                         Log.e(TAG, "Cannot talk to package manager", re);
1729                     }
1730                 }
1731                 r.addUri(uri);
1732                 grantUriPermission(owner, uri, uid, r.getPackageName(), userId);
1733             }
1734         }
1735 
1736         @Override
1737         /**
1738          * Clears inline URI permission grants by destroying the permission owner for the specified
1739          * notification.
1740          */
1741         public void clearInlineReplyUriPermissions(String key, int callingUid) {
1742             synchronized (mNotificationLock) {
1743                 InlineReplyUriRecord uriRecord = mInlineReplyRecordsByKey.get(key);
1744                 if (uriRecord != null) {
1745                     destroyPermissionOwner(uriRecord.getPermissionOwner(), uriRecord.getUserId(),
1746                             "INLINE_REPLY: " + uriRecord.getKey());
1747                     mInlineReplyRecordsByKey.remove(key);
1748                 }
1749             }
1750         }
1751 
1752         @Override
1753         public void onNotificationFeedbackReceived(String key, Bundle feedback) {
1754             exitIdle();
1755             synchronized (mNotificationLock) {
1756                 NotificationRecord r = mNotificationsByKey.get(key);
1757                 if (r == null) {
1758                     if (DBG) Slog.w(TAG, "No notification with key: " + key);
1759                     return;
1760                 }
1761                 mAssistants.notifyAssistantFeedbackReceived(r, feedback);
1762             }
1763         }
1764 
1765     };
1766 
1767     NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() {
1768         @Nullable
1769         @Override
1770         public NotificationRecord getNotificationByKey(String key) {
1771             synchronized (mNotificationLock) {
1772                 return mNotificationsByKey.get(key);
1773             }
1774         }
1775 
1776         @Override
1777         @FlaggedApi(Flags.FLAG_ALL_NOTIFS_NEED_TTL)
1778         public void timeoutNotification(String key) {
1779             boolean foundNotification = false;
1780             int uid = 0;
1781             int pid = 0;
1782             String packageName = null;
1783             String tag = null;
1784             int id = 0;
1785             int userId = 0;
1786 
1787             synchronized (mNotificationLock) {
1788                 NotificationRecord record = findNotificationByKeyLocked(key);
1789                 if (record != null) {
1790                     foundNotification = true;
1791                     uid = record.getUid();
1792                     pid = record.getSbn().getInitialPid();
1793                     packageName = record.getSbn().getPackageName();
1794                     tag = record.getSbn().getTag();
1795                     id = record.getSbn().getId();
1796                     userId = record.getUserId();
1797                 }
1798             }
1799             if (foundNotification) {
1800                 if (lifetimeExtensionRefactor()) {
1801                     cancelNotification(uid, pid, packageName, tag, id, 0,
1802                             FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
1803                                     | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
1804                             true, userId, REASON_TIMEOUT, null);
1805                 } else {
1806                     cancelNotification(uid, pid, packageName, tag, id, 0,
1807                             FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
1808                             true, userId, REASON_TIMEOUT, null);
1809                 }
1810             }
1811         }
1812     };
1813 
1814     @VisibleForTesting
logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)1815     void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
1816         // If the newly visible notification has smart suggestions
1817         // then log that the user has seen them.
1818         if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
1819                 && !r.hasSeenSmartReplies()) {
1820             r.setSeenSmartReplies(true);
1821             LogMaker logMaker = r.getLogMaker()
1822                     .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
1823                     .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
1824                             r.getNumSmartRepliesAdded())
1825                     .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
1826                             r.getNumSmartActionsAdded())
1827                     .addTaggedData(
1828                             MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1829                             r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1830                     // The fields in the NotificationVisibility.NotificationLocation enum map
1831                     // directly to the fields in the MetricsEvent.NotificationLocation enum.
1832                     .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
1833                     .addTaggedData(
1834                             MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1835                             r.getEditChoicesBeforeSending() ? 1 : 0);
1836             mMetricsLogger.write(logMaker);
1837             mNotificationRecordLogger.log(
1838                     NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLY_VISIBLE,
1839                     r);
1840         }
1841     }
1842 
logSensitiveAdjustmentReceived(boolean hasPosted, boolean hasSensitiveContent, int lifespanMs)1843     protected void logSensitiveAdjustmentReceived(boolean hasPosted,
1844             boolean hasSensitiveContent, int lifespanMs) {
1845         FrameworkStatsLog.write(FrameworkStatsLog.SENSITIVE_NOTIFICATION_REDACTION, hasPosted,
1846                 hasSensitiveContent, lifespanMs);
1847     }
1848 
1849     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
1850         @Override
1851         public void onReceive(Context context, Intent intent) {
1852             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
1853                 // update system notification channels
1854                 SystemNotificationChannels.createAll(context);
1855                 mZenModeHelper.updateZenRulesOnLocaleChange();
1856                 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
1857             }
1858         }
1859     };
1860 
1861     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
1862         @Override
1863         public void onReceive(Context context, Intent intent) {
1864             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
1865                 try {
1866                     String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
1867                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
1868                     int restoredFromSdkInt = intent.getIntExtra(
1869                             Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
1870                     mListeners.onSettingRestored(
1871                             element, newValue, restoredFromSdkInt, getSendingUserId());
1872                     mConditionProviders.onSettingRestored(
1873                             element, newValue, restoredFromSdkInt, getSendingUserId());
1874                 } catch (Exception e) {
1875                     Slog.wtf(TAG, "Cannot restore managed services from settings", e);
1876                 }
1877             }
1878         }
1879     };
1880 
1881     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
1882         @Override
1883         public void onReceive(Context context, Intent intent) {
1884             String action = intent.getAction();
1885             if (action == null) {
1886                 return;
1887             }
1888             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
1889                 final NotificationRecord record;
1890                 // TODO: b/323013410 - Record should be cloned instead of used directly.
1891                 synchronized (mNotificationLock) {
1892                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
1893                 }
1894                 if (record != null) {
1895                     if (lifetimeExtensionRefactor()) {
1896                         cancelNotification(record.getSbn().getUid(),
1897                                 record.getSbn().getInitialPid(),
1898                                 record.getSbn().getPackageName(), record.getSbn().getTag(),
1899                                 record.getSbn().getId(), 0,
1900                                 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
1901                                         | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
1902                                 true, record.getUserId(), REASON_TIMEOUT, null);
1903                     } else {
1904                         cancelNotification(record.getSbn().getUid(),
1905                                 record.getSbn().getInitialPid(),
1906                                 record.getSbn().getPackageName(), record.getSbn().getTag(),
1907                                 record.getSbn().getId(), 0,
1908                                 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
1909                                 true, record.getUserId(), REASON_TIMEOUT, null);
1910                     }
1911                 }
1912             }
1913         }
1914     };
1915 
1916     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
1917         @Override
1918         public void onReceive(Context context, Intent intent) {
1919             String action = intent.getAction();
1920             if (action == null) {
1921                 return;
1922             }
1923 
1924             boolean queryRemove = false;
1925             boolean packageChanged = false;
1926             boolean cancelNotifications = true;
1927             boolean hideNotifications = false;
1928             boolean unhideNotifications = false;
1929             int reason = REASON_PACKAGE_CHANGED;
1930 
1931             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
1932                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
1933                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
1934                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
1935                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
1936                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1937                     || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
1938                     || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1939                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1940                         USER_ALL);
1941                 String pkgList[] = null;
1942                 int uidList[] = null;
1943                 boolean removingPackage = queryRemove &&
1944                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1945                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
1946                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1947                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1948                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1949                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1950                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1951                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1952                     cancelNotifications = false;
1953                     hideNotifications = true;
1954                 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1955                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1956                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1957                     cancelNotifications = false;
1958                     unhideNotifications = true;
1959                 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1960                     final int distractionRestrictions =
1961                             intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
1962                                     PackageManager.RESTRICTION_NONE);
1963                     if ((distractionRestrictions
1964                             & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
1965                         pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1966                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1967                         cancelNotifications = false;
1968                         hideNotifications = true;
1969                     } else {
1970                         pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1971                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1972                         cancelNotifications = false;
1973                         unhideNotifications = true;
1974                     }
1975                 } else {
1976                     Uri uri = intent.getData();
1977                     if (uri == null) {
1978                         return;
1979                     }
1980                     String pkgName = uri.getSchemeSpecificPart();
1981                     if (pkgName == null) {
1982                         return;
1983                     }
1984                     if (packageChanged) {
1985                         // We cancel notifications for packages which have just been disabled
1986                         try {
1987                             final int enabled = mPackageManager.getApplicationEnabledSetting(
1988                                     pkgName,
1989                                     changeUserId != USER_ALL ? changeUserId :
1990                                             USER_SYSTEM);
1991                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1992                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1993                                 cancelNotifications = false;
1994                             }
1995                         } catch (IllegalArgumentException e) {
1996                             // Package doesn't exist; probably racing with uninstall.
1997                             // cancelNotifications is already true, so nothing to do here.
1998                             if (DBG) {
1999                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
2000                             }
2001                         } catch (RemoteException e) {
2002                             // Failed to talk to PackageManagerService Should never happen!
2003                         }
2004                     }
2005                     pkgList = new String[]{pkgName};
2006                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
2007                 }
2008                 if (pkgList != null && (pkgList.length > 0)) {
2009                     if (cancelNotifications) {
2010                         for (String pkgName : pkgList) {
2011                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
2012                                     changeUserId, reason);
2013                         }
2014                     } else if (hideNotifications && uidList != null && (uidList.length > 0)) {
2015                         hideNotificationsForPackages(pkgList, uidList);
2016                     } else if (unhideNotifications && uidList != null && (uidList.length > 0)) {
2017                         unhideNotificationsForPackages(pkgList, uidList);
2018                     }
2019                 }
2020                 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
2021             }
2022         }
2023     };
2024 
2025     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
2026         @Override
2027         public void onReceive(Context context, Intent intent) {
2028             String action = intent.getAction();
2029 
2030             if (action.equals(Intent.ACTION_USER_STOPPED)) {
2031                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
2032                 if (userHandle >= 0) {
2033                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
2034                             REASON_USER_STOPPED);
2035                 }
2036             } else if (
2037                     isProfileUnavailable(action)) {
2038                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
2039                 if (userHandle >= 0) {
2040                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
2041                             REASON_PROFILE_TURNED_OFF);
2042                     mSnoozeHelper.clearData(userHandle);
2043                 }
2044             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
2045                 if (!Flags.useSsmUserSwitchSignal()) {
2046                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2047                     mUserProfiles.updateCache(context);
2048                     if (!mUserProfiles.isProfileUser(userId, context)) {
2049                         // reload per-user settings
2050                         mSettingsObserver.update(null);
2051                         // Refresh managed services
2052                         mConditionProviders.onUserSwitched(userId);
2053                         mListeners.onUserSwitched(userId);
2054                         mZenModeHelper.onUserSwitched(userId);
2055                         mPreferencesHelper.syncChannelsBypassingDnd();
2056                     }
2057                     // assistant is the only thing that cares about managed profiles specifically
2058                     mAssistants.onUserSwitched(userId);
2059                 }
2060             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
2061                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2062                 if (userId != USER_NULL) {
2063                     mUserProfiles.updateCache(context);
2064                     if (!mUserProfiles.isProfileUser(userId, context)) {
2065                         allowDefaultApprovedServices(userId);
2066                     }
2067                     mHistoryManager.onUserAdded(userId);
2068                     mSettingsObserver.update(null, userId);
2069                 }
2070             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
2071                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2072                 mUserProfiles.updateCache(context);
2073                 mZenModeHelper.onUserRemoved(userId);
2074                 mPreferencesHelper.onUserRemoved(userId);
2075                 mListeners.onUserRemoved(userId);
2076                 mConditionProviders.onUserRemoved(userId);
2077                 mAssistants.onUserRemoved(userId);
2078                 mHistoryManager.onUserRemoved(userId);
2079                 mPreferencesHelper.syncChannelsBypassingDnd();
2080                 handleSavePolicyFile();
2081             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
2082                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2083                 mUserProfiles.updateCache(context);
2084                 mAssistants.onUserUnlocked(userId);
2085                 if (!mUserProfiles.isProfileUser(userId, context)) {
2086                     mConditionProviders.onUserUnlocked(userId);
2087                     mListeners.onUserUnlocked(userId);
2088                     if (!android.app.Flags.modesApi()) {
2089                         mZenModeHelper.onUserUnlocked(userId);
2090                     }
2091                 }
2092             }
2093         }
2094 
2095         private boolean isProfileUnavailable(String action) {
2096             return privateSpaceFlagsEnabled() ?
2097                     action.equals(Intent.ACTION_PROFILE_UNAVAILABLE) :
2098                     action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
2099         }
2100     };
2101 
2102     private final class SettingsObserver extends ContentObserver {
2103         private final Uri NOTIFICATION_BADGING_URI
2104                 = Secure.getUriFor(Secure.NOTIFICATION_BADGING);
2105         private final Uri NOTIFICATION_BUBBLES_URI
2106                 = Secure.getUriFor(Secure.NOTIFICATION_BUBBLES);
2107         private final Uri NOTIFICATION_RATE_LIMIT_URI
2108                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
2109         private final Uri NOTIFICATION_HISTORY_ENABLED
2110                 = Secure.getUriFor(Secure.NOTIFICATION_HISTORY_ENABLED);
2111         private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI
2112                 = Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS);
2113         private final Uri LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
2114                 = Secure.getUriFor(
2115                         Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
2116         private final Uri LOCK_SCREEN_SHOW_NOTIFICATIONS
2117                 = Secure.getUriFor(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
2118         private final Uri SHOW_NOTIFICATION_SNOOZE
2119                 = Secure.getUriFor(Secure.SHOW_NOTIFICATION_SNOOZE);
2120 
SettingsObserver(Handler handler)2121         SettingsObserver(Handler handler) {
2122             super(handler);
2123         }
2124 
observe()2125         void observe() {
2126             ContentResolver resolver = getContext().getContentResolver();
2127             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
2128                     false, this, USER_ALL);
2129             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
2130                     false, this, USER_ALL);
2131             resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
2132                     false, this, USER_ALL);
2133             resolver.registerContentObserver(NOTIFICATION_HISTORY_ENABLED,
2134                     false, this, USER_ALL);
2135             resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI,
2136                     false, this, USER_ALL);
2137 
2138             resolver.registerContentObserver(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
2139                     false, this, USER_ALL);
2140             resolver.registerContentObserver(LOCK_SCREEN_SHOW_NOTIFICATIONS,
2141                     false, this, USER_ALL);
2142 
2143             resolver.registerContentObserver(SHOW_NOTIFICATION_SNOOZE,
2144                     false, this, USER_ALL);
2145 
2146             update(null);
2147         }
2148 
destroy()2149         void destroy() {
2150             getContext().getContentResolver().unregisterContentObserver(this);
2151         }
2152 
onChange(boolean selfChange, Uri uri, int userId)2153         @Override public void onChange(boolean selfChange, Uri uri, int userId) {
2154             update(uri);
2155         }
2156 
update(Uri uri)2157         public void update(Uri uri) {
2158             ContentResolver resolver = getContext().getContentResolver();
2159             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
2160                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
2161                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
2162             }
2163             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
2164                 mPreferencesHelper.updateBadgingEnabled();
2165             }
2166             if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
2167                 mPreferencesHelper.updateBubblesEnabled();
2168             }
2169             if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) {
2170                 for (UserInfo userInfo : mUm.getUsers()) {
2171                     update(uri, userInfo.id);
2172                 }
2173             }
2174             if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) {
2175                 mPreferencesHelper.updateMediaNotificationFilteringEnabled();
2176             }
2177             if (uri == null || LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS.equals(uri)) {
2178                 mPreferencesHelper.updateLockScreenPrivateNotifications();
2179             }
2180             if (uri == null || LOCK_SCREEN_SHOW_NOTIFICATIONS.equals(uri)) {
2181                 mPreferencesHelper.updateLockScreenShowNotifications();
2182             }
2183             if (SHOW_NOTIFICATION_SNOOZE.equals(uri)) {
2184                 final boolean snoozeEnabled = Secure.getIntForUser(resolver,
2185                         Secure.SHOW_NOTIFICATION_SNOOZE, 0, UserHandle.USER_CURRENT)
2186                         != 0;
2187                 if (!snoozeEnabled) {
2188                     unsnoozeAll();
2189                 }
2190             }
2191         }
2192 
update(Uri uri, int userId)2193         public void update(Uri uri, int userId) {
2194             ContentResolver resolver = getContext().getContentResolver();
2195             if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) {
2196                 mArchive.updateHistoryEnabled(userId,
2197                         Secure.getIntForUser(resolver,
2198                                 Secure.NOTIFICATION_HISTORY_ENABLED, 0,
2199                                 userId) == 1);
2200                 // note: this setting is also handled in NotificationHistoryManager
2201             }
2202         }
2203     }
2204 
2205     private SettingsObserver mSettingsObserver;
2206     protected ZenModeHelper mZenModeHelper;
2207 
2208     protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
2209 
2210         SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray();
2211 
StrongAuthTracker(Context context)2212         StrongAuthTracker(Context context) {
2213             super(context);
2214         }
2215 
containsFlag(int haystack, int needle)2216         private boolean containsFlag(int haystack, int needle) {
2217             return (haystack & needle) != 0;
2218         }
2219 
2220         // Return whether the user is in lockdown mode.
2221         // If the flag is not set, we assume the user is not in lockdown.
isInLockDownMode(int userId)2222         public boolean isInLockDownMode(int userId) {
2223             return mUserInLockDownMode.get(userId, false);
2224         }
2225 
2226         @Override
onStrongAuthRequiredChanged(int userId)2227         public synchronized void onStrongAuthRequiredChanged(int userId) {
2228             boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
2229                     STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
2230 
2231             // Nothing happens if the lockdown mode of userId keeps the same.
2232             if (userInLockDownModeNext == isInLockDownMode(userId)) {
2233                 return;
2234             }
2235 
2236             // When the lockdown mode is changed, we perform the following steps.
2237             // If the userInLockDownModeNext is true, all the function calls to
2238             // notifyPostedLocked and notifyRemovedLocked will not be executed.
2239             // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked
2240             // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked.
2241             // So we shall call cancelNotificationsWhenEnterLockDownMode before
2242             // we set mUserInLockDownMode as true.
2243             // On the other hand, if the userInLockDownModeNext is false, we shall call
2244             // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode
2245             if (userInLockDownModeNext) {
2246                 cancelNotificationsWhenEnterLockDownMode(userId);
2247             }
2248 
2249             mUserInLockDownMode.put(userId, userInLockDownModeNext);
2250 
2251             if (!userInLockDownModeNext) {
2252                 postNotificationsWhenExitLockDownMode(userId);
2253             }
2254         }
2255     }
2256 
2257     private StrongAuthTracker mStrongAuthTracker;
2258 
NotificationManagerService(Context context)2259     public NotificationManagerService(Context context) {
2260         this(context,
2261                 new NotificationRecordLoggerImpl(),
2262                 new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX));
2263     }
2264 
2265     @VisibleForTesting
NotificationManagerService(Context context, NotificationRecordLogger notificationRecordLogger, InstanceIdSequence notificationInstanceIdSequence)2266     public NotificationManagerService(Context context,
2267             NotificationRecordLogger notificationRecordLogger,
2268             InstanceIdSequence notificationInstanceIdSequence) {
2269         super(context);
2270         mNotificationRecordLogger = notificationRecordLogger;
2271         mNotificationInstanceIdSequence = notificationInstanceIdSequence;
2272         Notification.processAllowlistToken = ALLOWLIST_TOKEN;
2273     }
2274 
2275     // TODO - replace these methods with new fields in the VisibleForTesting constructor
2276     @VisibleForTesting
setStrongAuthTracker(StrongAuthTracker strongAuthTracker)2277     void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
2278         mStrongAuthTracker = strongAuthTracker;
2279     }
2280 
2281     @VisibleForTesting
setLockPatternUtils(LockPatternUtils lockUtils)2282     void setLockPatternUtils(LockPatternUtils lockUtils) {
2283         mLockUtils = lockUtils;
2284     }
2285 
2286     @VisibleForTesting
getShortcutHelper()2287     ShortcutHelper getShortcutHelper() {
2288         return mShortcutHelper;
2289     }
2290 
2291     @VisibleForTesting
setShortcutHelper(ShortcutHelper helper)2292     void setShortcutHelper(ShortcutHelper helper) {
2293         mShortcutHelper = helper;
2294     }
2295 
2296     @VisibleForTesting
getNotificationRecordCount()2297     int getNotificationRecordCount() {
2298         synchronized (mNotificationLock) {
2299             int count = mNotificationList.size() + mNotificationsByKey.size()
2300                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
2301             // subtract duplicates
2302             for (NotificationRecord posted : mNotificationList) {
2303                 if (mNotificationsByKey.containsKey(posted.getKey())) {
2304                     count--;
2305                 }
2306                 if (posted.getSbn().isGroup() && posted.getNotification().isGroupSummary()) {
2307                     count--;
2308                 }
2309             }
2310 
2311             return count;
2312         }
2313     }
2314 
2315     @VisibleForTesting
clearNotifications()2316     void clearNotifications() {
2317         synchronized (mNotificationLock) {
2318             mEnqueuedNotifications.clear();
2319             mNotificationList.clear();
2320             mNotificationsByKey.clear();
2321             mSummaryByGroupKey.clear();
2322         }
2323     }
2324 
2325     @VisibleForTesting
addNotification(NotificationRecord r)2326     void addNotification(NotificationRecord r) {
2327         synchronized (mNotificationLock) {
2328             mNotificationList.add(r);
2329             mNotificationsByKey.put(r.getSbn().getKey(), r);
2330             if (r.getSbn().isGroup()) {
2331                 mSummaryByGroupKey.put(r.getGroupKey(), r);
2332             }
2333         }
2334     }
2335 
2336     @VisibleForTesting
addEnqueuedNotification(NotificationRecord r)2337     void addEnqueuedNotification(NotificationRecord r) {
2338         synchronized (mNotificationLock) {
2339             mEnqueuedNotifications.add(r);
2340         }
2341     }
2342 
2343     @VisibleForTesting
getNotificationRecord(String key)2344     NotificationRecord getNotificationRecord(String key) {
2345         synchronized (mNotificationLock) {
2346             return mNotificationsByKey.get(key);
2347         }
2348     }
2349 
2350     @VisibleForTesting
setHandler(WorkerHandler handler)2351     void setHandler(WorkerHandler handler) {
2352         mHandler = handler;
2353     }
2354 
2355     @VisibleForTesting
setRankingHelper(RankingHelper rankingHelper)2356     void setRankingHelper(RankingHelper rankingHelper) {
2357         mRankingHelper = rankingHelper;
2358     }
2359 
2360     @VisibleForTesting
setPreferencesHelper(PreferencesHelper prefHelper)2361     void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
2362 
2363     @VisibleForTesting
setZenHelper(ZenModeHelper zenHelper)2364     void setZenHelper(ZenModeHelper zenHelper) {
2365         mZenModeHelper = zenHelper;
2366     }
2367 
2368     @VisibleForTesting
setAttentionHelper(NotificationAttentionHelper nah)2369     void setAttentionHelper(NotificationAttentionHelper nah) {
2370         mAttentionHelper = nah;
2371     }
2372 
2373     @VisibleForTesting
setIsTelevision(boolean isTelevision)2374     void setIsTelevision(boolean isTelevision) {
2375         mIsTelevision = isTelevision;
2376     }
2377 
2378     @VisibleForTesting
setTelecomManager(TelecomManager tm)2379     void setTelecomManager(TelecomManager tm) {
2380         mTelecomManager = tm;
2381     }
2382 
2383     // TODO: All tests should use this init instead of the one-off setters above.
2384     @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, ActivityManagerInternal ami, MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper, UsageStatsManagerInternal usageStatsManagerInternal, TelecomManager telecomManager, NotificationChannelLogger channelLogger, SystemUiSystemPropertiesFlags.FlagResolver flagResolver, PermissionManager permissionManager, PowerManager powerManager, PostNotificationTrackerFactory postNotificationTrackerFactory)2385     void init(WorkerHandler handler, RankingHandler rankingHandler,
2386             IPackageManager packageManager, PackageManager packageManagerClient,
2387             LightsManager lightsManager, NotificationListeners notificationListeners,
2388             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
2389             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
2390             NotificationUsageStats usageStats, AtomicFile policyFile,
2391             ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
2392             ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats,
2393             DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
2394             UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
2395             NotificationHistoryManager historyManager, StatsManager statsManager,
2396             ActivityManagerInternal ami,
2397             MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
2398             UsageStatsManagerInternal usageStatsManagerInternal,
2399             TelecomManager telecomManager, NotificationChannelLogger channelLogger,
2400             SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
2401             PermissionManager permissionManager, PowerManager powerManager,
2402             PostNotificationTrackerFactory postNotificationTrackerFactory) {
2403         mHandler = handler;
2404         Resources resources = getContext().getResources();
2405         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
2406                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
2407                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
2408 
2409         mAccessibilityManager =
2410                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2411         mAm = am;
2412         mAtm = atm;
2413         mAtm.setBackgroundActivityStartCallback(new NotificationTrampolineCallback());
2414         mUgm = ugm;
2415         mUgmInternal = ugmInternal;
2416         mPackageManager = packageManager;
2417         mPackageManagerClient = packageManagerClient;
2418         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
2419         mPermissionManager = permissionManager;
2420         mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
2421         mUmInternal = LocalServices.getService(UserManagerInternal.class);
2422         mUsageStatsManagerInternal = usageStatsManagerInternal;
2423         mAppOps = appOps;
2424         mAppUsageStats = appUsageStats;
2425         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
2426         mCompanionManager = companionManager;
2427         mActivityManager = activityManager;
2428         mAmi = ami;
2429         mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class);
2430         mDpm = dpm;
2431         mUm = userManager;
2432         mTelecomManager = telecomManager;
2433         mPowerManager = powerManager;
2434         mPostNotificationTrackerFactory = postNotificationTrackerFactory;
2435         mPlatformCompat = IPlatformCompat.Stub.asInterface(
2436                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
2437 
2438         mStrongAuthTracker = new StrongAuthTracker(getContext());
2439         String[] extractorNames;
2440         try {
2441             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
2442         } catch (Resources.NotFoundException e) {
2443             extractorNames = new String[0];
2444         }
2445         mUsageStats = usageStats;
2446         mMetricsLogger = new MetricsLogger();
2447         mRankingHandler = rankingHandler;
2448         mConditionProviders = conditionProviders;
2449         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(),
2450                 mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient));
2451         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
2452             @Override
2453             public void onConfigChanged() {
2454                 handleSavePolicyFile();
2455             }
2456 
2457             @Override
2458             void onZenModeChanged() {
2459                 Binder.withCleanCallingIdentity(() -> {
2460                     sendRegisteredOnlyBroadcast(ACTION_INTERRUPTION_FILTER_CHANGED);
2461                     getContext().sendBroadcastAsUser(
2462                             new Intent(ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
2463                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
2464                             UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
2465                     synchronized (mNotificationLock) {
2466                         updateInterruptionFilterLocked();
2467                     }
2468                     mRankingHandler.requestSort();
2469                 });
2470             }
2471 
2472             @Override
2473             void onPolicyChanged(Policy newPolicy) {
2474                 Binder.withCleanCallingIdentity(() -> {
2475                     Intent intent = new Intent(ACTION_NOTIFICATION_POLICY_CHANGED);
2476                     if (android.app.Flags.modesApi()) {
2477                         intent.putExtra(EXTRA_NOTIFICATION_POLICY, newPolicy);
2478                     }
2479                     sendRegisteredOnlyBroadcast(intent);
2480                     mRankingHandler.requestSort();
2481                 });
2482             }
2483 
2484             @Override
2485             void onConsolidatedPolicyChanged(Policy newConsolidatedPolicy) {
2486                 Binder.withCleanCallingIdentity(() -> {
2487                     if (android.app.Flags.modesApi()) {
2488                         Intent intent = new Intent(ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED);
2489                         intent.putExtra(EXTRA_NOTIFICATION_POLICY, newConsolidatedPolicy);
2490                         sendRegisteredOnlyBroadcast(intent);
2491                     }
2492                     mRankingHandler.requestSort();
2493                 });
2494             }
2495 
2496             @Override
2497             void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
2498                 Binder.withCleanCallingIdentity(() -> {
2499                     Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED);
2500                     intent.setPackage(pkg);
2501                     intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id);
2502                     intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status);
2503                     getContext().sendBroadcastAsUser(intent, UserHandle.of(userId));
2504                 });
2505             }
2506         });
2507         mPermissionHelper = permissionHelper;
2508         mNotificationChannelLogger = channelLogger;
2509         mUserProfiles.updateCache(getContext());
2510         mPreferencesHelper = new PreferencesHelper(getContext(),
2511                 mPackageManagerClient,
2512                 mRankingHandler,
2513                 mZenModeHelper,
2514                 mPermissionHelper,
2515                 mPermissionManager,
2516                 mNotificationChannelLogger,
2517                 mAppOps,
2518                 mUserProfiles,
2519                 mShowReviewPermissionsNotification,
2520                 Clock.systemUTC());
2521         mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper,
2522                 mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat);
2523         mSnoozeHelper = snoozeHelper;
2524         mGroupHelper = groupHelper;
2525         mHistoryManager = historyManager;
2526         if (Flags.allNotifsNeedTtl()) {
2527             mTtlHelper = new TimeToLiveHelper(mNotificationManagerPrivate, getContext());
2528         }
2529 
2530         // This is a ManagedServices object that keeps track of the listeners.
2531         mListeners = notificationListeners;
2532 
2533         // This is a MangedServices object that keeps track of the assistant.
2534         mAssistants = notificationAssistants;
2535 
2536         // Needs to be set before loadPolicyFile
2537         mAllowedManagedServicePackages = this::canUseManagedServices;
2538 
2539         mPolicyFile = policyFile;
2540         loadPolicyFile();
2541         mStatusBar = getLocalService(StatusBarManagerInternal.class);
2542         if (mStatusBar != null) {
2543             mStatusBar.setNotificationDelegate(mNotificationDelegate);
2544         }
2545 
2546         mZenModeHelper.initZenMode();
2547         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
2548 
2549         mSettingsObserver = new SettingsObserver(mHandler);
2550 
2551         mArchive = new Archive(resources.getInteger(
2552                 R.integer.config_notificationServiceArchiveSize));
2553 
2554         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
2555                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
2556 
2557         mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
2558                 com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
2559 
2560         mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger(
2561                 com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes);
2562         mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
2563                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
2564 
2565         mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
2566                 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
2567         mDefaultSearchSelectorPkg = getContext().getString(getContext().getResources()
2568                 .getIdentifier("config_defaultSearchSelectorPackageName", "string", "android"));
2569 
2570         mFlagResolver = flagResolver;
2571 
2572         mStatsManager = statsManager;
2573 
2574         mToastRateLimiter = toastRateLimiter;
2575 
2576         mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
2577                 mAccessibilityManager, mPackageManagerClient, userManager, usageStats,
2578                 mNotificationManagerPrivate, mZenModeHelper, flagResolver);
2579 
2580         // register for various Intents.
2581         // If this is called within a test, make sure to unregister the intent receivers by
2582         // calling onDestroy()
2583         IntentFilter filter = new IntentFilter();
2584         filter.addAction(Intent.ACTION_USER_STOPPED);
2585         if (!Flags.useSsmUserSwitchSignal()) {
2586             filter.addAction(Intent.ACTION_USER_SWITCHED);
2587         }
2588         filter.addAction(Intent.ACTION_USER_ADDED);
2589         filter.addAction(Intent.ACTION_USER_REMOVED);
2590         filter.addAction(Intent.ACTION_USER_UNLOCKED);
2591         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
2592         if (privateSpaceFlagsEnabled()){
2593             filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE);
2594         }
2595         getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
2596 
2597         IntentFilter pkgFilter = new IntentFilter();
2598         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
2599         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
2600         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
2601         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
2602         pkgFilter.addDataScheme("package");
2603         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
2604                 null);
2605 
2606         IntentFilter suspendedPkgFilter = new IntentFilter();
2607         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
2608         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
2609         suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
2610         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
2611                 suspendedPkgFilter, null, null);
2612 
2613         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
2614         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
2615                 null);
2616 
2617         if (!Flags.allNotifsNeedTtl()) {
2618             IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
2619             timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
2620             getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter,
2621                     Context.RECEIVER_EXPORTED_UNAUDITED);
2622         }
2623 
2624         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
2625         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
2626 
2627         IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
2628         getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
2629 
2630         mReviewNotificationPermissionsReceiver = new ReviewNotificationPermissionsReceiver();
2631         getContext().registerReceiver(mReviewNotificationPermissionsReceiver,
2632                 ReviewNotificationPermissionsReceiver.getFilter(),
2633                 Context.RECEIVER_NOT_EXPORTED);
2634 
2635         mAppOpsListener = new AppOpsManager.OnOpChangedInternalListener() {
2636             @Override
2637             public void onOpChanged(@NonNull String op, @NonNull String packageName,
2638                     int userId) {
2639                 mHandler.post(
2640                         () -> handleNotificationPermissionChange(packageName, userId));
2641             }
2642         };
2643 
2644         mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsListener);
2645     }
2646 
2647     /**
2648      * Cleanup broadcast receivers change listeners.
2649      */
onDestroy()2650     public void onDestroy() {
2651         if (mIntentReceiver != null) {
2652             getContext().unregisterReceiver(mIntentReceiver);
2653         }
2654         if (mPackageIntentReceiver != null) {
2655             getContext().unregisterReceiver(mPackageIntentReceiver);
2656         }
2657         if (Flags.allNotifsNeedTtl()) {
2658             if (mTtlHelper != null) {
2659                 mTtlHelper.destroy();
2660             }
2661         } else {
2662             if (mNotificationTimeoutReceiver != null) {
2663                 getContext().unregisterReceiver(mNotificationTimeoutReceiver);
2664             }
2665         }
2666         if (mRestoreReceiver != null) {
2667             getContext().unregisterReceiver(mRestoreReceiver);
2668         }
2669         if (mLocaleChangeReceiver != null) {
2670             getContext().unregisterReceiver(mLocaleChangeReceiver);
2671         }
2672         if (mSettingsObserver != null) {
2673             mSettingsObserver.destroy();
2674         }
2675         if (mRoleObserver != null) {
2676             mRoleObserver.destroy();
2677         }
2678         if (mShortcutHelper != null) {
2679             mShortcutHelper.destroy();
2680         }
2681         if (mStatsManager != null) {
2682             mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES);
2683             mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
2684             mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
2685             mStatsManager.clearPullAtomCallback(DND_MODE_RULE);
2686         }
2687         if (mAppOps != null) {
2688             mAppOps.stopWatchingMode(mAppOpsListener);
2689         }
2690         if (mAlarmManager != null) {
2691             mAlarmManager.cancelAll();
2692         }
2693     }
2694 
getStringArrayResource(int key)2695     protected String[] getStringArrayResource(int key) {
2696         return getContext().getResources().getStringArray(key);
2697     }
2698 
2699     @Override
onStart()2700     public void onStart() {
2701         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
2702             try {
2703                 if (DBG) {
2704                     Slog.d(TAG, "Reposting " + r.getKey() + " " + muteOnReturn);
2705                 }
2706                 enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
2707                         r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
2708                         r.getSbn().getId(),  r.getSbn().getNotification(), userId, muteOnReturn,
2709                         false /* byForegroundService */);
2710             } catch (Exception e) {
2711                 Slog.e(TAG, "Cannot un-snooze notification", e);
2712             }
2713         }, mUserProfiles);
2714 
2715         final File systemDir = new File(Environment.getDataDirectory(), "system");
2716         mRankingThread.start();
2717 
2718         WorkerHandler handler = new WorkerHandler(Looper.myLooper());
2719 
2720         mShowReviewPermissionsNotification = getContext().getResources().getBoolean(
2721                 R.bool.config_notificationReviewPermissions);
2722 
2723         init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
2724                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
2725                 getLocalService(LightsManager.class),
2726                 new NotificationListeners(getContext(), mNotificationLock, mUserProfiles,
2727                         AppGlobals.getPackageManager()),
2728                 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
2729                         AppGlobals.getPackageManager()),
2730                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
2731                 null /*CDM is not initialized yet*/, snoozeHelper,
2732                 new NotificationUsageStats(getContext()),
2733                 new AtomicFile(new File(
2734                         systemDir, "notification_policy.xml"), "notification-policy"),
2735                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
2736                 getGroupHelper(), ActivityManager.getService(),
2737                 LocalServices.getService(ActivityTaskManagerInternal.class),
2738                 LocalServices.getService(UsageStatsManagerInternal.class),
2739                 LocalServices.getService(DevicePolicyManagerInternal.class),
2740                 UriGrantsManager.getService(),
2741                 LocalServices.getService(UriGrantsManagerInternal.class),
2742                 getContext().getSystemService(AppOpsManager.class),
2743                 getContext().getSystemService(UserManager.class),
2744                 new NotificationHistoryManager(getContext(), handler),
2745                 mStatsManager = (StatsManager) getContext().getSystemService(
2746                         Context.STATS_MANAGER),
2747                 LocalServices.getService(ActivityManagerInternal.class),
2748                 createToastRateLimiter(), new PermissionHelper(getContext(),
2749                         AppGlobals.getPackageManager(),
2750                         AppGlobals.getPermissionManager()),
2751                 LocalServices.getService(UsageStatsManagerInternal.class),
2752                 getContext().getSystemService(TelecomManager.class),
2753                 new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(),
2754                 getContext().getSystemService(PermissionManager.class),
2755                 getContext().getSystemService(PowerManager.class),
2756                 new PostNotificationTrackerFactory() {});
2757 
2758         publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
2759                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
2760         publishLocalService(NotificationManagerInternal.class, mInternalService);
2761     }
2762 
registerNotificationPreferencesPullers()2763     private void registerNotificationPreferencesPullers() {
2764         mPullAtomCallback = new StatsPullAtomCallbackImpl();
2765         mStatsManager.setPullAtomCallback(
2766                 PACKAGE_NOTIFICATION_PREFERENCES,
2767                 null, // use default PullAtomMetadata values
2768                 ConcurrentUtils.DIRECT_EXECUTOR,
2769                 mPullAtomCallback
2770         );
2771         mStatsManager.setPullAtomCallback(
2772                 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
2773                 null, // use default PullAtomMetadata values
2774                 ConcurrentUtils.DIRECT_EXECUTOR,
2775                 mPullAtomCallback
2776         );
2777         mStatsManager.setPullAtomCallback(
2778                 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
2779                 null, // use default PullAtomMetadata values
2780                 ConcurrentUtils.DIRECT_EXECUTOR,
2781                 mPullAtomCallback
2782         );
2783         mStatsManager.setPullAtomCallback(
2784                 DND_MODE_RULE,
2785                 null, // use default PullAtomMetadata values
2786                 ConcurrentUtils.DIRECT_EXECUTOR,
2787                 mPullAtomCallback
2788         );
2789     }
2790 
2791     private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
2792         @Override
onPullAtom(int atomTag, List<StatsEvent> data)2793         public int onPullAtom(int atomTag, List<StatsEvent> data) {
2794             switch (atomTag) {
2795                 case PACKAGE_NOTIFICATION_PREFERENCES:
2796                 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
2797                 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
2798                 case DND_MODE_RULE:
2799                     return pullNotificationStates(atomTag, data);
2800                 default:
2801                     throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
2802             }
2803         }
2804     }
2805 
pullNotificationStates(int atomTag, List<StatsEvent> data)2806     private int pullNotificationStates(int atomTag, List<StatsEvent> data) {
2807         switch(atomTag) {
2808             case PACKAGE_NOTIFICATION_PREFERENCES:
2809                 mPreferencesHelper.pullPackagePreferencesStats(data,
2810                         getAllUsersNotificationPermissions());
2811                 break;
2812             case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
2813                 mPreferencesHelper.pullPackageChannelPreferencesStats(data);
2814                 break;
2815             case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
2816                 mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data);
2817                 break;
2818             case DND_MODE_RULE:
2819                 mZenModeHelper.pullRules(data);
2820                 break;
2821         }
2822         return StatsManager.PULL_SUCCESS;
2823     }
2824 
getGroupHelper()2825     private GroupHelper getGroupHelper() {
2826         mAutoGroupAtCount =
2827                 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
2828         return new GroupHelper(getContext(), getContext().getPackageManager(),
2829                 mAutoGroupAtCount, new GroupHelper.Callback() {
2830             @Override
2831             public void addAutoGroup(String key, boolean requestSort) {
2832                         synchronized (mNotificationLock) {
2833                             addAutogroupKeyLocked(key, requestSort);
2834                         }
2835             }
2836 
2837             @Override
2838             public void removeAutoGroup(String key) {
2839                 synchronized (mNotificationLock) {
2840                     removeAutogroupKeyLocked(key);
2841                 }
2842             }
2843 
2844             @Override
2845             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
2846                     NotificationAttributes summaryAttr) {
2847                 NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey,
2848                         summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor,
2849                         summaryAttr.visibility);
2850                 if (r != null) {
2851                     final boolean isAppForeground =
2852                             mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
2853                     mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
2854                             mPostNotificationTrackerFactory.newTracker(null)));
2855                 }
2856             }
2857 
2858             @Override
2859             public void removeAutoGroupSummary(int userId, String pkg) {
2860                 synchronized (mNotificationLock) {
2861                     clearAutogroupSummaryLocked(userId, pkg);
2862                 }
2863             }
2864 
2865             @Override
2866             public void updateAutogroupSummary(int userId, String pkg,
2867                     NotificationAttributes summaryAttr) {
2868                 boolean isAppForeground = pkg != null
2869                         && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
2870                 synchronized (mNotificationLock) {
2871                     updateAutobundledSummaryLocked(userId, pkg, summaryAttr, isAppForeground);
2872                 }
2873             }
2874         });
2875     }
2876 
2877     private void sendRegisteredOnlyBroadcast(String action) {
2878         sendRegisteredOnlyBroadcast(new Intent(action));
2879     }
2880 
2881     private void sendRegisteredOnlyBroadcast(Intent baseIntent) {
2882         int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true);
2883         Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
2884         for (int userId : userIds) {
2885             getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
2886         }
2887         // explicitly send the broadcast to all DND packages, even if they aren't currently running
2888         for (int userId : userIds) {
2889             for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
2890                 Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags(
2891                         Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2892                 getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
2893             }
2894         }
2895     }
2896 
2897     @Override
2898     public void onBootPhase(int phase) {
2899         onBootPhase(phase, Looper.getMainLooper());
2900     }
2901 
2902     @VisibleForTesting
2903     void onBootPhase(int phase, Looper mainLooper) {
2904         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
2905             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
2906             mZenModeHelper.onSystemReady();
2907             RoleObserver roleObserver = new RoleObserver(getContext(),
2908                     getContext().getSystemService(RoleManager.class),
2909                     mPackageManager, mainLooper);
2910             roleObserver.init();
2911             mRoleObserver = roleObserver;
2912             LauncherApps launcherApps =
2913                     (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
2914             UserManager userManager = (UserManager) getContext().getSystemService(
2915                     Context.USER_SERVICE);
2916             mShortcutHelper = new ShortcutHelper(launcherApps, mShortcutListener, getLocalService(
2917                     ShortcutServiceInternal.class), userManager);
2918             BubbleExtractor bubbsExtractor = mRankingHelper.findExtractor(BubbleExtractor.class);
2919             if (bubbsExtractor != null) {
2920                 bubbsExtractor.setShortcutHelper(mShortcutHelper);
2921             }
2922             registerNotificationPreferencesPullers();
2923             if (mLockUtils == null) {
2924                 mLockUtils = new LockPatternUtils(getContext());
2925             }
2926             mLockUtils.registerStrongAuthTracker(mStrongAuthTracker);
2927             mAttentionHelper.onSystemReady();
2928         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
2929             // This observer will force an update when observe is called, causing us to
2930             // bind to listener services.
2931             mSettingsObserver.observe();
2932             mListeners.onBootPhaseAppsCanStart();
2933             mAssistants.onBootPhaseAppsCanStart();
2934             mConditionProviders.onBootPhaseAppsCanStart();
2935             mHistoryManager.onBootPhaseAppsCanStart();
2936             migrateDefaultNAS();
2937             maybeShowInitialReviewPermissionsNotification();
2938 
2939             if (android.app.Flags.modesApi()) {
2940                 // Cannot be done earlier, as some services aren't ready until this point.
2941                 mZenModeHelper.setDeviceEffectsApplier(
2942                         new DefaultDeviceEffectsApplier(getContext()));
2943             }
2944             List<ModuleInfo> moduleInfoList =
2945             mPackageManagerClient.getInstalledModules(
2946                 PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
2947             // Cache adservices module info
2948             for (ModuleInfo mi : moduleInfoList) {
2949                 if (Objects.equals(mi.getApexModuleName(), ADSERVICES_MODULE_PKG_NAME)) {
2950                     mAdservicesModuleInfo = mi;
2951                 }
2952             }
2953         } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
2954             mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
2955         } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
2956             mPreferencesHelper.updateFixedImportance(mUm.getUsers());
2957             mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers());
2958         } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
2959             if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) {
2960                 new Thread(() -> {
2961                     while (true) {
2962                         try {
2963                             Thread.sleep(5000);
2964                         } catch (InterruptedException e) { }
2965                         mInternalService.removeBitmaps();
2966                     }
2967                 }).start();
2968             } else if (expireBitmaps()) {
2969                 NotificationBitmapJobService.scheduleJob(getContext());
2970             }
2971         }
2972     }
2973 
2974     @Override
2975     public void onUserUnlocked(@NonNull TargetUser user) {
2976         mHandler.post(() -> {
2977             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser");
2978             try {
2979                 mHistoryManager.onUserUnlocked(user.getUserIdentifier());
2980             } finally {
2981                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
2982             }
2983         });
2984     }
2985 
2986     private void sendAppBlockStateChangedBroadcast(String pkg, int uid, boolean blocked) {
2987         // From Android T, revoking the notification permission will cause the app to be killed.
2988         // delay this broadcast so it doesn't race with that process death
2989         mHandler.postDelayed(() -> {
2990             try {
2991                 getContext().sendBroadcastAsUser(
2992                         new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2993                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, blocked)
2994                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2995                                 .setPackage(pkg),
2996                         UserHandle.of(UserHandle.getUserId(uid)), null);
2997             } catch (SecurityException e) {
2998                 Slog.w(TAG, "Can't notify app about app block change", e);
2999             }
3000         }, 500);
3001     }
3002 
3003     @Override
3004     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
3005         if (!Flags.useSsmUserSwitchSignal()) {
3006             return;
3007         }
3008         final int userId = to.getUserIdentifier();
3009         mUserProfiles.updateCache(getContext());
3010         if (!mUserProfiles.isProfileUser(userId, getContext())) {
3011             // reload per-user settings
3012             mSettingsObserver.update(null);
3013             // Refresh managed services
3014             mConditionProviders.onUserSwitched(userId);
3015             mListeners.onUserSwitched(userId);
3016             mZenModeHelper.onUserSwitched(userId);
3017             mPreferencesHelper.syncChannelsBypassingDnd();
3018         }
3019         // assistant is the only thing that cares about managed profiles specifically
3020         mAssistants.onUserSwitched(userId);
3021     }
3022 
3023     @Override
3024     public void onUserStopping(@NonNull TargetUser user) {
3025         mHandler.post(() -> {
3026             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser");
3027             try {
3028                 mHistoryManager.onUserStopped(user.getUserIdentifier());
3029             } finally {
3030                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
3031             }
3032         });
3033     }
3034 
3035     @GuardedBy("mNotificationLock")
3036     private void updateListenerHintsLocked() {
3037         final int hints = calculateHints();
3038         if (hints == mListenerHints) return;
3039         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
3040         mListenerHints = hints;
3041         scheduleListenerHintsChanged(hints);
3042     }
3043 
3044     @GuardedBy("mNotificationLock")
3045     private void updateEffectsSuppressorLocked() {
3046         final long updatedSuppressedEffects = calculateSuppressedEffects();
3047         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
3048         final List<ComponentName> suppressors = getSuppressors();
3049         ZenLog.traceEffectsSuppressorChanged(
3050                 mEffectsSuppressors, suppressors, updatedSuppressedEffects);
3051         mEffectsSuppressors = suppressors;
3052         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
3053         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
3054     }
3055 
3056     private void exitIdle() {
3057         if (mDeviceIdleManager != null) {
3058             mDeviceIdleManager.endIdle("notification interaction");
3059         }
3060     }
3061 
3062     void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
3063             boolean fromListener) {
3064         if (channel.getImportance() == IMPORTANCE_NONE) {
3065             // cancel
3066             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0,
3067                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED
3068             );
3069             if (isUidSystemOrPhone(uid)) {
3070                 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
3071                 int N = profileIds.size();
3072                 for (int i = 0; i < N; i++) {
3073                     int profileId = profileIds.get(i);
3074                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0,
3075                             profileId, REASON_CHANNEL_BANNED
3076                     );
3077                 }
3078             }
3079         }
3080         final NotificationChannel preUpdate =
3081                 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
3082 
3083         mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true,
3084                 Binder.getCallingUid(), isCallerSystemOrSystemUi());
3085         if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
3086             mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
3087                     channel.getImportance() != IMPORTANCE_NONE, true);
3088         }
3089         maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
3090 
3091         if (!fromListener) {
3092             final NotificationChannel modifiedChannel = mPreferencesHelper.getNotificationChannel(
3093                     pkg, uid, channel.getId(), false);
3094             mListeners.notifyNotificationChannelChanged(
3095                     pkg, UserHandle.getUserHandleForUid(uid),
3096                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
3097         }
3098 
3099         handleSavePolicyFile();
3100     }
3101 
3102     private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
3103             NotificationChannel update) {
3104         try {
3105             if ((preUpdate.getImportance() == IMPORTANCE_NONE
3106                     && update.getImportance() != IMPORTANCE_NONE)
3107                     || (preUpdate.getImportance() != IMPORTANCE_NONE
3108                     && update.getImportance() == IMPORTANCE_NONE)) {
3109                 getContext().sendBroadcastAsUser(
3110                         new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
3111                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
3112                                         update.getId())
3113                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
3114                                         update.getImportance() == IMPORTANCE_NONE)
3115                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3116                                 .setPackage(pkg),
3117                         UserHandle.of(UserHandle.getUserId(uid)), null);
3118             }
3119         } catch (SecurityException e) {
3120             Slog.w(TAG, "Can't notify app about channel change", e);
3121         }
3122     }
3123 
3124     void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
3125             boolean fromApp, boolean fromListener) {
3126         Objects.requireNonNull(group);
3127         Objects.requireNonNull(pkg);
3128 
3129         final NotificationChannelGroup preUpdate =
3130                 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
3131         mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
3132                 fromApp, Binder.getCallingUid(), isCallerSystemOrSystemUi());
3133         if (!fromApp) {
3134             maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
3135         }
3136         if (!fromListener) {
3137             mListeners.notifyNotificationChannelGroupChanged(pkg,
3138                     UserHandle.of(UserHandle.getCallingUserId()), group,
3139                     NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
3140         }
3141     }
3142 
3143     private void maybeNotifyChannelGroupOwner(String pkg, int uid,
3144             NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
3145         try {
3146             if (preUpdate.isBlocked() != update.isBlocked()) {
3147                 getContext().sendBroadcastAsUser(
3148                         new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
3149                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
3150                                         update.getId())
3151                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
3152                                         update.isBlocked())
3153                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3154                                 .setPackage(pkg),
3155                         UserHandle.of(UserHandle.getUserId(uid)), null);
3156             }
3157         } catch (SecurityException e) {
3158             Slog.w(TAG, "Can't notify app about group change", e);
3159         }
3160     }
3161 
3162     private ArrayList<ComponentName> getSuppressors() {
3163         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
3164         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
3165             ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
3166 
3167             for (ComponentName info : serviceInfoList) {
3168                 names.add(info);
3169             }
3170         }
3171 
3172         return names;
3173     }
3174 
3175     private boolean removeDisabledHints(ManagedServiceInfo info) {
3176         return removeDisabledHints(info, 0);
3177     }
3178 
3179     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
3180         boolean removed = false;
3181 
3182         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
3183             final int hint = mListenersDisablingEffects.keyAt(i);
3184             final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
3185 
3186             if (hints == 0 || (hint & hints) == hint) {
3187                 removed |= listeners.remove(info.component);
3188             }
3189         }
3190 
3191         return removed;
3192     }
3193 
3194     private void addDisabledHints(ManagedServiceInfo info, int hints) {
3195         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3196             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
3197         }
3198 
3199         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
3200             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
3201         }
3202 
3203         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
3204             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
3205         }
3206     }
3207 
3208     private void addDisabledHint(ManagedServiceInfo info, int hint) {
3209         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
3210             mListenersDisablingEffects.put(hint, new ArraySet<>());
3211         }
3212 
3213         ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
3214         hintListeners.add(info.component);
3215     }
3216 
3217     private int calculateHints() {
3218         int hints = 0;
3219         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
3220             int hint = mListenersDisablingEffects.keyAt(i);
3221             ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
3222 
3223             if (!serviceInfoList.isEmpty()) {
3224                 hints |= hint;
3225             }
3226         }
3227 
3228         return hints;
3229     }
3230 
3231     private long calculateSuppressedEffects() {
3232         int hints = calculateHints();
3233         long suppressedEffects = 0;
3234 
3235         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3236             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
3237         }
3238 
3239         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
3240             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
3241         }
3242 
3243         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
3244             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
3245         }
3246 
3247         return suppressedEffects;
3248     }
3249 
3250     @GuardedBy("mNotificationLock")
3251     private void updateInterruptionFilterLocked() {
3252         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
3253         if (interruptionFilter == mInterruptionFilter) return;
3254         mInterruptionFilter = interruptionFilter;
3255         scheduleInterruptionFilterChanged(interruptionFilter);
3256     }
3257 
3258     int correctCategory(int requestedCategoryList, int categoryType,
3259             int currentCategoryList) {
3260         if ((requestedCategoryList & categoryType) != 0
3261                 && (currentCategoryList & categoryType) == 0) {
3262             requestedCategoryList &= ~categoryType;
3263         } else if ((requestedCategoryList & categoryType) == 0
3264                 && (currentCategoryList & categoryType) != 0){
3265             requestedCategoryList |= categoryType;
3266         }
3267         return requestedCategoryList;
3268     }
3269 
3270     @VisibleForTesting
3271     INotificationManager getBinderService() {
3272         return INotificationManager.Stub.asInterface(mService);
3273     }
3274 
3275     /**
3276      * Report to usage stats that the notification was seen.
3277      * @param r notification record
3278      */
3279     @GuardedBy("mNotificationLock")
3280     protected void reportSeen(NotificationRecord r) {
3281         if (!r.isProxied()) {
3282             mAppUsageStats.reportEvent(r.getSbn().getPackageName(),
3283                     getRealUserId(r.getSbn().getUserId()),
3284                     UsageEvents.Event.NOTIFICATION_SEEN);
3285         }
3286     }
3287 
3288     protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
3289             int targetSdkVersion) {
3290         if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
3291             return incomingPolicy.suppressedVisualEffects;
3292         }
3293         final int[] effectsIntroducedInP = {
3294                 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
3295                 SUPPRESSED_EFFECT_LIGHTS,
3296                 SUPPRESSED_EFFECT_PEEK,
3297                 SUPPRESSED_EFFECT_STATUS_BAR,
3298                 SUPPRESSED_EFFECT_BADGE,
3299                 SUPPRESSED_EFFECT_AMBIENT,
3300                 SUPPRESSED_EFFECT_NOTIFICATION_LIST
3301         };
3302 
3303         int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
3304         if (targetSdkVersion < Build.VERSION_CODES.P) {
3305             // unset higher order bits introduced in P, maintain the user's higher order bits
3306             for (int i = 0; i < effectsIntroducedInP.length ; i++) {
3307                 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
3308                 newSuppressedVisualEffects |=
3309                         (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
3310             }
3311             // set higher order bits according to lower order bits
3312             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
3313                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
3314                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
3315             }
3316             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
3317                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
3318             }
3319         } else {
3320             boolean hasNewEffects = (newSuppressedVisualEffects
3321                     - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
3322             // if any of the new effects introduced in P are set
3323             if (hasNewEffects) {
3324                 // clear out the deprecated effects
3325                 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
3326                         | SUPPRESSED_EFFECT_SCREEN_OFF);
3327 
3328                 // set the deprecated effects according to the new more specific effects
3329                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) != 0) {
3330                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
3331                 }
3332                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) != 0
3333                         && (newSuppressedVisualEffects
3334                         & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
3335                         && (newSuppressedVisualEffects
3336                         & SUPPRESSED_EFFECT_AMBIENT) != 0) {
3337                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
3338                 }
3339             } else {
3340                 // set higher order bits according to lower order bits
3341                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
3342                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
3343                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
3344                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
3345                 }
3346                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
3347                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
3348                 }
3349             }
3350         }
3351 
3352         return newSuppressedVisualEffects;
3353     }
3354 
3355     @GuardedBy("mNotificationLock")
3356     protected void maybeRecordInterruptionLocked(NotificationRecord r) {
3357         if (r.isInterruptive() && !r.hasRecordedInterruption()) {
3358             mAppUsageStats.reportInterruptiveNotification(r.getSbn().getPackageName(),
3359                     r.getChannel().getId(),
3360                     getRealUserId(r.getSbn().getUserId()));
3361             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryAddItem");
3362             try {
3363                 if (r.getNotification().getSmallIcon() != null) {
3364                     mHistoryManager.addNotification(new HistoricalNotification.Builder()
3365                             .setPackage(r.getSbn().getPackageName())
3366                             .setUid(r.getSbn().getUid())
3367                             .setUserId(r.getSbn().getNormalizedUserId())
3368                             .setChannelId(r.getChannel().getId())
3369                             .setChannelName(r.getChannel().getName().toString())
3370                             .setPostedTimeMs(System.currentTimeMillis())
3371                             .setTitle(getHistoryTitle(r.getNotification()))
3372                             .setText(getHistoryText(r.getNotification()))
3373                             .setIcon(r.getNotification().getSmallIcon())
3374                             .build());
3375                 }
3376             } finally {
3377                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
3378             }
3379             r.setRecordedInterruption(true);
3380         }
3381     }
3382 
3383     protected void reportForegroundServiceUpdate(boolean shown,
3384             final Notification notification, final int id, final String pkg, final int userId) {
3385         mHandler.post(() -> {
3386             mAmi.onForegroundServiceNotificationUpdate(shown, notification, id, pkg, userId);
3387         });
3388     }
3389 
3390     protected void maybeReportForegroundServiceUpdate(final NotificationRecord r, boolean shown) {
3391         if (r.isForegroundService()) {
3392             // snapshot live state for the asynchronous operation
3393             final StatusBarNotification sbn = r.getSbn();
3394             reportForegroundServiceUpdate(shown, sbn.getNotification(), sbn.getId(),
3395                     sbn.getPackageName(), sbn.getUser().getIdentifier());
3396         }
3397     }
3398 
3399     private String getHistoryTitle(Notification n) {
3400         CharSequence title = null;
3401         if (n.extras != null) {
3402             title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
3403             if (title == null) {
3404                 title = n.extras.getCharSequence(EXTRA_TITLE_BIG);
3405             }
3406         }
3407         return title == null ? getContext().getResources().getString(
3408             com.android.internal.R.string.notification_history_title_placeholder)
3409             : String.valueOf(title);
3410     }
3411 
3412     /**
3413      * Returns the appropriate substring for this notification based on the style of notification.
3414      */
3415     private String getHistoryText(Notification n) {
3416         CharSequence text = null;
3417         if (n.extras != null) {
3418             text = n.extras.getCharSequence(EXTRA_TEXT);
3419             Notification.Builder nb = Notification.Builder.recoverBuilder(getContext(), n);
3420 
3421             if (nb.getStyle() instanceof Notification.BigTextStyle) {
3422                 text = ((Notification.BigTextStyle) nb.getStyle()).getBigText();
3423             } else if (nb.getStyle() instanceof MessagingStyle) {
3424                 MessagingStyle ms = (MessagingStyle) nb.getStyle();
3425                 final List<MessagingStyle.Message> messages = ms.getMessages();
3426                 if (messages != null && messages.size() > 0) {
3427                     text = messages.get(messages.size() - 1).getText();
3428                 }
3429             }
3430 
3431             if (TextUtils.isEmpty(text)) {
3432                 text = n.extras.getCharSequence(EXTRA_TEXT);
3433             }
3434         }
3435         return text == null ? null : String.valueOf(text);
3436     }
3437 
3438     protected void maybeRegisterMessageSent(NotificationRecord r) {
3439         if (r.isConversation()) {
3440             if (r.getShortcutInfo() != null) {
3441                 if (mPreferencesHelper.setValidMessageSent(
3442                         r.getSbn().getPackageName(), r.getUid())) {
3443                     handleSavePolicyFile();
3444                 } else if (r.getNotification().getBubbleMetadata() != null) {
3445                     // If bubble metadata is present it is valid (if invalid it's removed
3446                     // via BubbleExtractor).
3447                     if (mPreferencesHelper.setValidBubbleSent(
3448                             r.getSbn().getPackageName(), r.getUid())) {
3449                         handleSavePolicyFile();
3450                     }
3451                 }
3452             } else {
3453                 if (mPreferencesHelper.setInvalidMessageSent(
3454                         r.getSbn().getPackageName(), r.getUid())) {
3455                     handleSavePolicyFile();
3456                 }
3457             }
3458         }
3459     }
3460 
3461     /**
3462      * Report to usage stats that the user interacted with the notification.
3463      * @param r notification record
3464      */
3465     protected void reportUserInteraction(NotificationRecord r) {
3466         mAppUsageStats.reportEvent(r.getSbn().getPackageName(),
3467                 getRealUserId(r.getSbn().getUserId()),
3468                 UsageEvents.Event.USER_INTERACTION);
3469 
3470         if (Flags.politeNotifications()) {
3471             mAttentionHelper.onUserInteraction(r);
3472         }
3473     }
3474 
3475     private int getRealUserId(int userId) {
3476         return userId == USER_ALL ? USER_SYSTEM : userId;
3477     }
3478 
3479     private ToastRecord getToastRecord(int uid, int pid, String packageName, boolean isSystemToast,
3480             IBinder token, @Nullable CharSequence text, @Nullable ITransientNotification callback,
3481             int duration, Binder windowToken, int displayId,
3482             @Nullable ITransientNotificationCallback textCallback) {
3483         if (callback == null) {
3484             return new TextToastRecord(this, mStatusBar, uid, pid, packageName,
3485                     isSystemToast, token, text, duration, windowToken, displayId, textCallback);
3486         } else {
3487             return new CustomToastRecord(this, uid, pid, packageName,
3488                     isSystemToast, token, callback, duration, windowToken, displayId);
3489         }
3490     }
3491 
3492     @VisibleForTesting
3493     NotificationManagerInternal getInternalService() {
3494         return mInternalService;
3495     }
3496 
3497     private MultiRateLimiter createToastRateLimiter() {
3498         return new MultiRateLimiter.Builder(getContext()).addRateLimits(TOAST_RATE_LIMITS).build();
3499     }
3500 
3501     protected int checkComponentPermission(String permission, int uid, int owningUid,
3502             boolean exported) {
3503         return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
3504     }
3505 
3506     @VisibleForTesting
3507     final IBinder mService = new INotificationManager.Stub() {
3508         // Toasts
3509         // ============================================================================
3510 
3511         @Override
3512         public boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
3513                 boolean isUiContext, int displayId,
3514                 @Nullable ITransientNotificationCallback textCallback) {
3515             return enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext,
3516                     displayId, textCallback);
3517         }
3518 
3519         @Override
3520         public boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback,
3521                 int duration, boolean isUiContext, int displayId) {
3522             return enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext,
3523                     displayId, /* textCallback= */ null);
3524         }
3525 
3526         private boolean enqueueToast(String pkg, IBinder token, @Nullable CharSequence text,
3527                 @Nullable ITransientNotification callback, int duration, boolean isUiContext,
3528                 int displayId, @Nullable ITransientNotificationCallback textCallback) {
3529             if (DBG) {
3530                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration
3531                         + " isUiContext=" + isUiContext + " displayId=" + displayId);
3532             }
3533 
3534             if (pkg == null || (text == null && callback == null)
3535                     || (text != null && callback != null) || token == null) {
3536                 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback="
3537                         + " token=" + token);
3538                 return false;
3539             }
3540 
3541             final int callingUid = Binder.getCallingUid();
3542             if (!isUiContext && displayId == Display.DEFAULT_DISPLAY
3543                     && mUm.isVisibleBackgroundUsersSupported()) {
3544                 // When the caller is a visible background user using a non-UI context (like the
3545                 // application context), the Toast must be displayed in the display the user was
3546                 // started visible on.
3547                 int userId = UserHandle.getUserId(callingUid);
3548                 int userDisplayId = mUmInternal.getMainDisplayAssignedToUser(userId);
3549                 if (displayId != userDisplayId) {
3550                     if (DBG) {
3551                         Slogf.d(TAG, "Changing display id from %d to %d on user %d", displayId,
3552                                 userDisplayId, userId);
3553                     }
3554                     displayId = userDisplayId;
3555                 }
3556             }
3557 
3558             checkCallerIsSameApp(pkg);
3559             final boolean isSystemToast = isCallerSystemOrSystemUi()
3560                     || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
3561             boolean isAppRenderedToast = (callback != null);
3562             if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast,
3563                     isSystemToast)) {
3564                 return false;
3565             }
3566 
3567             synchronized (mToastQueue) {
3568                 int callingPid = Binder.getCallingPid();
3569                 final long callingId = Binder.clearCallingIdentity();
3570                 try {
3571                     ToastRecord record;
3572                     int index = indexOfToastLocked(pkg, token);
3573                     // If it's already in the queue, we update it in place, we don't
3574                     // move it to the end of the queue.
3575                     if (index >= 0) {
3576                         record = mToastQueue.get(index);
3577                         record.update(duration);
3578                     } else {
3579                         // Limit the number of toasts that any given package can enqueue.
3580                         // Prevents DOS attacks and deals with leaks.
3581                         int count = 0;
3582                         final int N = mToastQueue.size();
3583                         for (int i = 0; i < N; i++) {
3584                             final ToastRecord r = mToastQueue.get(i);
3585                             if (r.pkg.equals(pkg)) {
3586                                 count++;
3587                                 if (count >= MAX_PACKAGE_TOASTS) {
3588                                     Slog.e(TAG, "Package has already queued " + count
3589                                             + " toasts. Not showing more. Package=" + pkg);
3590                                     return false;
3591                                 }
3592                             }
3593                         }
3594 
3595                         Binder windowToken = new Binder();
3596                         mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId,
3597                                 null /* options */);
3598                         record = getToastRecord(callingUid, callingPid, pkg, isSystemToast, token,
3599                                 text, callback, duration, windowToken, displayId, textCallback);
3600 
3601                         // Insert system toasts at the front of the queue
3602                         int systemToastInsertIdx = mToastQueue.size();
3603                         if (isSystemToast) {
3604                             systemToastInsertIdx = getInsertIndexForSystemToastLocked();
3605                         }
3606                         if (systemToastInsertIdx < mToastQueue.size()) {
3607                             index = systemToastInsertIdx;
3608                             mToastQueue.add(index, record);
3609                         } else {
3610                             mToastQueue.add(record);
3611                             index = mToastQueue.size() - 1;
3612                         }
3613                         keepProcessAliveForToastIfNeededLocked(callingPid);
3614                     }
3615                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
3616                     // new or just been updated, show it.
3617                     // If the callback fails, this will remove it from the list, so don't
3618                     // assume that it's valid after this.
3619                     if (index == 0) {
3620                         showNextToastLocked(false);
3621                     }
3622                 } finally {
3623                     Binder.restoreCallingIdentity(callingId);
3624                 }
3625             }
3626             return true;
3627         }
3628 
3629         @GuardedBy("mToastQueue")
3630         private int getInsertIndexForSystemToastLocked() {
3631             // If there are other system toasts: insert after the last one
3632             int idx = 0;
3633             for (ToastRecord r : mToastQueue) {
3634                 if (idx == 0 && mIsCurrentToastShown) {
3635                     idx++;
3636                     continue;
3637                 }
3638                 if (!r.isSystemToast) {
3639                     return idx;
3640                 }
3641                 idx++;
3642             }
3643             return idx;
3644         }
3645 
3646         private boolean checkCanEnqueueToast(String pkg, int callingUid, int displayId,
3647                 boolean isAppRenderedToast, boolean isSystemToast) {
3648             final boolean isPackageSuspended = isPackagePaused(pkg);
3649             final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
3650                     callingUid);
3651 
3652             final boolean appIsForeground;
3653             final long callingIdentity = Binder.clearCallingIdentity();
3654             try {
3655                 appIsForeground = mActivityManager.getUidImportance(callingUid)
3656                         == IMPORTANCE_FOREGROUND;
3657             } finally {
3658                 Binder.restoreCallingIdentity(callingIdentity);
3659             }
3660 
3661             if (!isSystemToast && ((notificationsDisabledForPackage && !appIsForeground)
3662                     || isPackageSuspended)) {
3663                 Slog.e(TAG, "Suppressing toast from package " + pkg
3664                         + (isPackageSuspended ? " due to package suspended."
3665                         : " by user request."));
3666                 return false;
3667             }
3668 
3669             if (blockToast(callingUid, isSystemToast, isAppRenderedToast,
3670                     isPackageInForegroundForToast(callingUid))) {
3671                 Slog.w(TAG, "Blocking custom toast from package " + pkg
3672                         + " due to package not in the foreground at time the toast was posted");
3673                 return false;
3674             }
3675 
3676             int userId = UserHandle.getUserId(callingUid);
3677             if (!isSystemToast && !mUmInternal.isUserVisible(userId, displayId)) {
3678                 Slog.e(TAG, "Suppressing toast from package " + pkg + "/" + callingUid + " as user "
3679                         + userId + " is not visible on display " + displayId);
3680                 return false;
3681             }
3682 
3683             return true;
3684         }
3685 
3686         @Override
3687         public void cancelToast(String pkg, IBinder token) {
3688             Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token);
3689 
3690             if (pkg == null || token == null) {
3691                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token);
3692                 return;
3693             }
3694 
3695             synchronized (mToastQueue) {
3696                 final long callingId = Binder.clearCallingIdentity();
3697                 try {
3698                     int index = indexOfToastLocked(pkg, token);
3699                     if (index >= 0) {
3700                         cancelToastLocked(index);
3701                     } else {
3702                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
3703                                 + " token=" + token);
3704                     }
3705                 } finally {
3706                     Binder.restoreCallingIdentity(callingId);
3707                 }
3708             }
3709         }
3710 
3711         @Override
3712         @EnforcePermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING)
3713         public void setToastRateLimitingEnabled(boolean enable) {
3714 
3715             super.setToastRateLimitingEnabled_enforcePermission();
3716 
3717             synchronized (mToastQueue) {
3718                 int uid = Binder.getCallingUid();
3719                 int userId = UserHandle.getUserId(uid);
3720                 if (enable) {
3721                     mToastRateLimitingDisabledUids.remove(uid);
3722                     try {
3723                         String[] packages = mPackageManager.getPackagesForUid(uid);
3724                         if (packages == null) {
3725                             Slog.e(TAG, "setToastRateLimitingEnabled method haven't found any "
3726                                     + "packages for the  given uid: " + uid + ", toast rate "
3727                                     + "limiter not reset for that uid.");
3728                             return;
3729                         }
3730                         for (String pkg : packages) {
3731                             mToastRateLimiter.clear(userId, pkg);
3732                         }
3733                     } catch (RemoteException e) {
3734                         Slog.e(TAG, "Failed to reset toast rate limiter for given uid", e);
3735                     }
3736                 } else {
3737                     mToastRateLimitingDisabledUids.add(uid);
3738                 }
3739             }
3740         }
3741 
3742         @Override
3743         public void finishToken(String pkg, IBinder token) {
3744             synchronized (mToastQueue) {
3745                 final long callingId = Binder.clearCallingIdentity();
3746                 try {
3747                     int index = indexOfToastLocked(pkg, token);
3748                     if (index >= 0) {
3749                         ToastRecord record = mToastQueue.get(index);
3750                         finishWindowTokenLocked(record.windowToken, record.displayId);
3751                     } else {
3752                         Slog.w(TAG, "Toast already killed. pkg=" + pkg
3753                                 + " token=" + token);
3754                     }
3755                 } finally {
3756                     Binder.restoreCallingIdentity(callingId);
3757                 }
3758             }
3759         }
3760 
3761         @Override
3762         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
3763                 Notification notification, int userId) throws RemoteException {
3764             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
3765                     Binder.getCallingPid(), tag, id, notification, userId,
3766                     false /* byForegroundService */);
3767         }
3768 
3769         @Override
3770         public void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id,
3771                 int userId) {
3772             // Don't allow client applications to cancel foreground service notifs, user-initiated
3773             // job notifs, autobundled summaries, or notifs that have been replied to.
3774             int mustNotHaveFlags = isCallingUidSystem() ? 0 :
3775                     (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
3776             if (lifetimeExtensionRefactor()) {
3777                 // Also don't allow client apps to cancel lifetime extended notifs.
3778                 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3779             }
3780 
3781             cancelNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(),
3782                     tag, id, userId, mustNotHaveFlags);
3783         }
3784 
3785         @Override
3786         public void cancelAllNotifications(String pkg, int userId) {
3787             checkCallerIsSystemOrSameApp(pkg);
3788 
3789             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
3790                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
3791 
3792             // Don't allow the app to cancel active FGS or UIJ notifications
3793             if (lifetimeExtensionRefactor()) {
3794                 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
3795                         pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
3796                                 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
3797                         userId, REASON_APP_CANCEL_ALL);
3798                 final int packageImportance = getPackageImportanceWithIdentity(pkg);
3799                 // If cancellation will be prevented due to lifetime extension, we send updates
3800                 // to system UI.
3801                 synchronized (mNotificationLock) {
3802                     maybeNotifySystemUiListenerLifetimeExtendedListLocked(mNotificationList,
3803                             packageImportance);
3804                     maybeNotifySystemUiListenerLifetimeExtendedListLocked(mEnqueuedNotifications,
3805                             packageImportance);
3806                 }
3807             } else {
3808                 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
3809                         pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
3810                         userId, REASON_APP_CANCEL_ALL);
3811             }
3812         }
3813 
3814         @Override
3815         public void silenceNotificationSound() {
3816             checkCallerIsSystem();
3817 
3818             mNotificationDelegate.clearEffects();
3819         }
3820 
3821         @Override
3822         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
3823             enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
3824             boolean wasEnabled = mPermissionHelper.hasPermission(uid);
3825             if (wasEnabled == enabled) {
3826                 return;
3827             }
3828             mPermissionHelper.setNotificationPermission(
3829                     pkg, UserHandle.getUserId(uid), enabled, true);
3830             sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
3831 
3832             mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
3833                     .setType(MetricsEvent.TYPE_ACTION)
3834                     .setPackageName(pkg)
3835                     .setSubtype(enabled ? 1 : 0));
3836             mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled);
3837 
3838             // Outstanding notifications from this package will be cancelled as soon as we get the
3839             // callback from AppOpsManager.
3840         }
3841 
3842         /**
3843          * Updates the enabled state for notifications for the given package (and uid).
3844          * Additionally, this method marks the app importance as locked by the user, which
3845          * means
3846          * that notifications from the app will <b>not</b> be considered for showing a
3847          * blocking helper.
3848          *
3849          * @param pkg     package that owns the notifications to update
3850          * @param uid     uid of the app providing notifications
3851          * @param enabled whether notifications should be enabled for the app
3852          * @see #setNotificationsEnabledForPackage(String, int, boolean)
3853          */
3854         @Override
3855         public void setNotificationsEnabledWithImportanceLockForPackage(
3856                 String pkg, int uid, boolean enabled) {
3857             setNotificationsEnabledForPackage(pkg, uid, enabled);
3858         }
3859 
3860         /**
3861          * Use this when you just want to know if notifications are OK for this package.
3862          */
3863         @Override
3864         public boolean areNotificationsEnabled(String pkg) {
3865             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
3866         }
3867 
3868         /**
3869          * Use this when you just want to know if notifications are OK for this package.
3870          */
3871         @Override
3872         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
3873             enforceSystemOrSystemUIOrSamePackage(pkg,
3874                     "Caller not system or systemui or same package");
3875             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
3876                 getContext().enforceCallingPermission(
3877                         android.Manifest.permission.INTERACT_ACROSS_USERS,
3878                         "canNotifyAsPackage for uid " + uid);
3879             }
3880 
3881             return areNotificationsEnabledForPackageInt(pkg, uid);
3882         }
3883 
3884         /**
3885          * @return true if and only if "all" bubbles are allowed from the provided package.
3886          */
3887         @Override
3888         public boolean areBubblesAllowed(String pkg) {
3889             return getBubblePreferenceForPackage(pkg, Binder.getCallingUid())
3890                     == BUBBLE_PREFERENCE_ALL;
3891         }
3892 
3893         /**
3894          * @return true if this user has bubbles enabled at the feature-level.
3895          */
3896         @Override
3897         public boolean areBubblesEnabled(UserHandle user) {
3898             if (UserHandle.getCallingUserId() != user.getIdentifier()) {
3899                 getContext().enforceCallingPermission(
3900                         android.Manifest.permission.INTERACT_ACROSS_USERS,
3901                         "areBubblesEnabled for user " + user.getIdentifier());
3902             }
3903             return mPreferencesHelper.bubblesEnabled(user);
3904         }
3905 
3906         @Override
3907         public int getBubblePreferenceForPackage(String pkg, int uid) {
3908             enforceSystemOrSystemUIOrSamePackage(pkg,
3909                     "Caller not system or systemui or same package");
3910 
3911             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
3912                 getContext().enforceCallingPermission(
3913                         android.Manifest.permission.INTERACT_ACROSS_USERS,
3914                         "getBubblePreferenceForPackage for uid " + uid);
3915             }
3916 
3917             return mPreferencesHelper.getBubblePreference(pkg, uid);
3918         }
3919 
3920         @Override
3921         public void setBubblesAllowed(String pkg, int uid, int bubblePreference) {
3922             checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
3923             mPreferencesHelper.setBubblesAllowed(pkg, uid, bubblePreference);
3924             handleSavePolicyFile();
3925         }
3926 
3927         @Override
3928         public boolean shouldHideSilentStatusIcons(String callingPkg) {
3929             checkCallerIsSameApp(callingPkg);
3930 
3931             if (isCallerSystemOrPhone()
3932                     || mListeners.isListenerPackage(callingPkg)) {
3933                 return mPreferencesHelper.shouldHideSilentStatusIcons();
3934             } else {
3935                 throw new SecurityException("Only available for notification listeners");
3936             }
3937         }
3938 
3939         @Override
3940         public void setHideSilentStatusIcons(boolean hide) {
3941             checkCallerIsSystem();
3942 
3943             mPreferencesHelper.setHideSilentStatusIcons(hide);
3944             handleSavePolicyFile();
3945 
3946             mListeners.onStatusBarIconsBehaviorChanged(hide);
3947         }
3948 
3949         @Override
3950         public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) {
3951             checkCallerIsSystem();
3952             mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime);
3953         }
3954 
3955         @Override
3956         public NotificationListenerFilter getListenerFilter(ComponentName cn, int userId) {
3957             checkCallerIsSystem();
3958             return mListeners.getNotificationListenerFilter(Pair.create(cn, userId));
3959         }
3960 
3961         @Override
3962         public void setListenerFilter(ComponentName cn, int userId,
3963                 NotificationListenerFilter nlf) {
3964             checkCallerIsSystem();
3965             mListeners.setNotificationListenerFilter(Pair.create(cn, userId), nlf);
3966             // TODO (b/173052211): cancel notifications for listeners that can no longer see them
3967             handleSavePolicyFile();
3968         }
3969 
3970         @Override
3971         public int getPackageImportance(String pkg) {
3972             checkCallerIsSystemOrSameApp(pkg);
3973             if (mPermissionHelper.hasPermission(Binder.getCallingUid())) {
3974                 return IMPORTANCE_DEFAULT;
3975             } else {
3976                 return IMPORTANCE_NONE;
3977             }
3978         }
3979 
3980         @Override
3981         public boolean isImportanceLocked(String pkg, int uid) {
3982             checkCallerIsSystem();
3983             return mPreferencesHelper.isImportanceLocked(pkg, uid);
3984         }
3985 
3986         @Override
3987         public boolean canShowBadge(String pkg, int uid) {
3988             checkCallerIsSystem();
3989             return mPreferencesHelper.canShowBadge(pkg, uid);
3990         }
3991 
3992         @Override
3993         public void setShowBadge(String pkg, int uid, boolean showBadge) {
3994             checkCallerIsSystem();
3995             mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
3996             handleSavePolicyFile();
3997         }
3998 
3999         @Override
4000         public boolean hasSentValidMsg(String pkg, int uid) {
4001             checkCallerIsSystem();
4002             return mPreferencesHelper.hasSentValidMsg(pkg, uid);
4003         }
4004 
4005         @Override
4006         public boolean isInInvalidMsgState(String pkg, int uid) {
4007             checkCallerIsSystem();
4008             return mPreferencesHelper.isInInvalidMsgState(pkg, uid);
4009         }
4010 
4011         @Override
4012         public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) {
4013             checkCallerIsSystem();
4014             return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid);
4015         }
4016 
4017         @Override
4018         public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) {
4019             checkCallerIsSystem();
4020             mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted);
4021             handleSavePolicyFile();
4022         }
4023 
4024         @Override
4025         public boolean hasSentValidBubble(String pkg, int uid) {
4026             checkCallerIsSystem();
4027             return mPreferencesHelper.hasSentValidBubble(pkg, uid);
4028         }
4029 
4030         @Override
4031         public void setNotificationDelegate(String callingPkg, String delegate) {
4032             checkCallerIsSameApp(callingPkg);
4033             final int callingUid = Binder.getCallingUid();
4034             UserHandle user = UserHandle.getUserHandleForUid(callingUid);
4035             if (delegate == null) {
4036                 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
4037                 handleSavePolicyFile();
4038             } else {
4039                 try {
4040                     ApplicationInfo info =
4041                             mPackageManager.getApplicationInfo(delegate,
4042                                     MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
4043                                     user.getIdentifier());
4044                     if (info != null) {
4045                         mPreferencesHelper.setNotificationDelegate(
4046                                 callingPkg, callingUid, delegate, info.uid);
4047                         handleSavePolicyFile();
4048                     }
4049                 } catch (RemoteException e) {
4050                     e.rethrowFromSystemServer();
4051                 }
4052             }
4053         }
4054 
4055         @Override
4056         public String getNotificationDelegate(String callingPkg) {
4057             // callable by Settings also
4058             checkCallerIsSystemOrSameApp(callingPkg);
4059             return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
4060         }
4061 
4062         @Override
4063         public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) {
4064             checkCallerIsSameApp(callingPkg);
4065             final int callingUid = Binder.getCallingUid();
4066             UserHandle user = UserHandle.getUserHandleForUid(callingUid);
4067             if (user.getIdentifier() != userId) {
4068                 getContext().enforceCallingPermission(
4069                         android.Manifest.permission.INTERACT_ACROSS_USERS,
4070                         "canNotifyAsPackage for user " + userId);
4071             }
4072             if (callingPkg.equals(targetPkg)) {
4073                 return true;
4074             }
4075             try {
4076                 ApplicationInfo info =
4077                         mPackageManager.getApplicationInfo(targetPkg,
4078                                 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
4079                                 userId);
4080                 if (info != null) {
4081                     return mPreferencesHelper.isDelegateAllowed(
4082                             targetPkg, info.uid, callingPkg, callingUid);
4083                 }
4084             } catch (RemoteException e) {
4085                 // :(
4086             }
4087             return false;
4088         }
4089 
4090         @Override
4091         public boolean canUseFullScreenIntent(@NonNull AttributionSource attributionSource) {
4092             final String packageName = attributionSource.getPackageName();
4093             final int uid = attributionSource.getUid();
4094             final int userId = UserHandle.getUserId(uid);
4095             checkCallerIsSameApp(packageName, uid, userId);
4096 
4097             final ApplicationInfo applicationInfo;
4098             try {
4099                 applicationInfo = mPackageManagerClient.getApplicationInfoAsUser(
4100                         packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
4101             } catch (NameNotFoundException e) {
4102                 Slog.e(TAG, "Failed to getApplicationInfo() in canUseFullScreenIntent()", e);
4103                 return false;
4104             }
4105             return checkUseFullScreenIntentPermission(attributionSource, applicationInfo,
4106                     false /* forDataDelivery */);
4107         }
4108 
4109         @Override
4110         public void updateNotificationChannelGroupForPackage(String pkg, int uid,
4111                 NotificationChannelGroup group) throws RemoteException {
4112             enforceSystemOrSystemUI("Caller not system or systemui");
4113             createNotificationChannelGroup(pkg, uid, group, false, false);
4114             handleSavePolicyFile();
4115         }
4116 
4117         @Override
4118         public void createNotificationChannelGroups(String pkg,
4119                 ParceledListSlice channelGroupList) throws RemoteException {
4120             checkCallerIsSystemOrSameApp(pkg);
4121             List<NotificationChannelGroup> groups = channelGroupList.getList();
4122             final int groupSize = groups.size();
4123             for (int i = 0; i < groupSize; i++) {
4124                 final NotificationChannelGroup group = groups.get(i);
4125                 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
4126             }
4127             handleSavePolicyFile();
4128         }
4129 
4130         private void createNotificationChannelsImpl(String pkg, int uid,
4131                 ParceledListSlice channelsList) {
4132             createNotificationChannelsImpl(pkg, uid, channelsList,
4133                     ActivityTaskManager.INVALID_TASK_ID);
4134         }
4135 
4136         private void createNotificationChannelsImpl(String pkg, int uid,
4137                 ParceledListSlice channelsList, int startingTaskId) {
4138             List<NotificationChannel> channels = channelsList.getList();
4139             final int channelsSize = channels.size();
4140             ParceledListSlice<NotificationChannel> oldChannels =
4141                     mPreferencesHelper.getNotificationChannels(pkg, uid, true);
4142             final boolean hadChannel = oldChannels != null && !oldChannels.getList().isEmpty();
4143             boolean needsPolicyFileChange = false;
4144             boolean hasRequestedNotificationPermission = false;
4145             for (int i = 0; i < channelsSize; i++) {
4146                 final NotificationChannel channel = channels.get(i);
4147                 Objects.requireNonNull(channel, "channel in list is null");
4148                 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid,
4149                         channel, true /* fromTargetApp */,
4150                         mConditionProviders.isPackageOrComponentAllowed(
4151                                 pkg, UserHandle.getUserId(uid)), Binder.getCallingUid(),
4152                         isCallerSystemOrSystemUi());
4153                 if (needsPolicyFileChange) {
4154                     mListeners.notifyNotificationChannelChanged(pkg,
4155                             UserHandle.getUserHandleForUid(uid),
4156                             mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
4157                                     false),
4158                             NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
4159                     boolean hasChannel = hadChannel || hasRequestedNotificationPermission;
4160                     if (!hasChannel) {
4161                         ParceledListSlice<NotificationChannel> currChannels =
4162                                 mPreferencesHelper.getNotificationChannels(pkg, uid, true);
4163                         hasChannel = currChannels != null && !currChannels.getList().isEmpty();
4164                     }
4165                     if (!hadChannel && hasChannel && !hasRequestedNotificationPermission
4166                             && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
4167                         hasRequestedNotificationPermission = true;
4168                         if (mPermissionPolicyInternal == null) {
4169                             mPermissionPolicyInternal =
4170                                     LocalServices.getService(PermissionPolicyInternal.class);
4171                         }
4172                         mHandler.post(new ShowNotificationPermissionPromptRunnable(pkg,
4173                                 UserHandle.getUserId(uid), startingTaskId,
4174                                 mPermissionPolicyInternal));
4175                     }
4176                 }
4177             }
4178             if (needsPolicyFileChange) {
4179                 handleSavePolicyFile();
4180             }
4181         }
4182 
4183         @Override
4184         public void createNotificationChannels(String pkg, ParceledListSlice channelsList) {
4185             checkCallerIsSystemOrSameApp(pkg);
4186             int taskId = ActivityTaskManager.INVALID_TASK_ID;
4187             try {
4188                 int uid = mPackageManager.getPackageUid(pkg, 0,
4189                         UserHandle.getUserId(Binder.getCallingUid()));
4190                 taskId = mAtm.getTaskToShowPermissionDialogOn(pkg, uid);
4191             } catch (RemoteException e) {
4192                 // Do nothing
4193             }
4194             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList, taskId);
4195         }
4196 
4197         @Override
4198         public void createNotificationChannelsForPackage(String pkg, int uid,
4199                 ParceledListSlice channelsList) {
4200             enforceSystemOrSystemUI("only system can call this");
4201             createNotificationChannelsImpl(pkg, uid, channelsList);
4202         }
4203 
4204         @Override
4205         public void createConversationNotificationChannelForPackage(String pkg, int uid,
4206                 NotificationChannel parentChannel, String conversationId) {
4207             enforceSystemOrSystemUI("only system can call this");
4208             checkNotNull(parentChannel);
4209             checkNotNull(conversationId);
4210             String parentId = parentChannel.getId();
4211             NotificationChannel conversationChannel = parentChannel;
4212             conversationChannel.setId(String.format(
4213                     CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId));
4214             conversationChannel.setConversationId(parentId, conversationId);
4215             createNotificationChannelsImpl(
4216                     pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel)));
4217             mRankingHandler.requestSort();
4218             handleSavePolicyFile();
4219         }
4220 
4221         @Override
4222         public NotificationChannel getNotificationChannel(String callingPkg, int userId,
4223                 String targetPkg, String channelId) {
4224             return getConversationNotificationChannel(
4225                     callingPkg, userId, targetPkg, channelId, true, null);
4226         }
4227 
4228         @Override
4229         public NotificationChannel getConversationNotificationChannel(String callingPkg, int userId,
4230                 String targetPkg, String channelId, boolean returnParentIfNoConversationChannel,
4231                 String conversationId) {
4232             if (canNotifyAsPackage(callingPkg, targetPkg, userId)
4233                     || isCallerSystemOrSystemUiOrShell()) {
4234                 int targetUid = -1;
4235                 try {
4236                     targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4237                 } catch (NameNotFoundException e) {
4238                     /* ignore */
4239                 }
4240                 return mPreferencesHelper.getConversationNotificationChannel(
4241                         targetPkg, targetUid, channelId, conversationId,
4242                         returnParentIfNoConversationChannel, false /* includeDeleted */);
4243             }
4244             throw new SecurityException("Pkg " + callingPkg
4245                     + " cannot read channels for " + targetPkg + " in " + userId);
4246         }
4247 
4248         @Override
4249         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
4250                 String channelId, String conversationId, boolean includeDeleted) {
4251             checkCallerIsSystem();
4252             return mPreferencesHelper.getConversationNotificationChannel(
4253                     pkg, uid, channelId, conversationId, true, includeDeleted);
4254         }
4255 
4256         // Returns 'true' if the given channel has a notification associated
4257         // with an active foreground service.
4258         private void enforceDeletingChannelHasNoFgService(String pkg, int userId,
4259                 String channelId) {
4260             if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) {
4261                 Slog.w(TAG, "Package u" + userId + "/" + pkg
4262                         + " may not delete notification channel '"
4263                         + channelId + "' with fg service");
4264                 throw new SecurityException("Not allowed to delete channel " + channelId
4265                         + " with a foreground service");
4266             }
4267         }
4268 
4269         // Throws a security exception if the given channel has a notification associated
4270         // with an active user-initiated job.
4271         private void enforceDeletingChannelHasNoUserInitiatedJob(String pkg, int userId,
4272                 String channelId) {
4273             final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
4274             if (js != null && js.isNotificationChannelAssociatedWithAnyUserInitiatedJobs(
4275                     channelId, userId, pkg)) {
4276                 Slog.w(TAG, "Package u" + userId + "/" + pkg
4277                         + " may not delete notification channel '"
4278                         + channelId + "' with user-initiated job");
4279                 throw new SecurityException("Not allowed to delete channel " + channelId
4280                         + " with a user-initiated job");
4281             }
4282         }
4283 
4284         @Override
4285         public void deleteNotificationChannel(String pkg, String channelId) {
4286             checkCallerIsSystemOrSameApp(pkg);
4287             final int callingUid = Binder.getCallingUid();
4288             final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
4289             final int callingUser = UserHandle.getUserId(callingUid);
4290             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4291                 throw new IllegalArgumentException("Cannot delete default channel");
4292             }
4293             enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
4294             enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId);
4295             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
4296                     callingUser, REASON_CHANNEL_REMOVED);
4297             boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
4298                     pkg, callingUid, channelId, callingUid, isSystemOrSystemUi);
4299             if (previouslyExisted) {
4300                 // Remove from both recent notification archive (recently dismissed notifications)
4301                 // and notification history
4302                 mArchive.removeChannelNotifications(pkg, callingUser, channelId);
4303                 mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
4304                 mListeners.notifyNotificationChannelChanged(pkg,
4305                         UserHandle.getUserHandleForUid(callingUid),
4306                         mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
4307                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
4308                 handleSavePolicyFile();
4309             }
4310         }
4311 
4312         @Override
4313         public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
4314             checkCallerIsSystemOrSameApp(pkg);
4315             return mPreferencesHelper.getNotificationChannelGroupWithChannels(
4316                     pkg, Binder.getCallingUid(), groupId, false);
4317         }
4318 
4319         @Override
4320         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
4321                 String pkg) {
4322             checkCallerIsSystemOrSameApp(pkg);
4323             return mPreferencesHelper.getNotificationChannelGroups(
4324                     pkg, Binder.getCallingUid(), false, false, true, true, null);
4325         }
4326 
4327         @Override
4328         public void deleteNotificationChannelGroup(String pkg, String groupId) {
4329             checkCallerIsSystemOrSameApp(pkg);
4330 
4331             final int callingUid = Binder.getCallingUid();
4332             final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
4333             NotificationChannelGroup groupToDelete =
4334                     mPreferencesHelper.getNotificationChannelGroupWithChannels(
4335                             pkg, callingUid, groupId, false);
4336             if (groupToDelete != null) {
4337                 // Preflight for allowability
4338                 final int userId = UserHandle.getUserId(callingUid);
4339                 List<NotificationChannel> groupChannels = groupToDelete.getChannels();
4340                 for (int i = 0; i < groupChannels.size(); i++) {
4341                     final String channelId = groupChannels.get(i).getId();
4342                     enforceDeletingChannelHasNoFgService(pkg, userId, channelId);
4343                     enforceDeletingChannelHasNoUserInitiatedJob(pkg, userId, channelId);
4344                 }
4345                 List<NotificationChannel> deletedChannels =
4346                         mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId,
4347                                 callingUid, isSystemOrSystemUi);
4348                 for (int i = 0; i < deletedChannels.size(); i++) {
4349                     final NotificationChannel deletedChannel = deletedChannels.get(i);
4350                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
4351                             userId, REASON_CHANNEL_REMOVED
4352                     );
4353                     mListeners.notifyNotificationChannelChanged(pkg,
4354                             UserHandle.getUserHandleForUid(callingUid),
4355                             deletedChannel,
4356                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
4357                 }
4358                 mListeners.notifyNotificationChannelGroupChanged(
4359                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
4360                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
4361                 handleSavePolicyFile();
4362             }
4363         }
4364 
4365         @Override
4366         public void updateNotificationChannelForPackage(String pkg, int uid,
4367                 NotificationChannel channel) {
4368             checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
4369             Objects.requireNonNull(channel);
4370             updateNotificationChannelInt(pkg, uid, channel, false);
4371         }
4372 
4373         @Override
4374         public void unlockNotificationChannel(String pkg, int uid, String channelId) {
4375             checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
4376             mPreferencesHelper.unlockNotificationChannelImportance(pkg, uid, channelId);
4377             handleSavePolicyFile();
4378         }
4379 
4380         @Override
4381         public void unlockAllNotificationChannels() {
4382             checkCallerIsSystem();
4383             mPreferencesHelper.unlockAllNotificationChannels();
4384             handleSavePolicyFile();
4385         }
4386 
4387         @Override
4388         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
4389                 int uid, boolean includeDeleted) {
4390             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
4391             return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
4392         }
4393 
4394         @Override
4395         public int getNumNotificationChannelsForPackage(String pkg, int uid,
4396                 boolean includeDeleted) {
4397             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
4398             return NotificationManagerService.this
4399                     .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted);
4400         }
4401 
4402         @Override
4403         public boolean onlyHasDefaultChannel(String pkg, int uid) {
4404             enforceSystemOrSystemUI("onlyHasDefaultChannel");
4405             return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
4406         }
4407 
4408         @Override
4409         public int getDeletedChannelCount(String pkg, int uid) {
4410             enforceSystemOrSystemUI("getDeletedChannelCount");
4411             return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
4412         }
4413 
4414         @Override
4415         public int getBlockedChannelCount(String pkg, int uid) {
4416             enforceSystemOrSystemUI("getBlockedChannelCount");
4417             return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
4418         }
4419 
4420         @Override
4421         public ParceledListSlice<ConversationChannelWrapper> getConversations(
4422                 boolean onlyImportant) {
4423             enforceSystemOrSystemUI("getConversations");
4424             IntArray userIds = mUserProfiles.getCurrentProfileIds();
4425             ArrayList<ConversationChannelWrapper> conversations =
4426                     mPreferencesHelper.getConversations(userIds, onlyImportant);
4427             for (ConversationChannelWrapper conversation : conversations) {
4428                 if (mShortcutHelper == null) {
4429                     conversation.setShortcutInfo(null);
4430                 } else {
4431                     conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
4432                             conversation.getNotificationChannel().getConversationId(),
4433                             conversation.getPkg(),
4434                             UserHandle.of(UserHandle.getUserId(conversation.getUid()))));
4435                 }
4436             }
4437             return new ParceledListSlice<>(conversations);
4438         }
4439 
4440         @Override
4441         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
4442                 String pkg, int uid, boolean includeDeleted) {
4443             enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
4444             return mPreferencesHelper.getNotificationChannelGroups(
4445                     pkg, uid, includeDeleted, true, false, true, null);
4446         }
4447 
4448         @Override
4449         public ParceledListSlice<NotificationChannelGroup>
4450                 getRecentBlockedNotificationChannelGroupsForPackage(String pkg, int uid) {
4451             enforceSystemOrSystemUI("getRecentBlockedNotificationChannelGroupsForPackage");
4452             Set<String> recentlySentChannels = new HashSet<>();
4453             long now = System.currentTimeMillis();
4454             long startTime = now - (DateUtils.DAY_IN_MILLIS * 14);
4455             UsageEvents events = mUsageStatsManagerInternal.queryEventsForUser(
4456                 UserHandle.getUserId(uid),  startTime, now, UsageEvents.SHOW_ALL_EVENT_DATA);
4457             // get all channelids that sent notifs in the past 2 weeks
4458             if (events != null) {
4459                 UsageEvents.Event event = new UsageEvents.Event();
4460                 while (events.hasNextEvent()) {
4461                     events.getNextEvent(event);
4462                     if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) {
4463                         if (pkg.equals(event.mPackage)) {
4464                             String channelId = event.mNotificationChannelId;
4465                             if (channelId != null) {
4466                                 recentlySentChannels.add(channelId);
4467                             }
4468                         }
4469                     }
4470                 }
4471             }
4472 
4473             return mPreferencesHelper.getNotificationChannelGroups(
4474                     pkg, uid, false, true, false, true, recentlySentChannels);
4475         }
4476 
4477         @Override
4478         public ParceledListSlice<ConversationChannelWrapper> getConversationsForPackage(String pkg,
4479                 int uid) {
4480             enforceSystemOrSystemUI("getConversationsForPackage");
4481             ArrayList<ConversationChannelWrapper> conversations =
4482                     mPreferencesHelper.getConversations(pkg, uid);
4483             for (ConversationChannelWrapper conversation : conversations) {
4484                 if (mShortcutHelper == null) {
4485                     conversation.setShortcutInfo(null);
4486                 } else {
4487                     conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
4488                             conversation.getNotificationChannel().getConversationId(),
4489                             pkg,
4490                             UserHandle.of(UserHandle.getUserId(uid))));
4491                 }
4492             }
4493             return new ParceledListSlice<>(conversations);
4494         }
4495 
4496         @Override
4497         public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
4498                 String pkg, int uid, String groupId, boolean includeDeleted) {
4499             enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
4500             return mPreferencesHelper.getNotificationChannelGroupWithChannels(
4501                     pkg, uid, groupId, includeDeleted);
4502         }
4503 
4504         @Override
4505         public NotificationChannelGroup getNotificationChannelGroupForPackage(
4506                 String groupId, String pkg, int uid) {
4507             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
4508             return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
4509         }
4510 
4511         @Override
4512         public ParceledListSlice<NotificationChannel> getNotificationChannels(
4513                 String callingPkg, String targetPkg, int userId) {
4514             if (canNotifyAsPackage(callingPkg, targetPkg, userId)
4515                 || isCallingUidSystem()) {
4516                 int targetUid = -1;
4517                 try {
4518                     targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4519                 } catch (NameNotFoundException e) {
4520                     /* ignore */
4521                 }
4522                 return mPreferencesHelper.getNotificationChannels(
4523                         targetPkg, targetUid, false /* includeDeleted */);
4524             }
4525             throw new SecurityException("Pkg " + callingPkg
4526                     + " cannot read channels for " + targetPkg + " in " + userId);
4527         }
4528 
4529         @Override
4530         public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
4531                 String pkg, int uid) {
4532             checkCallerIsSystem();
4533             if (!areNotificationsEnabledForPackage(pkg, uid)) {
4534                 return ParceledListSlice.emptyList();
4535             }
4536             return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid);
4537         }
4538 
4539         @Override
4540         public List<String> getPackagesBypassingDnd(int userId,
4541                                                     boolean includeConversationChannels) {
4542             checkCallerIsSystem();
4543 
4544             final ArraySet<String> packageNames = new ArraySet<>();
4545 
4546             for (int user : mUm.getProfileIds(userId, false)) {
4547                 List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, user);
4548                 for (PackageInfo pi : pkgs) {
4549                     String pkg = pi.packageName;
4550                     // If any NotificationChannel for this package is bypassing, the
4551                     // package is considered bypassing.
4552                     for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg,
4553                             pi.applicationInfo.uid).getList()) {
4554                         // Skips non-demoted conversation channels.
4555                         if (!includeConversationChannels
4556                                 && !TextUtils.isEmpty(channel.getConversationId())
4557                                 && !channel.isDemoted()) {
4558                             continue;
4559                         }
4560                         packageNames.add(pkg);
4561                     }
4562                 }
4563             }
4564             return new ArrayList<String>(packageNames);
4565         }
4566 
4567         @Override
4568         public boolean areChannelsBypassingDnd() {
4569             if (android.app.Flags.modesApi()) {
4570                 return mZenModeHelper.getConsolidatedNotificationPolicy().allowPriorityChannels()
4571                         && mPreferencesHelper.areChannelsBypassingDnd();
4572             }
4573             return mPreferencesHelper.areChannelsBypassingDnd();
4574         }
4575 
4576         @Override
4577         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
4578             boolean packagesChanged = false;
4579             checkCallerIsSystem();
4580             // Cancel posted notifications
4581             final int userId = UserHandle.getUserId(uid);
4582             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0,
4583                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CLEAR_DATA);
4584 
4585             // Zen
4586             packagesChanged |=
4587                     mConditionProviders.resetPackage(packageName, userId);
4588 
4589             // Listener
4590             ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
4591                     mListeners.resetComponents(packageName, userId);
4592             packagesChanged |= changedListeners.get(true).size() > 0
4593                     || changedListeners.get(false).size() > 0;
4594 
4595             // When a listener is enabled, we enable the dnd package as a secondary
4596             for (int i = 0; i < changedListeners.get(true).size(); i++) {
4597                 mConditionProviders.setPackageOrComponentEnabled(
4598                         changedListeners.get(true).get(i).getPackageName(),
4599                         userId, false, true);
4600             }
4601 
4602             // Assistant
4603             ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants =
4604                     mAssistants.resetComponents(packageName, userId);
4605             packagesChanged |= changedAssistants.get(true).size() > 0
4606                     || changedAssistants.get(false).size() > 0;
4607 
4608             // we want only one assistant enabled
4609             for (int i = 1; i < changedAssistants.get(true).size(); i++) {
4610                 mAssistants.setPackageOrComponentEnabled(
4611                         changedAssistants.get(true).get(i).flattenToString(),
4612                         userId, true, false);
4613             }
4614 
4615             // When the default assistant is enabled, we enable the dnd package as a secondary
4616             if (changedAssistants.get(true).size() > 0) {
4617                 //we want only one assistant active
4618                 mConditionProviders
4619                         .setPackageOrComponentEnabled(
4620                                 changedAssistants.get(true).get(0).getPackageName(),
4621                                 userId, false, true);
4622 
4623             }
4624 
4625             // Snoozing
4626             mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
4627 
4628             // Reset notification preferences
4629             if (!fromApp) {
4630                 mPreferencesHelper.clearData(packageName, uid);
4631             }
4632 
4633             if (packagesChanged) {
4634                 getContext().sendBroadcastAsUser(new Intent(
4635                                 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4636                                 .setPackage(packageName)
4637                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
4638                         UserHandle.of(userId), null);
4639             }
4640 
4641             handleSavePolicyFile();
4642         }
4643 
4644         @Override
4645         public List<String> getAllowedAssistantAdjustments(String pkg) {
4646             checkCallerIsSystemOrSameApp(pkg);
4647 
4648             if (!isCallerSystemOrPhone()
4649                     && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
4650                     throw new SecurityException("Not currently an assistant");
4651             }
4652 
4653             return mAssistants.getAllowedAssistantAdjustments();
4654         }
4655 
4656         /**
4657          * @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead.
4658          */
4659         @Deprecated
4660         @Override
4661         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
4662             return getActiveNotificationsWithAttribution(callingPkg, null);
4663         }
4664 
4665         /**
4666          * System-only API for getting a list of current (i.e. not cleared) notifications.
4667          *
4668          * Requires ACCESS_NOTIFICATIONS which is signature|system.
4669          * @returns A list of all the notifications, in natural order.
4670          */
4671         @Override
4672         @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
4673         public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg,
4674                 String callingAttributionTag) {
4675             // enforce() will ensure the calling uid has the correct permission
4676             getActiveNotificationsWithAttribution_enforcePermission();
4677 
4678             ArrayList<StatusBarNotification> tmp = new ArrayList<>();
4679             int uid = Binder.getCallingUid();
4680 
4681             ArrayList<Integer> currentUsers = new ArrayList<>();
4682             currentUsers.add(USER_ALL);
4683             Binder.withCleanCallingIdentity(() -> {
4684                 for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) {
4685                     currentUsers.add(user);
4686                 }
4687             });
4688 
4689             // noteOp will check to make sure the callingPkg matches the uid
4690             int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
4691                         callingAttributionTag, null);
4692             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
4693                 synchronized (mNotificationLock) {
4694                     final int N = mNotificationList.size();
4695                     for (int i = 0; i < N; i++) {
4696                         final StatusBarNotification sbn = mNotificationList.get(i).getSbn();
4697                         if (currentUsers.contains(sbn.getUserId())) {
4698                             tmp.add(sbn);
4699                         }
4700                     }
4701                 }
4702             }
4703             return tmp.toArray(new StatusBarNotification[tmp.size()]);
4704         }
4705 
4706         /**
4707          * Public API for getting a list of current notifications for the calling package/uid.
4708          *
4709          * Note that since notification posting is done asynchronously, this will not return
4710          * notifications that are in the process of being posted.
4711          *
4712          * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as
4713          * an app's notification delegate via
4714          * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}.
4715          *
4716          * @returns A list of all the package's notifications, in natural order.
4717          */
4718         @Override
4719         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
4720                 int incomingUserId) {
4721             checkCallerIsSystemOrSameApp(pkg);
4722             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
4723                     Binder.getCallingUid(), incomingUserId, true, false,
4724                     "getAppActiveNotifications", pkg);
4725             synchronized (mNotificationLock) {
4726                 final ArrayMap<String, StatusBarNotification> map
4727                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
4728                 final int N = mNotificationList.size();
4729                 for (int i = 0; i < N; i++) {
4730                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
4731                             mNotificationList.get(i).getSbn());
4732                     if (sbn != null) {
4733                         map.put(sbn.getKey(), sbn);
4734                     }
4735                 }
4736                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
4737                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.getSbn());
4738                     if (sbn != null) {
4739                         map.put(sbn.getKey(), sbn);
4740                     }
4741                 }
4742                 final int M = mEnqueuedNotifications.size();
4743                 for (int i = 0; i < M; i++) {
4744                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
4745                             mEnqueuedNotifications.get(i).getSbn());
4746                     if (sbn != null) {
4747                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
4748                     }
4749                 }
4750                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
4751                 list.addAll(map.values());
4752                 return new ParceledListSlice<StatusBarNotification>(list);
4753             }
4754         }
4755 
4756         /** Notifications returned here will have allowlistToken stripped from them. */
4757         private StatusBarNotification sanitizeSbn(String pkg, int userId,
4758                 StatusBarNotification sbn) {
4759             if (sbn.getUserId() == userId) {
4760                 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) {
4761                     // We could pass back a cloneLight() but clients might get confused and
4762                     // try to send this thing back to notify() again, which would not work
4763                     // very well.
4764                     Notification notification = sbn.getNotification().clone();
4765                     // Remove background token before returning notification to untrusted app, this
4766                     // ensures the app isn't able to perform background operations that are
4767                     // associated with notification interactions.
4768                     notification.overrideAllowlistToken(null);
4769                     return new StatusBarNotification(
4770                             sbn.getPackageName(),
4771                             sbn.getOpPkg(),
4772                             sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
4773                             notification,
4774                             sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
4775                 }
4776             }
4777             return null;
4778         }
4779 
4780         /**
4781          * @deprecated Use {@link #getHistoricalNotificationsWithAttribution} instead.
4782          */
4783         @Deprecated
4784         @Override
4785         @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
4786         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count,
4787                 boolean includeSnoozed) {
4788             return getHistoricalNotificationsWithAttribution(callingPkg, null, count,
4789                     includeSnoozed);
4790         }
4791 
4792         /**
4793          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
4794          */
4795         @Override
4796         @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
4797         @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
4798         public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg,
4799                 String callingAttributionTag, int count, boolean includeSnoozed) {
4800             // enforce() will ensure the calling uid has the correct permission
4801             getHistoricalNotificationsWithAttribution_enforcePermission();
4802 
4803             StatusBarNotification[] tmp = null;
4804             int uid = Binder.getCallingUid();
4805 
4806             // noteOp will check to make sure the callingPkg matches the uid
4807             int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
4808                         callingAttributionTag, null);
4809             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
4810                 synchronized (mArchive) {
4811                     tmp = mArchive.getArray(mUm, count, includeSnoozed);
4812                 }
4813             }
4814             return tmp;
4815         }
4816 
4817         /**
4818          * System-only API for getting a list of historical notifications. May contain multiple days
4819          * of notifications.
4820          */
4821         @Override
4822         @WorkerThread
4823         @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
4824         @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
4825         public NotificationHistory getNotificationHistory(String callingPkg,
4826                 String callingAttributionTag) {
4827             // enforce() will ensure the calling uid has the correct permission
4828             getNotificationHistory_enforcePermission();
4829             int uid = Binder.getCallingUid();
4830 
4831             // noteOp will check to make sure the callingPkg matches the uid
4832             int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
4833                         callingAttributionTag, null);
4834             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
4835                 IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();
4836                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory");
4837                 try {
4838                     return mHistoryManager.readNotificationHistory(currentUserIds.toArray());
4839                 } finally {
4840                     Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
4841                 }
4842             }
4843             return new NotificationHistory();
4844         }
4845 
4846         /**
4847          * Register a listener to be notified when a call notification is posted or removed
4848          * for a specific package and user.
4849          * @param packageName Which package to monitor
4850          * @param userHandle Which user to monitor
4851          * @param listener Listener to register
4852          */
4853         @Override
4854         @EnforcePermission(allOf = {
4855                 android.Manifest.permission.INTERACT_ACROSS_USERS,
4856                 android.Manifest.permission.ACCESS_NOTIFICATIONS})
4857         public void registerCallNotificationEventListener(String packageName, UserHandle userHandle,
4858                 ICallNotificationEventCallback listener) {
4859             registerCallNotificationEventListener_enforcePermission();
4860 
4861             final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT
4862                     ? userHandle.getIdentifier() : mAmi.getCurrentUserId();
4863 
4864             synchronized (mCallNotificationEventCallbacks) {
4865                 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
4866                         callbacksForPackage =
4867                         mCallNotificationEventCallbacks.getOrDefault(packageName, new ArrayMap<>());
4868                 RemoteCallbackList<ICallNotificationEventCallback> callbackList =
4869                         callbacksForPackage.getOrDefault(userId, new RemoteCallbackList<>());
4870 
4871                 if (callbackList.register(listener)) {
4872                     callbacksForPackage.put(userId, callbackList);
4873                     mCallNotificationEventCallbacks.put(packageName, callbacksForPackage);
4874                 } else {
4875                     Log.e(TAG,
4876                             "registerCallNotificationEventListener failed to register listener: "
4877                                 + packageName + " " + userHandle + " " + listener);
4878                     return;
4879                 }
4880             }
4881 
4882             synchronized (mNotificationLock) {
4883                 for (NotificationRecord r : mNotificationList) {
4884                     if (r.getNotification().isStyle(Notification.CallStyle.class)
4885                             && notificationMatchesUserId(r, userId, false)
4886                             && r.getSbn().getPackageName().equals(packageName)) {
4887                         try {
4888                             listener.onCallNotificationPosted(packageName, r.getUser());
4889                         } catch (RemoteException e) {
4890                             throw new RuntimeException(e);
4891                         }
4892                     }
4893                 }
4894             }
4895         }
4896 
4897         /**
4898          * Unregister a listener that was previously
4899          * registered with {@link #registerCallNotificationEventListener}
4900          *
4901          * @param packageName Which package to stop monitoring
4902          * @param userHandle Which user to stop monitoring
4903          * @param listener Listener to unregister
4904          */
4905         @Override
4906         @EnforcePermission(allOf = {
4907             android.Manifest.permission.INTERACT_ACROSS_USERS,
4908             android.Manifest.permission.ACCESS_NOTIFICATIONS})
4909         public void unregisterCallNotificationEventListener(String packageName,
4910                     UserHandle userHandle, ICallNotificationEventCallback listener) {
4911             unregisterCallNotificationEventListener_enforcePermission();
4912             synchronized (mCallNotificationEventCallbacks) {
4913                 final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT
4914                         ? userHandle.getIdentifier() : mAmi.getCurrentUserId();
4915 
4916                 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
4917                         callbacksForPackage = mCallNotificationEventCallbacks.get(packageName);
4918                 if (callbacksForPackage == null) {
4919                     return;
4920                 }
4921                 RemoteCallbackList<ICallNotificationEventCallback> callbackList =
4922                         callbacksForPackage.get(userId);
4923                 if (callbackList == null) {
4924                     return;
4925                 }
4926                 if (!callbackList.unregister(listener)) {
4927                     Log.e(TAG,
4928                             "unregisterCallNotificationEventListener listener not found for: "
4929                             + packageName + " " + userHandle + " " + listener);
4930                 }
4931             }
4932         }
4933 
4934         /**
4935          * Register a listener binder directly with the notification manager.
4936          *
4937          * Only works with system callers. Apps should extend
4938          * {@link NotificationListenerService}.
4939          */
4940         @Override
4941         public void registerListener(final INotificationListener listener,
4942                 final ComponentName component, final int userid) {
4943             enforceSystemOrSystemUI("INotificationManager.registerListener");
4944             mListeners.registerSystemService(listener, component, userid, Binder.getCallingUid());
4945         }
4946 
4947         /**
4948          * Remove a listener binder directly
4949          */
4950         @Override
4951         public void unregisterListener(INotificationListener token, int userid) {
4952             mListeners.unregisterService(token, userid);
4953         }
4954 
4955         /**
4956          * Allow an INotificationListener to simulate a "clear all" operation.
4957          *
4958          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
4959          *
4960          * @param token The binder for the listener, to check that the caller is allowed
4961          */
4962         @Override
4963         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
4964             final int callingUid = Binder.getCallingUid();
4965             final int callingPid = Binder.getCallingPid();
4966             final long identity = Binder.clearCallingIdentity();
4967             boolean notificationsRapidlyCleared = false;
4968             final String pkg;
4969             final int packageImportance;
4970             final ManagedServiceInfo info;
4971             try {
4972                 synchronized (mNotificationLock) {
4973                     info = mListeners.checkServiceTokenLocked(token);
4974                     pkg = info.component.getPackageName();
4975                 }
4976                 if (lifetimeExtensionRefactor()) {
4977                     packageImportance = getPackageImportanceWithIdentity(pkg);
4978                 } else {
4979                     packageImportance = IMPORTANCE_NONE;
4980                 }
4981                 synchronized (mNotificationLock) {
4982                     // Cancellation reason. If the token comes from assistant, label the
4983                     // cancellation as coming from the assistant; default to LISTENER_CANCEL.
4984                     int reason = REASON_LISTENER_CANCEL;
4985                     if (mAssistants.isServiceTokenValidLocked(token)) {
4986                         reason = REASON_ASSISTANT_CANCEL;
4987                     }
4988 
4989                     if (keys != null) {
4990                         final int N = keys.length;
4991                         for (int i = 0; i < N; i++) {
4992                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
4993                             if (r == null) continue;
4994                             final int userId = r.getSbn().getUserId();
4995                             if (userId != info.userid && userId != USER_ALL &&
4996                                     !mUserProfiles.isCurrentProfile(userId)) {
4997                                 continue;
4998                             }
4999                             notificationsRapidlyCleared = notificationsRapidlyCleared
5000                                     || isNotificationRecent(r.getUpdateTimeMs());
5001                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
5002                                     r.getSbn().getPackageName(), r.getSbn().getTag(),
5003                                     r.getSbn().getId(), userId, reason);
5004                         }
5005                     } else {
5006                         for (NotificationRecord notificationRecord : mNotificationList) {
5007                             if (isNotificationRecent(notificationRecord.getUpdateTimeMs())) {
5008                                 notificationsRapidlyCleared = true;
5009                                 break;
5010                             }
5011                         }
5012                         if (lifetimeExtensionRefactor()) {
5013                             cancelAllLocked(callingUid, callingPid, info.userid,
5014                                     REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
5015                                     FLAG_ONGOING_EVENT | FLAG_NO_CLEAR
5016                                             | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
5017                             // If cancellation will be prevented due to lifetime extension, we send
5018                             // an update to system UI.
5019                             maybeNotifySystemUiListenerLifetimeExtendedListLocked(
5020                                     mNotificationList, packageImportance);
5021                             maybeNotifySystemUiListenerLifetimeExtendedListLocked(
5022                                     mEnqueuedNotifications, packageImportance);
5023                         } else {
5024                             cancelAllLocked(callingUid, callingPid, info.userid,
5025                                     REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
5026                                     FLAG_ONGOING_EVENT | FLAG_NO_CLEAR);
5027                         }
5028                     }
5029                 }
5030                 if (notificationsRapidlyCleared) {
5031                     mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
5032                             callingUid, pkg, /* attributionTag= */ null, /* message= */ null);
5033                 }
5034             } finally {
5035                 Binder.restoreCallingIdentity(identity);
5036             }
5037         }
5038 
5039         /**
5040          * Handle request from an approved listener to re-enable itself.
5041          *
5042          * @param component The componenet to be re-enabled, caller must match package.
5043          */
5044         @Override
5045         public void requestBindListener(ComponentName component) {
5046             checkCallerIsSystemOrSameApp(component.getPackageName());
5047             int uid = Binder.getCallingUid();
5048             final long identity = Binder.clearCallingIdentity();
5049             try {
5050                 ManagedServices manager =
5051                         mAssistants.isComponentEnabledForCurrentProfiles(component)
5052                         ? mAssistants
5053                         : mListeners;
5054                 manager.setComponentState(component, UserHandle.getUserId(uid), true);
5055             } finally {
5056                 Binder.restoreCallingIdentity(identity);
5057             }
5058         }
5059 
5060         @Override
5061         public void requestUnbindListener(INotificationListener token) {
5062             int uid = Binder.getCallingUid();
5063             final long identity = Binder.clearCallingIdentity();
5064             try {
5065                 // allow bound services to disable themselves
5066                 synchronized (mNotificationLock) {
5067                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5068                     info.getOwner().setComponentState(
5069                             info.component, UserHandle.getUserId(uid), false);
5070                 }
5071             } finally {
5072                 Binder.restoreCallingIdentity(identity);
5073             }
5074         }
5075 
5076         @Override
5077         public void requestUnbindListenerComponent(ComponentName component) {
5078             checkCallerIsSameApp(component.getPackageName());
5079             int uid = Binder.getCallingUid();
5080             final long identity = Binder.clearCallingIdentity();
5081             try {
5082                 synchronized (mNotificationLock) {
5083                     ManagedServices manager =
5084                             mAssistants.isComponentEnabledForCurrentProfiles(component)
5085                                     ? mAssistants
5086                                     : mListeners;
5087                     if (manager.isPackageOrComponentAllowed(component.flattenToString(),
5088                             UserHandle.getUserId(uid))) {
5089                         manager.setComponentState(component, UserHandle.getUserId(uid), false);
5090                     }
5091                 }
5092             } finally {
5093                 Binder.restoreCallingIdentity(identity);
5094             }
5095         }
5096 
5097         @Override
5098         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
5099             final long identity = Binder.clearCallingIdentity();
5100             try {
5101                 synchronized (mNotificationLock) {
5102                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5103                     if (keys == null) {
5104                         return;
5105                     }
5106                     ArrayList<NotificationRecord> seen = new ArrayList<>();
5107                     final int n = keys.length;
5108                     for (int i = 0; i < n; i++) {
5109                         NotificationRecord r = mNotificationsByKey.get(keys[i]);
5110                         if (r == null) continue;
5111                         final int userId = r.getSbn().getUserId();
5112                         if (userId != info.userid && userId != USER_ALL
5113                                 && !mUserProfiles.isCurrentProfile(userId)) {
5114                             continue;
5115                         }
5116                         seen.add(r);
5117                         if (!r.isSeen()) {
5118                             if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
5119                             reportSeen(r);
5120                             r.setSeen();
5121                             maybeRecordInterruptionLocked(r);
5122                         }
5123                     }
5124                     if (!seen.isEmpty()) {
5125                         mAssistants.onNotificationsSeenLocked(seen);
5126                     }
5127                 }
5128             } finally {
5129                 Binder.restoreCallingIdentity(identity);
5130             }
5131         }
5132 
5133         /**
5134          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
5135          *
5136          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
5137          *
5138          * @param info The binder for the listener, to check that the caller is allowed
5139          */
5140         @GuardedBy("mNotificationLock")
5141         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
5142                 int callingUid, int callingPid, String pkg, String tag, int id, int userId,
5143                 int reason) {
5144             int mustNotHaveFlags = FLAG_ONGOING_EVENT;
5145             if (lifetimeExtensionRefactor()) {
5146                 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
5147             }
5148             cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */,
5149                     mustNotHaveFlags,
5150                     true,
5151                     userId, reason, info);
5152         }
5153 
5154         /**
5155          * Allow an INotificationListener to snooze a single notification until a context.
5156          *
5157          * @param token The binder for the listener, to check that the caller is allowed
5158          */
5159         @Override
5160         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
5161                 String key, String snoozeCriterionId) {
5162             final int callingUid = Binder.getCallingUid();
5163             final long identity = Binder.clearCallingIdentity();
5164             try {
5165                 snoozeNotificationInt(callingUid, token, key, SNOOZE_UNTIL_UNSPECIFIED,
5166                         snoozeCriterionId);
5167             } finally {
5168                 Binder.restoreCallingIdentity(identity);
5169             }
5170         }
5171 
5172         /**
5173          * Allow an INotificationListener to snooze a single notification until a time.
5174          *
5175          * @param token The binder for the listener, to check that the caller is allowed
5176          */
5177         @Override
5178         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
5179                 long duration) {
5180             final int callingUid = Binder.getCallingUid();
5181             final long identity = Binder.clearCallingIdentity();
5182             try {
5183                 snoozeNotificationInt(callingUid, token, key, duration, null);
5184             } finally {
5185                 Binder.restoreCallingIdentity(identity);
5186             }
5187         }
5188 
5189         /**
5190          * Allows the notification assistant to un-snooze a single notification.
5191          *
5192          * @param token The binder for the assistant, to check that the caller is allowed
5193          */
5194         @Override
5195         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
5196             final long identity = Binder.clearCallingIdentity();
5197             try {
5198                 synchronized (mNotificationLock) {
5199                     final ManagedServiceInfo info =
5200                             mAssistants.checkServiceTokenLocked(token);
5201                     unsnoozeNotificationInt(key, info, false);
5202                 }
5203             } finally {
5204                 Binder.restoreCallingIdentity(identity);
5205             }
5206         }
5207 
5208         /**
5209          * Allows the notification assistant to un-snooze a single notification.
5210          *
5211          * @param token The binder for the listener, to check that the caller is allowed
5212          */
5213         @Override
5214         public void unsnoozeNotificationFromSystemListener(INotificationListener token,
5215                 String key) {
5216             final long identity = Binder.clearCallingIdentity();
5217             try {
5218                 synchronized (mNotificationLock) {
5219                     final ManagedServiceInfo info =
5220                             mListeners.checkServiceTokenLocked(token);
5221                     if (!info.isSystem) {
5222                         throw new SecurityException("Not allowed to unsnooze before deadline");
5223                     }
5224                     unsnoozeNotificationInt(key, info, true);
5225                 }
5226             } finally {
5227                 Binder.restoreCallingIdentity(identity);
5228             }
5229         }
5230 
5231         /**
5232          * Allows an app to set an initial notification listener filter
5233          *
5234          * @param token The binder for the listener, to check that the caller is allowed
5235          */
5236         @Override
5237         public void migrateNotificationFilter(INotificationListener token, int defaultTypes,
5238                 List<String> disallowedApps) {
5239             final long identity = Binder.clearCallingIdentity();
5240             try {
5241                 synchronized (mNotificationLock) {
5242                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5243 
5244                     Pair key = Pair.create(info.component, info.userid);
5245 
5246                     NotificationListenerFilter nlf = mListeners.getNotificationListenerFilter(key);
5247                     if (nlf == null) {
5248                         nlf = new NotificationListenerFilter();
5249                     }
5250                     if (nlf.getDisallowedPackages().isEmpty() && disallowedApps != null) {
5251                         for (String pkg : disallowedApps) {
5252                             // block the current user's version and any work profile versions
5253                             for (int userId : mUm.getProfileIds(info.userid, false)) {
5254                                 try {
5255                                     int uid = getUidForPackageAndUser(pkg, UserHandle.of(userId));
5256                                     if (uid != INVALID_UID) {
5257                                         VersionedPackage vp = new VersionedPackage(pkg, uid);
5258                                         nlf.addPackage(vp);
5259                                     }
5260                                 } catch (Exception e) {
5261                                     // pkg doesn't exist on that user; skip
5262                                 }
5263                             }
5264                         }
5265                     }
5266                     if (nlf.areAllTypesAllowed()) {
5267                         nlf.setTypes(defaultTypes);
5268                     }
5269                     mListeners.setNotificationListenerFilter(key, nlf);
5270                 }
5271             } finally {
5272                 Binder.restoreCallingIdentity(identity);
5273             }
5274         }
5275 
5276         /**
5277          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
5278          *
5279          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
5280          *
5281          * @param token The binder for the listener, to check that the caller is allowed
5282          */
5283         @Override
5284         public void cancelNotificationFromListener(INotificationListener token, String pkg,
5285                 String tag, int id) {
5286             Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) use " +
5287                     "cancelNotification(key) instead.");
5288         }
5289 
5290         /**
5291          * Allow an INotificationListener to request the list of outstanding notifications seen by
5292          * the current user. Useful when starting up, after which point the listener callbacks
5293          * should be used.
5294          *
5295          * @param token The binder for the listener, to check that the caller is allowed
5296          * @param keys An array of notification keys to fetch, or null to fetch everything
5297          * @returns The return value will contain the notifications specified in keys, in that
5298          *      order, or if keys is null, all the notifications, in natural order.
5299          */
5300         @Override
5301         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
5302                 INotificationListener token, String[] keys, int trim) {
5303             synchronized (mNotificationLock) {
5304                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5305                 final boolean getKeys = keys != null;
5306                 final int N = getKeys ? keys.length : mNotificationList.size();
5307                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
5308                 for (int i=0; i<N; i++) {
5309                     final NotificationRecord r = getKeys
5310                             ? mNotificationsByKey.get(keys[i])
5311                             : mNotificationList.get(i);
5312                     addToListIfNeeded(r, info, list, trim);
5313                 }
5314                 return new ParceledListSlice<>(list);
5315             }
5316         }
5317 
5318         /**
5319          * Allow an INotificationListener to request the list of outstanding snoozed notifications
5320          * seen by the current user. Useful when starting up, after which point the listener
5321          * callbacks should be used.
5322          *
5323          * @param token The binder for the listener, to check that the caller is allowed
5324          * @returns The return value will contain the notifications specified in keys, in that
5325          *      order, or if keys is null, all the notifications, in natural order.
5326          */
5327         @Override
5328         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
5329                 INotificationListener token, int trim) {
5330             synchronized (mNotificationLock) {
5331                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5332                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
5333                 final int N = snoozedRecords.size();
5334                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
5335                 for (int i=0; i < N; i++) {
5336                     addToListIfNeeded(snoozedRecords.get(i), info, list, trim);
5337                 }
5338                 return new ParceledListSlice<>(list);
5339             }
5340         }
5341 
5342         private void addToListIfNeeded(NotificationRecord r, ManagedServiceInfo info,
5343                 ArrayList<StatusBarNotification> notifications, int trim) {
5344             if (r == null) return;
5345             StatusBarNotification sbn = r.getSbn();
5346             if (!isVisibleToListener(sbn, r.getNotificationType(), info)) return;
5347             if (mListeners.hasSensitiveContent(r) && !mListeners.isUidTrusted(info.uid)) {
5348                 notifications.add(mListeners.redactStatusBarNotification(sbn));
5349             } else {
5350                 notifications.add((trim == TRIM_FULL) ? sbn : sbn.cloneLight());
5351             }
5352 
5353         }
5354 
5355         @Override
5356         public void clearRequestedListenerHints(INotificationListener token) {
5357             final long identity = Binder.clearCallingIdentity();
5358             try {
5359                 synchronized (mNotificationLock) {
5360                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5361                     removeDisabledHints(info);
5362                     updateListenerHintsLocked();
5363                     updateEffectsSuppressorLocked();
5364                 }
5365             } finally {
5366                 Binder.restoreCallingIdentity(identity);
5367             }
5368         }
5369 
5370         @Override
5371         public void requestHintsFromListener(INotificationListener token, int hints) {
5372             final long identity = Binder.clearCallingIdentity();
5373             try {
5374                 synchronized (mNotificationLock) {
5375                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5376                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
5377                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
5378                             | HINT_HOST_DISABLE_CALL_EFFECTS;
5379                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
5380                     if (disableEffects) {
5381                         addDisabledHints(info, hints);
5382                     } else {
5383                         removeDisabledHints(info, hints);
5384                     }
5385                     updateListenerHintsLocked();
5386                     updateEffectsSuppressorLocked();
5387                 }
5388             } finally {
5389                 Binder.restoreCallingIdentity(identity);
5390             }
5391         }
5392 
5393         @Override
5394         public int getHintsFromListener(INotificationListener token) {
5395             synchronized (mNotificationLock) {
5396                 return mListenerHints;
5397             }
5398         }
5399 
5400         @Override
5401         public int getHintsFromListenerNoToken() {
5402             synchronized (mNotificationLock) {
5403                 return mListenerHints;
5404             }
5405         }
5406 
5407         @Override
5408         public void requestInterruptionFilterFromListener(INotificationListener token,
5409                 int interruptionFilter) throws RemoteException {
5410             if (android.app.Flags.modesApi()) {
5411                 final int callingUid = Binder.getCallingUid();
5412                 ManagedServiceInfo info;
5413                 synchronized (mNotificationLock) {
5414                     info = mListeners.checkServiceTokenLocked(token);
5415                 }
5416 
5417                 final int zenMode = zenModeFromInterruptionFilter(interruptionFilter, -1);
5418                 if (zenMode == -1) return;
5419                 if (!canManageGlobalZenPolicy(info.component.getPackageName(), callingUid)) {
5420                     mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(
5421                             info.component.getPackageName(), callingUid, zenMode);
5422                 } else {
5423                     int origin = computeZenOrigin(/* fromUser= */ false);
5424                     Binder.withCleanCallingIdentity(() -> {
5425                         mZenModeHelper.setManualZenMode(zenMode, /* conditionId= */ null, origin,
5426                                 "listener:" + info.component.flattenToShortString(),
5427                                 /* caller= */ info.component.getPackageName(),
5428                                 callingUid);
5429                     });
5430                 }
5431             } else {
5432                 final int callingUid = Binder.getCallingUid();
5433                 final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
5434                 final long identity = Binder.clearCallingIdentity();
5435                 try {
5436                     synchronized (mNotificationLock) {
5437                         final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5438                         mZenModeHelper.requestFromListener(info.component, interruptionFilter,
5439                                 callingUid, isSystemOrSystemUi);
5440                         updateInterruptionFilterLocked();
5441                     }
5442                 } finally {
5443                     Binder.restoreCallingIdentity(identity);
5444                 }
5445             }
5446         }
5447 
5448         @Override
5449         public int getInterruptionFilterFromListener(INotificationListener token)
5450                 throws RemoteException {
5451             synchronized (mNotificationLock) {
5452                 return mInterruptionFilter;
5453             }
5454         }
5455 
5456         @Override
5457         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
5458                 throws RemoteException {
5459             synchronized (mNotificationLock) {
5460                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5461                 if (info == null) return;
5462                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
5463             }
5464         }
5465 
5466         @Override
5467         public int getZenMode() {
5468             return mZenModeHelper.getZenMode();
5469         }
5470 
5471         @Override
5472         public ZenModeConfig getZenModeConfig() {
5473             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
5474             return mZenModeHelper.getConfig();
5475         }
5476 
5477         @Override
5478         public void setZenMode(int mode, Uri conditionId, String reason, boolean fromUser) {
5479             enforceSystemOrSystemUI("INotificationManager.setZenMode");
5480             enforceUserOriginOnlyFromSystem(fromUser, "setZenMode");
5481 
5482             final int callingUid = Binder.getCallingUid();
5483             final long identity = Binder.clearCallingIdentity();
5484             try {
5485                 mZenModeHelper.setManualZenMode(mode, conditionId, computeZenOrigin(fromUser),
5486                         reason, /* caller= */ null, callingUid);
5487             } finally {
5488                 Binder.restoreCallingIdentity(identity);
5489             }
5490         }
5491 
5492         // TODO: b/310620812 - Remove getZenRules() when MODES_API is inlined.
5493         @Override
5494         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
5495             enforcePolicyAccess(Binder.getCallingUid(), "getZenRules");
5496             return mZenModeHelper.getZenRules();
5497         }
5498 
5499         @Override
5500         public Map<String, AutomaticZenRule> getAutomaticZenRules() {
5501             if (!android.app.Flags.modesApi()) {
5502                 throw new IllegalStateException("getAutomaticZenRules called with flag off!");
5503             }
5504             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
5505             return mZenModeHelper.getAutomaticZenRules();
5506         }
5507 
5508         @Override
5509         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
5510             Objects.requireNonNull(id, "Id is null");
5511             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
5512             return mZenModeHelper.getAutomaticZenRule(id);
5513         }
5514 
5515         @Override
5516         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg,
5517                 boolean fromUser) {
5518             validateAutomaticZenRule(/* updateId= */ null, automaticZenRule);
5519             checkCallerIsSameApp(pkg);
5520             if (automaticZenRule.getZenPolicy() != null
5521                     && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
5522                 throw new IllegalArgumentException("ZenPolicy is only applicable to "
5523                         + "INTERRUPTION_FILTER_PRIORITY filters");
5524             }
5525             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
5526             enforceUserOriginOnlyFromSystem(fromUser, "addAutomaticZenRule");
5527 
5528             // If the calling app is the system (from any user), take the package name from the
5529             // rule's owner rather than from the caller's package.
5530             String rulePkg = pkg;
5531             if (isCallingAppIdSystem()) {
5532                 if (automaticZenRule.getOwner() != null) {
5533                     rulePkg = automaticZenRule.getOwner().getPackageName();
5534                 }
5535             }
5536 
5537             return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
5538                     computeZenOrigin(fromUser), "addAutomaticZenRule", Binder.getCallingUid());
5539         }
5540 
5541         @Override
5542         public void setManualZenRuleDeviceEffects(ZenDeviceEffects effects) throws RemoteException {
5543             checkCallerIsSystem();
5544 
5545             mZenModeHelper.setManualZenRuleDeviceEffects(effects, computeZenOrigin(true),
5546                     "Update manual mode non-policy settings", Binder.getCallingUid());
5547         }
5548 
5549         @Override
5550         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule,
5551                 boolean fromUser) throws RemoteException {
5552             validateAutomaticZenRule(id, automaticZenRule);
5553             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
5554             enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule");
5555 
5556             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
5557                     computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid());
5558         }
5559 
5560         private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) {
5561             Objects.requireNonNull(rule, "automaticZenRule is null");
5562             Objects.requireNonNull(rule.getName(), "Name is null");
5563             rule.validate();
5564 
5565             // Implicit rules have no ConditionProvider or Activity. We allow the user to customize
5566             // them (via Settings), but not the owner app. Should the app want to start using it as
5567             // a "normal" rule, it must provide a CP/ConfigActivity too.
5568             if (android.app.Flags.modesApi()) {
5569                 boolean isImplicitRuleUpdateFromSystem = updateId != null
5570                         && ZenModeHelper.isImplicitRuleId(updateId)
5571                         && isCallerSystemOrSystemUi();
5572                 if (!isImplicitRuleUpdateFromSystem
5573                         && rule.getOwner() == null
5574                         && rule.getConfigurationActivity() == null) {
5575                     throw new NullPointerException(
5576                             "Rule must have a ConditionProviderService and/or configuration "
5577                                     + "activity");
5578                 }
5579             } else {
5580                 if (rule.getOwner() == null && rule.getConfigurationActivity() == null) {
5581                     throw new NullPointerException(
5582                             "Rule must have a ConditionProviderService and/or configuration "
5583                                     + "activity");
5584                 }
5585             }
5586             Objects.requireNonNull(rule.getConditionId(), "ConditionId is null");
5587 
5588             if (android.app.Flags.modesApi()) {
5589                 if (isCallerSystemOrSystemUi()) {
5590                     return; // System callers can use any type.
5591                 }
5592                 int uid = Binder.getCallingUid();
5593                 int userId = UserHandle.getUserId(uid);
5594 
5595                 if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) {
5596                     boolean isDeviceOwner = Binder.withCleanCallingIdentity(
5597                             () -> mDpm.isActiveDeviceOwner(uid));
5598                     if (!isDeviceOwner) {
5599                         throw new IllegalArgumentException(
5600                                 "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED");
5601                     }
5602                 } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) {
5603                     String wellbeingPackage = getContext().getResources().getString(
5604                             com.android.internal.R.string.config_systemWellbeing);
5605                     boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage)
5606                             && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId);
5607                     if (!isCallerWellbeing) {
5608                         throw new IllegalArgumentException(
5609                                 "Only the 'Wellbeing' package can use AutomaticZenRules with "
5610                                         + "TYPE_BEDTIME");
5611                     }
5612                 }
5613             }
5614         }
5615 
5616         @Override
5617         public boolean removeAutomaticZenRule(String id, boolean fromUser) throws RemoteException {
5618             Objects.requireNonNull(id, "Id is null");
5619             // Verify that they can modify zen rules.
5620             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
5621             enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRule");
5622 
5623             return mZenModeHelper.removeAutomaticZenRule(id, computeZenOrigin(fromUser),
5624                     "removeAutomaticZenRule", Binder.getCallingUid());
5625         }
5626 
5627         @Override
5628         public boolean removeAutomaticZenRules(String packageName, boolean fromUser)
5629                 throws RemoteException {
5630             Objects.requireNonNull(packageName, "Package name is null");
5631             enforceSystemOrSystemUI("removeAutomaticZenRules");
5632             enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRules");
5633 
5634             return mZenModeHelper.removeAutomaticZenRules(packageName, computeZenOrigin(fromUser),
5635                     packageName + "|removeAutomaticZenRules", Binder.getCallingUid());
5636         }
5637 
5638         @Override
5639         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
5640             Objects.requireNonNull(owner, "Owner is null");
5641             enforceSystemOrSystemUI("getRuleInstanceCount");
5642 
5643             return mZenModeHelper.getCurrentInstanceCount(owner);
5644         }
5645 
5646         @Override
5647         @Condition.State
5648         public int getAutomaticZenRuleState(@NonNull String id) {
5649             Objects.requireNonNull(id, "id is null");
5650             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRuleState");
5651             return mZenModeHelper.getAutomaticZenRuleState(id);
5652         }
5653 
5654         @Override
5655         public void setAutomaticZenRuleState(String id, Condition condition) {
5656             Objects.requireNonNull(id, "id is null");
5657             Objects.requireNonNull(condition, "Condition is null");
5658             condition.validate();
5659 
5660             enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
5661             boolean fromUser = (condition.source == Condition.SOURCE_USER_ACTION);
5662 
5663             mZenModeHelper.setAutomaticZenRuleState(id, condition, computeZenOrigin(fromUser),
5664                     Binder.getCallingUid());
5665         }
5666 
5667         @ZenModeConfig.ConfigChangeOrigin
5668         private int computeZenOrigin(boolean fromUser) {
5669             // "fromUser" is introduced with MODES_API, so only consider it in that case.
5670             // (Non-MODES_API behavior should also not depend at all on UPDATE_ORIGIN_USER).
5671             if (android.app.Flags.modesApi() && fromUser) {
5672                 return ZenModeConfig.UPDATE_ORIGIN_USER;
5673             } else if (isCallerSystemOrSystemUi()) {
5674                 return ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI;
5675             } else {
5676                 return ZenModeConfig.UPDATE_ORIGIN_APP;
5677             }
5678         }
5679 
5680         private void enforceUserOriginOnlyFromSystem(boolean fromUser, String method) {
5681             if (android.app.Flags.modesApi()
5682                     && fromUser
5683                     && !isCallerSystemOrSystemUiOrShell()) {
5684                 throw new SecurityException(TextUtils.formatSimple(
5685                         "Calling %s with fromUser == true is only allowed for system", method));
5686             }
5687         }
5688 
5689         @Override
5690         public void setInterruptionFilter(String pkg, int filter, boolean fromUser) {
5691             enforcePolicyAccess(pkg, "setInterruptionFilter");
5692             final int zen = zenModeFromInterruptionFilter(filter, -1);
5693             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
5694             final int callingUid = Binder.getCallingUid();
5695             enforceUserOriginOnlyFromSystem(fromUser, "setInterruptionFilter");
5696 
5697             if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
5698                 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(pkg, callingUid, zen);
5699                 return;
5700             }
5701 
5702             final long identity = Binder.clearCallingIdentity();
5703             try {
5704                 mZenModeHelper.setManualZenMode(zen, null, computeZenOrigin(fromUser),
5705                         /* reason= */ "setInterruptionFilter", /* caller= */ pkg,
5706                         callingUid);
5707             } finally {
5708                 Binder.restoreCallingIdentity(identity);
5709             }
5710         }
5711 
5712         @Override
5713         public void notifyConditions(final String pkg, IConditionProvider provider,
5714                 final Condition[] conditions) {
5715             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
5716             checkCallerIsSystemOrSameApp(pkg);
5717             mHandler.post(new Runnable() {
5718                 @Override
5719                 public void run() {
5720                     mConditionProviders.notifyConditions(pkg, info, conditions);
5721                 }
5722             });
5723         }
5724 
5725         @Override
5726         public void requestUnbindProvider(IConditionProvider provider) {
5727             int uid = Binder.getCallingUid();
5728             final long identity = Binder.clearCallingIdentity();
5729             try {
5730                 // allow bound services to disable themselves
5731                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
5732                 info.getOwner().setComponentState(info.component, UserHandle.getUserId(uid), false);
5733             } finally {
5734                 Binder.restoreCallingIdentity(identity);
5735             }
5736         }
5737 
5738         @Override
5739         public void requestBindProvider(ComponentName component) {
5740             checkCallerIsSystemOrSameApp(component.getPackageName());
5741             int uid = Binder.getCallingUid();
5742             final long identity = Binder.clearCallingIdentity();
5743             try {
5744                 mConditionProviders.setComponentState(component, UserHandle.getUserId(uid), true);
5745             } finally {
5746                 Binder.restoreCallingIdentity(identity);
5747             }
5748         }
5749 
5750         private void enforceSystemOrSystemUI(String message) {
5751             if (isCallerSystemOrPhone()) return;
5752             getContext().enforceCallingPermission(STATUS_BAR_SERVICE,
5753                     message);
5754         }
5755 
5756         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
5757             try {
5758                 checkCallerIsSystemOrSameApp(pkg);
5759             } catch (SecurityException e) {
5760                 getContext().enforceCallingPermission(
5761                         STATUS_BAR_SERVICE,
5762                         message);
5763             }
5764         }
5765 
5766         private void enforcePolicyAccess(int uid, String method) {
5767             if (PERMISSION_GRANTED == getContext().checkCallingPermission(
5768                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
5769                 return;
5770             }
5771             boolean accessAllowed = false;
5772             String[] packages = mPackageManagerClient.getPackagesForUid(uid);
5773             final int packageCount = packages.length;
5774             for (int i = 0; i < packageCount; i++) {
5775                 if (mConditionProviders.isPackageOrComponentAllowed(
5776                         packages[i], UserHandle.getUserId(uid))) {
5777                     accessAllowed = true;
5778                 }
5779             }
5780             if (!accessAllowed) {
5781                 Slog.w(TAG, "Notification policy access denied calling " + method);
5782                 throw new SecurityException("Notification policy access denied");
5783             }
5784         }
5785 
5786         private boolean canManageGlobalZenPolicy(String callingPkg, int callingUid) {
5787             boolean isCompatChangeEnabled = Binder.withCleanCallingIdentity(
5788                     () -> CompatChanges.isChangeEnabled(MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES,
5789                             callingUid));
5790             return !isCompatChangeEnabled
5791                     || isCallerSystemOrSystemUi()
5792                     || hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid),
5793                             Set.of(AssociationRequest.DEVICE_PROFILE_WATCH,
5794                                     AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION));
5795         }
5796 
5797         private void enforcePolicyAccess(String pkg, String method) {
5798             if (PERMISSION_GRANTED == getContext().checkCallingPermission(
5799                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
5800                 return;
5801             }
5802             checkCallerIsSameApp(pkg);
5803             if (!checkPolicyAccess(pkg)) {
5804                 Slog.w(TAG, "Notification policy access denied calling " + method);
5805                 throw new SecurityException("Notification policy access denied");
5806             }
5807         }
5808 
5809         private boolean checkPackagePolicyAccess(String pkg) {
5810             return mConditionProviders.isPackageOrComponentAllowed(
5811                     pkg, getCallingUserHandle().getIdentifier());
5812         }
5813 
5814         private boolean checkPolicyAccess(String pkg) {
5815             final int uid;
5816             try {
5817                 uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
5818                         UserHandle.getCallingUserId());
5819                 if (PERMISSION_GRANTED == checkComponentPermission(
5820                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
5821                         -1, true)) {
5822                     return true;
5823                 }
5824             } catch (NameNotFoundException e) {
5825                 return false;
5826             }
5827             //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
5828             return checkPackagePolicyAccess(pkg)
5829                     || mListeners.isComponentEnabledForPackage(pkg)
5830                     || (mDpm != null && (mDpm.isActiveProfileOwner(uid)
5831                                 || mDpm.isActiveDeviceOwner(uid)));
5832         }
5833 
5834         @Override
5835         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5836             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
5837             final DumpFilter filter = DumpFilter.parseFromArguments(args);
5838             final long token = Binder.clearCallingIdentity();
5839             try {
5840                 final ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions =
5841                         getAllUsersNotificationPermissions();
5842                 if (filter.stats) {
5843                     dumpJson(pw, filter, pkgPermissions);
5844                 } else if (filter.rvStats) {
5845                     dumpRemoteViewStats(pw, filter);
5846                 } else if (filter.proto) {
5847                     dumpProto(fd, filter, pkgPermissions);
5848                 } else if (filter.criticalPriority) {
5849                     dumpNotificationRecords(pw, filter);
5850                 } else {
5851                     dumpImpl(pw, filter, pkgPermissions);
5852                 }
5853             } finally {
5854                 Binder.restoreCallingIdentity(token);
5855             }
5856         }
5857 
5858         @Override
5859         public ComponentName getEffectsSuppressor() {
5860             ComponentName suppressor = !mEffectsSuppressors.isEmpty()
5861                     ? mEffectsSuppressors.get(0)
5862                     : null;
5863             if (isCallerSystemOrSystemUiOrShell() || suppressor == null
5864                     || mPackageManagerInternal.isSameApp(suppressor.getPackageName(),
5865                     Binder.getCallingUid(), UserHandle.getUserId(Binder.getCallingUid()))) {
5866                 return suppressor;
5867             }
5868 
5869             return null;
5870         }
5871 
5872         @Override
5873         public boolean matchesCallFilter(Bundle extras) {
5874             // Because matchesCallFilter may use contact data to filter calls, the callers of this
5875             // method need to either have notification listener access or permission to read
5876             // contacts.
5877             boolean systemAccess = false;
5878             try {
5879                 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
5880                 systemAccess = true;
5881             } catch (SecurityException e) {
5882             }
5883 
5884             boolean listenerAccess = false;
5885             try {
5886                 String[] pkgNames = mPackageManager.getPackagesForUid(Binder.getCallingUid());
5887                 for (int i = 0; i < pkgNames.length; i++) {
5888                     // in most cases there should only be one package here
5889                     listenerAccess |= mListeners.hasAllowedListener(pkgNames[i],
5890                             Binder.getCallingUserHandle().getIdentifier());
5891                 }
5892             } catch (RemoteException e) {
5893             } finally {
5894                 if (!systemAccess && !listenerAccess) {
5895                     getContext().enforceCallingPermission(Manifest.permission.READ_CONTACTS,
5896                             "matchesCallFilter requires listener permission, contacts read access,"
5897                             + " or system level access");
5898                 }
5899             }
5900 
5901             return mZenModeHelper.matchesCallFilter(
5902                     Binder.getCallingUserHandle(),
5903                     extras,
5904                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
5905                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
5906                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY,
5907                     Binder.getCallingUid());
5908         }
5909 
5910         @Override
5911         public void cleanUpCallersAfter(long timeThreshold) {
5912             enforceSystemOrSystemUI("INotificationManager.cleanUpCallersAfter");
5913             mZenModeHelper.cleanUpCallersAfter(timeThreshold);
5914         }
5915 
5916         @Override
5917         public boolean isSystemConditionProviderEnabled(String path) {
5918             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
5919             return mConditionProviders.isSystemProviderEnabled(path);
5920         }
5921 
5922         // Backup/restore interface
5923         @Override
5924         public byte[] getBackupPayload(int user) {
5925             checkCallerIsSystem();
5926             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
5927             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
5928             try {
5929                 writePolicyXml(baos, true /*forBackup*/, user);
5930                 return baos.toByteArray();
5931             } catch (IOException e) {
5932                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
5933             }
5934             return null;
5935         }
5936 
5937         @Override
5938         public void applyRestore(byte[] payload, int user) {
5939             checkCallerIsSystem();
5940             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
5941                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
5942             if (payload == null) {
5943                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
5944                 return;
5945             }
5946             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
5947             try {
5948                 readPolicyXml(bais, true /*forRestore*/, user);
5949                 handleSavePolicyFile();
5950             } catch (NumberFormatException | XmlPullParserException | IOException e) {
5951                 Slog.w(TAG, "applyRestore: error reading payload", e);
5952             }
5953         }
5954 
5955         @Override
5956         public boolean isNotificationPolicyAccessGranted(String pkg) {
5957             return checkPolicyAccess(pkg);
5958         }
5959 
5960         @Override
5961         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
5962             enforceSystemOrSystemUIOrSamePackage(pkg,
5963                     "request policy access status for another package");
5964             return checkPolicyAccess(pkg);
5965         }
5966 
5967         @Override
5968         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
5969                 throws RemoteException {
5970             setNotificationPolicyAccessGrantedForUser(
5971                     pkg, getCallingUserHandle().getIdentifier(), granted);
5972         }
5973 
5974         @Override
5975         public void setNotificationPolicyAccessGrantedForUser(
5976                 String pkg, int userId, boolean granted) {
5977             checkCallerIsSystemOrShell();
5978             final long identity = Binder.clearCallingIdentity();
5979             try {
5980                 if (mAllowedManagedServicePackages.test(
5981                         pkg, userId, mConditionProviders.getRequiredPermission())) {
5982                     mConditionProviders.setPackageOrComponentEnabled(
5983                             pkg, userId, true, granted);
5984 
5985                     getContext().sendBroadcastAsUser(new Intent(
5986                             ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5987                                     .setPackage(pkg)
5988                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
5989                             UserHandle.of(userId), null);
5990                     handleSavePolicyFile();
5991                 }
5992             } finally {
5993                 Binder.restoreCallingIdentity(identity);
5994             }
5995         }
5996 
5997         @Override
5998         public Policy getNotificationPolicy(String pkg) {
5999             final int callingUid = Binder.getCallingUid();
6000             if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
6001                 return mZenModeHelper.getNotificationPolicyFromImplicitZenRule(pkg);
6002             }
6003             final long identity = Binder.clearCallingIdentity();
6004             try {
6005                 return mZenModeHelper.getNotificationPolicy();
6006             } finally {
6007                 Binder.restoreCallingIdentity(identity);
6008             }
6009         }
6010 
6011         @Override
6012         public Policy getConsolidatedNotificationPolicy() {
6013             final long identity = Binder.clearCallingIdentity();
6014             try {
6015                 return mZenModeHelper.getConsolidatedNotificationPolicy();
6016             } finally {
6017                 Binder.restoreCallingIdentity(identity);
6018             }
6019         }
6020 
6021         /**
6022          * Sets the notification policy.  Apps that target API levels below
6023          * {@link Build.VERSION_CODES#P} cannot change user-designated values to
6024          * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
6025          * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
6026          * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
6027          */
6028         @Override
6029         public void setNotificationPolicy(String pkg, Policy policy, boolean fromUser) {
6030             enforcePolicyAccess(pkg, "setNotificationPolicy");
6031             enforceUserOriginOnlyFromSystem(fromUser, "setNotificationPolicy");
6032             int callingUid = Binder.getCallingUid();
6033             @ZenModeConfig.ConfigChangeOrigin int origin = computeZenOrigin(fromUser);
6034 
6035             boolean shouldApplyAsImplicitRule = android.app.Flags.modesApi()
6036                     && !canManageGlobalZenPolicy(pkg, callingUid);
6037 
6038             final long identity = Binder.clearCallingIdentity();
6039             try {
6040                 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
6041                         0, UserHandle.getUserId(callingUid));
6042                 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
6043 
6044                 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
6045                     int priorityCategories = policy.priorityCategories;
6046                     // ignore alarm and media values from new policy
6047                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
6048                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
6049                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
6050                     // use user-designated values
6051                     priorityCategories |= currPolicy.priorityCategories
6052                             & Policy.PRIORITY_CATEGORY_ALARMS;
6053                     priorityCategories |= currPolicy.priorityCategories
6054                             & Policy.PRIORITY_CATEGORY_MEDIA;
6055                     priorityCategories |= currPolicy.priorityCategories
6056                             & Policy.PRIORITY_CATEGORY_SYSTEM;
6057 
6058                     policy = new Policy(priorityCategories,
6059                             policy.priorityCallSenders, policy.priorityMessageSenders,
6060                             policy.suppressedVisualEffects);
6061                 }
6062                 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
6063                     int priorityCategories = correctCategory(policy.priorityCategories,
6064                             Policy.PRIORITY_CATEGORY_CONVERSATIONS,
6065                             currPolicy.priorityCategories);
6066 
6067                     policy = new Policy(priorityCategories,
6068                             policy.priorityCallSenders, policy.priorityMessageSenders,
6069                             policy.suppressedVisualEffects, currPolicy.priorityConversationSenders);
6070                 }
6071                 int newVisualEffects = calculateSuppressedVisualEffects(
6072                             policy, currPolicy, applicationInfo.targetSdkVersion);
6073                 policy = new Policy(policy.priorityCategories,
6074                         policy.priorityCallSenders, policy.priorityMessageSenders,
6075                         newVisualEffects, policy.priorityConversationSenders);
6076 
6077                 if (shouldApplyAsImplicitRule) {
6078                     mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(pkg, callingUid, policy);
6079                 } else {
6080                     ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion,
6081                             policy);
6082                     mZenModeHelper.setNotificationPolicy(policy, origin, callingUid);
6083                 }
6084             } catch (RemoteException e) {
6085                 Slog.e(TAG, "Failed to set notification policy", e);
6086             } finally {
6087                 Binder.restoreCallingIdentity(identity);
6088             }
6089         }
6090 
6091         /**
6092          * Gets the device-default zen policy as a ZenPolicy.
6093          */
6094         @Override
6095         public ZenPolicy getDefaultZenPolicy() {
6096             enforceSystemOrSystemUI("INotificationManager.getDefaultZenPolicy");
6097             final long identity = Binder.clearCallingIdentity();
6098             try {
6099                 return mZenModeHelper.getDefaultZenPolicy();
6100             } finally {
6101                 Binder.restoreCallingIdentity(identity);
6102             }
6103         }
6104 
6105         @Override
6106         public List<String> getEnabledNotificationListenerPackages() {
6107             checkCallerIsSystem();
6108             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
6109         }
6110 
6111         @Override
6112         public List<ComponentName> getEnabledNotificationListeners(int userId) {
6113             checkNotificationListenerAccess();
6114             return mListeners.getAllowedComponents(userId);
6115         }
6116 
6117         @Override
6118         public ComponentName getAllowedNotificationAssistantForUser(int userId) {
6119             checkCallerIsSystemOrSystemUiOrShell();
6120             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
6121             if (allowedComponents.size() > 1) {
6122                 throw new IllegalStateException(
6123                         "At most one NotificationAssistant: " + allowedComponents.size());
6124             }
6125             return CollectionUtils.firstOrNull(allowedComponents);
6126         }
6127 
6128         @Override
6129         public ComponentName getAllowedNotificationAssistant() {
6130             return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier());
6131         }
6132 
6133         @Override
6134         public ComponentName getDefaultNotificationAssistant() {
6135             checkCallerIsSystem();
6136             return mAssistants.getDefaultFromConfig();
6137         }
6138 
6139         @Override
6140         public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) {
6141             checkCallerIsSystem();
6142             setNASMigrationDone(userId);
6143             if (loadFromConfig) {
6144                 mAssistants.resetDefaultFromConfig();
6145             } else {
6146                 mAssistants.clearDefaults();
6147             }
6148         }
6149 
6150 
6151         @Override
6152         public boolean hasEnabledNotificationListener(String packageName, int userId) {
6153             checkCallerIsSystem();
6154             return mListeners.isPackageAllowed(packageName, userId);
6155         }
6156 
6157         @Override
6158         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
6159             Objects.requireNonNull(listener);
6160             checkCallerIsSystemOrSameApp(listener.getPackageName());
6161             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
6162                     getCallingUserHandle().getIdentifier());
6163         }
6164 
6165         @Override
6166         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
6167                 int userId) {
6168             Objects.requireNonNull(listener);
6169             checkCallerIsSystem();
6170             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
6171                     userId);
6172         }
6173 
6174         @Override
6175         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
6176             Objects.requireNonNull(assistant);
6177             checkCallerIsSystemOrSameApp(assistant.getPackageName());
6178             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
6179                     getCallingUserHandle().getIdentifier());
6180         }
6181 
6182         @Override
6183         public void setNotificationListenerAccessGranted(ComponentName listener,
6184                 boolean granted, boolean userSet) throws RemoteException {
6185             setNotificationListenerAccessGrantedForUser(
6186                     listener, getCallingUserHandle().getIdentifier(), granted, userSet);
6187         }
6188 
6189         @Override
6190         public void setNotificationAssistantAccessGranted(ComponentName assistant,
6191                 boolean granted) {
6192             setNotificationAssistantAccessGrantedForUser(
6193                     assistant, getCallingUserHandle().getIdentifier(), granted);
6194         }
6195 
6196         @Override
6197         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
6198                 boolean granted, boolean userSet) {
6199             Objects.requireNonNull(listener);
6200             if (UserHandle.getCallingUserId() != userId) {
6201                 getContext().enforceCallingOrSelfPermission(
6202                         android.Manifest.permission.INTERACT_ACROSS_USERS,
6203                         "setNotificationListenerAccessGrantedForUser for user " + userId);
6204             }
6205             checkNotificationListenerAccess();
6206             if (granted && listener.flattenToString().length()
6207                     > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
6208                 throw new IllegalArgumentException(
6209                         "Component name too long: " + listener.flattenToString());
6210             }
6211             if (!userSet && isNotificationListenerAccessUserSet(listener, userId)) {
6212                 // Don't override user's choice
6213                 return;
6214             }
6215             final long identity = Binder.clearCallingIdentity();
6216             try {
6217                 if (mAllowedManagedServicePackages.test(
6218                         listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
6219                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
6220                             userId, false, granted, userSet);
6221                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
6222                             userId, true, granted, userSet);
6223 
6224                     getContext().sendBroadcastAsUser(new Intent(
6225                             ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
6226                                     .setPackage(listener.getPackageName())
6227                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
6228                             UserHandle.of(userId), null);
6229 
6230                     handleSavePolicyFile();
6231                 }
6232             } finally {
6233                 Binder.restoreCallingIdentity(identity);
6234             }
6235         }
6236 
6237         private boolean isNotificationListenerAccessUserSet(ComponentName listener, int userId) {
6238             return mListeners.isPackageOrComponentUserSet(listener.flattenToString(), userId);
6239         }
6240 
6241         @Override
6242         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
6243                 int userId, boolean granted) {
6244             checkCallerIsSystemOrSystemUiOrShell();
6245             for (UserInfo ui : mUm.getEnabledProfiles(userId)) {
6246                 mAssistants.setUserSet(ui.id, true);
6247             }
6248             final long identity = Binder.clearCallingIdentity();
6249             try {
6250                 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
6251                         true);
6252             } finally {
6253                 Binder.restoreCallingIdentity(identity);
6254             }
6255         }
6256 
6257         @Override
6258         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
6259                 Adjustment adjustment) {
6260             boolean foundEnqueued = false;
6261             final long identity = Binder.clearCallingIdentity();
6262             try {
6263                 synchronized (mNotificationLock) {
6264                     mAssistants.checkServiceTokenLocked(token);
6265                     int N = mEnqueuedNotifications.size();
6266                     for (int i = 0; i < N; i++) {
6267                         final NotificationRecord r = mEnqueuedNotifications.get(i);
6268                         if (Objects.equals(adjustment.getKey(), r.getKey())
6269                                 && Objects.equals(adjustment.getUser(), r.getUserId())
6270                                 && mAssistants.isSameUser(token, r.getUserId())) {
6271                             applyAdjustmentLocked(r, adjustment, false);
6272                             r.applyAdjustments();
6273                             // importance is checked at the beginning of the
6274                             // PostNotificationRunnable, before the signal extractors are run, so
6275                             // calculate the final importance here
6276                             r.calculateImportance();
6277                             foundEnqueued = true;
6278                         }
6279                     }
6280                     if (!foundEnqueued) {
6281                         applyAdjustmentsFromAssistant(token, List.of(adjustment));
6282                     }
6283                 }
6284             } finally {
6285                 Binder.restoreCallingIdentity(identity);
6286             }
6287         }
6288 
6289         @Override
6290         public void applyAdjustmentFromAssistant(INotificationListener token,
6291                 Adjustment adjustment) {
6292             List<Adjustment> adjustments = new ArrayList<>();
6293             adjustments.add(adjustment);
6294             applyAdjustmentsFromAssistant(token, adjustments);
6295         }
6296 
6297         @Override
6298         public void applyAdjustmentsFromAssistant(INotificationListener token,
6299                 List<Adjustment> adjustments) {
6300 
6301             boolean needsSort = false;
6302             final long identity = Binder.clearCallingIdentity();
6303             try {
6304                 synchronized (mNotificationLock) {
6305                     mAssistants.checkServiceTokenLocked(token);
6306                     for (Adjustment adjustment : adjustments) {
6307                         NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
6308                         if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
6309                             applyAdjustmentLocked(r, adjustment, true);
6310                             // If the assistant has blocked the notification, cancel it
6311                             // This will trigger a sort, so we don't have to explicitly ask for
6312                             // one here.
6313                             if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
6314                                     && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
6315                                     == IMPORTANCE_NONE) {
6316                                 cancelNotificationsFromListener(token, new String[]{r.getKey()});
6317                             } else {
6318                                 r.setPendingLogUpdate(true);
6319                                 needsSort = true;
6320                             }
6321                         }
6322                     }
6323                 }
6324                 if (needsSort) {
6325                     mRankingHandler.requestSort();
6326                 }
6327             } finally {
6328                 Binder.restoreCallingIdentity(identity);
6329             }
6330         }
6331 
6332         @Override
6333         public void updateNotificationChannelGroupFromPrivilegedListener(
6334                 INotificationListener token, String pkg, UserHandle user,
6335                 NotificationChannelGroup group) throws RemoteException {
6336             Objects.requireNonNull(user);
6337             verifyPrivilegedListener(token, user, false);
6338             createNotificationChannelGroup(
6339                     pkg, getUidForPackageAndUser(pkg, user), group, false, true);
6340             handleSavePolicyFile();
6341         }
6342 
6343         @Override
6344         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
6345                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
6346             Objects.requireNonNull(channel);
6347             Objects.requireNonNull(pkg);
6348             Objects.requireNonNull(user);
6349 
6350             verifyPrivilegedListener(token, user, false);
6351 
6352             final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
6353                     pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true);
6354             verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel);
6355             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
6356         }
6357 
6358         @Override
6359         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
6360                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
6361             Objects.requireNonNull(pkg);
6362             Objects.requireNonNull(user);
6363             verifyPrivilegedListener(token, user, true);
6364 
6365             return mPreferencesHelper.getNotificationChannels(pkg,
6366                     getUidForPackageAndUser(pkg, user), false /* includeDeleted */);
6367         }
6368 
6369         @Override
6370         public ParceledListSlice<NotificationChannelGroup>
6371                 getNotificationChannelGroupsFromPrivilegedListener(
6372                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
6373             Objects.requireNonNull(pkg);
6374             Objects.requireNonNull(user);
6375             verifyPrivilegedListener(token, user, true);
6376 
6377             List<NotificationChannelGroup> groups = new ArrayList<>();
6378             groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
6379                     pkg, getUidForPackageAndUser(pkg, user)));
6380             return new ParceledListSlice<>(groups);
6381         }
6382 
6383         @Override
6384         public boolean isInCall(String pkg, int uid) {
6385             checkCallerIsSystemOrSystemUiOrShell();
6386             return isCallNotification(pkg, uid);
6387         }
6388 
6389         @Override
6390         public void setPrivateNotificationsAllowed(boolean allow) {
6391             if (PERMISSION_GRANTED
6392                     != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
6393                 throw new SecurityException(
6394                         "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
6395             }
6396             if (allow != mLockScreenAllowSecureNotifications) {
6397                 mLockScreenAllowSecureNotifications = allow;
6398                 if (android.app.Flags.keyguardPrivateNotifications()) {
6399                     getContext().sendBroadcast(
6400                             new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED)
6401                                     .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED,
6402                                             mLockScreenAllowSecureNotifications),
6403                             STATUS_BAR_SERVICE);
6404                 }
6405 
6406                 handleSavePolicyFile();
6407             }
6408         }
6409 
6410         @Override
6411         public boolean getPrivateNotificationsAllowed() {
6412             if (PERMISSION_GRANTED
6413                     != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
6414                 throw new SecurityException(
6415                         "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
6416             }
6417             return mLockScreenAllowSecureNotifications;
6418         }
6419 
6420         @Override
6421         public boolean isPackagePaused(String pkg) {
6422             Objects.requireNonNull(pkg);
6423             checkCallerIsSameApp(pkg);
6424 
6425             return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
6426         }
6427 
6428         @Override
6429         public boolean isPermissionFixed(String pkg, @UserIdInt int userId) {
6430             enforceSystemOrSystemUI("isPermissionFixed");
6431             return mPermissionHelper.isPermissionFixed(pkg, userId);
6432         }
6433 
6434         private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
6435                 boolean assistantAllowed) {
6436             ManagedServiceInfo info;
6437             synchronized (mNotificationLock) {
6438                 info = mListeners.checkServiceTokenLocked(token);
6439             }
6440             if (!hasCompanionDevice(info)) {
6441                 synchronized (mNotificationLock) {
6442                     if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
6443                         throw new SecurityException(info + " does not have access");
6444                     }
6445                 }
6446             }
6447             if (!info.enabledAndUserMatches(user.getIdentifier())) {
6448                 throw new SecurityException(info + " does not have access");
6449             }
6450         }
6451 
6452         private void verifyPrivilegedListenerUriPermission(int sourceUid,
6453                 @NonNull NotificationChannel updateChannel,
6454                 @Nullable NotificationChannel originalChannel) {
6455             // Check that the NLS has the required permissions to access the channel
6456             final Uri soundUri = updateChannel.getSound();
6457             final Uri originalSoundUri =
6458                     (originalChannel != null) ? originalChannel.getSound() : null;
6459             if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) {
6460                 Binder.withCleanCallingIdentity(() -> {
6461                     mUgmInternal.checkGrantUriPermission(sourceUid, null,
6462                             ContentProvider.getUriWithoutUserId(soundUri),
6463                             Intent.FLAG_GRANT_READ_URI_PERMISSION,
6464                             ContentProvider.getUserIdFromUri(soundUri,
6465                             UserHandle.getUserId(sourceUid)));
6466                 });
6467             }
6468         }
6469 
6470         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
6471             int uid = INVALID_UID;
6472             final long identity = Binder.clearCallingIdentity();
6473             try {
6474                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
6475             } finally {
6476                 Binder.restoreCallingIdentity(identity);
6477             }
6478             return uid;
6479         }
6480 
6481         @Override
6482         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
6483                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
6484                 throws RemoteException {
6485             new NotificationShellCmd(NotificationManagerService.this)
6486                     .exec(this, in, out, err, args, callback, resultReceiver);
6487         }
6488 
6489         /**
6490          * Get stats committed after startNs
6491          *
6492          * @param startNs Report stats committed after this time in nanoseconds.
6493          * @param report  Indicatess which section to include in the stats.
6494          * @param doAgg   Whether to aggregate the stats or keep them separated.
6495          * @param out   List of protos of individual commits or one representing the
6496          *                aggregate.
6497          * @return the report time in nanoseconds, or 0 on error.
6498          */
6499         @Override
6500         public long pullStats(long startNs, int report, boolean doAgg,
6501                 List<ParcelFileDescriptor> out) {
6502             checkCallerIsSystemOrShell();
6503             long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS);
6504 
6505             final long identity = Binder.clearCallingIdentity();
6506             try {
6507                 switch (report) {
6508                     case REPORT_REMOTE_VIEWS:
6509                         Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: "
6510                                 + startMs + "  with " + doAgg);
6511                         PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg);
6512                         if (stats != null) {
6513                             out.add(stats.toParcelFileDescriptor(report));
6514                             Slog.e(TAG, "exiting pullStats with: " + out.size());
6515                             long endNs = TimeUnit.NANOSECONDS
6516                                     .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS);
6517                             return endNs;
6518                         }
6519                         Slog.e(TAG, "null stats for: " + report);
6520                 }
6521             } catch (IOException e) {
6522 
6523                 Slog.e(TAG, "exiting pullStats: on error", e);
6524                 return 0;
6525             } finally {
6526                 Binder.restoreCallingIdentity(identity);
6527             }
6528             Slog.e(TAG, "exiting pullStats: bad request");
6529             return 0;
6530         }
6531     };
6532 
6533     private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) {
6534         if (!mUmInternal.isUserInitialized(userId)) {
6535             return; // App-op "updates" are sent when starting a new user the first time.
6536         }
6537         int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId);
6538         if (uid == INVALID_UID) {
6539             Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId));
6540             return;
6541         }
6542         boolean hasPermission = mPermissionHelper.hasPermission(uid);
6543         if (!hasPermission) {
6544             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null,
6545                     /* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId,
6546                     REASON_PACKAGE_BANNED);
6547         }
6548     }
6549 
6550     protected void checkNotificationListenerAccess() {
6551         if (!isCallerSystemOrPhone()) {
6552             getContext().enforceCallingPermission(
6553                     permission.MANAGE_NOTIFICATION_LISTENERS,
6554                     "Caller must hold " + permission.MANAGE_NOTIFICATION_LISTENERS);
6555         }
6556     }
6557 
6558     @VisibleForTesting
6559     protected void setNotificationAssistantAccessGrantedForUserInternal(
6560             ComponentName assistant, int baseUserId, boolean granted, boolean userSet) {
6561         List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
6562         if (users != null) {
6563             for (UserInfo user : users) {
6564                 int userId = user.id;
6565                 if (assistant == null) {
6566                     ComponentName allowedAssistant = CollectionUtils.firstOrNull(
6567                             mAssistants.getAllowedComponents(userId));
6568                     if (allowedAssistant != null) {
6569                         setNotificationAssistantAccessGrantedForUserInternal(
6570                                 allowedAssistant, userId, false, userSet);
6571                     }
6572                     continue;
6573                 }
6574                 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
6575                         userId, mAssistants.getRequiredPermission())) {
6576                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
6577                             userId, false, granted);
6578                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
6579                             userId, true, granted, userSet);
6580 
6581                     getContext().sendBroadcastAsUser(
6582                             new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
6583                                     .setPackage(assistant.getPackageName())
6584                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
6585                             UserHandle.of(userId), null);
6586 
6587                     handleSavePolicyFile();
6588                 }
6589             }
6590         }
6591     }
6592 
6593     @GuardedBy("mNotificationLock")
6594     private void applyAdjustmentLocked(NotificationRecord r, Adjustment adjustment,
6595             boolean isPosted) {
6596         if (r == null) {
6597             return;
6598         }
6599         if (adjustment.getSignals() != null) {
6600             final Bundle adjustments = adjustment.getSignals();
6601             Bundle.setDefusable(adjustments, true);
6602             List<String> toRemove = new ArrayList<>();
6603             for (String potentialKey : adjustments.keySet()) {
6604                 if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
6605                     toRemove.add(potentialKey);
6606                 }
6607             }
6608             for (String removeKey : toRemove) {
6609                 adjustments.remove(removeKey);
6610             }
6611             r.addAdjustment(adjustment);
6612             if (adjustment.getSignals().containsKey(Adjustment.KEY_SENSITIVE_CONTENT)) {
6613                 logSensitiveAdjustmentReceived(isPosted,
6614                         adjustment.getSignals().getBoolean(Adjustment.KEY_SENSITIVE_CONTENT),
6615                         r.getLifespanMs(System.currentTimeMillis()));
6616             }
6617         }
6618     }
6619 
6620     @GuardedBy("mNotificationLock")
6621     void addAutogroupKeyLocked(String key, boolean requestSort) {
6622         NotificationRecord r = mNotificationsByKey.get(key);
6623         if (r == null) {
6624             return;
6625         }
6626         if (r.getSbn().getOverrideGroupKey() == null) {
6627             addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
6628             EventLogTags.writeNotificationAutogrouped(key);
6629             if (!android.app.Flags.checkAutogroupBeforePost() || requestSort) {
6630                 mRankingHandler.requestSort();
6631             }
6632         }
6633     }
6634 
6635     @GuardedBy("mNotificationLock")
6636     void removeAutogroupKeyLocked(String key) {
6637         NotificationRecord r = mNotificationsByKey.get(key);
6638         if (r == null) {
6639             Slog.w(TAG, "Failed to remove autogroup " + key);
6640             return;
6641         }
6642         if (r.getSbn().getOverrideGroupKey() != null) {
6643             addAutoGroupAdjustment(r, null);
6644             EventLogTags.writeNotificationUnautogrouped(key);
6645             mRankingHandler.requestSort();
6646         }
6647     }
6648 
6649     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
6650         Bundle signals = new Bundle();
6651         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
6652         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
6653                 r.getSbn().getUserId());
6654         r.addAdjustment(adjustment);
6655     }
6656 
6657     // Clears the 'fake' auto-group summary.
6658     @VisibleForTesting
6659     @GuardedBy("mNotificationLock")
6660     void clearAutogroupSummaryLocked(int userId, String pkg) {
6661         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
6662         if (summaries != null && summaries.containsKey(pkg)) {
6663             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
6664             if (removed != null) {
6665                 final StatusBarNotification sbn = removed.getSbn();
6666                 cancelNotification(MY_UID, MY_PID, pkg, sbn.getTag(), sbn.getId(), 0, 0, false,
6667                         userId, REASON_UNAUTOBUNDLED, null);
6668             }
6669         }
6670     }
6671 
6672     @GuardedBy("mNotificationLock")
6673     private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
6674         ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
6675         return summaries != null && summaries.containsKey(sbn.getPackageName());
6676     }
6677 
6678     // Creates a 'fake' summary for a package that has exceeded the solo-notification limit.
6679     NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
6680             int flagsToSet, Icon summaryIcon, int summaryIconColor, int summaryVisibilty) {
6681         NotificationRecord summaryRecord = null;
6682         boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
6683         synchronized (mNotificationLock) {
6684             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
6685             if (notificationRecord == null) {
6686                 // The notification could have been cancelled again already. A successive
6687                 // adjustment will post a summary if needed.
6688                 return null;
6689             }
6690             final StatusBarNotification adjustedSbn = notificationRecord.getSbn();
6691             userId = adjustedSbn.getUser().getIdentifier();
6692             int uid =  adjustedSbn.getUid();
6693             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
6694             if (summaries == null) {
6695                 summaries = new ArrayMap<>();
6696             }
6697             mAutobundledSummaries.put(userId, summaries);
6698             if (!summaries.containsKey(pkg)) {
6699                 // Add summary
6700                 final ApplicationInfo appInfo =
6701                         adjustedSbn.getNotification().extras.getParcelable(
6702                                 EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
6703                 final Bundle extras = new Bundle();
6704                 extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, appInfo);
6705                 final String channelId = notificationRecord.getChannel().getId();
6706 
6707                 final Notification summaryNotification =
6708                                 new Notification.Builder(getContext(), channelId)
6709                                 .setSmallIcon(summaryIcon)
6710                                 .setGroupSummary(true)
6711                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
6712                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
6713                                 .setFlag(flagsToSet, true)
6714                                 .setColor(summaryIconColor)
6715                                 .setVisibility(summaryVisibilty)
6716                                 .build();
6717                 summaryNotification.extras.putAll(extras);
6718                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
6719                 if (appIntent != null) {
6720                     summaryNotification.contentIntent = mAmi.getPendingIntentActivityAsApp(
6721                             0, appIntent, PendingIntent.FLAG_IMMUTABLE, null,
6722                             pkg, appInfo.uid);
6723                 }
6724                 final StatusBarNotification summarySbn =
6725                         new StatusBarNotification(adjustedSbn.getPackageName(),
6726                                 adjustedSbn.getOpPkg(),
6727                                 Integer.MAX_VALUE,
6728                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
6729                                 adjustedSbn.getInitialPid(), summaryNotification,
6730                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
6731                                 System.currentTimeMillis());
6732                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
6733                         notificationRecord.getChannel());
6734                 summaryRecord.setImportanceFixed(isPermissionFixed);
6735                 summaryRecord.setIsAppImportanceLocked(
6736                         notificationRecord.getIsAppImportanceLocked());
6737                 summaries.put(pkg, summarySbn.getKey());
6738             }
6739             if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
6740                     summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
6741                     true, false)) {
6742                 return summaryRecord;
6743             }
6744         }
6745         return null;
6746     }
6747 
6748     // Gets packages that have requested notification permission, and whether that has been
6749     // allowed/denied, for all users on the device.
6750     // Returns a single map containing that info keyed by (uid, package name) for all users.
6751     // Because this calls into mPermissionHelper, this method must never be called with a lock held.
6752     @VisibleForTesting
6753     protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
6754             getAllUsersNotificationPermissions() {
6755         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>();
6756         final List<UserInfo> allUsers = mUm.getUsers();
6757         // for each of these, get the package notification permissions that are associated
6758         // with this user and add it to the map
6759         for (UserInfo ui : allUsers) {
6760             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> userPermissions =
6761                     mPermissionHelper.getNotificationPermissionValues(
6762                             ui.getUserHandle().getIdentifier());
6763             for (Pair<Integer, String> pair : userPermissions.keySet()) {
6764                 allPermissions.put(pair, userPermissions.get(pair));
6765             }
6766         }
6767         return allPermissions;
6768     }
6769 
6770     private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter,
6771             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
6772         JSONObject dump = new JSONObject();
6773         try {
6774             dump.put("service", "Notification Manager");
6775             dump.put("bans", mPreferencesHelper.dumpBansJson(filter, pkgPermissions));
6776             dump.put("ranking", mPreferencesHelper.dumpJson(filter, pkgPermissions));
6777             dump.put("stats", mUsageStats.dumpJson(filter));
6778             dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
6779         } catch (JSONException e) {
6780             e.printStackTrace();
6781         }
6782         pw.println(dump);
6783     }
6784 
6785     private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) {
6786         PulledStats stats = mUsageStats.remoteViewStats(filter.since, true);
6787         if (stats == null) {
6788             pw.println("no remote view stats reported.");
6789             return;
6790         }
6791         stats.dump(REPORT_REMOTE_VIEWS, pw, filter);
6792     }
6793 
6794     private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter,
6795             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
6796         final ProtoOutputStream proto = new ProtoOutputStream(fd);
6797         synchronized (mNotificationLock) {
6798             int N = mNotificationList.size();
6799             for (int i = 0; i < N; i++) {
6800                 final NotificationRecord nr = mNotificationList.get(i);
6801                 if (filter.filtered && !filter.matches(nr.getSbn())) continue;
6802                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
6803                         NotificationRecordProto.POSTED);
6804             }
6805             N = mEnqueuedNotifications.size();
6806             for (int i = 0; i < N; i++) {
6807                 final NotificationRecord nr = mEnqueuedNotifications.get(i);
6808                 if (filter.filtered && !filter.matches(nr.getSbn())) continue;
6809                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
6810                         NotificationRecordProto.ENQUEUED);
6811             }
6812             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
6813             N = snoozed.size();
6814             for (int i = 0; i < N; i++) {
6815                 final NotificationRecord nr = snoozed.get(i);
6816                 if (filter.filtered && !filter.matches(nr.getSbn())) continue;
6817                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
6818                         NotificationRecordProto.SNOOZED);
6819             }
6820 
6821             long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
6822             mZenModeHelper.dump(proto);
6823             for (ComponentName suppressor : mEffectsSuppressors) {
6824                 suppressor.dumpDebug(proto, ZenModeProto.SUPPRESSORS);
6825             }
6826             proto.end(zenLog);
6827 
6828             long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
6829             mListeners.dump(proto, filter);
6830             proto.end(listenersToken);
6831 
6832             proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
6833 
6834             for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
6835                 long effectsToken = proto.start(
6836                     NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
6837 
6838                 proto.write(
6839                     ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
6840                 final ArraySet<ComponentName> listeners =
6841                     mListenersDisablingEffects.valueAt(i);
6842                 for (int j = 0; j < listeners.size(); j++) {
6843                     final ComponentName componentName = listeners.valueAt(j);
6844                     componentName.dumpDebug(proto,
6845                             ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
6846                 }
6847 
6848                 proto.end(effectsToken);
6849             }
6850 
6851             long assistantsToken = proto.start(
6852                 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
6853             mAssistants.dump(proto, filter);
6854             proto.end(assistantsToken);
6855 
6856             long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
6857             mConditionProviders.dump(proto, filter);
6858             proto.end(conditionsToken);
6859 
6860             long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
6861             mRankingHelper.dump(proto, filter);
6862             mPreferencesHelper.dump(proto, filter, pkgPermissions);
6863             proto.end(rankingToken);
6864         }
6865 
6866         proto.flush();
6867     }
6868 
6869     private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
6870         synchronized (mNotificationLock) {
6871             int N;
6872             N = mNotificationList.size();
6873             if (N > 0) {
6874                 pw.println("  Notification List:");
6875                 for (int i = 0; i < N; i++) {
6876                     final NotificationRecord nr = mNotificationList.get(i);
6877                     if (filter.filtered && !filter.matches(nr.getSbn())) continue;
6878                     nr.dump(pw, "    ", getContext(), filter.redact);
6879                 }
6880                 pw.println("  ");
6881             }
6882         }
6883     }
6884 
6885     void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter,
6886             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
6887         pw.print("Current Notification Manager state");
6888         if (filter.filtered) {
6889             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
6890         }
6891         pw.println(':');
6892         int N;
6893         final boolean zenOnly = filter.filtered && filter.zen;
6894 
6895         if (!zenOnly) {
6896             synchronized (mToastQueue) {
6897                 N = mToastQueue.size();
6898                 if (N > 0) {
6899                     pw.println("  Toast Queue:");
6900                     for (int i=0; i<N; i++) {
6901                         mToastQueue.get(i).dump(pw, "    ", filter);
6902                     }
6903                     pw.println("  ");
6904                 }
6905             }
6906         }
6907 
6908         synchronized (mNotificationLock) {
6909             if (!zenOnly) {
6910                 // Priority filters are only set when called via bugreport. If set
6911                 // skip sections that are part of the critical section.
6912                 if (!filter.normalPriority) {
6913                     dumpNotificationRecords(pw, filter);
6914                 }
6915                 if (!filter.filtered) {
6916                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
6917                     pw.println("  hideSilentStatusBar="
6918                             + mPreferencesHelper.shouldHideSilentStatusIcons());
6919                     mAttentionHelper.dump(pw, "    ", filter);
6920                 }
6921                 pw.println("  mArchive=" + mArchive.toString());
6922                 mArchive.dumpImpl(pw, filter);
6923 
6924                 if (!zenOnly) {
6925                     N = mEnqueuedNotifications.size();
6926                     if (N > 0) {
6927                         pw.println("  Enqueued Notification List:");
6928                         for (int i = 0; i < N; i++) {
6929                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
6930                             if (filter.filtered && !filter.matches(nr.getSbn())) continue;
6931                             nr.dump(pw, "    ", getContext(), filter.redact);
6932                         }
6933                         pw.println("  ");
6934                     }
6935 
6936                     mSnoozeHelper.dump(pw, filter);
6937                 }
6938             }
6939 
6940             if (!zenOnly) {
6941                 pw.println("\n  Ranking Config:");
6942                 mRankingHelper.dump(pw, "    ", filter);
6943 
6944                 pw.println("\n Notification Preferences:");
6945                 mPreferencesHelper.dump(pw, "    ", filter, pkgPermissions);
6946 
6947                 pw.println("\n  Notification listeners:");
6948                 mListeners.dump(pw, filter);
6949                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
6950                 pw.print("    mListenersDisablingEffects: (");
6951                 N = mListenersDisablingEffects.size();
6952                 for (int i = 0; i < N; i++) {
6953                     final int hint = mListenersDisablingEffects.keyAt(i);
6954                     if (i > 0) pw.print(';');
6955                     pw.print("hint[" + hint + "]:");
6956 
6957                     final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
6958                     final int listenerSize = listeners.size();
6959 
6960                     for (int j = 0; j < listenerSize; j++) {
6961                         if (j > 0) pw.print(',');
6962                         final ComponentName listener = listeners.valueAt(j);
6963                         if (listener != null) {
6964                             pw.print(listener);
6965                         }
6966                     }
6967                 }
6968                 pw.println(')');
6969                 pw.println("\n  Notification assistant services:");
6970                 mAssistants.dump(pw, filter);
6971             }
6972 
6973             if (!filter.filtered || zenOnly) {
6974                 pw.println("\n  Zen Mode:");
6975                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
6976                 mZenModeHelper.dump(pw, "    ");
6977 
6978                 pw.println("\n  Zen Log:");
6979                 ZenLog.dump(pw, "    ");
6980             }
6981 
6982             pw.println("\n  Condition providers:");
6983             mConditionProviders.dump(pw, filter);
6984 
6985             pw.println("\n  Group summaries:");
6986             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
6987                 NotificationRecord r = entry.getValue();
6988                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
6989                 if (mNotificationsByKey.get(r.getKey()) != r) {
6990                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
6991                     r.dump(pw, "      ", getContext(), filter.redact);
6992                 }
6993             }
6994 
6995             if (!zenOnly) {
6996                 pw.println("\n  Usage Stats:");
6997                 mUsageStats.dump(pw, "    ", filter);
6998 
6999                 if (Flags.allNotifsNeedTtl()) {
7000                     pw.println("\n  TimeToLive alarms:");
7001                     mTtlHelper.dump(pw, "    ");
7002                 }
7003             }
7004         }
7005     }
7006 
7007     /**
7008      * The private API only accessible to the system process.
7009      */
7010     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
7011 
7012         @Override
7013         public NotificationChannel getNotificationChannel(String pkg, int uid, String
7014                 channelId) {
7015             return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
7016         }
7017 
7018         @Override
7019         public NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String
7020                 channelId) {
7021             return mPreferencesHelper.getGroupForChannel(pkg, uid, channelId);
7022         }
7023 
7024         @Override
7025         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
7026                 String tag, int id, Notification notification, int userId) {
7027             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
7028                     userId, false /* byForegroundService */);
7029         }
7030 
7031         @Override
7032         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
7033                 String tag, int id, Notification notification, int userId,
7034                 boolean byForegroundService) {
7035             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
7036                     userId, byForegroundService);
7037         }
7038 
7039         @Override
7040         public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid,
7041                 String tag, int id, int userId) {
7042             // Don't allow client applications to cancel foreground service notifs,
7043             // user-initiated job notifs or autobundled summaries.
7044             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
7045                     (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
7046             cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId,
7047                     mustNotHaveFlags);
7048         }
7049 
7050         @Override
7051         public boolean isNotificationShown(String pkg, String tag, int notificationId, int userId) {
7052             return isNotificationShownInternal(pkg, tag, notificationId, userId);
7053         }
7054 
7055         @Override
7056         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
7057                 int userId) {
7058             checkCallerIsSystem();
7059             mHandler.post(() -> {
7060                 synchronized (mNotificationLock) {
7061                     removeFlagFromNotificationLocked(pkg, notificationId, userId,
7062                             FLAG_FOREGROUND_SERVICE);
7063                 }
7064             });
7065         }
7066 
7067         @Override
7068         public void removeUserInitiatedJobFlagFromNotification(String pkg, int notificationId,
7069                 int userId) {
7070             checkCallerIsSystem();
7071             mHandler.post(() -> {
7072                 synchronized (mNotificationLock) {
7073                     removeFlagFromNotificationLocked(pkg, notificationId, userId,
7074                             FLAG_USER_INITIATED_JOB);
7075                 }
7076             });
7077         }
7078 
7079         @GuardedBy("mNotificationLock")
7080         private void removeFlagFromNotificationLocked(String pkg, int notificationId, int userId,
7081                 int flag) {
7082             int count = getNotificationCount(pkg, userId);
7083             boolean removeFlagFromNotification = false;
7084             if (count > MAX_PACKAGE_NOTIFICATIONS) {
7085                 mUsageStats.registerOverCountQuota(pkg);
7086                 removeFlagFromNotification = true;
7087             }
7088             if (removeFlagFromNotification) {
7089                 NotificationRecord r = findNotificationLocked(pkg, null, notificationId, userId);
7090                 if (r != null) {
7091                     if (DBG) {
7092                         final String type = (flag ==  FLAG_FOREGROUND_SERVICE) ? "FGS" : "UIJ";
7093                         Slog.d(TAG, "Remove " + type + " flag not allow. "
7094                                 + "Cancel " + type + " notification");
7095                     }
7096                     removeFromNotificationListsLocked(r);
7097                     cancelNotificationLocked(r, false, REASON_APP_CANCEL, true,
7098                             null, SystemClock.elapsedRealtime());
7099                 }
7100             } else {
7101                 List<NotificationRecord> enqueued = findNotificationsByListLocked(
7102                         mEnqueuedNotifications, pkg, null, notificationId, userId);
7103                 for (int i = 0; i < enqueued.size(); i++) {
7104                     final NotificationRecord r = enqueued.get(i);
7105                     if (r != null) {
7106                         // strip flag from all enqueued notifications. listeners will be informed
7107                         // in post runnable.
7108                         StatusBarNotification sbn = r.getSbn();
7109                         sbn.getNotification().flags = (r.mOriginalFlags & ~flag);
7110                     }
7111                 }
7112 
7113                 NotificationRecord r = findNotificationByListLocked(
7114                         mNotificationList, pkg, null, notificationId, userId);
7115                 if (r != null) {
7116                     // if posted notification exists, strip its flag and tell listeners
7117                     StatusBarNotification sbn = r.getSbn();
7118                     sbn.getNotification().flags = (r.mOriginalFlags & ~flag);
7119                     mRankingHelper.sort(mNotificationList);
7120                     mListeners.notifyPostedLocked(r, r);
7121                 }
7122             }
7123         }
7124 
7125         @Override
7126         public void onConversationRemoved(String pkg, int uid, Set<String> shortcuts) {
7127             onConversationRemovedInternal(pkg, uid, shortcuts);
7128         }
7129 
7130         @Override
7131         public int getNumNotificationChannelsForPackage(String pkg, int uid,
7132                 boolean includeDeleted) {
7133             return NotificationManagerService.this
7134                     .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted);
7135         }
7136 
7137         @Override
7138         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
7139             return areNotificationsEnabledForPackageInt(pkg, uid);
7140         }
7141 
7142         @Override
7143         public void sendReviewPermissionsNotification() {
7144             if (!mShowReviewPermissionsNotification) {
7145                 // don't show if this notification is turned off
7146                 return;
7147             }
7148 
7149             // This method is meant to be called from the JobService upon running the job for this
7150             // notification having been rescheduled; so without checking any other state, it will
7151             // send the notification.
7152             checkCallerIsSystem();
7153             NotificationManager nm = getContext().getSystemService(NotificationManager.class);
7154             nm.notify(TAG,
7155                     SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS,
7156                     createReviewPermissionsNotification());
7157             Settings.Global.putInt(getContext().getContentResolver(),
7158                     Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
7159                     NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN);
7160         }
7161 
7162         @Override
7163         public void cleanupHistoryFiles() {
7164             checkCallerIsSystem();
7165             mHistoryManager.cleanupHistoryFiles();
7166         }
7167 
7168         @Override
7169         public void removeBitmaps() {
7170             // Check all NotificationRecords, remove expired bitmaps and icon URIs, repost silently.
7171             synchronized (mNotificationLock) {
7172                 for (NotificationRecord r: mNotificationList) {
7173 
7174                     // System#currentTimeMillis when posted
7175                     final long timePostedMs = r.getSbn().getPostTime();
7176                     final long timeNowMs = System.currentTimeMillis();
7177 
7178                     final long bitmapDuration;
7179                     if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) {
7180                         bitmapDuration = Duration.ofSeconds(5).toMillis();
7181                     } else {
7182                         bitmapDuration = BITMAP_DURATION.toMillis();
7183                     }
7184 
7185                     if (isBitmapExpired(timePostedMs, timeNowMs, bitmapDuration)) {
7186                         removeBitmapAndRepost(r);
7187                     }
7188                 }
7189             }
7190         }
7191 
7192         @Override
7193         public void setDeviceEffectsApplier(DeviceEffectsApplier applier) {
7194             if (!android.app.Flags.modesApi()) {
7195                 return;
7196             }
7197             if (mZenModeHelper == null) {
7198                 throw new IllegalStateException("ZenModeHelper is not yet ready!");
7199             }
7200             // This can also throw IllegalStateException if called too late.
7201             mZenModeHelper.setDeviceEffectsApplier(applier);
7202         }
7203     };
7204 
7205     private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
7206         final boolean isBigPicture = n.isStyle(Notification.BigPictureStyle.class);
7207         if (!isBigPicture) {
7208             return false;
7209         }
7210 
7211         final boolean hasBitmap = n.extras.containsKey(Notification.EXTRA_PICTURE)
7212                 && n.extras.getParcelable(Notification.EXTRA_PICTURE) != null;
7213         if (hasBitmap) {
7214             return true;
7215         }
7216 
7217         final boolean hasIcon = n.extras.containsKey(Notification.EXTRA_PICTURE_ICON)
7218                 && n.extras.getParcelable(Notification.EXTRA_PICTURE_ICON) != null;
7219         if (hasIcon) {
7220             return true;
7221         }
7222         return false;
7223     }
7224 
7225     private static boolean isBitmapExpired(long timePostedMs, long timeNowMs, long timeToLiveMs) {
7226         final long timeDiff = timeNowMs - timePostedMs;
7227         return timeDiff > timeToLiveMs;
7228     }
7229 
7230     private void removeBitmapAndRepost(NotificationRecord r) {
7231         if (!isBigPictureWithBitmapOrIcon(r.getNotification())) {
7232             return;
7233         }
7234         // Remove Notification object's reference to picture bitmap or URI. Leave the extras set to
7235         // null to avoid crashing apps that came to expect them to be present but null.
7236         r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE, null);
7237         r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE_ICON, null);
7238 
7239         // Make Notification silent
7240         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
7241 
7242         // Repost
7243         enqueueNotificationInternal(r.getSbn().getPackageName(),
7244                 r.getSbn().getOpPkg(), r.getSbn().getUid(),
7245                 r.getSbn().getInitialPid(), r.getSbn().getTag(),
7246                 r.getSbn().getId(), r.getNotification(),
7247                 r.getSbn().getUserId(), /* postSilently= */ true,
7248                 /* byForegroundService= */ false);
7249     }
7250 
7251     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
7252         return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted).getList()
7253                 .size();
7254     }
7255 
7256     void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid,
7257             String tag, int id, int userId, int mustNotHaveFlags) {
7258         userId = ActivityManager.handleIncomingUser(callingPid,
7259                 callingUid, userId, true, false, "cancelNotificationWithTag", pkg);
7260 
7261         // ensure opPkg is delegate if does not match pkg
7262 
7263         int uid = INVALID_UID;
7264 
7265         try {
7266             uid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
7267         } catch (NameNotFoundException e) {
7268             // package either never existed so there's no posted notification or it's being
7269             // uninstalled so we'll be cleaning it up soon. log and return immediately below.
7270         }
7271 
7272         if (uid == INVALID_UID) {
7273             Slog.w(TAG, opPkg + ":" + callingUid + " trying to cancel notification "
7274                     + "for nonexistent pkg " + pkg + " in user " + userId);
7275             return;
7276         }
7277 
7278         // if opPkg is not the same as pkg, make sure the notification given was posted
7279         // by opPkg
7280         if (!Objects.equals(pkg, opPkg)) {
7281             synchronized (mNotificationLock) {
7282                 // Look for the notification, searching both the posted and enqueued lists.
7283                 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
7284                 if (r != null) {
7285                     if (!Objects.equals(opPkg, r.getSbn().getOpPkg())) {
7286                         throw new SecurityException(opPkg + " does not have permission to "
7287                                 + "cancel a notification they did not post " + tag + " " + id);
7288                     }
7289                 }
7290             }
7291         }
7292         if (Flags.traceCancelEvents()) {
7293             Trace.instant(Trace.TRACE_TAG_SYSTEM_SERVER, "cancelNotificationInternal: " +
7294                     SmallHash.hash(Objects.hashCode(tag) ^ id));
7295         }
7296 
7297         cancelNotification(uid, callingPid, pkg, tag, id, 0,
7298                 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
7299     }
7300 
7301     boolean isNotificationShownInternal(String pkg, String tag, int notificationId, int userId) {
7302         synchronized (mNotificationLock) {
7303             return findNotificationLocked(pkg, tag, notificationId, userId) != null;
7304         }
7305     }
7306 
7307     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
7308             final int callingPid, final String tag, final int id, final Notification notification,
7309             int incomingUserId, boolean byForegroundService) {
7310         enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
7311                 incomingUserId, false /* postSilently */, byForegroundService);
7312     }
7313 
7314     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
7315             final int callingPid, final String tag, final int id, final Notification notification,
7316             int incomingUserId, boolean postSilently, boolean byForegroundService) {
7317         PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
7318         boolean enqueued = false;
7319         try {
7320             enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
7321                     notification, incomingUserId, postSilently, tracker, byForegroundService);
7322         } finally {
7323             if (!enqueued) {
7324                 tracker.cancel();
7325             }
7326         }
7327     }
7328 
7329     private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) {
7330         // The package probably doesn't have WAKE_LOCK permission and should not require it.
7331         return Binder.withCleanCallingIdentity(() -> {
7332             WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
7333                     "NotificationManagerService:post:" + pkg);
7334             wakeLock.setWorkSource(new WorkSource(uid, pkg));
7335             wakeLock.acquire(POST_WAKE_LOCK_TIMEOUT.toMillis());
7336             return mPostNotificationTrackerFactory.newTracker(wakeLock);
7337         });
7338     }
7339 
7340     /**
7341      * @return True if we successfully processed the notification and handed off the task of
7342      * enqueueing it to a background thread; false otherwise.
7343      */
7344     private boolean enqueueNotificationInternal(final String pkg, final String opPkg,  //HUI
7345             final int callingUid, final int callingPid, final String tag, final int id,
7346             final Notification notification, int incomingUserId, boolean postSilently,
7347             PostNotificationTracker tracker, boolean byForegroundService) {
7348         if (DBG) {
7349             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
7350                     + " notification=" + notification);
7351         }
7352 
7353         if (pkg == null || notification == null) {
7354             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
7355                     + " id=" + id + " notification=" + notification);
7356         }
7357 
7358         final int userId = ActivityManager.handleIncomingUser(callingPid,
7359                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
7360         final UserHandle user = UserHandle.of(userId);
7361 
7362         // Can throw a SecurityException if the calling uid doesn't have permission to post
7363         // as "pkg"
7364         int notificationUid = INVALID_UID;
7365 
7366         try {
7367             notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
7368         } catch (NameNotFoundException e) {
7369             // not great -  throw immediately below
7370         }
7371 
7372         if (notificationUid == INVALID_UID) {
7373             throw new SecurityException("Caller " + opPkg + ":" + callingUid
7374                     + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
7375         }
7376 
7377         if (android.app.Flags.secureAllowlistToken()) {
7378             IBinder allowlistToken = notification.getAllowlistToken();
7379             if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) {
7380                 throw new SecurityException(
7381                         "Unexpected allowlist token received from " + callingUid);
7382             }
7383             // allowlistToken is populated by unparceling, so it can be null if the notification was
7384             // posted from inside system_server. Ensure it's the expected value.
7385             notification.overrideAllowlistToken(ALLOWLIST_TOKEN);
7386         }
7387 
7388         checkRestrictedCategories(notification);
7389 
7390         // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
7391         // but it's also possible that the app has called notify() with an update to an
7392         // FGS notification that hasn't yet been displayed.  Make sure we check for any
7393         // FGS-related situation up front, outside of any locks so it's safe to call into
7394         // the Activity Manager.
7395         final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
7396                 notification, tag, id, pkg, userId);
7397 
7398         boolean stripUijFlag = true;
7399         final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
7400         if (js != null) {
7401             stripUijFlag = !js.isNotificationAssociatedWithAnyUserInitiatedJobs(id, userId, pkg);
7402         }
7403 
7404         // Fix the notification as best we can.
7405         try {
7406             fixNotification(notification, pkg, tag, id, userId, notificationUid,
7407                     policy, stripUijFlag);
7408         } catch (Exception e) {
7409             if (notification.isForegroundService()) {
7410                 throw new SecurityException("Invalid FGS notification", e);
7411             }
7412             Slog.e(TAG, "Cannot fix notification", e);
7413             return false;
7414         }
7415 
7416         if (policy == ServiceNotificationPolicy.UPDATE_ONLY) {
7417             // Proceed if the notification is already showing/known, otherwise ignore
7418             // because the service lifecycle logic has retained responsibility for its
7419             // handling.
7420             if (!isNotificationShownInternal(pkg, tag, id, userId)) {
7421                 reportForegroundServiceUpdate(false, notification, id, pkg, userId);
7422                 return false;
7423             }
7424         }
7425 
7426         mUsageStats.registerEnqueuedByApp(pkg);
7427 
7428         final StatusBarNotification n = new StatusBarNotification(
7429                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
7430                 user, null, System.currentTimeMillis());
7431 
7432         // setup local book-keeping
7433         String channelId = notification.getChannelId();
7434         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
7435             channelId = (new Notification.TvExtender(notification)).getChannelId();
7436         }
7437         String shortcutId = n.getShortcutId();
7438         final NotificationChannel channel = getNotificationChannelRestoreDeleted(pkg,
7439                 callingUid, notificationUid, channelId, shortcutId);
7440         if (channel == null) {
7441             final String noChannelStr = "No Channel found for "
7442                     + "pkg=" + pkg
7443                     + ", channelId=" + channelId
7444                     + ", id=" + id
7445                     + ", tag=" + tag
7446                     + ", opPkg=" + opPkg
7447                     + ", callingUid=" + callingUid
7448                     + ", userId=" + userId
7449                     + ", incomingUserId=" + incomingUserId
7450                     + ", notificationUid=" + notificationUid
7451                     + ", notification=" + notification;
7452             Slog.e(TAG, noChannelStr);
7453             boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
7454 
7455 
7456             if (!appNotificationsOff) {
7457                 doChannelWarningToast(notificationUid,
7458                         "Developer warning for package \"" + pkg + "\"\n" +
7459                         "Failed to post notification on channel \"" + channelId + "\"\n" +
7460                         "See log for more details");
7461             }
7462             return false;
7463         }
7464 
7465         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
7466         r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
7467         r.setPostSilently(postSilently);
7468         r.setFlagBubbleRemoved(false);
7469         r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
7470         boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
7471         r.setImportanceFixed(isImportanceFixed);
7472 
7473         if (notification.isFgsOrUij()) {
7474             if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
7475                         || !channel.isUserVisibleTaskShown())
7476                     && (r.getImportance() == IMPORTANCE_MIN
7477                             || r.getImportance() == IMPORTANCE_NONE)) {
7478                 // Increase the importance of fgs/uij notifications unless the user had
7479                 // an opinion otherwise (and the channel hasn't yet shown a fgs/uij).
7480                 channel.setImportance(IMPORTANCE_LOW);
7481                 r.setSystemImportance(IMPORTANCE_LOW);
7482                 if (!channel.isUserVisibleTaskShown()) {
7483                     channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
7484                     channel.setUserVisibleTaskShown(true);
7485                 }
7486                 mPreferencesHelper.updateNotificationChannel(
7487                         pkg, notificationUid, channel, false, callingUid,
7488                         isCallerSystemOrSystemUi());
7489                 r.updateNotificationChannel(channel);
7490             } else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId)
7491                     && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
7492                 channel.setUserVisibleTaskShown(true);
7493                 r.updateNotificationChannel(channel);
7494             }
7495         }
7496 
7497         ShortcutInfo info = mShortcutHelper != null
7498                 ? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user)
7499                 : null;
7500         if (notification.getShortcutId() != null && info == null) {
7501             Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut");
7502         }
7503         r.setShortcutInfo(info);
7504         r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid));
7505         r.userDemotedAppFromConvoSpace(
7506                 mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
7507 
7508         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
7509                 r.getSbn().getOverrideGroupKey() != null, byForegroundService)) {
7510             return false;
7511         }
7512 
7513         mUsageStats.registerEnqueuedByAppAndAccepted(pkg);
7514 
7515         if (info != null) {
7516             // Cache the shortcut synchronously after the associated notification is posted in case
7517             // the app unpublishes this shortcut immediately after posting the notification. If the
7518             // user does not modify the notification settings on this conversation, the shortcut
7519             // will be uncached by People Service when all the associated notifications are removed.
7520             mShortcutHelper.cacheShortcut(info, user);
7521         }
7522 
7523         // temporarily allow apps to perform extra work when their pending intents are launched
7524         if (notification.allPendingIntents != null) {
7525             final int intentCount = notification.allPendingIntents.size();
7526             if (intentCount > 0) {
7527                 final long duration = LocalServices.getService(
7528                         DeviceIdleInternal.class).getNotificationAllowlistDuration();
7529                 for (int i = 0; i < intentCount; i++) {
7530                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
7531                     if (pendingIntent != null) {
7532                         mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
7533                                 ALLOWLIST_TOKEN, duration,
7534                                 TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
7535                                 REASON_NOTIFICATION_SERVICE,
7536                                 "NotificationManagerService");
7537                         mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
7538                                 ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
7539                                         | FLAG_SERVICE_SENDER));
7540                     }
7541                 }
7542             }
7543         }
7544 
7545         // Need escalated privileges to get package importance.
7546         final int packageImportance = getPackageImportanceWithIdentity(pkg);
7547         boolean isAppForeground = packageImportance == IMPORTANCE_FOREGROUND;
7548         mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, tracker));
7549         return true;
7550     }
7551 
7552     /**
7553      * Returns a channel, if exists, and restores deleted conversation channels.
7554      */
7555     @Nullable
7556     private NotificationChannel getNotificationChannelRestoreDeleted(String pkg,
7557             int callingUid, int notificationUid, String channelId, String conversationId) {
7558         // Restore a deleted conversation channel, if exists. Otherwise use the parent channel.
7559         NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
7560                 pkg, notificationUid, channelId, conversationId,
7561                 true /* parent ok */, !TextUtils.isEmpty(conversationId) /* includeDeleted */);
7562         // Restore deleted conversation channel
7563         if (channel != null && channel.isDeleted()) {
7564             if (Objects.equals(conversationId, channel.getConversationId())) {
7565                 boolean needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(
7566                         pkg, notificationUid, channel, true /* fromTargetApp */,
7567                         mConditionProviders.isPackageOrComponentAllowed(pkg,
7568                         UserHandle.getUserId(notificationUid)), callingUid, true);
7569                 // Update policy file if the conversation channel was restored
7570                 if (needsPolicyFileChange) {
7571                     handleSavePolicyFile();
7572                 }
7573             } else {
7574                 // Do not restore parent channel
7575                 channel = null;
7576             }
7577         }
7578         return channel;
7579     }
7580 
7581     private void onConversationRemovedInternal(String pkg, int uid, Set<String> shortcuts) {
7582         checkCallerIsSystem();
7583         Preconditions.checkStringNotEmpty(pkg);
7584 
7585         mHistoryManager.deleteConversations(pkg, uid, shortcuts);
7586         List<String> deletedChannelIds =
7587                 mPreferencesHelper.deleteConversations(pkg, uid, shortcuts,
7588                         /* callingUid */ Process.SYSTEM_UID, /* is system */ true);
7589         for (String channelId : deletedChannelIds) {
7590             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
7591                     UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED
7592             );
7593         }
7594         handleSavePolicyFile();
7595     }
7596 
7597     private void makeStickyHun(Notification notification, String pkg, @UserIdInt int userId) {
7598         if (mPermissionHelper.hasRequestedPermission(
7599                 Manifest.permission.USE_FULL_SCREEN_INTENT, pkg, userId)) {
7600             notification.flags |= FLAG_FSI_REQUESTED_BUT_DENIED;
7601         }
7602         if (notification.contentIntent == null) {
7603             // On notification click, if contentIntent is null, SystemUI launches the
7604             // fullScreenIntent instead.
7605             notification.contentIntent = notification.fullScreenIntent;
7606         }
7607         notification.fullScreenIntent = null;
7608     }
7609 
7610     @VisibleForTesting
7611     protected void fixNotification(Notification notification, String pkg, String tag, int id,
7612             @UserIdInt int userId, int notificationUid,
7613             ServiceNotificationPolicy fgsPolicy, boolean stripUijFlag)
7614             throws NameNotFoundException, RemoteException {
7615         final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
7616                 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
7617                 (userId == USER_ALL) ? USER_SYSTEM : userId);
7618         Notification.addFieldsFromContext(ai, notification);
7619 
7620         if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) {
7621             notification.flags &= ~FLAG_FOREGROUND_SERVICE;
7622         }
7623         if (notification.isUserInitiatedJob() && stripUijFlag) {
7624             notification.flags &= ~FLAG_USER_INITIATED_JOB;
7625         }
7626 
7627         // Remove FLAG_AUTO_CANCEL from notifications that are associated with a FGS or UIJ.
7628         if (notification.isFgsOrUij()) {
7629             notification.flags &= ~FLAG_AUTO_CANCEL;
7630         }
7631 
7632         // Only notifications that can be non-dismissible can have the flag FLAG_NO_DISMISS
7633         if (((notification.flags & FLAG_ONGOING_EVENT) > 0)
7634                 && canBeNonDismissible(ai, notification)) {
7635             notification.flags |= FLAG_NO_DISMISS;
7636         } else {
7637             notification.flags &= ~FLAG_NO_DISMISS;
7638         }
7639 
7640         int canColorize = getContext().checkPermission(
7641                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, -1, notificationUid);
7642 
7643         if (canColorize == PERMISSION_GRANTED) {
7644             notification.flags |= Notification.FLAG_CAN_COLORIZE;
7645         } else {
7646             notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
7647         }
7648 
7649         if (notification.extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, false)) {
7650             int hasShowDuringSetupPerm = getContext().checkPermission(
7651                     android.Manifest.permission.NOTIFICATION_DURING_SETUP, -1, notificationUid);
7652             if (hasShowDuringSetupPerm != PERMISSION_GRANTED) {
7653                 notification.extras.remove(Notification.EXTRA_ALLOW_DURING_SETUP);
7654                 if (DBG) {
7655                     Slog.w(TAG, "warning: pkg " + pkg + " attempting to show during setup"
7656                             + " without holding perm "
7657                             + Manifest.permission.NOTIFICATION_DURING_SETUP);
7658                 }
7659             }
7660         }
7661 
7662         notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED;
7663 
7664         // Apps cannot post notifications that are lifetime extended.
7665         if (lifetimeExtensionRefactor()) {
7666             notification.flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7667         }
7668 
7669         if (notification.fullScreenIntent != null) {
7670             final AttributionSource attributionSource =
7671                     new AttributionSource.Builder(notificationUid).setPackageName(pkg).build();
7672             final boolean canUseFullScreenIntent = checkUseFullScreenIntentPermission(
7673                     attributionSource, ai, true /* forDataDelivery */);
7674             if (!canUseFullScreenIntent) {
7675                 makeStickyHun(notification, pkg, userId);
7676             }
7677         }
7678 
7679         // Ensure all actions are present
7680         if (notification.actions != null) {
7681             boolean hasNullActions = false;
7682             int nActions = notification.actions.length;
7683             for (int i = 0; i < nActions; i++) {
7684                 if (notification.actions[i] == null) {
7685                     hasNullActions = true;
7686                     break;
7687                 }
7688             }
7689             if (hasNullActions) {
7690                 ArrayList<Notification.Action> nonNullActions = new ArrayList<>();
7691                 for (int i = 0; i < nActions; i++) {
7692                     if (notification.actions[i] != null) {
7693                         nonNullActions.add(notification.actions[i]);
7694                     }
7695                 }
7696                 if (nonNullActions.size() != 0) {
7697                     notification.actions = nonNullActions.toArray(new Notification.Action[0]);
7698                 } else {
7699                     notification.actions = null;
7700                 }
7701             }
7702         }
7703 
7704         // Ensure CallStyle has all the correct actions
7705         if (notification.isStyle(Notification.CallStyle.class)) {
7706             Notification.Builder builder =
7707                     Notification.Builder.recoverBuilder(getContext(), notification);
7708             Notification.CallStyle style = (Notification.CallStyle) builder.getStyle();
7709             List<Notification.Action> actions = style.getActionsListWithSystemActions();
7710             notification.actions = new Notification.Action[actions.size()];
7711             actions.toArray(notification.actions);
7712         }
7713 
7714         // Ensure MediaStyle has correct permissions for remote device extras
7715         if (notification.isStyle(Notification.MediaStyle.class)
7716                 || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) {
7717             int hasMediaContentControlPermission = getContext().checkPermission(
7718                     android.Manifest.permission.MEDIA_CONTENT_CONTROL, -1, notificationUid);
7719             if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
7720                 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE);
7721                 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON);
7722                 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT);
7723                 if (DBG) {
7724                     Slog.w(TAG, "Package " + pkg + ": Use of setRemotePlayback requires the "
7725                             + "MEDIA_CONTENT_CONTROL permission");
7726                 }
7727             }
7728 
7729             // Enforce NO_CLEAR flag on MediaStyle notification for apps with targetSdk >= V.
7730             if (CompatChanges.isChangeEnabled(ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION,
7731                     notificationUid)) {
7732                 notification.flags |= FLAG_NO_CLEAR;
7733             }
7734         }
7735 
7736         // Ensure only allowed packages have a substitute app name
7737         if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
7738             int hasSubstituteAppNamePermission = getContext().checkPermission(
7739                     permission.SUBSTITUTE_NOTIFICATION_APP_NAME, -1, notificationUid);
7740             if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
7741                 notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
7742                 if (DBG) {
7743                     Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name"
7744                             + " without holding perm "
7745                             + Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
7746                 }
7747             }
7748         }
7749 
7750         // Remote views? Are they too big?
7751         checkRemoteViews(pkg, tag, id, notification);
7752 
7753         if (Flags.allNotifsNeedTtl()) {
7754             if (notification.getTimeoutAfter() == 0) {
7755                 notification.setTimeoutAfter(NOTIFICATION_TTL);
7756             }
7757         }
7758     }
7759 
7760     /**
7761      * Whether a notification can be non-dismissible.
7762      * A notification should be dismissible, unless it's exempted for some reason.
7763      */
7764     private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) {
7765         return notification.isMediaNotification() || isEnterpriseExempted(ai)
7766                 || notification.isStyle(Notification.CallStyle.class)
7767                 || isDefaultSearchSelectorPackage(ai.packageName)
7768                 || isDefaultAdservicesPackage(ai.packageName);
7769     }
7770 
7771     private boolean isDefaultSearchSelectorPackage(String pkg) {
7772         return Objects.equals(mDefaultSearchSelectorPkg, pkg);
7773     }
7774 
7775     private boolean isDefaultAdservicesPackage(String pkg) {
7776         if (mAdservicesModuleInfo == null) {
7777             return false;
7778         }
7779         // Handles the special package structure for mainline modules
7780         for (String apkName : mAdservicesModuleInfo.getApkInApexPackageNames()) {
7781             if (Objects.equals(apkName, pkg)) {
7782                 return true;
7783             }
7784         }
7785         return false;
7786     }
7787 
7788     private boolean isEnterpriseExempted(ApplicationInfo ai) {
7789         // Check if the app is an organization admin app
7790         // TODO(b/234609037): Replace with new DPM APIs to check if organization admin
7791         if (mDpm != null && (mDpm.isActiveProfileOwner(ai.uid)
7792                 || mDpm.isActiveDeviceOwner(ai.uid))) {
7793             return true;
7794         }
7795         // Check if an app has been given system exemption
7796         if (ai.uid == Process.SYSTEM_UID) {
7797             return false;
7798         }
7799         return mAppOps.checkOpNoThrow(
7800                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
7801                 ai.packageName) == MODE_ALLOWED;
7802     }
7803 
7804     private boolean checkUseFullScreenIntentPermission(@NonNull AttributionSource attributionSource,
7805             @NonNull ApplicationInfo applicationInfo,
7806             boolean forDataDelivery) {
7807         if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
7808             return true;
7809         }
7810         final int permissionResult;
7811         if (forDataDelivery) {
7812             permissionResult = mPermissionManager.checkPermissionForDataDelivery(
7813                     permission.USE_FULL_SCREEN_INTENT, attributionSource, /* message= */ null);
7814         } else {
7815             permissionResult = mPermissionManager.checkPermissionForPreflight(
7816                     permission.USE_FULL_SCREEN_INTENT, attributionSource);
7817         }
7818         return permissionResult == PermissionManager.PERMISSION_GRANTED;
7819     }
7820 
7821     private void checkRemoteViews(String pkg, String tag, int id, Notification notification) {
7822         if (android.app.Flags.removeRemoteViews()) {
7823             if (notification.contentView != null || notification.bigContentView != null
7824                     ||  notification.headsUpContentView != null
7825                     || (notification.publicVersion != null
7826                     && (notification.publicVersion.contentView != null
7827                     || notification.publicVersion.bigContentView != null
7828                     || notification.publicVersion.headsUpContentView != null))) {
7829                 Slog.i(TAG, "Removed customViews for " + pkg);
7830                 mUsageStats.registerImageRemoved(pkg);
7831             }
7832             notification.contentView = null;
7833             notification.bigContentView = null;
7834             notification.headsUpContentView = null;
7835             if (notification.publicVersion != null) {
7836                 notification.publicVersion.contentView = null;
7837                 notification.publicVersion.bigContentView = null;
7838                 notification.publicVersion.headsUpContentView = null;
7839             }
7840         } else {
7841             if (removeRemoteView(pkg, tag, id, notification.contentView)) {
7842                 notification.contentView = null;
7843             }
7844             if (removeRemoteView(pkg, tag, id, notification.bigContentView)) {
7845                 notification.bigContentView = null;
7846             }
7847             if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) {
7848                 notification.headsUpContentView = null;
7849             }
7850             if (notification.publicVersion != null) {
7851                 if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) {
7852                     notification.publicVersion.contentView = null;
7853                 }
7854                 if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) {
7855                     notification.publicVersion.bigContentView = null;
7856                 }
7857                 if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) {
7858                     notification.publicVersion.headsUpContentView = null;
7859                 }
7860             }
7861         }
7862     }
7863 
7864     private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) {
7865         if (contentView == null) {
7866             return false;
7867         }
7868         final int contentViewSize = contentView.estimateMemoryUsage();
7869         if (contentViewSize > mWarnRemoteViewsSizeBytes
7870                 && contentViewSize < mStripRemoteViewsSizeBytes) {
7871             Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id
7872                     + " this might be stripped in a future release");
7873         }
7874         if (contentViewSize >= mStripRemoteViewsSizeBytes) {
7875             mUsageStats.registerImageRemoved(pkg);
7876             Slog.w(TAG, "Removed too large RemoteViews (" + contentViewSize + " bytes) on pkg: "
7877                     + pkg + " tag: " + tag + " id: " + id);
7878             return true;
7879         }
7880         return false;
7881     }
7882 
7883     /**
7884      * Strips any flags from BubbleMetadata that wouldn't apply (e.g. app not foreground).
7885      */
7886     private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) {
7887         Notification notification = r.getNotification();
7888         Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
7889         if (metadata == null) {
7890             // Nothing to update
7891             return;
7892         }
7893         if (!isAppForeground) {
7894             // Auto expand only works if foreground
7895             int flags = metadata.getFlags();
7896             flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
7897             metadata.setFlags(flags);
7898         }
7899         if (!metadata.isBubbleSuppressable()) {
7900             // If it's not suppressable remove the suppress flag
7901             int flags = metadata.getFlags();
7902             flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
7903             metadata.setFlags(flags);
7904         }
7905     }
7906 
7907     private ShortcutHelper.ShortcutListener mShortcutListener =
7908             new ShortcutHelper.ShortcutListener() {
7909                 @Override
7910                 public void onShortcutRemoved(String key) {
7911                     String packageName;
7912                     synchronized (mNotificationLock) {
7913                         NotificationRecord r = mNotificationsByKey.get(key);
7914                         packageName = r != null ? r.getSbn().getPackageName() : null;
7915                     }
7916                     final int packageImportance = getPackageImportanceWithIdentity(packageName);
7917                     boolean isAppForeground = packageName != null
7918                             && packageImportance == IMPORTANCE_FOREGROUND;
7919                     synchronized (mNotificationLock) {
7920                         NotificationRecord r = mNotificationsByKey.get(key);
7921                         if (r != null) {
7922                             r.setShortcutInfo(null);
7923                             // Enqueue will trigger resort & flag is updated that way.
7924                             r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
7925                             mHandler.post(
7926                                     new EnqueueNotificationRunnable(
7927                                             r.getUser().getIdentifier(), r, isAppForeground,
7928                                             mPostNotificationTrackerFactory.newTracker(null)));
7929                         }
7930                     }
7931                 }
7932             };
7933 
7934     protected void doChannelWarningToast(int forUid, CharSequence toastText) {
7935         Binder.withCleanCallingIdentity(() -> {
7936             final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
7937                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0) != 0;
7938             if (warningEnabled) {
7939                 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
7940                         Toast.LENGTH_SHORT);
7941                 toast.show();
7942             }
7943         });
7944     }
7945 
7946     @VisibleForTesting
7947     int resolveNotificationUid(String callingPkg, String targetPkg, int callingUid, int userId)
7948             throws NameNotFoundException {
7949         if (userId == USER_ALL) {
7950             userId = USER_SYSTEM;
7951         }
7952         // posted from app A on behalf of app A
7953         if (isCallerSameApp(targetPkg, callingUid, userId)
7954                 && (TextUtils.equals(callingPkg, targetPkg)
7955                 || isCallerSameApp(callingPkg, callingUid, userId))) {
7956             return callingUid;
7957         }
7958 
7959         int targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
7960 
7961         // posted from app A on behalf of app B
7962         if (isCallerAndroid(callingPkg, callingUid)
7963                 || mPreferencesHelper.isDelegateAllowed(
7964                         targetPkg, targetUid, callingPkg, callingUid)) {
7965             return targetUid;
7966         }
7967 
7968         throw new SecurityException("Caller " + callingPkg + ":" + callingUid
7969                 + " cannot post for pkg " + targetPkg + " in user " + userId);
7970     }
7971 
7972     public boolean hasFlag(final int flags, final int flag) {
7973         return (flags & flag) != 0;
7974     }
7975     /**
7976      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
7977      *
7978      * Has side effects.
7979      */
7980     boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
7981             NotificationRecord r, boolean isAutogroup, boolean byForegroundService) {
7982         Notification n = r.getNotification();
7983         final String pkg = r.getSbn().getPackageName();
7984         final boolean isSystemNotification =
7985                 isUidSystemOrPhone(uid) || ("android".equals(pkg));
7986         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
7987 
7988         // Limit the number of notifications that any given package except the android
7989         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
7990         if (!isSystemNotification && !isNotificationFromListener) {
7991             final int callingUid = Binder.getCallingUid();
7992             synchronized (mNotificationLock) {
7993                 if (mNotificationsByKey.get(r.getSbn().getKey()) == null
7994                         && isCallerInstantApp(callingUid, userId)) {
7995                     // Ephemeral apps have some special constraints for notifications.
7996                     // They are not allowed to create new notifications however they are allowed to
7997                     // update notifications created by the system (e.g. a foreground service
7998                     // notification).
7999                     throw new SecurityException("Instant app " + pkg
8000                             + " cannot create notifications");
8001                 }
8002 
8003                 // Rate limit updates that aren't completed progress notifications
8004                 // Search for the original one in the posted and not-yet-posted (enqueued) lists.
8005                 boolean isUpdate = mNotificationsByKey.get(r.getSbn().getKey()) != null
8006                         || findNotificationByListLocked(mEnqueuedNotifications, r.getSbn().getKey())
8007                         != null;
8008                 if (isUpdate && !r.getNotification().hasCompletedProgress() && !isAutogroup) {
8009                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
8010                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
8011                         mUsageStats.registerOverRateQuota(pkg);
8012                         final long now = SystemClock.elapsedRealtime();
8013                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
8014                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
8015                                     + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg);
8016                             mLastOverRateLogTime = now;
8017                         }
8018                         return false;
8019                     }
8020                 }
8021             }
8022 
8023             // limit the number of non-fgs/uij outstanding notificationrecords an app can have
8024             if (!n.isFgsOrUij()) {
8025                 int count = getNotificationCount(pkg, userId, id, tag);
8026                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
8027                     mUsageStats.registerOverCountQuota(pkg);
8028                     Slog.e(TAG, "Package has already posted or enqueued " + count
8029                             + " notifications.  Not showing more.  package=" + pkg);
8030                     return false;
8031                 }
8032             }
8033         }
8034 
8035         // bubble or inline reply that's immutable?
8036         if (n.getBubbleMetadata() != null
8037                 && n.getBubbleMetadata().getIntent() != null
8038                 && hasFlag(mAmi.getPendingIntentFlags(
8039                         n.getBubbleMetadata().getIntent().getTarget()),
8040                         PendingIntent.FLAG_IMMUTABLE)) {
8041             throw new IllegalArgumentException(r.getKey() + " Not posted."
8042                     + " PendingIntents attached to bubbles must be mutable");
8043         }
8044 
8045         if (n.actions != null) {
8046             for (Notification.Action action : n.actions) {
8047                 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null)
8048                         && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()),
8049                         PendingIntent.FLAG_IMMUTABLE)) {
8050                     throw new IllegalArgumentException(r.getKey() + " Not posted."
8051                             + " PendingIntents attached to actions with remote"
8052                             + " inputs must be mutable");
8053                 }
8054             }
8055         }
8056 
8057         if (r.getSystemGeneratedSmartActions() != null) {
8058             for (Notification.Action action : r.getSystemGeneratedSmartActions()) {
8059                 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null)
8060                         && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()),
8061                         PendingIntent.FLAG_IMMUTABLE)) {
8062                     throw new IllegalArgumentException(r.getKey() + " Not posted."
8063                             + " PendingIntents attached to contextual actions with remote inputs"
8064                             + " must be mutable");
8065                 }
8066             }
8067         }
8068 
8069         if (n.isStyle(Notification.CallStyle.class)) {
8070             boolean hasFullScreenIntent = n.fullScreenIntent != null;
8071             boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
8072             if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent
8073                     && !byForegroundService) {
8074                 throw new IllegalArgumentException(r.getKey() + " Not posted."
8075                         + " CallStyle notifications must be for a foreground service or"
8076                         + " user initated job or use a fullScreenIntent.");
8077             }
8078         }
8079 
8080         // snoozed apps
8081         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
8082             MetricsLogger.action(r.getLogMaker()
8083                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
8084                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
8085             mNotificationRecordLogger.log(
8086                     NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED,
8087                     r);
8088             if (DBG) {
8089                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
8090             }
8091             mSnoozeHelper.update(userId, r);
8092             handleSavePolicyFile();
8093             return false;
8094         }
8095 
8096         // blocked apps
8097         boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid);
8098         synchronized (mNotificationLock) {
8099             isBlocked |= isRecordBlockedLocked(r);
8100         }
8101         if (isBlocked && !(n.isMediaNotification() || isCallNotification(pkg, uid, n))) {
8102             if (DBG) {
8103                 Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
8104                         + " by user request.");
8105             }
8106             mUsageStats.registerBlocked(r);
8107             return false;
8108         }
8109 
8110         if (Flags.rejectOldNotifications() && n.hasAppProvidedWhen() && n.getWhen() > 0
8111                 && (System.currentTimeMillis() - n.getWhen()) > NOTIFICATION_MAX_AGE_AT_POST) {
8112             Slog.d(TAG, "Ignored enqueue for old " + n.getWhen() + " notification " + r.getKey());
8113             mUsageStats.registerTooOldBlocked(r);
8114             return false;
8115         }
8116 
8117         return true;
8118     }
8119 
8120     private boolean isCallNotification(String pkg, int uid, Notification n) {
8121         if (n.isStyle(Notification.CallStyle.class)) {
8122             return isCallNotification(pkg, uid);
8123         }
8124         return false;
8125     }
8126 
8127     private boolean isCallNotification(String pkg, int uid) {
8128         final long identity = Binder.clearCallingIdentity();
8129         try {
8130             if (mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)
8131                     && mTelecomManager != null) {
8132                 try {
8133                     return mTelecomManager.isInManagedCall()
8134                             || mTelecomManager.isInSelfManagedCall(pkg,
8135                             UserHandle.ALL);
8136                 } catch (IllegalStateException ise) {
8137                     // Telecom is not ready (this is likely early boot), so there are no calls.
8138                     return false;
8139                 }
8140             }
8141             return false;
8142         } finally {
8143             Binder.restoreCallingIdentity(identity);
8144         }
8145     }
8146 
8147     private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
8148         return mPermissionHelper.hasPermission(uid);
8149     }
8150 
8151     private int getNotificationCount(String pkg, int userId) {
8152         int count = 0;
8153         synchronized (mNotificationLock) {
8154             final int numListSize = mNotificationList.size();
8155             for (int i = 0; i < numListSize; i++) {
8156                 final NotificationRecord existing = mNotificationList.get(i);
8157                 if (existing.getSbn().getPackageName().equals(pkg)
8158                         && existing.getSbn().getUserId() == userId) {
8159                     count++;
8160                 }
8161             }
8162             final int numEnqSize = mEnqueuedNotifications.size();
8163             for (int i = 0; i < numEnqSize; i++) {
8164                 final NotificationRecord existing = mEnqueuedNotifications.get(i);
8165                 if (existing.getSbn().getPackageName().equals(pkg)
8166                         && existing.getSbn().getUserId() == userId) {
8167                     count++;
8168                 }
8169             }
8170         }
8171         return count;
8172     }
8173 
8174     protected int getNotificationCount(String pkg, int userId, int excludedId,
8175             String excludedTag) {
8176         int count = 0;
8177         synchronized (mNotificationLock) {
8178             final int N = mNotificationList.size();
8179             for (int i = 0; i < N; i++) {
8180                 final NotificationRecord existing = mNotificationList.get(i);
8181                 if (existing.getSbn().getPackageName().equals(pkg)
8182                         && existing.getSbn().getUserId() == userId) {
8183                     if (existing.getSbn().getId() == excludedId
8184                             && TextUtils.equals(existing.getSbn().getTag(), excludedTag)) {
8185                         continue;
8186                     }
8187                     count++;
8188                 }
8189             }
8190             final int M = mEnqueuedNotifications.size();
8191             for (int i = 0; i < M; i++) {
8192                 final NotificationRecord existing = mEnqueuedNotifications.get(i);
8193                 if (existing.getSbn().getPackageName().equals(pkg)
8194                         && existing.getSbn().getUserId() == userId) {
8195                     count++;
8196                 }
8197             }
8198         }
8199         return count;
8200     }
8201 
8202     /**
8203      * Checks whether a notification is banned at a group or channel level or if the NAS or system
8204      * has blocked the notification.
8205      */
8206     @GuardedBy("mNotificationLock")
8207     boolean isRecordBlockedLocked(NotificationRecord r) {
8208         final String pkg = r.getSbn().getPackageName();
8209         final int callingUid = r.getSbn().getUid();
8210         return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
8211                 || r.getImportance() == IMPORTANCE_NONE;
8212     }
8213 
8214     protected class SnoozeNotificationRunnable implements Runnable {
8215         private final String mKey;
8216         private final long mDuration;
8217         private final String mSnoozeCriterionId;
8218 
8219         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
8220             mKey = key;
8221             mDuration = duration;
8222             mSnoozeCriterionId = snoozeCriterionId;
8223         }
8224 
8225         @Override
8226         public void run() {
8227             synchronized (mNotificationLock) {
8228                 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey);
8229                 if (r != null) {
8230                     snoozeLocked(r);
8231                 }
8232             }
8233         }
8234 
8235         @GuardedBy("mNotificationLock")
8236         void snoozeLocked(NotificationRecord r) {
8237             final List<NotificationRecord> recordsToSnooze = new ArrayList<>();
8238             if (r.getSbn().isGroup()) {
8239                 final List<NotificationRecord> groupNotifications =
8240                         findCurrentAndSnoozedGroupNotificationsLocked(
8241                         r.getSbn().getPackageName(),
8242                                 r.getSbn().getGroupKey(), r.getSbn().getUserId());
8243                 if (r.getNotification().isGroupSummary()) {
8244                     // snooze all children
8245                     for (int i = 0; i < groupNotifications.size(); i++) {
8246                         if (!mKey.equals(groupNotifications.get(i).getKey())) {
8247                             recordsToSnooze.add(groupNotifications.get(i));
8248                         }
8249                     }
8250                 } else {
8251                     // if there is a valid summary for this group, and we are snoozing the only
8252                     // child, also snooze the summary
8253                     if (mSummaryByGroupKey.containsKey(r.getSbn().getGroupKey())) {
8254                         if (groupNotifications.size() == 2) {
8255                             // snooze summary and the one child
8256                             for (int i = 0; i < groupNotifications.size(); i++) {
8257                                 if (!mKey.equals(groupNotifications.get(i).getKey())) {
8258                                     recordsToSnooze.add(groupNotifications.get(i));
8259                                 }
8260                             }
8261                         }
8262                     }
8263                 }
8264             }
8265             // snooze the notification
8266             recordsToSnooze.add(r);
8267 
8268             if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) {
8269                 for (int i = 0; i < recordsToSnooze.size(); i++) {
8270                     snoozeNotificationLocked(recordsToSnooze.get(i));
8271                 }
8272             } else {
8273                 Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications");
8274             }
8275         }
8276 
8277         @GuardedBy("mNotificationLock")
8278         void snoozeNotificationLocked(NotificationRecord r) {
8279             MetricsLogger.action(r.getLogMaker()
8280                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
8281                     .setType(MetricsEvent.TYPE_CLOSE)
8282                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
8283                             mDuration)
8284                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
8285                             mSnoozeCriterionId == null ? 0 : 1));
8286             mNotificationRecordLogger.log(
8287                     NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, r);
8288             reportUserInteraction(r);
8289             boolean wasPosted = removeFromNotificationListsLocked(r);
8290             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null,
8291                     SystemClock.elapsedRealtime());
8292             mAttentionHelper.updateLightsLocked();
8293             if (isSnoozable(r)) {
8294                 if (mSnoozeCriterionId != null) {
8295                     mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId);
8296                     mSnoozeHelper.snooze(r, mSnoozeCriterionId);
8297                 } else {
8298                     mSnoozeHelper.snooze(r, mDuration);
8299                 }
8300                 r.recordSnoozed();
8301                 handleSavePolicyFile();
8302             }
8303         }
8304 
8305         /**
8306          * Autogroup summaries are not snoozable
8307          * They will be recreated as needed when the group children are unsnoozed
8308          */
8309         private boolean isSnoozable(NotificationRecord record) {
8310             return !(record.getNotification().isGroupSummary() && GroupHelper.AUTOGROUP_KEY.equals(
8311                     record.getNotification().getGroup()));
8312         }
8313     }
8314 
8315     private void unsnoozeAll() {
8316         synchronized (mNotificationLock) {
8317             mSnoozeHelper.repostAll(mUserProfiles.getCurrentProfileIds());
8318             handleSavePolicyFile();
8319         }
8320     }
8321 
8322     protected class CancelNotificationRunnable implements Runnable {
8323         private final int mCallingUid;
8324         private final int mCallingPid;
8325         private final String mPkg;
8326         private final String mTag;
8327         private final int mId;
8328         private final int mMustHaveFlags;
8329         private final int mMustNotHaveFlags;
8330         private final boolean mSendDelete;
8331         private final int mUserId;
8332         private final int mReason;
8333         private final int mRank;
8334         private final int mCount;
8335         private final ManagedServiceInfo mListener;
8336         private final long mCancellationElapsedTimeMs;
8337 
8338         CancelNotificationRunnable(final int callingUid, final int callingPid,
8339                 final String pkg, final String tag, final int id,
8340                 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
8341                 final int userId, final int reason, int rank, int count,
8342                 final ManagedServiceInfo listener,
8343                 @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
8344             this.mCallingUid = callingUid;
8345             this.mCallingPid = callingPid;
8346             this.mPkg = pkg;
8347             this.mTag = tag;
8348             this.mId = id;
8349             this.mMustHaveFlags = mustHaveFlags;
8350             this.mMustNotHaveFlags = mustNotHaveFlags;
8351             this.mSendDelete = sendDelete;
8352             this.mUserId = userId;
8353             this.mReason = reason;
8354             this.mRank = rank;
8355             this.mCount = count;
8356             this.mListener = listener;
8357             this.mCancellationElapsedTimeMs = cancellationElapsedTimeMs;
8358         }
8359 
8360         @Override
8361         public void run() {
8362             String listenerName = mListener == null ? null : mListener.component.toShortString();
8363             if (DBG) {
8364                 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
8365                         mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
8366             }
8367             int packageImportance = IMPORTANCE_NONE;
8368             if (lifetimeExtensionRefactor()) {
8369                 packageImportance = getPackageImportanceWithIdentity(mPkg);
8370             }
8371             synchronized (mNotificationLock) {
8372                 // Look for the notification, searching both the posted and enqueued lists.
8373                 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
8374 
8375                 if (r != null) {
8376                     // The notification was found, check if it should be removed.
8377                     // Ideally we'd do this in the caller of this method. However, that would
8378                     // require the caller to also find the notification.
8379                     if (mReason == REASON_CLICK) {
8380                         mUsageStats.registerClickedByUser(r);
8381                     }
8382 
8383                     if ((mReason == REASON_LISTENER_CANCEL
8384                             && r.getNotification().isBubbleNotification())
8385                             || (mReason == REASON_CLICK && r.canBubble()
8386                             && r.isFlagBubbleRemoved())) {
8387                         int flags = 0;
8388                         if (r.getNotification().getBubbleMetadata() != null) {
8389                             flags = r.getNotification().getBubbleMetadata().getFlags();
8390                         }
8391                         flags |= FLAG_SUPPRESS_NOTIFICATION;
8392                         mNotificationDelegate.onBubbleMetadataFlagChanged(r.getKey(), flags);
8393                         return;
8394                     }
8395                     if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
8396                         return;
8397                     }
8398                     if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
8399                         if (lifetimeExtensionRefactor()) {
8400                             // If cancellation will be prevented due to lifetime extension,
8401                             // we need to send an update to system UI first.
8402                             maybeNotifySystemUiListenerLifetimeExtendedLocked(r, mPkg,
8403                                     packageImportance);
8404                         }
8405                         return;
8406                     }
8407 
8408                     FlagChecker childrenFlagChecker = (flags) -> {
8409                             if (mReason == REASON_CANCEL
8410                                     || mReason == REASON_CLICK
8411                                     || mReason == REASON_CANCEL_ALL) {
8412                                 // Bubbled children get to stick around if the summary was manually
8413                                 // cancelled (user removed) from systemui.
8414                                 if ((flags & FLAG_BUBBLE) != 0) {
8415                                     return false;
8416                                 }
8417                             } else if (mReason == REASON_APP_CANCEL) {
8418                                 if ((flags & FLAG_FOREGROUND_SERVICE) != 0
8419                                         || (flags & FLAG_USER_INITIATED_JOB) != 0) {
8420                                     return false;
8421                                 }
8422                             }
8423                             if ((flags & mMustNotHaveFlags) != 0) {
8424                                 return false;
8425                             }
8426                             return true;
8427                         };
8428 
8429                     // Cancel the notification.
8430                     boolean wasPosted = removeFromNotificationListsLocked(r);
8431                     cancelNotificationLocked(
8432                             r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName,
8433                             mCancellationElapsedTimeMs);
8434                     cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
8435                             mSendDelete, childrenFlagChecker, mReason,
8436                             mCancellationElapsedTimeMs);
8437                     mAttentionHelper.updateLightsLocked();
8438                     if (mShortcutHelper != null) {
8439                         mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
8440                                 true /* isRemoved */,
8441                                 mHandler);
8442                     }
8443                 } else {
8444                     // No notification was found, assume that it is snoozed and cancel it.
8445                     if (mReason != REASON_SNOOZED) {
8446                         final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
8447                         if (wasSnoozed) {
8448                             handleSavePolicyFile();
8449                         }
8450                     }
8451                 }
8452             }
8453         }
8454     }
8455 
8456     protected static class ShowNotificationPermissionPromptRunnable implements Runnable {
8457         private final String mPkgName;
8458         private final int mUserId;
8459         private final int mTaskId;
8460         private final PermissionPolicyInternal mPpi;
8461 
8462         ShowNotificationPermissionPromptRunnable(String pkg, int user, int task,
8463                 PermissionPolicyInternal pPi) {
8464             mPkgName = pkg;
8465             mUserId = user;
8466             mTaskId = task;
8467             mPpi = pPi;
8468         }
8469 
8470         @Override
8471         public boolean equals(Object o) {
8472             if (!(o instanceof ShowNotificationPermissionPromptRunnable)) {
8473                 return false;
8474             }
8475 
8476             ShowNotificationPermissionPromptRunnable other =
8477                     (ShowNotificationPermissionPromptRunnable) o;
8478 
8479             return Objects.equals(mPkgName, other.mPkgName) && mUserId == other.mUserId
8480                     && mTaskId == other.mTaskId;
8481         }
8482 
8483         @Override
8484         public int hashCode() {
8485             return Objects.hash(mPkgName, mUserId, mTaskId);
8486         }
8487 
8488         @Override
8489         public void run() {
8490             mPpi.showNotificationPromptIfNeeded(mPkgName, mUserId, mTaskId);
8491         }
8492     }
8493 
8494     protected class EnqueueNotificationRunnable implements Runnable {
8495         private final NotificationRecord r;
8496         private final int userId;
8497         private final boolean isAppForeground;
8498         private final PostNotificationTracker mTracker;
8499 
8500         EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground,
8501                 PostNotificationTracker tracker) {
8502             this.userId = userId;
8503             this.r = r;
8504             this.isAppForeground = foreground;
8505             this.mTracker = checkNotNull(tracker);
8506         }
8507 
8508         @Override
8509         public void run() {
8510             boolean enqueued = false;
8511             try {
8512                 enqueued = enqueueNotification();
8513             } finally {
8514                 if (!enqueued) {
8515                     mTracker.cancel();
8516                 }
8517             }
8518         }
8519 
8520         /**
8521          * @return True if we successfully enqueued the notification and handed off the task of
8522          * posting it to a background thread; false otherwise.
8523          */
8524         private boolean enqueueNotification() {
8525             synchronized (mNotificationLock) {
8526                 final long snoozeAt =
8527                         mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
8528                                 r.getUser().getIdentifier(),
8529                                 r.getSbn().getPackageName(), r.getSbn().getKey());
8530                 final long currentTime = System.currentTimeMillis();
8531                 if (snoozeAt > currentTime) {
8532                     (new SnoozeNotificationRunnable(r.getSbn().getKey(),
8533                             snoozeAt - currentTime, null)).snoozeLocked(r);
8534                     return false;
8535                 }
8536 
8537                 final String contextId =
8538                         mSnoozeHelper.getSnoozeContextForUnpostedNotification(
8539                                 r.getUser().getIdentifier(),
8540                                 r.getSbn().getPackageName(), r.getSbn().getKey());
8541                 if (contextId != null) {
8542                     (new SnoozeNotificationRunnable(r.getSbn().getKey(),
8543                             0, contextId)).snoozeLocked(r);
8544                     return false;
8545                 }
8546 
8547                 mEnqueuedNotifications.add(r);
8548                 if (Flags.allNotifsNeedTtl()) {
8549                     mTtlHelper.scheduleTimeoutLocked(r, SystemClock.elapsedRealtime());
8550                 } else {
8551                     scheduleTimeoutLocked(r);
8552                 }
8553 
8554                 final StatusBarNotification n = r.getSbn();
8555                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
8556                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
8557                 if (old != null) {
8558                     // Retain ranking information from previous record
8559                     r.copyRankingInformation(old);
8560                 }
8561 
8562                 final int callingUid = n.getUid();
8563                 final int callingPid = n.getInitialPid();
8564                 final Notification notification = n.getNotification();
8565                 final String pkg = n.getPackageName();
8566                 final int id = n.getId();
8567                 final String tag = n.getTag();
8568 
8569                 // We need to fix the notification up a little for bubbles
8570                 updateNotificationBubbleFlags(r, isAppForeground);
8571 
8572                 // Handle grouped notifications and bail out early if we
8573                 // can to avoid extracting signals.
8574                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
8575 
8576                 // if this is a group child, unsnooze parent summary
8577                 if (n.isGroup() && notification.isGroupChild()) {
8578                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
8579                 }
8580 
8581                 // This conditional is a dirty hack to limit the logging done on
8582                 //     behalf of the download manager without affecting other apps.
8583                 if (!pkg.equals("com.android.providers.downloads")
8584                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
8585                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
8586                     if (old != null) {
8587                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
8588                     }
8589                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
8590                             pkg, id, tag, userId, notification.toString(),
8591                             enqueueStatus);
8592                 }
8593 
8594                 // tell the assistant service about the notification
8595                 if (mAssistants.isEnabled()) {
8596                     mAssistants.onNotificationEnqueuedLocked(r);
8597                     mHandler.postDelayed(
8598                             new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
8599                                     r.getUid(), mTracker),
8600                             DELAY_FOR_ASSISTANT_TIME);
8601                 } else {
8602                     mHandler.post(
8603                             new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
8604                                     r.getUid(), mTracker));
8605                 }
8606                 return true;
8607             }
8608         }
8609     }
8610 
8611     @GuardedBy("mNotificationLock")
8612     boolean isPackagePausedOrSuspended(String pkg, int uid) {
8613         boolean isPaused;
8614 
8615         final PackageManagerInternal pmi = LocalServices.getService(
8616                 PackageManagerInternal.class);
8617         int flags = pmi.getDistractingPackageRestrictions(
8618                 pkg, Binder.getCallingUserHandle().getIdentifier());
8619         isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
8620 
8621         isPaused |= isPackageSuspendedForUser(pkg, uid);
8622 
8623         return isPaused;
8624     }
8625 
8626     protected class PostNotificationRunnable implements Runnable {
8627         private final String key;
8628         private final String pkg;
8629         private final int uid;
8630         private final PostNotificationTracker mTracker;
8631 
8632         PostNotificationRunnable(String key, String pkg, int uid, PostNotificationTracker tracker) {
8633             this.key = key;
8634             this.pkg = pkg;
8635             this.uid = uid;
8636             this.mTracker = checkNotNull(tracker);
8637         }
8638 
8639         @Override
8640         public void run() {
8641             boolean posted = false;
8642             try {
8643                 posted = postNotification();
8644             }  catch (Exception e) {
8645                 Slog.e(TAG, "Error posting", e);
8646             } finally {
8647                 if (!posted) {
8648                     mTracker.cancel();
8649                 }
8650             }
8651         }
8652 
8653         /**
8654          * @return True if we successfully processed the notification and handed off the task of
8655          * notifying all listeners to a background thread; false otherwise.
8656          */
8657         private boolean postNotification() {
8658             boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
8659             boolean isCallNotification = isCallNotification(pkg, uid);
8660             boolean posted = false;
8661             synchronized (mNotificationLock) {
8662                 try {
8663                     NotificationRecord r = findNotificationByListLocked(mEnqueuedNotifications,
8664                             key);
8665                     if (r == null) {
8666                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
8667                         return false;
8668                     }
8669 
8670                     final StatusBarNotification n = r.getSbn();
8671                     final Notification notification = n.getNotification();
8672                     boolean isCallNotificationAndCorrectStyle = isCallNotification
8673                             && notification.isStyle(Notification.CallStyle.class);
8674 
8675                     if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle)
8676                             && (appBanned || isRecordBlockedLocked(r))) {
8677                         mUsageStats.registerBlocked(r);
8678                         if (DBG) {
8679                             Slog.e(TAG, "Suppressing notification from package " + pkg);
8680                         }
8681                         return false;
8682                     }
8683 
8684                     final boolean isPackageSuspended =
8685                             isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid());
8686                     r.setHidden(isPackageSuspended);
8687                     if (isPackageSuspended) {
8688                         mUsageStats.registerSuspendedByAdmin(r);
8689                     }
8690                     NotificationRecord old = mNotificationsByKey.get(key);
8691 
8692                     // Make sure the SBN has an instance ID for statsd logging.
8693                     if (old == null || old.getSbn().getInstanceId() == null) {
8694                         n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
8695                     } else {
8696                         n.setInstanceId(old.getSbn().getInstanceId());
8697                     }
8698 
8699                     int index = indexOfNotificationLocked(n.getKey());
8700                     if (index < 0) {
8701                         mNotificationList.add(r);
8702                         mUsageStats.registerPostedByApp(r);
8703                         mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(),
8704                                 r.getSbn().getUser(), mTracker.getStartTime());
8705                         final boolean isInterruptive = isVisuallyInterruptive(null, r);
8706                         r.setInterruptive(isInterruptive);
8707                         r.setTextChanged(isInterruptive);
8708                     } else {
8709                         old = mNotificationList.get(index);  // Potentially *changes* old
8710                         mNotificationList.set(index, r);
8711                         mUsageStats.registerUpdatedByApp(r, old);
8712                         mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(),
8713                                 r.getSbn().getUser(), mTracker.getStartTime());
8714                         // Make sure we don't lose the foreground service state.
8715                         notification.flags |=
8716                                 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
8717                         r.isUpdate = true;
8718                         final boolean isInterruptive = isVisuallyInterruptive(old, r);
8719                         r.setTextChanged(isInterruptive);
8720                         if (sortSectionByTime()) {
8721                             if (isInterruptive) {
8722                                 r.resetRankingTime();
8723                             }
8724                         }
8725                     }
8726 
8727                     mNotificationsByKey.put(n.getKey(), r);
8728 
8729                     // Ensure if this is a foreground service that the proper additional
8730                     // flags are set.
8731                     if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
8732                         notification.flags |= FLAG_NO_CLEAR;
8733                     }
8734 
8735                     // Posts the notification if it has a small icon, and potentially autogroup
8736                     // the new notification.
8737                     if (android.app.Flags.checkAutogroupBeforePost()) {
8738                         if (notification.getSmallIcon() != null && !isCritical(r)) {
8739                             StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
8740                             if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())
8741                                     || oldSbn.getNotification().flags
8742                                     != n.getNotification().flags) {
8743                                 synchronized (mNotificationLock) {
8744                                     boolean willBeAutogrouped = mGroupHelper.onNotificationPosted(n,
8745                                             hasAutoGroupSummaryLocked(n));
8746                                     if (willBeAutogrouped) {
8747                                         // The newly posted notification will be autogrouped, but
8748                                         // was not autogrouped onPost, to avoid an unnecessary sort.
8749                                         // We add the autogroup key to the notification without a
8750                                         // sort here, and it'll be sorted below with extractSignals.
8751                                         addAutogroupKeyLocked(key, /*requestSort=*/false);
8752                                     }
8753                                 }
8754                             }
8755                         }
8756                     }
8757 
8758                     mRankingHelper.extractSignals(r);
8759                     mRankingHelper.sort(mNotificationList);
8760                     final int position = mRankingHelper.indexOf(mNotificationList, r);
8761 
8762                     int buzzBeepBlinkLoggingCode = 0;
8763                     if (!r.isHidden()) {
8764                         buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
8765                                 new NotificationAttentionHelper.Signals(
8766                                         mUserProfiles.isCurrentProfile(r.getUserId()),
8767                                         mListenerHints));
8768                     }
8769 
8770                     if (notification.getSmallIcon() != null) {
8771                         NotificationRecordLogger.NotificationReported maybeReport =
8772                                 mNotificationRecordLogger.prepareToLogNotificationPosted(r, old,
8773                                         position, buzzBeepBlinkLoggingCode,
8774                                         getGroupInstanceId(r.getSbn().getGroupKey()));
8775                         notifyListenersPostedAndLogLocked(r, old, mTracker, maybeReport);
8776                         posted = true;
8777 
8778                         if (!android.app.Flags.checkAutogroupBeforePost()) {
8779                             StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
8780                             if (oldSbn == null
8781                                     || !Objects.equals(oldSbn.getGroup(), n.getGroup())
8782                                     || oldSbn.getNotification().flags
8783                                         != n.getNotification().flags) {
8784                                 if (!isCritical(r)) {
8785                                     mHandler.post(() -> {
8786                                         synchronized (mNotificationLock) {
8787                                             mGroupHelper.onNotificationPosted(
8788                                                     n, hasAutoGroupSummaryLocked(n));
8789                                         }
8790                                     });
8791                                 }
8792                             }
8793                         }
8794                     } else {
8795                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
8796                         if (old != null && !old.isCanceled) {
8797                             mListeners.notifyRemovedLocked(r,
8798                                     REASON_ERROR, r.getStats());
8799                             mHandler.post(new Runnable() {
8800                                 @Override
8801                                 public void run() {
8802                                     mGroupHelper.onNotificationRemoved(n);
8803                                 }
8804                             });
8805                         }
8806 
8807                         if (callstyleCallbackApi()) {
8808                             notifyCallNotificationEventListenerOnRemoved(r);
8809                         }
8810 
8811                         // ATTENTION: in a future release we will bail out here
8812                         // so that we do not play sounds, show lights, etc. for invalid
8813                         // notifications
8814                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
8815                                 + n.getPackageName());
8816                     }
8817 
8818                     if (mShortcutHelper != null) {
8819                         mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
8820                                 false /* isRemoved */,
8821                                 mHandler);
8822                     }
8823 
8824                     maybeRecordInterruptionLocked(r);
8825                     maybeRegisterMessageSent(r);
8826                     maybeReportForegroundServiceUpdate(r, true);
8827                 } finally {
8828                     int N = mEnqueuedNotifications.size();
8829                     for (int i = 0; i < N; i++) {
8830                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
8831                         if (Objects.equals(key, enqueued.getKey())) {
8832                             mEnqueuedNotifications.remove(i);
8833                             break;
8834                         }
8835                     }
8836                 }
8837             }
8838             return posted;
8839         }
8840     }
8841 
8842     /**
8843      *
8844      */
8845     @GuardedBy("mNotificationLock")
8846     InstanceId getGroupInstanceId(String groupKey) {
8847         if (groupKey == null) {
8848             return null;
8849         }
8850         NotificationRecord group = mSummaryByGroupKey.get(groupKey);
8851         if (group == null) {
8852             return null;
8853         }
8854         return group.getSbn().getInstanceId();
8855     }
8856 
8857     /**
8858      * If the notification differs enough visually, consider it a new interruptive notification.
8859      */
8860     @GuardedBy("mNotificationLock")
8861     @VisibleForTesting
8862     protected boolean isVisuallyInterruptive(@Nullable NotificationRecord old,
8863             @NonNull NotificationRecord r) {
8864         // Ignore summary updates because we don't display most of the information.
8865         if (r.getSbn().isGroup() && r.getSbn().getNotification().isGroupSummary()) {
8866             if (DEBUG_INTERRUPTIVENESS) {
8867                 Slog.v(TAG, "INTERRUPTIVENESS: "
8868                         +  r.getKey() + " is not interruptive: summary");
8869             }
8870             return false;
8871         }
8872 
8873         if (old == null) {
8874             if (DEBUG_INTERRUPTIVENESS) {
8875                 Slog.v(TAG, "INTERRUPTIVENESS: "
8876                         +  r.getKey() + " is interruptive: new notification");
8877             }
8878             return true;
8879         }
8880 
8881         Notification oldN = old.getSbn().getNotification();
8882         Notification newN = r.getSbn().getNotification();
8883         if (oldN.extras == null || newN.extras == null) {
8884             if (DEBUG_INTERRUPTIVENESS) {
8885                 Slog.v(TAG, "INTERRUPTIVENESS: "
8886                         +  r.getKey() + " is not interruptive: no extras");
8887             }
8888             return false;
8889         }
8890 
8891         if (sortSectionByTime()) {
8892             // Ignore visual interruptions from FGS/UIJs because users
8893             // consider them one 'session'. Count them for everything else.
8894             if (r.getSbn().getNotification().isFgsOrUij()) {
8895                 if (DEBUG_INTERRUPTIVENESS) {
8896                     Slog.v(TAG, "INTERRUPTIVENESS: "
8897                             + r.getKey() + " is not interruptive: FGS/UIJ");
8898                 }
8899                 return false;
8900             }
8901         } else {
8902             // Ignore visual interruptions from foreground services because users
8903             // consider them one 'session'. Count them for everything else.
8904             if ((r.getSbn().getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
8905                 if (DEBUG_INTERRUPTIVENESS) {
8906                     Slog.v(TAG, "INTERRUPTIVENESS: "
8907                             + r.getKey() + " is not interruptive: foreground service");
8908                 }
8909                 return false;
8910             }
8911         }
8912 
8913         final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
8914         final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
8915         if (!Objects.equals(oldTitle, newTitle)) {
8916             if (DEBUG_INTERRUPTIVENESS) {
8917                 Slog.v(TAG, "INTERRUPTIVENESS: "
8918                         +  r.getKey() + " is interruptive: changed title");
8919                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old title: %s (%s@0x%08x)",
8920                         oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
8921                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new title: %s (%s@0x%08x)",
8922                         newTitle, newTitle.getClass(), newTitle.hashCode()));
8923             }
8924             return true;
8925         }
8926 
8927         // Do not compare Spannables (will always return false); compare unstyled Strings
8928         final String oldText = String.valueOf(oldN.extras.get(EXTRA_TEXT));
8929         final String newText = String.valueOf(newN.extras.get(EXTRA_TEXT));
8930         if (!Objects.equals(oldText, newText)) {
8931             if (DEBUG_INTERRUPTIVENESS) {
8932                 Slog.v(TAG, "INTERRUPTIVENESS: "
8933                         + r.getKey() + " is interruptive: changed text");
8934                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old text: %s (%s@0x%08x)",
8935                         oldText, oldText.getClass(), oldText.hashCode()));
8936                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new text: %s (%s@0x%08x)",
8937                         newText, newText.getClass(), newText.hashCode()));
8938             }
8939             return true;
8940         }
8941 
8942         if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
8943             if (DEBUG_INTERRUPTIVENESS) {
8944                 Slog.v(TAG, "INTERRUPTIVENESS: "
8945                     +  r.getKey() + " is interruptive: completed progress");
8946             }
8947             return true;
8948         }
8949 
8950         if (Notification.areIconsDifferent(oldN, newN)) {
8951             if (DEBUG_INTERRUPTIVENESS) {
8952                 Slog.v(TAG, "INTERRUPTIVENESS: "
8953                         +  r.getKey() + " is interruptive: icons differ");
8954             }
8955             return true;
8956         }
8957 
8958         // Fields below are invisible to bubbles.
8959         if (r.canBubble()) {
8960             if (DEBUG_INTERRUPTIVENESS) {
8961                 Slog.v(TAG, "INTERRUPTIVENESS: "
8962                         +  r.getKey() + " is not interruptive: bubble");
8963             }
8964             return false;
8965         }
8966 
8967         // Actions
8968         if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
8969             if (DEBUG_INTERRUPTIVENESS) {
8970                 Slog.v(TAG, "INTERRUPTIVENESS: "
8971                         +  r.getKey() + " is interruptive: changed actions");
8972             }
8973             return true;
8974         }
8975 
8976         try {
8977             Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
8978             Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
8979 
8980             // Style based comparisons
8981             if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
8982                 if (DEBUG_INTERRUPTIVENESS) {
8983                     Slog.v(TAG, "INTERRUPTIVENESS: "
8984                             +  r.getKey() + " is interruptive: styles differ");
8985                 }
8986                 return true;
8987             }
8988 
8989             // Remote views
8990             if (Notification.areRemoteViewsChanged(oldB, newB)) {
8991                 if (DEBUG_INTERRUPTIVENESS) {
8992                     Slog.v(TAG, "INTERRUPTIVENESS: "
8993                             +  r.getKey() + " is interruptive: remoteviews differ");
8994                 }
8995                 return true;
8996             }
8997         } catch (Exception e) {
8998             Slog.w(TAG, "error recovering builder", e);
8999         }
9000         return false;
9001     }
9002 
9003     /**
9004      * Check if the notification is classified as critical.
9005      *
9006      * @param record the record to test for criticality
9007      * @return {@code true} if notification is considered critical
9008      *
9009      * @see CriticalNotificationExtractor for criteria
9010      */
9011     private boolean isCritical(NotificationRecord record) {
9012         // 0 is the most critical
9013         return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
9014     }
9015 
9016     /**
9017      * Ensures that grouped notification receive their special treatment.
9018      *
9019      * <p>Cancels group children if the new notification causes a group to lose
9020      * its summary.</p>
9021      *
9022      * <p>Updates mSummaryByGroupKey.</p>
9023      */
9024     @GuardedBy("mNotificationLock")
9025     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
9026             int callingUid, int callingPid) {
9027         StatusBarNotification sbn = r.getSbn();
9028         Notification n = sbn.getNotification();
9029         if (n.isGroupSummary() && !sbn.isAppGroup())  {
9030             // notifications without a group shouldn't be a summary, otherwise autobundling can
9031             // lead to bugs
9032             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
9033         }
9034 
9035         String group = sbn.getGroupKey();
9036         boolean isSummary = n.isGroupSummary();
9037 
9038         Notification oldN = old != null ? old.getSbn().getNotification() : null;
9039         String oldGroup = old != null ? old.getSbn().getGroupKey() : null;
9040         boolean oldIsSummary = old != null && oldN.isGroupSummary();
9041 
9042         if (oldIsSummary) {
9043             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
9044             if (removedSummary != old) {
9045                 String removedKey =
9046                         removedSummary != null ? removedSummary.getKey() : "<null>";
9047                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
9048                         ", removed=" + removedKey);
9049             }
9050         }
9051         if (isSummary) {
9052             mSummaryByGroupKey.put(group, r);
9053         }
9054 
9055         FlagChecker childrenFlagChecker = (flags) -> {
9056             if ((flags & FLAG_FOREGROUND_SERVICE) != 0 || (flags & FLAG_USER_INITIATED_JOB) != 0) {
9057                 return false;
9058             }
9059             return true;
9060         };
9061 
9062         // Clear out group children of the old notification if the update
9063         // causes the group summary to go away. This happens when the old
9064         // notification was a summary and the new one isn't, or when the old
9065         // notification was a summary and its group key changed.
9066         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
9067             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
9068                     childrenFlagChecker, REASON_APP_CANCEL, SystemClock.elapsedRealtime());
9069         }
9070     }
9071 
9072     private PendingIntent getNotificationTimeoutPendingIntent(NotificationRecord record,
9073             int flags) {
9074         flags |= PendingIntent.FLAG_IMMUTABLE;
9075         return PendingIntent.getBroadcast(getContext(),
9076                 REQUEST_CODE_TIMEOUT,
9077                 new Intent(ACTION_NOTIFICATION_TIMEOUT)
9078                         .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
9079                         .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
9080                                 .appendPath(record.getKey()).build())
9081                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
9082                         .putExtra(EXTRA_KEY, record.getKey()),
9083                 flags);
9084     }
9085 
9086     @VisibleForTesting
9087     @GuardedBy("mNotificationLock")
9088     void scheduleTimeoutLocked(NotificationRecord record) {
9089         if (record.getNotification().getTimeoutAfter() > 0) {
9090             final PendingIntent pi = getNotificationTimeoutPendingIntent(
9091                     record, PendingIntent.FLAG_UPDATE_CURRENT);
9092             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
9093                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
9094         }
9095     }
9096 
9097     @VisibleForTesting
9098     @GuardedBy("mNotificationLock")
9099     void cancelScheduledTimeoutLocked(NotificationRecord record) {
9100         final PendingIntent pi = getNotificationTimeoutPendingIntent(
9101                 record, PendingIntent.FLAG_CANCEL_CURRENT);
9102         if (pi != null) {
9103             mAlarmManager.cancel(pi);
9104         }
9105     }
9106 
9107     @GuardedBy("mToastQueue")
9108     void showNextToastLocked(boolean lastToastWasTextRecord) {
9109         if (mIsCurrentToastShown) {
9110             return; // Don't show the same toast twice.
9111         }
9112 
9113         ToastRecord record = mToastQueue.get(0);
9114         while (record != null) {
9115             int userId = UserHandle.getUserId(record.uid);
9116             boolean rateLimitingEnabled =
9117                     !mToastRateLimitingDisabledUids.contains(record.uid);
9118             boolean isWithinQuota =
9119                     mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG)
9120                             || isExemptFromRateLimiting(record.pkg, userId);
9121             boolean isPackageInForeground = isPackageInForegroundForToast(record.uid);
9122 
9123             if (tryShowToast(
9124                     record, rateLimitingEnabled, isWithinQuota, isPackageInForeground)) {
9125                 scheduleDurationReachedLocked(record, lastToastWasTextRecord);
9126                 mIsCurrentToastShown = true;
9127                 if (rateLimitingEnabled && !isPackageInForeground) {
9128                     mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG);
9129                 }
9130                 return;
9131             }
9132 
9133             int index = mToastQueue.indexOf(record);
9134             if (index >= 0) {
9135                 ToastRecord toast = mToastQueue.remove(index);
9136                 mWindowManagerInternal.removeWindowToken(
9137                         toast.windowToken, true /* removeWindows */, toast.displayId);
9138             }
9139             record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null;
9140         }
9141     }
9142 
9143     /** Returns true if it successfully showed the toast. */
9144     private boolean tryShowToast(ToastRecord record, boolean rateLimitingEnabled,
9145             boolean isWithinQuota, boolean isPackageInForeground) {
9146         if (rateLimitingEnabled && !isWithinQuota && !isPackageInForeground) {
9147             reportCompatRateLimitingToastsChange(record.uid);
9148             Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the "
9149                     + "following toast was blocked and discarded: " + record);
9150             return false;
9151         }
9152         if (blockToast(record.uid, record.isSystemToast, record.isAppRendered(),
9153                 isPackageInForeground)) {
9154             Slog.w(TAG, "Blocking custom toast from package " + record.pkg
9155                     + " due to package not in the foreground at the time of showing the toast");
9156             return false;
9157         }
9158         return record.show();
9159     }
9160 
9161     private boolean isExemptFromRateLimiting(String pkg, int userId) {
9162         boolean isExemptFromRateLimiting = false;
9163         try {
9164             isExemptFromRateLimiting = mPackageManager.checkPermission(
9165                     android.Manifest.permission.UNLIMITED_TOASTS, pkg, userId)
9166                     == PERMISSION_GRANTED;
9167         } catch (RemoteException e) {
9168             Slog.e(TAG, "Failed to connect with package manager");
9169         }
9170         return isExemptFromRateLimiting;
9171     }
9172 
9173     /** Reports rate limiting toasts compat change (used when the toast was blocked). */
9174     private void reportCompatRateLimitingToastsChange(int uid) {
9175         final long id = Binder.clearCallingIdentity();
9176         try {
9177             mPlatformCompat.reportChangeByUid(RATE_LIMIT_TOASTS, uid);
9178         } catch (RemoteException e) {
9179             Slog.e(TAG, "Unexpected exception while reporting toast was blocked due to rate"
9180                     + " limiting", e);
9181         } finally {
9182             Binder.restoreCallingIdentity(id);
9183         }
9184     }
9185 
9186     @GuardedBy("mToastQueue")
9187     void cancelToastLocked(int index) {
9188         ToastRecord record = mToastQueue.get(index);
9189         record.hide();
9190 
9191         if (index == 0) {
9192             mIsCurrentToastShown = false;
9193         }
9194 
9195         ToastRecord lastToast = mToastQueue.remove(index);
9196 
9197         // We need to schedule a timeout to make sure the token is eventually killed
9198         scheduleKillTokenTimeout(lastToast);
9199 
9200         keepProcessAliveForToastIfNeededLocked(record.pid);
9201         if (mToastQueue.size() > 0) {
9202             // Show the next one. If the callback fails, this will remove
9203             // it from the list, so don't assume that the list hasn't changed
9204             // after this point.
9205             showNextToastLocked(lastToast instanceof TextToastRecord);
9206         }
9207     }
9208 
9209     void finishWindowTokenLocked(IBinder t, int displayId) {
9210         mHandler.removeCallbacksAndMessages(t);
9211         // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
9212         // remaining surfaces as either the client has called finishToken indicating
9213         // it has successfully removed the views, or the client has timed out
9214         // at which point anything goes.
9215         mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
9216     }
9217 
9218     @GuardedBy("mToastQueue")
9219     private void scheduleDurationReachedLocked(ToastRecord r, boolean lastToastWasTextRecord)
9220     {
9221         mHandler.removeCallbacksAndMessages(r);
9222         Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
9223         int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
9224         // Accessibility users may need longer timeout duration. This api compares original delay
9225         // with user's preference and return longer one. It returns original delay if there's no
9226         // preference.
9227         delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
9228                 AccessibilityManager.FLAG_CONTENT_TEXT);
9229 
9230         if (lastToastWasTextRecord) {
9231             delay += 250; // delay to account for previous toast's "out" animation
9232         }
9233         if (r instanceof TextToastRecord) {
9234             delay += 333; // delay to account for this toast's "in" animation
9235         }
9236 
9237         mHandler.sendMessageDelayed(m, delay);
9238     }
9239 
9240     private void handleDurationReached(ToastRecord record)
9241     {
9242         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " token=" + record.token);
9243         synchronized (mToastQueue) {
9244             int index = indexOfToastLocked(record.pkg, record.token);
9245             if (index >= 0) {
9246                 cancelToastLocked(index);
9247             }
9248         }
9249     }
9250 
9251     @GuardedBy("mToastQueue")
9252     private void scheduleKillTokenTimeout(ToastRecord r)
9253     {
9254         mHandler.removeCallbacksAndMessages(r);
9255         Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
9256         mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
9257     }
9258 
9259     private void handleKillTokenTimeout(ToastRecord record)
9260     {
9261         if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.windowToken);
9262         synchronized (mToastQueue) {
9263             finishWindowTokenLocked(record.windowToken, record.displayId);
9264         }
9265     }
9266 
9267     @GuardedBy("mToastQueue")
9268     int indexOfToastLocked(String pkg, IBinder token) {
9269         ArrayList<ToastRecord> list = mToastQueue;
9270         int len = list.size();
9271         for (int i=0; i<len; i++) {
9272             ToastRecord r = list.get(i);
9273             if (r.pkg.equals(pkg) && r.token == token) {
9274                 return i;
9275             }
9276         }
9277         return -1;
9278     }
9279 
9280     /**
9281      * Adjust process {@code pid} importance according to whether it has toasts in the queue or not.
9282      */
9283     public void keepProcessAliveForToastIfNeeded(int pid) {
9284         synchronized (mToastQueue) {
9285             keepProcessAliveForToastIfNeededLocked(pid);
9286         }
9287     }
9288 
9289     @GuardedBy("mToastQueue")
9290     private void keepProcessAliveForToastIfNeededLocked(int pid) {
9291         int toastCount = 0; // toasts from this pid, rendered by the app
9292         ArrayList<ToastRecord> list = mToastQueue;
9293         int n = list.size();
9294         for (int i = 0; i < n; i++) {
9295             ToastRecord r = list.get(i);
9296             if (r.pid == pid && r.keepProcessAlive()) {
9297                 toastCount++;
9298             }
9299         }
9300         try {
9301             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
9302         } catch (RemoteException e) {
9303             // Shouldn't happen.
9304         }
9305     }
9306 
9307     /**
9308      * Implementation note: Our definition of foreground for toasts is an implementation matter
9309      * and should strike a balance between functionality and anti-abuse effectiveness. We
9310      * currently worry about the following cases:
9311      * <ol>
9312      *     <li>App with fullscreen activity: Allow toasts
9313      *     <li>App behind translucent activity from other app: Block toasts
9314      *     <li>App in multi-window: Allow toasts
9315      *     <li>App with expanded bubble: Allow toasts
9316      *     <li>App posting toasts on onCreate(), onStart(), onResume(): Allow toasts
9317      *     <li>App posting toasts on onPause(), onStop(), onDestroy(): Block toasts
9318      * </ol>
9319      * Checking if the UID has any resumed activities satisfy use-cases above.
9320      *
9321      * <p>Checking if {@code mActivityManager.getUidImportance(callingUid) ==
9322      * IMPORTANCE_FOREGROUND} does not work because it considers the app in foreground if it has
9323      * any visible activities, failing case 2 in list above.
9324      */
9325     private boolean isPackageInForegroundForToast(int callingUid) {
9326         return mAtm.hasResumedActivity(callingUid);
9327     }
9328 
9329     /**
9330      * True if the toast should be blocked. It will return true if all of the following conditions
9331      * apply: it's a custom toast, it's not a system toast, the package that sent the toast is in
9332      * the background and CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is enabled.
9333      *
9334      * CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so it will return false for apps
9335      * with targetSdk < R. For apps with targetSdk R+, text toasts are not app-rendered, so
9336      * isAppRenderedToast == true means it's a custom toast.
9337      */
9338     private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast,
9339             boolean isPackageInForeground) {
9340         return isAppRenderedToast
9341                 && !isSystemToast
9342                 && !isPackageInForeground
9343                 && CompatChanges.isChangeEnabled(CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, uid);
9344     }
9345 
9346     private void handleRankingReconsideration(Message message) {
9347         if (!(message.obj instanceof RankingReconsideration)) return;
9348         RankingReconsideration recon = (RankingReconsideration) message.obj;
9349         recon.run();
9350         boolean changed;
9351         synchronized (mNotificationLock) {
9352             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
9353             if (record == null) {
9354                 return;
9355             }
9356             int indexBefore = findNotificationRecordIndexLocked(record);
9357             boolean interceptBefore = record.isIntercepted();
9358             int visibilityBefore = record.getPackageVisibilityOverride();
9359             boolean interruptiveBefore = record.isInterruptive();
9360 
9361             recon.applyChangesLocked(record);
9362             applyZenModeLocked(record);
9363             mRankingHelper.sort(mNotificationList);
9364             boolean indexChanged = indexBefore != findNotificationRecordIndexLocked(record);
9365             boolean interceptChanged = interceptBefore != record.isIntercepted();
9366             boolean visibilityChanged = visibilityBefore != record.getPackageVisibilityOverride();
9367 
9368             // Broadcast isInterruptive changes for bubbles.
9369             boolean interruptiveChanged =
9370                     record.canBubble() && (interruptiveBefore != record.isInterruptive());
9371 
9372             changed = indexChanged
9373                     || interceptChanged
9374                     || visibilityChanged
9375                     || interruptiveChanged;
9376             if (interceptBefore && !record.isIntercepted()
9377                     && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
9378 
9379                 mAttentionHelper.buzzBeepBlinkLocked(record,
9380                         new NotificationAttentionHelper.Signals(mUserProfiles.isCurrentProfile(
9381                                 record.getUserId()), mListenerHints));
9382 
9383                 // Log alert after change in intercepted state to Zen Log as well
9384                 ZenLog.traceAlertOnUpdatedIntercept(record);
9385             }
9386         }
9387         if (changed) {
9388             mHandler.scheduleSendRankingUpdate();
9389         }
9390     }
9391 
9392     void handleRankingSort() {
9393         if (mRankingHelper == null) return;
9394         synchronized (mNotificationLock) {
9395             final int N = mNotificationList.size();
9396             // Any field that can change via one of the extractors needs to be added here.
9397             ArrayMap<String, NotificationRecordExtractorData> extractorDataBefore =
9398                     new ArrayMap<>(N);
9399             for (int i = 0; i < N; i++) {
9400                 final NotificationRecord r = mNotificationList.get(i);
9401                 NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData(
9402                         i,
9403                         r.getPackageVisibilityOverride(),
9404                         r.canShowBadge(),
9405                         r.canBubble(),
9406                         r.getNotification().isBubbleNotification(),
9407                         r.getChannel(),
9408                         r.getGroupKey(),
9409                         r.getPeopleOverride(),
9410                         r.getSnoozeCriteria(),
9411                         r.getUserSentiment(),
9412                         r.getSuppressedVisualEffects(),
9413                         r.getSystemGeneratedSmartActions(),
9414                         r.getSmartReplies(),
9415                         r.getImportance(),
9416                         r.getRankingScore(),
9417                         r.isConversation(),
9418                         r.getProposedImportance(),
9419                         r.hasSensitiveContent());
9420                 extractorDataBefore.put(r.getKey(), extractorData);
9421                 mRankingHelper.extractSignals(r);
9422             }
9423             mRankingHelper.sort(mNotificationList);
9424             for (int i = 0; i < N; i++) {
9425                 final NotificationRecord r = mNotificationList.get(i);
9426                 if (!extractorDataBefore.containsKey(r.getKey())) {
9427                     // This shouldn't happen given that we just built this with all the
9428                     // notifications, but check just to be safe.
9429                     continue;
9430                 }
9431                 if (extractorDataBefore.get(r.getKey()).hasDiffForRankingLocked(r, i)) {
9432                     mHandler.scheduleSendRankingUpdate();
9433                 }
9434 
9435                 // If this notification is one for which we wanted to log an update, and
9436                 // sufficient relevant bits are different, log update.
9437                 if (r.hasPendingLogUpdate()) {
9438                     // We need to acquire the previous data associated with this specific
9439                     // notification, as the one at the current index may be unrelated if
9440                     // notification order has changed.
9441                     NotificationRecordExtractorData prevData = extractorDataBefore.get(r.getKey());
9442                     if (prevData.hasDiffForLoggingLocked(r, i)) {
9443                         mNotificationRecordLogger.logNotificationAdjusted(r, i, 0,
9444                                 getGroupInstanceId(r.getSbn().getGroupKey()));
9445                     }
9446 
9447                     // Remove whether there was a diff or not; we've sorted the key, so if it
9448                     // turns out there was nothing to log, that's fine too.
9449                     r.setPendingLogUpdate(false);
9450                 }
9451             }
9452         }
9453     }
9454 
9455     @GuardedBy("mNotificationLock")
9456     private void recordCallerLocked(NotificationRecord record) {
9457         if (mZenModeHelper.isCall(record)) {
9458             mZenModeHelper.recordCaller(record);
9459         }
9460     }
9461 
9462     // let zen mode evaluate this record
9463     @GuardedBy("mNotificationLock")
9464     private void applyZenModeLocked(NotificationRecord record) {
9465         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
9466         if (record.isIntercepted()) {
9467             record.setSuppressedVisualEffects(
9468                     mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
9469         } else {
9470             record.setSuppressedVisualEffects(0);
9471         }
9472     }
9473 
9474     @GuardedBy("mNotificationLock")
9475     private int findNotificationRecordIndexLocked(NotificationRecord target) {
9476         return mRankingHelper.indexOf(mNotificationList, target);
9477     }
9478 
9479     private void handleSendRankingUpdate() {
9480         synchronized (mNotificationLock) {
9481             mListeners.notifyRankingUpdateLocked(null);
9482         }
9483     }
9484 
9485     private void scheduleListenerHintsChanged(int state) {
9486         if (!Flags.notificationReduceMessagequeueUsage()) {
9487             mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
9488         }
9489         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
9490     }
9491 
9492     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
9493         if (!Flags.notificationReduceMessagequeueUsage()) {
9494             mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
9495         }
9496         mHandler.obtainMessage(
9497                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
9498                 listenerInterruptionFilter,
9499                 0).sendToTarget();
9500     }
9501 
9502     private void handleListenerHintsChanged(int hints) {
9503         synchronized (mNotificationLock) {
9504             mListeners.notifyListenerHintsChangedLocked(hints);
9505         }
9506     }
9507 
9508     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
9509         synchronized (mNotificationLock) {
9510             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
9511         }
9512     }
9513 
9514     void handleOnPackageChanged(boolean removingPackage, int changeUserId,
9515             String[] pkgList, int[] uidList) {
9516         boolean preferencesChanged = removingPackage;
9517         mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
9518         mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
9519         mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
9520         preferencesChanged |= mPreferencesHelper.onPackagesChanged(
9521                 removingPackage, changeUserId, pkgList, uidList);
9522         if (removingPackage) {
9523             int size = Math.min(pkgList.length, uidList.length);
9524             for (int i = 0; i < size; i++) {
9525                 final String pkg = pkgList[i];
9526                 final int uid = uidList[i];
9527                 final int userHandle = UserHandle.getUserId(uid);
9528                 // Removes this package's notifications from both recent notification archive
9529                 // (recently dismissed notifications) and notification history.
9530                 mArchive.removePackageNotifications(pkg, userHandle);
9531                 mHistoryManager.onPackageRemoved(userHandle, pkg);
9532             }
9533         }
9534         if (preferencesChanged) {
9535             handleSavePolicyFile();
9536         }
9537     }
9538 
9539     protected class WorkerHandler extends Handler
9540     {
9541         public WorkerHandler(Looper looper) {
9542             super(looper);
9543         }
9544 
9545         @Override
9546         public void handleMessage(Message msg)
9547         {
9548             switch (msg.what)
9549             {
9550                 case MESSAGE_DURATION_REACHED:
9551                     handleDurationReached((ToastRecord) msg.obj);
9552                     break;
9553                 case MESSAGE_FINISH_TOKEN_TIMEOUT:
9554                     handleKillTokenTimeout((ToastRecord) msg.obj);
9555                     break;
9556                 case MESSAGE_SEND_RANKING_UPDATE:
9557                     handleSendRankingUpdate();
9558                     break;
9559                 case MESSAGE_LISTENER_HINTS_CHANGED:
9560                     handleListenerHintsChanged(msg.arg1);
9561                     break;
9562                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
9563                     handleListenerInterruptionFilterChanged(msg.arg1);
9564                     break;
9565                 case MESSAGE_ON_PACKAGE_CHANGED:
9566                     SomeArgs args = (SomeArgs) msg.obj;
9567                     handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2,
9568                             (int[]) args.arg3);
9569                     args.recycle();
9570                     break;
9571             }
9572         }
9573 
9574         protected void scheduleSendRankingUpdate() {
9575             if (Flags.notificationReduceMessagequeueUsage()) {
9576                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
9577                 sendMessage(m);
9578             } else {
9579                 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
9580                     Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
9581                     sendMessage(m);
9582                 }
9583             }
9584         }
9585 
9586         protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable,
9587                                                   int delay) {
9588             if (lifetimeExtensionRefactor()) {
9589                 sendMessageDelayed(Message.obtain(this, cancelRunnable), delay);
9590             } else {
9591                 if (Flags.notificationReduceMessagequeueUsage()) {
9592                     sendMessage(Message.obtain(this, cancelRunnable));
9593                 } else {
9594                     if (!hasCallbacks(cancelRunnable)) {
9595                         sendMessage(Message.obtain(this, cancelRunnable));
9596                     }
9597                 }
9598             }
9599         }
9600 
9601         protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId,
9602                 String[] pkgList, int[] uidList) {
9603             SomeArgs args = SomeArgs.obtain();
9604             args.arg1 = removingPackage;
9605             args.argi1 = changeUserId;
9606             args.arg2 = pkgList;
9607             args.arg3 = uidList;
9608             sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args));
9609         }
9610     }
9611 
9612     private final class RankingHandlerWorker extends Handler implements RankingHandler
9613     {
9614         public RankingHandlerWorker(Looper looper) {
9615             super(looper);
9616         }
9617 
9618         @Override
9619         public void handleMessage(Message msg) {
9620             switch (msg.what) {
9621                 case MESSAGE_RECONSIDER_RANKING:
9622                     handleRankingReconsideration(msg);
9623                     break;
9624                 case MESSAGE_RANKING_SORT:
9625                     handleRankingSort();
9626                     break;
9627             }
9628         }
9629 
9630         public void requestSort() {
9631             if (!Flags.notificationReduceMessagequeueUsage()) {
9632                 removeMessages(MESSAGE_RANKING_SORT);
9633             }
9634             Message msg = Message.obtain();
9635             msg.what = MESSAGE_RANKING_SORT;
9636             sendMessage(msg);
9637         }
9638 
9639         public void requestReconsideration(RankingReconsideration recon) {
9640             Message m = Message.obtain(this,
9641                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
9642             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
9643             sendMessageDelayed(m, delay);
9644         }
9645     }
9646 
9647     // Notifications
9648     // ============================================================================
9649     static int clamp(int x, int low, int high) {
9650         return (x < low) ? low : ((x > high) ? high : x);
9651     }
9652 
9653     /**
9654      * Removes all NotificationsRecords with the same key as the given notification record
9655      * from both lists. Do not call this method while iterating over either list.
9656      */
9657     @GuardedBy("mNotificationLock")
9658     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
9659         // Remove from both lists, either list could have a separate Record for what is
9660         // effectively the same notification.
9661         boolean wasPosted = false;
9662         NotificationRecord recordInList = null;
9663         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
9664                 != null) {
9665             mNotificationList.remove(recordInList);
9666             mNotificationsByKey.remove(recordInList.getSbn().getKey());
9667             wasPosted = true;
9668         }
9669         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
9670                 != null) {
9671             mEnqueuedNotifications.remove(recordInList);
9672         }
9673         return wasPosted;
9674     }
9675 
9676     @GuardedBy("mNotificationLock")
9677     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete,
9678             @NotificationListenerService.NotificationCancelReason int reason,
9679             boolean wasPosted, String listenerName,
9680             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
9681         cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName,
9682                 cancellationElapsedTimeMs);
9683     }
9684 
9685     @GuardedBy("mNotificationLock")
9686     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete,
9687             @NotificationListenerService.NotificationCancelReason int reason,
9688             int rank, int count, boolean wasPosted, String listenerName,
9689             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
9690         final String canceledKey = r.getKey();
9691         if (Flags.allNotifsNeedTtl()) {
9692             mTtlHelper.cancelScheduledTimeoutLocked(r);
9693         } else {
9694             cancelScheduledTimeoutLocked(r);
9695         }
9696 
9697         // Record caller.
9698         recordCallerLocked(r);
9699 
9700         if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
9701             r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
9702         }
9703 
9704         // tell the app
9705         if (sendDelete) {
9706             final PendingIntent deleteIntent = r.getNotification().deleteIntent;
9707             if (deleteIntent != null) {
9708                 try {
9709                     // make sure deleteIntent cannot be used to start activities from background
9710                     LocalServices.getService(ActivityManagerInternal.class)
9711                             .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(),
9712                                     ALLOWLIST_TOKEN);
9713                     deleteIntent.send();
9714                 } catch (PendingIntent.CanceledException ex) {
9715                     // do nothing - there's no relevant way to recover, and
9716                     //     no reason to let this propagate
9717                     Slog.w(TAG, "canceled PendingIntent for " + r.getSbn().getPackageName(), ex);
9718                 }
9719             }
9720         }
9721 
9722         // Only cancel these if this notification actually got to be posted.
9723         if (wasPosted) {
9724             // status bar
9725             if (r.getNotification().getSmallIcon() != null) {
9726                 if (reason != REASON_SNOOZED) {
9727                     r.isCanceled = true;
9728                 }
9729                 mListeners.notifyRemovedLocked(r, reason, r.getStats());
9730                 mHandler.post(new Runnable() {
9731                     @Override
9732                     public void run() {
9733                         mGroupHelper.onNotificationRemoved(r.getSbn());
9734                     }
9735                 });
9736                 if (callstyleCallbackApi()) {
9737                     notifyCallNotificationEventListenerOnRemoved(r);
9738                 }
9739             }
9740 
9741             mAttentionHelper.clearEffectsLocked(canceledKey);
9742         }
9743 
9744         // Record usage stats
9745         // TODO: add unbundling stats?
9746         switch (reason) {
9747             case REASON_CANCEL:
9748             case REASON_CANCEL_ALL:
9749             case REASON_LISTENER_CANCEL:
9750             case REASON_LISTENER_CANCEL_ALL:
9751                 mUsageStats.registerDismissedByUser(r);
9752                 break;
9753             case REASON_APP_CANCEL:
9754             case REASON_APP_CANCEL_ALL:
9755                 mUsageStats.registerRemovedByApp(r);
9756                 mUsageStatsManagerInternal.reportNotificationRemoved(r.getSbn().getOpPkg(),
9757                         r.getUser(), cancellationElapsedTimeMs);
9758                 break;
9759         }
9760 
9761         String groupKey = r.getGroupKey();
9762         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
9763         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
9764             mSummaryByGroupKey.remove(groupKey);
9765         }
9766         final ArrayMap<String, String> summaries =
9767                 mAutobundledSummaries.get(r.getSbn().getUserId());
9768         if (summaries != null && r.getSbn().getKey().equals(
9769                 summaries.get(r.getSbn().getPackageName()))) {
9770             summaries.remove(r.getSbn().getPackageName());
9771         }
9772 
9773         // Save it for users of getHistoricalNotifications(), unless the whole channel was deleted
9774         if (reason != REASON_CHANNEL_REMOVED) {
9775             mArchive.record(r.getSbn(), reason);
9776         }
9777 
9778         final long now = System.currentTimeMillis();
9779         final LogMaker logMaker = r.getItemLogMaker()
9780                 .setType(MetricsEvent.TYPE_DISMISS)
9781                 .setSubtype(reason);
9782         if (rank != -1 && count != -1) {
9783             logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
9784                     .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
9785         }
9786         MetricsLogger.action(logMaker);
9787         EventLogTags.writeNotificationCanceled(canceledKey, reason,
9788                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
9789                 rank, count, listenerName);
9790         if (wasPosted) {
9791             mNotificationRecordLogger.logNotificationCancelled(r, reason,
9792                     r.getStats().getDismissalSurface());
9793         }
9794     }
9795 
9796     @VisibleForTesting
9797     void updateUriPermissions(@Nullable NotificationRecord newRecord,
9798             @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
9799         updateUriPermissions(newRecord, oldRecord, targetPkg, targetUserId, false);
9800     }
9801 
9802     @VisibleForTesting
9803     void updateUriPermissions(@Nullable NotificationRecord newRecord,
9804             @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId,
9805             boolean onlyRevokeCurrentTarget) {
9806         final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
9807         if (DBG) Slog.d(TAG, key + ": updating permissions");
9808 
9809         final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
9810         final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
9811 
9812         // Shortcut when no Uris involved
9813         if (newUris == null && oldUris == null) {
9814             return;
9815         }
9816 
9817         // Inherit any existing owner
9818         IBinder permissionOwner = null;
9819         if (newRecord != null && permissionOwner == null) {
9820             permissionOwner = newRecord.permissionOwner;
9821         }
9822         if (oldRecord != null && permissionOwner == null) {
9823             permissionOwner = oldRecord.permissionOwner;
9824         }
9825 
9826         // If we have Uris to grant, but no owner yet, go create one
9827         if (newUris != null && permissionOwner == null) {
9828             if (DBG) Slog.d(TAG, key + ": creating owner");
9829             permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
9830         }
9831 
9832         // If we have no Uris to grant, but an existing owner, go destroy it
9833         // When revoking permissions of a single listener, destroying the owner will revoke
9834         // permissions of other listeners who need to keep access.
9835         if (newUris == null && permissionOwner != null && !onlyRevokeCurrentTarget) {
9836             destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key);
9837             permissionOwner = null;
9838         }
9839 
9840         // Grant access to new Uris
9841         if (newUris != null && permissionOwner != null) {
9842             for (int i = 0; i < newUris.size(); i++) {
9843                 final Uri uri = newUris.valueAt(i);
9844                 if (oldUris == null || !oldUris.contains(uri)) {
9845                     if (DBG) {
9846                         Slog.d(TAG, key + ": granting " + uri);
9847                     }
9848                     grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
9849                             targetUserId);
9850                 }
9851             }
9852         }
9853 
9854         // Revoke access to old Uris
9855         if (oldUris != null && permissionOwner != null) {
9856             for (int i = 0; i < oldUris.size(); i++) {
9857                 final Uri uri = oldUris.valueAt(i);
9858                 if (newUris == null || !newUris.contains(uri)) {
9859                     if (DBG) Slog.d(TAG, key + ": revoking " + uri);
9860                     if (onlyRevokeCurrentTarget) {
9861                         // We're revoking permission from one listener only; other listeners may
9862                         // still need access because the notification may still exist
9863                         revokeUriPermission(permissionOwner, uri,
9864                                 UserHandle.getUserId(oldRecord.getUid()), targetPkg, targetUserId);
9865                     } else {
9866                         // This is broad to unilaterally revoke permissions to this Uri as granted
9867                         // by this notification.  But this code-path can only be used when the
9868                         // reason for revoking is that the notification posted again without this
9869                         // Uri, not when removing an individual listener.
9870                         revokeUriPermission(permissionOwner, uri,
9871                                 UserHandle.getUserId(oldRecord.getUid()),
9872                                 null, USER_ALL);
9873                     }
9874                 }
9875             }
9876         }
9877 
9878         if (newRecord != null) {
9879             newRecord.permissionOwner = permissionOwner;
9880         }
9881     }
9882 
9883     private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
9884             int targetUserId) {
9885         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
9886         final long ident = Binder.clearCallingIdentity();
9887         try {
9888             mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
9889                     ContentProvider.getUriWithoutUserId(uri),
9890                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
9891                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
9892                     targetUserId);
9893         } catch (RemoteException ignored) {
9894             // Ignored because we're in same process
9895         } catch (SecurityException e) {
9896             Slog.e(TAG, "Cannot grant uri access; " + sourceUid + " does not own " + uri);
9897         } finally {
9898             Binder.restoreCallingIdentity(ident);
9899         }
9900     }
9901 
9902     private void revokeUriPermission(IBinder owner, Uri uri, int sourceUserId, String targetPkg,
9903             int targetUserId) {
9904         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
9905         int userId = ContentProvider.getUserIdFromUri(uri, sourceUserId);
9906 
9907         final long ident = Binder.clearCallingIdentity();
9908         try {
9909             mUgmInternal.revokeUriPermissionFromOwner(
9910                     owner,
9911                     ContentProvider.getUriWithoutUserId(uri),
9912                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
9913                     userId, targetPkg, targetUserId);
9914         } finally {
9915             Binder.restoreCallingIdentity(ident);
9916         }
9917     }
9918 
9919     private void destroyPermissionOwner(IBinder owner, int userId, String logKey) {
9920         final long ident = Binder.clearCallingIdentity();
9921         try {
9922             if (DBG) Slog.d(TAG, logKey + ": destroying owner");
9923             mUgmInternal.revokeUriPermissionFromOwner(owner, null, ~0, userId);
9924         } finally {
9925             Binder.restoreCallingIdentity(ident);
9926         }
9927     }
9928 
9929     /**
9930      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
9931      * and none of the {@code mustNotHaveFlags}.
9932      */
9933     void cancelNotification(final int callingUid, final int callingPid,
9934             final String pkg, final String tag, int id,
9935             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
9936             final int userId, final int reason, final ManagedServiceInfo listener) {
9937         cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
9938                 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
9939     }
9940 
9941     /**
9942      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
9943      * and none of the {@code mustNotHaveFlags}.
9944      */
9945     void cancelNotification(final int callingUid, final int callingPid,
9946             final String pkg, final String tag, final int id,
9947             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
9948             final int userId, final int reason, int rank, int count,
9949             final ManagedServiceInfo listener) {
9950         // In enqueueNotificationInternal notifications are added by scheduling the
9951         // work on the worker handler. Hence, we also schedule the cancel on this
9952         // handler to avoid a scenario where an add notification call followed by a
9953         // remove notification call ends up in not removing the notification.
9954         mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
9955                 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
9956                 count, listener, SystemClock.elapsedRealtime()), 0);
9957     }
9958 
9959     /**
9960      * Determine whether the userId applies to the notification in question, either because
9961      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
9962      */
9963     private static boolean notificationMatchesUserId(NotificationRecord r, int userId,
9964             boolean isAutogroupSummary) {
9965         if (isAutogroupSummary) {
9966             return r.getUserId() == userId;
9967         } else {
9968             return
9969                 // looking for USER_ALL notifications? match everything
9970                 userId == USER_ALL
9971                         // a notification sent to USER_ALL matches any query
9972                         || r.getUserId() == USER_ALL
9973                         // an exact user match
9974                         || r.getUserId() == userId;
9975         }
9976     }
9977 
9978     /**
9979      * Determine whether the userId applies to the notification in question, either because
9980      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
9981      * because it matches one of the users profiles.
9982      */
9983     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
9984         return notificationMatchesUserId(r, userId, false)
9985                 || mUserProfiles.isCurrentProfile(r.getUserId());
9986     }
9987 
9988     /**
9989      * Cancels all notifications from a given package that have all of the
9990      * {@code mustHaveFlags} and none of the {@code mustNotHaveFlags}.
9991      */
9992     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg,
9993             @Nullable String channelId, int mustHaveFlags, int mustNotHaveFlags, int userId,
9994             int reason) {
9995         final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime();
9996         mHandler.post(new Runnable() {
9997             @Override
9998             public void run() {
9999                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
10000                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
10001                         /* listener= */ null);
10002 
10003                 synchronized (mNotificationLock) {
10004                     FlagChecker flagChecker = (int flags) -> {
10005                         if ((flags & mustHaveFlags) != mustHaveFlags) {
10006                             return false;
10007                         }
10008                         if ((flags & mustNotHaveFlags) != 0) {
10009                             return false;
10010                         }
10011                         return true;
10012                     };
10013                     cancelAllNotificationsByListLocked(mNotificationList, pkg,
10014                             true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
10015                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
10016                             null /* listenerName */, true /* wasPosted */,
10017                             cancellationElapsedTimeMs);
10018                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, pkg,
10019                             true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
10020                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
10021                             null /* listenerName */, false /* wasPosted */,
10022                             cancellationElapsedTimeMs);
10023                     mSnoozeHelper.cancel(userId, pkg);
10024                 }
10025             }
10026         });
10027     }
10028 
10029     private interface FlagChecker {
10030         // Returns false if these flags do not pass the defined flag test.
10031         public boolean apply(int flags);
10032     }
10033 
10034     @GuardedBy("mNotificationLock")
10035     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
10036             @Nullable String pkg, boolean nullPkgIndicatesUserSwitch, @Nullable String channelId,
10037             FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, boolean sendDelete,
10038             int reason, String listenerName, boolean wasPosted,
10039             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
10040         Set<String> childNotifications = null;
10041         for (int i = notificationList.size() - 1; i >= 0; --i) {
10042             NotificationRecord r = notificationList.get(i);
10043             if (includeCurrentProfiles) {
10044                 if (!notificationMatchesCurrentProfiles(r, userId)) {
10045                     continue;
10046                 }
10047             } else if (!notificationMatchesUserId(r, userId, false)) {
10048                 continue;
10049             }
10050             // Don't remove notifications to all, if there's no package name specified
10051             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == USER_ALL) {
10052                 continue;
10053             }
10054             if (!flagChecker.apply(r.getFlags())) {
10055                 continue;
10056             }
10057             if (pkg != null && !r.getSbn().getPackageName().equals(pkg)) {
10058                 continue;
10059             }
10060             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
10061                 continue;
10062             }
10063             if (r.getSbn().isGroup() && r.getNotification().isGroupChild()) {
10064                 if (childNotifications == null) {
10065                     childNotifications = new HashSet<>();
10066                 }
10067                 childNotifications.add(r.getKey());
10068                 continue;
10069             }
10070             notificationList.remove(i);
10071             mNotificationsByKey.remove(r.getKey());
10072             r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
10073             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName,
10074                     cancellationElapsedTimeMs);
10075         }
10076         if (childNotifications != null) {
10077             final int M = notificationList.size();
10078             for (int i = M - 1; i >= 0; i--) {
10079                 NotificationRecord r = notificationList.get(i);
10080                 if (childNotifications.contains(r.getKey())) {
10081                     // dismiss conditions were checked in the first loop and so don't need to be
10082                     // checked again
10083                     notificationList.remove(i);
10084                     mNotificationsByKey.remove(r.getKey());
10085                     r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
10086                     cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName,
10087                             cancellationElapsedTimeMs);
10088                 }
10089             }
10090             mAttentionHelper.updateLightsLocked();
10091         }
10092     }
10093 
10094     void snoozeNotificationInt(int callingUid, INotificationListener token, String key,
10095             long duration, String snoozeCriterionId) {
10096         final String packageName;
10097         final long notificationUpdateTimeMs;
10098 
10099         synchronized (mNotificationLock) {
10100             final ManagedServiceInfo listener = mListeners.checkServiceTokenLocked(token);
10101             if (listener == null) {
10102                 return;
10103             }
10104             packageName = listener.component.getPackageName();
10105             String listenerName = listener.component.toShortString();
10106             if ((duration <= 0 && snoozeCriterionId == null) || key == null) {
10107                 return;
10108             }
10109 
10110             final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key);
10111             if (r == null) {
10112                 return;
10113             }
10114             if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){
10115                 return;
10116             }
10117             notificationUpdateTimeMs = r.getUpdateTimeMs();
10118 
10119             if (DBG) {
10120                 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
10121                         snoozeCriterionId, listenerName));
10122             }
10123             // Needs to post so that it can cancel notifications not yet enqueued.
10124             mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
10125         }
10126 
10127         if (isNotificationRecent(notificationUpdateTimeMs)) {
10128             mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
10129                     callingUid, packageName, /* attributionTag= */ null, /* message= */ null);
10130         }
10131     }
10132 
10133     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) {
10134         String listenerName = listener == null ? null : listener.component.toShortString();
10135         if (DBG) {
10136             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
10137         }
10138         mSnoozeHelper.repost(key, muteOnReturn);
10139         handleSavePolicyFile();
10140     }
10141 
10142     private boolean isNotificationRecent(long notificationUpdateTimeMs) {
10143         if (!rapidClearNotificationsByListenerAppOpEnabled()) {
10144             return false;
10145         }
10146         return System.currentTimeMillis() - notificationUpdateTimeMs
10147                 < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS;
10148     }
10149 
10150     @GuardedBy("mNotificationLock")
10151     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
10152             ManagedServiceInfo listener, boolean includeCurrentProfiles, int mustNotHaveFlags) {
10153         final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime();
10154         mHandler.post(new Runnable() {
10155             @Override
10156             public void run() {
10157                 synchronized (mNotificationLock) {
10158                     String listenerName =
10159                             listener == null ? null : listener.component.toShortString();
10160                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
10161                             null, userId, 0, 0, reason, listenerName);
10162 
10163                     FlagChecker flagChecker = (int flags) -> {
10164                         int flagsToCheck = mustNotHaveFlags;
10165                         if (REASON_LISTENER_CANCEL_ALL == reason
10166                                 || REASON_CANCEL_ALL == reason) {
10167                             flagsToCheck |= FLAG_BUBBLE;
10168                         }
10169                         if ((flags & flagsToCheck) != 0) {
10170                             return false;
10171                         }
10172                         return true;
10173                     };
10174 
10175                     cancelAllNotificationsByListLocked(mNotificationList,
10176                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
10177                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
10178                             listenerName, true, cancellationElapsedTimeMs);
10179                     cancelAllNotificationsByListLocked(mEnqueuedNotifications,
10180                             null, false /*nullPkgIndicatesUserSwitch*/, null,
10181                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
10182                             reason, listenerName, false, cancellationElapsedTimeMs);
10183                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
10184                 }
10185             }
10186         });
10187     }
10188 
10189     // Warning: The caller is responsible for invoking updateLightsLocked().
10190     @GuardedBy("mNotificationLock")
10191     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
10192             String listenerName, boolean sendDelete, FlagChecker flagChecker, int reason,
10193             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
10194         Notification n = r.getNotification();
10195         if (!n.isGroupSummary()) {
10196             return;
10197         }
10198 
10199         String pkg = r.getSbn().getPackageName();
10200 
10201         if (pkg == null) {
10202             if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey());
10203             return;
10204         }
10205 
10206         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
10207                 sendDelete, true, flagChecker, reason, cancellationElapsedTimeMs);
10208         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
10209                 listenerName, sendDelete, false, flagChecker, reason, cancellationElapsedTimeMs);
10210     }
10211 
10212     @GuardedBy("mNotificationLock")
10213     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
10214             NotificationRecord parentNotification, int callingUid, int callingPid,
10215             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker,
10216             int reason, @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
10217         final String pkg = parentNotification.getSbn().getPackageName();
10218         final int userId = parentNotification.getUserId();
10219         final int childReason = REASON_GROUP_SUMMARY_CANCELED;
10220         for (int i = notificationList.size() - 1; i >= 0; i--) {
10221             final NotificationRecord childR = notificationList.get(i);
10222             final StatusBarNotification childSbn = childR.getSbn();
10223             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
10224                     childR.getGroupKey().equals(parentNotification.getGroupKey())
10225                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))
10226                     && (!childR.getChannel().isImportantConversation()
10227                             || reason != REASON_CANCEL)) {
10228                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
10229                         childSbn.getTag(), userId, 0, 0, childReason, listenerName);
10230                 notificationList.remove(i);
10231                 mNotificationsByKey.remove(childR.getKey());
10232                 cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName,
10233                         cancellationElapsedTimeMs);
10234             }
10235         }
10236     }
10237 
10238     @GuardedBy("mNotificationLock")
10239     @NonNull
10240     List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg,
10241             String groupKey, int userId) {
10242         List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId);
10243         records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId));
10244         return records;
10245     }
10246 
10247     @GuardedBy("mNotificationLock")
10248     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
10249             String groupKey, int userId) {
10250         List<NotificationRecord> records = new ArrayList<>();
10251         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
10252         records.addAll(
10253                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
10254         return records;
10255     }
10256 
10257     @GuardedBy("mNotificationLock")
10258     private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) {
10259         NotificationRecord r = findNotificationByKeyLocked(key);
10260         if (r == null) {
10261             r = mSnoozeHelper.getNotification(key);
10262         }
10263         return r;
10264 
10265     }
10266 
10267     @GuardedBy("mNotificationLock")
10268     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
10269             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
10270         List<NotificationRecord> records = new ArrayList<>();
10271         final int len = list.size();
10272         for (int i = 0; i < len; i++) {
10273             NotificationRecord r = list.get(i);
10274             if (notificationMatchesUserId(r, userId, false) && r.getGroupKey().equals(groupKey)
10275                     && r.getSbn().getPackageName().equals(pkg)) {
10276                 records.add(r);
10277             }
10278         }
10279         return records;
10280     }
10281 
10282     // Searches both enqueued and posted notifications by key.
10283     // TODO: need to combine a bunch of these getters with slightly different behavior.
10284     // TODO: Should enqueuing just add to mNotificationsByKey instead?
10285     @GuardedBy("mNotificationLock")
10286     private NotificationRecord findNotificationByKeyLocked(String key) {
10287         NotificationRecord r;
10288         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
10289             return r;
10290         }
10291         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
10292             return r;
10293         }
10294         return null;
10295     }
10296 
10297     @GuardedBy("mNotificationLock")
10298     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
10299         NotificationRecord r;
10300         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
10301             return r;
10302         }
10303         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
10304                 != null) {
10305             return r;
10306         }
10307         return null;
10308     }
10309 
10310     @Nullable
10311     private static NotificationRecord findNotificationByListLocked(
10312             ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
10313         final int len = list.size();
10314         for (int i = 0; i < len; i++) {
10315             NotificationRecord r = list.get(i);
10316             if (notificationMatchesUserId(r, userId, (r.getFlags() & GroupHelper.BASE_FLAGS) != 0)
10317                     && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag)
10318                     && r.getSbn().getPackageName().equals(pkg)) {
10319                 return r;
10320             }
10321         }
10322         return null;
10323     }
10324 
10325     private static List<NotificationRecord> findNotificationsByListLocked(
10326             ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
10327         List<NotificationRecord> matching = new ArrayList<>();
10328         final int len = list.size();
10329         for (int i = 0; i < len; i++) {
10330             NotificationRecord r = list.get(i);
10331             if (notificationMatchesUserId(r, userId, false) && r.getSbn().getId() == id
10332                     && TextUtils.equals(r.getSbn().getTag(), tag)
10333                     && r.getSbn().getPackageName().equals(pkg)) {
10334                 matching.add(r);
10335             }
10336         }
10337         return matching;
10338     }
10339 
10340     @Nullable
10341     private static NotificationRecord findNotificationByListLocked(
10342             ArrayList<NotificationRecord> list, String key) {
10343         final int N = list.size();
10344         for (int i = 0; i < N; i++) {
10345             if (key.equals(list.get(i).getKey())) {
10346                 return list.get(i);
10347             }
10348         }
10349         return null;
10350     }
10351 
10352     @GuardedBy("mNotificationLock")
10353     int indexOfNotificationLocked(String key) {
10354         final int N = mNotificationList.size();
10355         for (int i = 0; i < N; i++) {
10356             if (key.equals(mNotificationList.get(i).getKey())) {
10357                 return i;
10358             }
10359         }
10360         return -1;
10361     }
10362 
10363     private void hideNotificationsForPackages(@NonNull String[] pkgs, @NonNull int[] uidList) {
10364         synchronized (mNotificationLock) {
10365             Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet());
10366             List<String> pkgList = Arrays.asList(pkgs);
10367             List<NotificationRecord> changedNotifications = new ArrayList<>();
10368             int numNotifications = mNotificationList.size();
10369             for (int i = 0; i < numNotifications; i++) {
10370                 NotificationRecord rec = mNotificationList.get(i);
10371                 if (pkgList.contains(rec.getSbn().getPackageName())
10372                         && uidSet.contains(rec.getUid())) {
10373                     rec.setHidden(true);
10374                     changedNotifications.add(rec);
10375                 }
10376             }
10377 
10378             mListeners.notifyHiddenLocked(changedNotifications);
10379         }
10380     }
10381 
10382     private void unhideNotificationsForPackages(@NonNull String[] pkgs,
10383             @NonNull int[] uidList) {
10384         synchronized (mNotificationLock) {
10385             Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet());
10386             List<String> pkgList = Arrays.asList(pkgs);
10387             List<NotificationRecord> changedNotifications = new ArrayList<>();
10388             int numNotifications = mNotificationList.size();
10389             for (int i = 0; i < numNotifications; i++) {
10390                 NotificationRecord rec = mNotificationList.get(i);
10391                 if (pkgList.contains(rec.getSbn().getPackageName())
10392                         && uidSet.contains(rec.getUid())) {
10393                     rec.setHidden(false);
10394                     changedNotifications.add(rec);
10395                 }
10396             }
10397 
10398             mListeners.notifyUnhiddenLocked(changedNotifications);
10399         }
10400     }
10401 
10402     private void cancelNotificationsWhenEnterLockDownMode(int userId) {
10403         synchronized (mNotificationLock) {
10404             int numNotifications = mNotificationList.size();
10405             for (int i = 0; i < numNotifications; i++) {
10406                 NotificationRecord rec = mNotificationList.get(i);
10407                 if (rec.getUser().getIdentifier() != userId) {
10408                     continue;
10409                 }
10410                 mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN,
10411                         rec.getStats());
10412             }
10413 
10414         }
10415     }
10416 
10417     private void postNotificationsWhenExitLockDownMode(int userId) {
10418         synchronized (mNotificationLock) {
10419             int numNotifications = mNotificationList.size();
10420             // Set the delay to spread out the burst of notifications.
10421             long delay = 0;
10422             for (int i = 0; i < numNotifications; i++) {
10423                 NotificationRecord rec = mNotificationList.get(i);
10424                 if (rec.getUser().getIdentifier() != userId) {
10425                     continue;
10426                 }
10427                 mHandler.postDelayed(() -> {
10428                     synchronized (mNotificationLock) {
10429                         mListeners.notifyPostedLocked(rec, rec);
10430                     }
10431                 }, delay);
10432                 delay += 20;
10433             }
10434         }
10435     }
10436 
10437     protected boolean isCallingUidSystem() {
10438         final int uid = Binder.getCallingUid();
10439         return uid == Process.SYSTEM_UID;
10440     }
10441 
10442     protected boolean isCallingAppIdSystem() {
10443         final int uid = Binder.getCallingUid();
10444         final int appid = UserHandle.getAppId(uid);
10445         return appid == Process.SYSTEM_UID;
10446     }
10447 
10448     protected boolean isUidSystemOrPhone(int uid) {
10449         final int appid = UserHandle.getAppId(uid);
10450         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID
10451                 || uid == Process.ROOT_UID);
10452     }
10453 
10454     // TODO: Most calls should probably move to isCallerSystem.
10455     protected boolean isCallerSystemOrPhone() {
10456         return isUidSystemOrPhone(Binder.getCallingUid());
10457     }
10458 
10459     @VisibleForTesting
10460     protected boolean isCallerSystemOrSystemUi() {
10461         if (isCallerSystemOrPhone()) {
10462             return true;
10463         }
10464         return getContext().checkCallingPermission(STATUS_BAR_SERVICE)
10465                 == PERMISSION_GRANTED;
10466     }
10467 
10468     private boolean isCallerSystemOrSystemUiOrShell() {
10469         int callingUid = Binder.getCallingUid();
10470         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
10471             return true;
10472         }
10473         return isCallerSystemOrSystemUi();
10474     }
10475 
10476     private void checkCallerIsSystemOrShell() {
10477         int callingUid = Binder.getCallingUid();
10478         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
10479             return;
10480         }
10481         checkCallerIsSystem();
10482     }
10483 
10484     private void checkCallerIsSystem() {
10485         if (isCallerSystemOrPhone()) {
10486             return;
10487         }
10488         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
10489     }
10490 
10491     private void checkCallerIsSystemOrSystemUiOrShell() {
10492         checkCallerIsSystemOrSystemUiOrShell(null);
10493     }
10494 
10495     private void checkCallerIsSystemOrSystemUiOrShell(String message) {
10496         int callingUid = Binder.getCallingUid();
10497         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
10498             return;
10499         }
10500         if (isCallerSystemOrPhone()) {
10501             return;
10502         }
10503         getContext().enforceCallingPermission(STATUS_BAR_SERVICE,
10504                 message);
10505     }
10506 
10507     private void checkCallerIsSystemOrSameApp(String pkg) {
10508         if (isCallerSystemOrPhone()) {
10509             return;
10510         }
10511         checkCallerIsSameApp(pkg);
10512     }
10513 
10514     private boolean isCallerAndroid(String callingPkg, int uid) {
10515         return isUidSystemOrPhone(uid) && callingPkg != null
10516                 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
10517     }
10518 
10519     /**
10520      * Check if the notification is of a category type that is restricted to system use only,
10521      * if so throw SecurityException
10522      */
10523     private void checkRestrictedCategories(final Notification notification) {
10524         try {
10525             if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
10526                 return;
10527             }
10528         } catch (RemoteException re) {
10529             if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
10530                     + "restrictions check thus the check will be done anyway");
10531         }
10532         if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
10533                 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
10534                 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
10535             getContext().enforceCallingPermission(
10536                     android.Manifest.permission.SEND_CATEGORY_CAR_NOTIFICATIONS,
10537                     String.format("Notification category %s restricted",
10538                             notification.category));
10539         }
10540     }
10541 
10542     @VisibleForTesting
10543     boolean isCallerInstantApp(int callingUid, int userId) {
10544         // System is always allowed to act for ephemeral apps.
10545         if (isUidSystemOrPhone(callingUid)) {
10546             return false;
10547         }
10548 
10549         if (userId == USER_ALL) {
10550             userId = USER_SYSTEM;
10551         }
10552 
10553         try {
10554             final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
10555             if (pkgs == null) {
10556                 throw new SecurityException("Unknown uid " + callingUid);
10557             }
10558             final String pkg = pkgs[0];
10559             mAppOps.checkPackage(callingUid, pkg);
10560 
10561             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
10562             if (ai == null) {
10563                 throw new SecurityException("Unknown package " + pkg);
10564             }
10565             return ai.isInstantApp();
10566         } catch (RemoteException re) {
10567             throw new SecurityException("Unknown uid " + callingUid, re);
10568         }
10569     }
10570 
10571     private void checkCallerIsSameApp(String pkg) {
10572         checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
10573     }
10574 
10575     private void checkCallerIsSameApp(String pkg, int uid, int userId) {
10576         if (uid == Process.ROOT_UID && ROOT_PKG.equals(pkg)) {
10577             return;
10578         }
10579         if (!mPackageManagerInternal.isSameApp(pkg, uid, userId)) {
10580             throw new SecurityException("Package " + pkg + " is not owned by uid " + uid);
10581         }
10582     }
10583 
10584     private boolean isCallerSameApp(String pkg, int uid, int userId) {
10585         try {
10586             checkCallerIsSameApp(pkg, uid, userId);
10587             return true;
10588         } catch (SecurityException e) {
10589             return false;
10590         }
10591     }
10592 
10593     private static String callStateToString(int state) {
10594         switch (state) {
10595             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
10596             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
10597             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
10598             default: return "CALL_STATE_UNKNOWN_" + state;
10599         }
10600     }
10601 
10602     /**
10603      * Generates a NotificationRankingUpdate from 'sbns', considering only
10604      * notifications visible to the given listener.
10605      */
10606     @GuardedBy("mNotificationLock")
10607     NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
10608         final int N = mNotificationList.size();
10609         final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>();
10610 
10611         for (int i = 0; i < N; i++) {
10612             NotificationRecord record = mNotificationList.get(i);
10613             if (isInLockDownMode(record.getUser().getIdentifier())) {
10614                 continue;
10615             }
10616             if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) {
10617                 continue;
10618             }
10619             final String key = record.getSbn().getKey();
10620             final NotificationListenerService.Ranking ranking =
10621                     new NotificationListenerService.Ranking();
10622             ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
10623             ArrayList<CharSequence> smartReplies = record.getSmartReplies();
10624             if (redactSensitiveNotificationsFromUntrustedListeners()
10625                     && info != null
10626                     && !mListeners.isUidTrusted(info.uid)
10627                     && mListeners.hasSensitiveContent(record)) {
10628                 smartActions = null;
10629                 smartReplies = null;
10630             }
10631             ranking.populate(
10632                     key,
10633                     rankings.size(),
10634                     !record.isIntercepted(),
10635                     record.getPackageVisibilityOverride(),
10636                     record.getSuppressedVisualEffects(),
10637                     record.getImportance(),
10638                     record.getImportanceExplanation(),
10639                     record.getSbn().getOverrideGroupKey(),
10640                     record.getChannel(),
10641                     record.getPeopleOverride(),
10642                     record.getSnoozeCriteria(),
10643                     record.canShowBadge(),
10644                     record.getUserSentiment(),
10645                     record.isHidden(),
10646                     record.getLastAudiblyAlertedMs(),
10647                     record.getSound() != null || record.getVibration() != null,
10648                     smartActions,
10649                     smartReplies,
10650                     record.canBubble(),
10651                     record.isTextChanged(),
10652                     record.isConversation(),
10653                     record.getShortcutInfo(),
10654                     record.getRankingScore() == 0
10655                             ? RANKING_UNCHANGED
10656                             : (record.getRankingScore() > 0 ?  RANKING_PROMOTED : RANKING_DEMOTED),
10657                     record.getNotification().isBubbleNotification(),
10658                     record.getProposedImportance(),
10659                     record.hasSensitiveContent()
10660             );
10661             rankings.add(ranking);
10662         }
10663 
10664         return new NotificationRankingUpdate(
10665                 rankings.toArray(new NotificationListenerService.Ranking[0]));
10666     }
10667 
10668     boolean isInLockDownMode(int userId) {
10669         return mStrongAuthTracker.isInLockDownMode(userId);
10670     }
10671 
10672     boolean hasCompanionDevice(ManagedServiceInfo info) {
10673         return hasCompanionDevice(info.component.getPackageName(),
10674                 info.userid, /* withDeviceProfile= */ null);
10675     }
10676 
10677     private boolean hasCompanionDevice(String pkg, @UserIdInt int userId,
10678             @Nullable Set</* @AssociationRequest.DeviceProfile */ String> withDeviceProfiles) {
10679         if (mCompanionManager == null) {
10680             mCompanionManager = getCompanionManager();
10681         }
10682         // Companion mgr doesn't exist on all device types
10683         if (mCompanionManager == null) {
10684             return false;
10685         }
10686         final long identity = Binder.clearCallingIdentity();
10687         try {
10688             List<AssociationInfo> associations = mCompanionManager.getAssociations(pkg, userId);
10689             for (AssociationInfo association : associations) {
10690                 if (withDeviceProfiles == null || withDeviceProfiles.contains(
10691                         association.getDeviceProfile())) {
10692                     return true;
10693                 }
10694             }
10695         } catch (SecurityException se) {
10696             // Not a privileged listener
10697         } catch (RemoteException re) {
10698             Slog.e(TAG, "Cannot reach companion device service", re);
10699         } catch (Exception e) {
10700             Slog.e(TAG, "Cannot verify caller pkg=" + pkg + ", userId=" + userId, e);
10701         } finally {
10702             Binder.restoreCallingIdentity(identity);
10703         }
10704         return false;
10705     }
10706 
10707     protected ICompanionDeviceManager getCompanionManager() {
10708         return ICompanionDeviceManager.Stub.asInterface(
10709                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
10710     }
10711 
10712     @VisibleForTesting
10713     boolean isVisibleToListener(StatusBarNotification sbn, int notificationType,
10714             ManagedServiceInfo listener) {
10715         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
10716             return false;
10717         }
10718         if (!isInteractionVisibleToListener(listener, sbn.getUserId())) {
10719             return false;
10720         }
10721         NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey);
10722         if (nls != null
10723                 && (!nls.isTypeAllowed(notificationType)
10724                 || !nls.isPackageAllowed(
10725                         new VersionedPackage(sbn.getPackageName(), sbn.getUid())))) {
10726             return false;
10727         }
10728         return true;
10729     }
10730 
10731     /**
10732      * Returns whether the given assistant should be informed about interactions on the given user.
10733      *
10734      * Normally an assistant would be able to see all interactions on the current user and any
10735      * associated profiles because they are notification listeners, but since NASes have one
10736      * instance per user, we want to filter out interactions that are not for the user that the
10737      * given NAS is bound in.
10738      */
10739     @VisibleForTesting
10740     boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) {
10741         boolean isAssistantService = isServiceTokenValid(info.getService());
10742         return !isAssistantService || info.isSameUser(userId);
10743     }
10744 
10745     private boolean isServiceTokenValid(IInterface service) {
10746         synchronized (mNotificationLock) {
10747             return mAssistants.isServiceTokenValidLocked(service);
10748         }
10749     }
10750 
10751     private boolean isPackageSuspendedForUser(String pkg, int uid) {
10752         final long identity = Binder.clearCallingIdentity();
10753         int userId = UserHandle.getUserId(uid);
10754         try {
10755             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
10756         } catch (RemoteException re) {
10757             throw new SecurityException("Could not talk to package manager service");
10758         } catch (IllegalArgumentException ex) {
10759             // Package not found.
10760             return false;
10761         } finally {
10762             Binder.restoreCallingIdentity(identity);
10763         }
10764     }
10765 
10766     @VisibleForTesting
10767     boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
10768         boolean canUseManagedServices = true;
10769         if (requiredPermission != null) {
10770             try {
10771                 if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
10772                         != PERMISSION_GRANTED) {
10773                     canUseManagedServices = false;
10774                 }
10775             } catch (RemoteException e) {
10776                 Slog.e(TAG, "can't talk to pm", e);
10777             }
10778         }
10779 
10780         return canUseManagedServices;
10781     }
10782 
10783     private class TrimCache {
10784         StatusBarNotification heavy;
10785         StatusBarNotification sbnClone;
10786         StatusBarNotification sbnCloneLight;
10787 
10788         TrimCache(StatusBarNotification sbn) {
10789             heavy = sbn;
10790         }
10791 
10792         StatusBarNotification ForListener(ManagedServiceInfo info) {
10793             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
10794                 if (sbnCloneLight == null) {
10795                     sbnCloneLight = heavy.cloneLight();
10796                 }
10797                 return sbnCloneLight;
10798             } else {
10799                 if (sbnClone == null) {
10800                     sbnClone = heavy.clone();
10801                 }
10802                 return sbnClone;
10803             }
10804         }
10805     }
10806 
10807     public class NotificationAssistants extends ManagedServices {
10808         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
10809 
10810         private static final String ATT_TYPES = "types";
10811 
10812         private final Object mLock = new Object();
10813 
10814         @GuardedBy("mLock")
10815         private Set<String> mAllowedAdjustments = new ArraySet<>();
10816 
10817         protected ComponentName mDefaultFromConfig = null;
10818 
10819         @Override
10820         protected void loadDefaultsFromConfig() {
10821             loadDefaultsFromConfig(true);
10822         }
10823 
10824         protected void loadDefaultsFromConfig(boolean addToDefault) {
10825             ArraySet<String> assistants = new ArraySet<>();
10826             assistants.addAll(Arrays.asList(mContext.getResources().getString(
10827                     com.android.internal.R.string.config_defaultAssistantAccessComponent)
10828                     .split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
10829             for (int i = 0; i < assistants.size(); i++) {
10830                 ComponentName assistantCn = ComponentName
10831                         .unflattenFromString(assistants.valueAt(i));
10832                 String packageName = assistants.valueAt(i);
10833                 if (assistantCn != null) {
10834                     packageName = assistantCn.getPackageName();
10835                 }
10836                 if (TextUtils.isEmpty(packageName)) {
10837                     continue;
10838                 }
10839                 ArraySet<ComponentName> approved = queryPackageForServices(packageName,
10840                         MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
10841                 if (approved.contains(assistantCn)) {
10842                     if (addToDefault) {
10843                         // add the default loaded from config file to mDefaultComponents and
10844                         // mDefaultPackages
10845                         addDefaultComponentOrPackage(assistantCn.flattenToString());
10846                     } else {
10847                         // otherwise, store in the mDefaultFromConfig for NAS settings migration
10848                         mDefaultFromConfig = assistantCn;
10849                     }
10850                 }
10851             }
10852         }
10853 
10854         ComponentName getDefaultFromConfig() {
10855             if (mDefaultFromConfig == null) {
10856                 loadDefaultsFromConfig(false);
10857             }
10858             return mDefaultFromConfig;
10859         }
10860 
10861         @Override
10862         protected void upgradeUserSet() {
10863             for (int userId: mApproved.keySet()) {
10864                 ArraySet<String> userSetServices = mUserSetServices.get(userId);
10865                 mIsUserChanged.put(userId, (userSetServices != null && userSetServices.size() > 0));
10866             }
10867         }
10868 
10869         @Override
10870         protected void addApprovedList(String approved, int userId, boolean isPrimary,
10871                 String userSet) {
10872             if (!TextUtils.isEmpty(approved)) {
10873                 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
10874                 if (approvedArray.length > 1) {
10875                     Slog.d(TAG, "More than one approved assistants");
10876                     approved = approvedArray[0];
10877                 }
10878             }
10879             super.addApprovedList(approved, userId, isPrimary, userSet);
10880         }
10881 
10882         public NotificationAssistants(Context context, Object lock, UserProfiles up,
10883                 IPackageManager pm) {
10884             super(context, lock, up, pm);
10885 
10886             // Add all default allowed adjustment types.
10887             for (int i = 0; i < ALLOWED_ADJUSTMENTS.length; i++) {
10888                 mAllowedAdjustments.add(ALLOWED_ADJUSTMENTS[i]);
10889             }
10890         }
10891 
10892         @Override
10893         protected Config getConfig() {
10894             Config c = new Config();
10895             c.caption = "notification assistant";
10896             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
10897             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
10898             c.secureSettingName = Secure.ENABLED_NOTIFICATION_ASSISTANT;
10899             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
10900             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
10901             c.clientLabel = R.string.notification_ranker_binding_label;
10902             return c;
10903         }
10904 
10905         @Override
10906         protected IInterface asInterface(IBinder binder) {
10907             return INotificationListener.Stub.asInterface(binder);
10908         }
10909 
10910         @Override
10911         protected boolean checkType(IInterface service) {
10912             return service instanceof INotificationListener;
10913         }
10914 
10915         @Override
10916         protected void onServiceAdded(ManagedServiceInfo info) {
10917             mListeners.registerGuestService(info);
10918         }
10919 
10920         @Override
10921         protected void ensureFilters(ServiceInfo si, int userId) {
10922             // nothing to filter; no user visible settings for types/packages like other
10923             // listeners
10924         }
10925 
10926         @Override
10927         @GuardedBy("mNotificationLock")
10928         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
10929             mListeners.unregisterService(removed.service, removed.userid);
10930         }
10931 
10932         @Override
10933         public void onUserUnlocked(int user) {
10934             if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
10935             // force rebind the assistant, as it might be keeping its own state in user locked
10936             // storage
10937             rebindServices(true, user);
10938         }
10939 
10940         @Override
10941         protected boolean allowRebindForParentUser() {
10942             return false;
10943         }
10944 
10945         @Override
10946         protected String getRequiredPermission() {
10947             // only signature/privileged apps can be bound.
10948             return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
10949         }
10950 
10951         protected List<String> getAllowedAssistantAdjustments() {
10952             synchronized (mLock) {
10953                 List<String> types = new ArrayList<>();
10954                 types.addAll(mAllowedAdjustments);
10955                 return types;
10956             }
10957         }
10958 
10959         protected boolean isAdjustmentAllowed(String type) {
10960             synchronized (mLock) {
10961                 return mAllowedAdjustments.contains(type);
10962             }
10963         }
10964 
10965         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
10966             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
10967                 ArrayList<String> keys = new ArrayList<>(records.size());
10968                 for (NotificationRecord r : records) {
10969                     boolean sbnVisible = isVisibleToListener(
10970                             r.getSbn(), r.getNotificationType(), info)
10971                             && info.isSameUser(r.getUserId());
10972                     if (sbnVisible) {
10973                         keys.add(r.getKey());
10974                     }
10975                 }
10976 
10977                 if (!keys.isEmpty()) {
10978                     mHandler.post(() -> notifySeen(info, keys));
10979                 }
10980             }
10981         }
10982 
10983         protected void onPanelRevealed(int items) {
10984             // send to all currently bounds NASes since notifications from both users will appear in
10985             // the panel
10986             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
10987                 mHandler.post(() -> {
10988                     final INotificationListener assistant = (INotificationListener) info.service;
10989                     try {
10990                         assistant.onPanelRevealed(items);
10991                     } catch (RemoteException ex) {
10992                         Slog.e(TAG, "unable to notify assistant (panel revealed): " + info, ex);
10993                     }
10994                 });
10995             }
10996         }
10997 
10998         protected void onPanelHidden() {
10999             // send to all currently bounds NASes since notifications from both users will appear in
11000             // the panel
11001             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
11002                 mHandler.post(() -> {
11003                     final INotificationListener assistant = (INotificationListener) info.service;
11004                     try {
11005                         assistant.onPanelHidden();
11006                     } catch (RemoteException ex) {
11007                         Slog.e(TAG, "unable to notify assistant (panel hidden): " + info, ex);
11008                     }
11009                 });
11010             }
11011         }
11012 
11013         boolean hasUserSet(int userId) {
11014             Boolean userSet = mIsUserChanged.get(userId);
11015             return (userSet != null && userSet);
11016         }
11017 
11018         void setUserSet(int userId, boolean set) {
11019             mIsUserChanged.put(userId, set);
11020         }
11021 
11022         private void notifySeen(final ManagedServiceInfo info,
11023                 final ArrayList<String> keys) {
11024             final INotificationListener assistant = (INotificationListener) info.service;
11025             try {
11026                 assistant.onNotificationsSeen(keys);
11027             } catch (RemoteException ex) {
11028                 Slog.e(TAG, "unable to notify assistant (seen): " + info, ex);
11029             }
11030         }
11031 
11032         @GuardedBy("mNotificationLock")
11033         private void onNotificationEnqueuedLocked(final NotificationRecord r) {
11034             final boolean debug = isVerboseLogEnabled();
11035             if (debug) {
11036                 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
11037             }
11038             final StatusBarNotification sbn = r.getSbn();
11039 
11040             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
11041                 boolean sbnVisible = isVisibleToListener(
11042                         sbn, r.getNotificationType(), info)
11043                         && info.isSameUser(r.getUserId());
11044                 if (sbnVisible) {
11045                     TrimCache trimCache = new TrimCache(sbn);
11046                     final INotificationListener assistant = (INotificationListener) info.service;
11047                     final StatusBarNotification sbnToPost = trimCache.ForListener(info);
11048                     final StatusBarNotificationHolder sbnHolder =
11049                             new StatusBarNotificationHolder(sbnToPost);
11050                     try {
11051                         if (debug) {
11052                             Slog.v(TAG,
11053                                     "calling onNotificationEnqueuedWithChannel " + sbnHolder);
11054                         }
11055                         final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
11056                         assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
11057                                 update);
11058                     } catch (RemoteException ex) {
11059                         Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
11060                     }
11061                 }
11062             }
11063         }
11064 
11065         @GuardedBy("mNotificationLock")
11066         void notifyAssistantVisibilityChangedLocked(
11067                 final NotificationRecord r,
11068                 final boolean isVisible) {
11069             final String key = r.getSbn().getKey();
11070             if (DBG) {
11071                 Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key);
11072             }
11073             notifyAssistantLocked(
11074                     r.getSbn(),
11075                     r.getNotificationType(),
11076                     true /* sameUserOnly */,
11077                     (assistant, sbnHolder) -> {
11078                         try {
11079                             assistant.onNotificationVisibilityChanged(key, isVisible);
11080                         } catch (RemoteException ex) {
11081                             Slog.e(TAG, "unable to notify assistant (visible): " + assistant, ex);
11082                         }
11083                     });
11084         }
11085 
11086         @GuardedBy("mNotificationLock")
11087         void notifyAssistantExpansionChangedLocked(
11088                 final StatusBarNotification sbn,
11089                 final int notificationType,
11090                 final boolean isUserAction,
11091                 final boolean isExpanded) {
11092             final String key = sbn.getKey();
11093             notifyAssistantLocked(
11094                     sbn,
11095                     notificationType,
11096                     true /* sameUserOnly */,
11097                     (assistant, sbnHolder) -> {
11098                         try {
11099                             assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
11100                         } catch (RemoteException ex) {
11101                             Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
11102                         }
11103                     });
11104         }
11105 
11106         @GuardedBy("mNotificationLock")
11107         void notifyAssistantNotificationDirectReplyLocked(
11108                 final NotificationRecord r) {
11109             final String key = r.getKey();
11110             notifyAssistantLocked(
11111                     r.getSbn(),
11112                     r.getNotificationType(),
11113                     true /* sameUserOnly */,
11114                     (assistant, sbnHolder) -> {
11115                         try {
11116                             assistant.onNotificationDirectReply(key);
11117                         } catch (RemoteException ex) {
11118                             Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
11119                         }
11120                     });
11121         }
11122 
11123         @GuardedBy("mNotificationLock")
11124         void notifyAssistantSuggestedReplySent(
11125                 final StatusBarNotification sbn, int notificationType,
11126                 CharSequence reply, boolean generatedByAssistant) {
11127             final String key = sbn.getKey();
11128             notifyAssistantLocked(
11129                     sbn,
11130                     notificationType,
11131                     true /* sameUserOnly */,
11132                     (assistant, sbnHolder) -> {
11133                         try {
11134                             assistant.onSuggestedReplySent(
11135                                     key,
11136                                     reply,
11137                                     generatedByAssistant
11138                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
11139                                             : NotificationAssistantService.SOURCE_FROM_APP);
11140                         } catch (RemoteException ex) {
11141                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
11142                         }
11143                     });
11144         }
11145 
11146         @GuardedBy("mNotificationLock")
11147         void notifyAssistantActionClicked(
11148                 final NotificationRecord r, Notification.Action action,
11149                 boolean generatedByAssistant) {
11150             final String key = r.getSbn().getKey();
11151             notifyAssistantLocked(
11152                     r.getSbn(),
11153                     r.getNotificationType(),
11154                     true /* sameUserOnly */,
11155                     (assistant, sbnHolder) -> {
11156                         try {
11157                             assistant.onActionClicked(
11158                                     key,
11159                                     action,
11160                                     generatedByAssistant
11161                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
11162                                             : NotificationAssistantService.SOURCE_FROM_APP);
11163                         } catch (RemoteException ex) {
11164                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
11165                         }
11166                     });
11167         }
11168 
11169         /**
11170          * asynchronously notify the assistant that a notification has been snoozed until a
11171          * context
11172          */
11173         @GuardedBy("mNotificationLock")
11174         private void notifyAssistantSnoozedLocked(
11175                 final NotificationRecord r, final String snoozeCriterionId) {
11176             notifyAssistantLocked(
11177                     r.getSbn(),
11178                     r.getNotificationType(),
11179                     true /* sameUserOnly */,
11180                     (assistant, sbnHolder) -> {
11181                         try {
11182                             assistant.onNotificationSnoozedUntilContext(
11183                                     sbnHolder, snoozeCriterionId);
11184                         } catch (RemoteException ex) {
11185                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
11186                         }
11187                     });
11188         }
11189 
11190         @GuardedBy("mNotificationLock")
11191         void notifyAssistantNotificationClicked(final NotificationRecord r) {
11192             final String key = r.getSbn().getKey();
11193             notifyAssistantLocked(
11194                     r.getSbn(),
11195                     r.getNotificationType(),
11196                     true /* sameUserOnly */,
11197                     (assistant, sbnHolder) -> {
11198                         try {
11199                             assistant.onNotificationClicked(key);
11200                         } catch (RemoteException ex) {
11201                             Slog.e(TAG, "unable to notify assistant (clicked): " + assistant, ex);
11202                         }
11203                     });
11204         }
11205 
11206         @GuardedBy("mNotificationLock")
11207         void notifyAssistantFeedbackReceived(final NotificationRecord r, Bundle feedback) {
11208             final StatusBarNotification sbn = r.getSbn();
11209 
11210             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
11211                 boolean sbnVisible = isVisibleToListener(
11212                         sbn, r.getNotificationType(), info)
11213                         && info.isSameUser(r.getUserId());
11214                 if (sbnVisible) {
11215                     final INotificationListener assistant = (INotificationListener) info.service;
11216                     try {
11217                         final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
11218                         assistant.onNotificationFeedbackReceived(sbn.getKey(), update, feedback);
11219                     } catch (RemoteException ex) {
11220                         Slog.e(TAG, "unable to notify assistant (feedback): " + assistant, ex);
11221                     }
11222                 }
11223             }
11224         }
11225 
11226         /**
11227          * Notifies the assistant something about the specified notification, only assistant
11228          * that is visible to the notification will be notified.
11229          *
11230          * @param sbn          the notification object that the update is about.
11231          * @param sameUserOnly should the update  be sent to the assistant in the same user only.
11232          * @param callback     the callback that provides the assistant to be notified, executed
11233          *                     in WorkerHandler.
11234          */
11235         @GuardedBy("mNotificationLock")
11236         private void notifyAssistantLocked(
11237                 final StatusBarNotification sbn,
11238                 int notificationType,
11239                 boolean sameUserOnly,
11240                 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
11241             TrimCache trimCache = new TrimCache(sbn);
11242             // There should be only one, but it's a list, so while we enforce
11243             // singularity elsewhere, we keep it general here, to avoid surprises.
11244 
11245             final boolean debug = isVerboseLogEnabled();
11246             if (debug) {
11247                 Slog.v(TAG,
11248                         "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
11249                                 + sameUserOnly + "], callback = [" + callback + "]");
11250             }
11251             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
11252                 boolean sbnVisible = isVisibleToListener(sbn, notificationType, info)
11253                         && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
11254                 if (debug) {
11255                     Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
11256                 }
11257                 if (!sbnVisible) {
11258                     continue;
11259                 }
11260                 final INotificationListener assistant = (INotificationListener) info.service;
11261                 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
11262                 final StatusBarNotificationHolder sbnHolder =
11263                         new StatusBarNotificationHolder(sbnToPost);
11264                 mHandler.post(() -> callback.accept(assistant, sbnHolder));
11265             }
11266         }
11267 
11268         public boolean isEnabled() {
11269             return !getServices().isEmpty();
11270         }
11271 
11272         protected void resetDefaultAssistantsIfNecessary() {
11273             final List<UserInfo> activeUsers = mUm.getAliveUsers();
11274             for (UserInfo userInfo : activeUsers) {
11275                 int userId = userInfo.getUserHandle().getIdentifier();
11276                 if (!hasUserSet(userId)) {
11277                     if (!isNASMigrationDone(userId)) {
11278                         resetDefaultFromConfig();
11279                         setNASMigrationDone(userId);
11280                     }
11281                     Slog.d(TAG, "Approving default notification assistant for user " + userId);
11282                     setDefaultAssistantForUser(userId);
11283                 }
11284             }
11285         }
11286 
11287         protected void resetDefaultFromConfig() {
11288             clearDefaults();
11289             loadDefaultsFromConfig();
11290         }
11291 
11292         protected void clearDefaults() {
11293             mDefaultComponents.clear();
11294             mDefaultPackages.clear();
11295         }
11296 
11297         @Override
11298         protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
11299                 boolean isPrimary, boolean enabled, boolean userSet) {
11300             // Ensures that only one component is enabled at a time
11301             if (enabled) {
11302                 List<ComponentName> allowedComponents = getAllowedComponents(userId);
11303                 if (!allowedComponents.isEmpty()) {
11304                     ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
11305                     if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
11306                     setNotificationAssistantAccessGrantedForUserInternal(
11307                             currentComponent, userId, false, userSet);
11308                 }
11309             }
11310             super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
11311         }
11312 
11313         private boolean isVerboseLogEnabled() {
11314             return Log.isLoggable("notification_assistant", Log.VERBOSE);
11315         }
11316     }
11317 
11318     /**
11319      * Asynchronously notify all listeners about a posted (new or updated) notification. This
11320      * should be called from {@link PostNotificationRunnable} to "complete" the post (since SysUI is
11321      * one of the NLSes, and will display it to the user).
11322      *
11323      * <p>This method will call {@link PostNotificationTracker#finish} on the supplied tracker
11324      * when every {@link NotificationListenerService} has received the news.
11325      *
11326      * <p>Also takes care of removing a notification that has been visible to a listener before,
11327      * but isn't anymore.
11328      */
11329     @GuardedBy("mNotificationLock")
11330     private void notifyListenersPostedAndLogLocked(NotificationRecord r, NotificationRecord old,
11331             @NonNull PostNotificationTracker tracker,
11332             @Nullable NotificationRecordLogger.NotificationReported report) {
11333         List<Runnable> listenerCalls = mListeners.prepareNotifyPostedLocked(r, old, true);
11334         mHandler.post(() -> {
11335             for (Runnable listenerCall : listenerCalls) {
11336                 listenerCall.run();
11337             }
11338 
11339             long postDurationMillis = tracker.finish();
11340             if (report != null) {
11341                 report.post_duration_millis = postDurationMillis;
11342                 mNotificationRecordLogger.logNotificationPosted(report);
11343             }
11344         });
11345 
11346         if (callstyleCallbackApi()) {
11347             notifyCallNotificationEventListenerOnPosted(r);
11348         }
11349     }
11350 
11351     @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR)
11352     @GuardedBy("mNotificationLock")
11353     private void maybeNotifySystemUiListenerLifetimeExtendedListLocked(
11354             List<NotificationRecord> notificationList, int packageImportance) {
11355         for (int i = notificationList.size() - 1; i >= 0; --i) {
11356             NotificationRecord record = notificationList.get(i);
11357             maybeNotifySystemUiListenerLifetimeExtendedLocked(record,
11358                     record.getSbn().getPackageName(), packageImportance);
11359         }
11360     }
11361 
11362     @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR)
11363     @GuardedBy("mNotificationLock")
11364     private void maybeNotifySystemUiListenerLifetimeExtendedLocked(NotificationRecord record,
11365             String pkg, int packageImportance) {
11366         if (record != null && (record.getSbn().getNotification().flags
11367                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) {
11368             boolean isAppForeground = pkg != null && packageImportance == IMPORTANCE_FOREGROUND;
11369 
11370             // Lifetime extended notifications don't need to alert on state change.
11371             record.setPostSilently(true);
11372             // We also set FLAG_ONLY_ALERT_ONCE to avoid the notification from HUN-ing again.
11373             record.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
11374 
11375             mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(),
11376                     record, isAppForeground,
11377                     mPostNotificationTrackerFactory.newTracker(null)));
11378         }
11379     }
11380 
11381     @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR)
11382     private int getPackageImportanceWithIdentity(String pkg) {
11383         final long token = Binder.clearCallingIdentity();
11384         final int packageImportance;
11385         try {
11386             packageImportance = mActivityManager.getPackageImportance(pkg);
11387         } finally {
11388             Binder.restoreCallingIdentity(token);
11389         }
11390         return packageImportance;
11391     }
11392 
11393     public class NotificationListeners extends ManagedServices {
11394         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
11395         static final String TAG_REQUESTED_LISTENERS = "request_listeners";
11396         static final String TAG_REQUESTED_LISTENER = "listener";
11397         static final String ATT_COMPONENT = "component";
11398         static final String ATT_TYPES = "types";
11399         static final String ATT_PKG = "pkg";
11400         static final String ATT_UID = "uid";
11401         static final String TAG_APPROVED = "allowed";
11402         static final String TAG_DISALLOWED= "disallowed";
11403         static final String XML_SEPARATOR = ",";
11404         static final String FLAG_SEPARATOR = "\\|";
11405 
11406         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
11407 
11408         @GuardedBy("mTrustedListenerUids")
11409         private final ArraySet<Integer> mTrustedListenerUids = new ArraySet<>();
11410         @GuardedBy("mRequestedNotificationListeners")
11411         private final ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter>
11412                 mRequestedNotificationListeners = new ArrayMap<>();
11413         private final boolean mIsHeadlessSystemUserMode;
11414 
11415         public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
11416                 IPackageManager pm) {
11417             this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode());
11418         }
11419 
11420         @VisibleForTesting
11421         public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
11422                 IPackageManager pm, boolean isHeadlessSystemUserMode) {
11423             super(context, lock, userProfiles, pm);
11424             this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode;
11425         }
11426 
11427         @Override
11428         protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
11429                 boolean isPrimary, boolean enabled, boolean userSet) {
11430             super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
11431             String pkgName = getPackageName(pkgOrComponent);
11432             if (redactSensitiveNotificationsFromUntrustedListeners()) {
11433                 int uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId);
11434                 if (!enabled && uid >= 0) {
11435                     synchronized (mTrustedListenerUids) {
11436                         mTrustedListenerUids.remove(uid);
11437                     }
11438                 }
11439                 if (enabled && uid >= 0 && isAppTrustedNotificationListenerService(uid, pkgName)) {
11440                     synchronized (mTrustedListenerUids) {
11441                         mTrustedListenerUids.add(uid);
11442                     }
11443                 }
11444             }
11445 
11446             mContext.sendBroadcastAsUser(
11447                     new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED)
11448                             .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
11449                     UserHandle.of(userId), null);
11450         }
11451 
11452         @Override
11453         protected void loadDefaultsFromConfig() {
11454             String defaultListenerAccess = mContext.getResources().getString(
11455                     R.string.config_defaultListenerAccessPackages);
11456             if (defaultListenerAccess != null) {
11457                 String[] listeners =
11458                         defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
11459                 for (int i = 0; i < listeners.length; i++) {
11460                     if (TextUtils.isEmpty(listeners[i])) {
11461                         continue;
11462                     }
11463                     int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
11464                     // In the headless system user mode, packages might not be installed for the
11465                     // system user. Match packages for any user since apps can be installed only for
11466                     // non-system users and would be considering uninstalled for the system user.
11467                     if (mIsHeadlessSystemUserMode) {
11468                         packageQueryFlags += MATCH_ANY_USER;
11469                     }
11470                     ArraySet<ComponentName> approvedListeners =
11471                             this.queryPackageForServices(listeners[i], packageQueryFlags,
11472                                     USER_SYSTEM);
11473                     for (int k = 0; k < approvedListeners.size(); k++) {
11474                         ComponentName cn = approvedListeners.valueAt(k);
11475                         addDefaultComponentOrPackage(cn.flattenToString());
11476                     }
11477                 }
11478             }
11479         }
11480 
11481         @Override
11482         protected int getBindFlags() {
11483             // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE
11484             // because too many 3P apps could be kept in memory as notification listeners and
11485             // cause extreme memory pressure.
11486             // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
11487             return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
11488                     | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
11489         }
11490 
11491         @Override
11492         protected Config getConfig() {
11493             Config c = new Config();
11494             c.caption = "notification listener";
11495             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
11496             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
11497             c.secureSettingName = Secure.ENABLED_NOTIFICATION_LISTENERS;
11498             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
11499             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
11500             c.clientLabel = R.string.notification_listener_binding_label;
11501             return c;
11502         }
11503 
11504         @Override
11505         protected IInterface asInterface(IBinder binder) {
11506             return INotificationListener.Stub.asInterface(binder);
11507         }
11508 
11509         @Override
11510         protected boolean checkType(IInterface service) {
11511             return service instanceof INotificationListener;
11512         }
11513 
11514         @Override
11515         public void onServiceAdded(ManagedServiceInfo info) {
11516             if (lifetimeExtensionRefactor()) {
11517                 // Generally, only System or System UI should have the permissions to call
11518                 // registerSystemService.
11519                 // isCallerSystemOrPhone tells us whether the caller is System. We negate this,
11520                 // to eliminate cases where the service was added by the system. This leaves
11521                 // services registered by system server.
11522                 // To identify system UI, we explicitly check the status bar permission for the
11523                 // uid in the info object.
11524                 // We can't use the calling uid here because it belongs to system server.
11525                 // Note that this will also return true for the shell, but we deem this
11526                 // acceptable, for the purposes of testing.
11527                 info.isSystemUi = !isCallerSystemOrPhone() && getContext().checkPermission(
11528                         android.Manifest.permission.STATUS_BAR_SERVICE, -1, info.uid)
11529                         == PERMISSION_GRANTED;
11530             }
11531             final INotificationListener listener = (INotificationListener) info.service;
11532             final NotificationRankingUpdate update;
11533             synchronized (mNotificationLock) {
11534                 update = makeRankingUpdateLocked(info);
11535                 updateUriPermissionsForActiveNotificationsLocked(info, true);
11536             }
11537             if (redactSensitiveNotificationsFromUntrustedListeners()
11538                     && isAppTrustedNotificationListenerService(
11539                     info.uid, info.component.getPackageName())) {
11540                 synchronized (mTrustedListenerUids) {
11541                     mTrustedListenerUids.add(info.uid);
11542                 }
11543             }
11544             try {
11545                 listener.onListenerConnected(update);
11546             } catch (RemoteException e) {
11547                 // we tried
11548             }
11549         }
11550 
11551         @Override
11552         @GuardedBy("mNotificationLock")
11553         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
11554             updateUriPermissionsForActiveNotificationsLocked(removed, false);
11555             if (removeDisabledHints(removed)) {
11556                 updateListenerHintsLocked();
11557                 updateEffectsSuppressorLocked();
11558             }
11559             if (redactSensitiveNotificationsFromUntrustedListeners()) {
11560                 synchronized (mTrustedListenerUids) {
11561                     mTrustedListenerUids.remove(removed.uid);
11562                 }
11563             }
11564             mLightTrimListeners.remove(removed);
11565         }
11566 
11567         @Override
11568         public void onUserRemoved(int user) {
11569             super.onUserRemoved(user);
11570             synchronized (mRequestedNotificationListeners) {
11571                 for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) {
11572                     if (mRequestedNotificationListeners.keyAt(i).second == user) {
11573                         mRequestedNotificationListeners.removeAt(i);
11574                     }
11575                 }
11576             }
11577         }
11578 
11579         @Override
11580         protected boolean allowRebindForParentUser() {
11581             return true;
11582         }
11583 
11584         @Override
11585         public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
11586             super.onPackagesChanged(removingPackage, pkgList, uidList);
11587 
11588             synchronized (mRequestedNotificationListeners) {
11589                 // Since the default behavior is to allow everything, we don't need to explicitly
11590                 // handle package add or update. they will be added to the xml file on next boot or
11591                 // when the user tries to change the settings.
11592                 if (removingPackage) {
11593                     for (int i = 0; i < pkgList.length; i++) {
11594                         String pkg = pkgList[i];
11595                         int userId = UserHandle.getUserId(uidList[i]);
11596                         for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
11597                             Pair<ComponentName, Integer> key =
11598                                     mRequestedNotificationListeners.keyAt(j);
11599                             if (key.second == userId && key.first.getPackageName().equals(pkg)) {
11600                                 mRequestedNotificationListeners.removeAt(j);
11601                             }
11602                         }
11603                     }
11604 
11605                     // Clean up removed package from the disallowed packages list
11606                     for (int i = 0; i < pkgList.length; i++) {
11607                         String pkg = pkgList[i];
11608                         for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
11609                             NotificationListenerFilter nlf =
11610                                     mRequestedNotificationListeners.valueAt(j);
11611                             VersionedPackage ai = new VersionedPackage(pkg, uidList[i]);
11612                             nlf.removePackage(ai);
11613                         }
11614                     }
11615                 }
11616             }
11617         }
11618 
11619         @Override
11620         protected String getRequiredPermission() {
11621             return null;
11622         }
11623 
11624         @Override
11625         protected boolean shouldReflectToSettings() {
11626             // androidx has a public method that reads the approved set of listeners from
11627             // Settings so we have to continue writing this list for this type of service
11628             return true;
11629         }
11630 
11631         @Override
11632         protected void readExtraTag(String tag, TypedXmlPullParser parser)
11633                 throws IOException, XmlPullParserException {
11634             if (TAG_REQUESTED_LISTENERS.equals(tag)) {
11635                 final int listenersOuterDepth = parser.getDepth();
11636                 while (XmlUtils.nextElementWithin(parser, listenersOuterDepth)) {
11637                     if (!TAG_REQUESTED_LISTENER.equals(parser.getName())) {
11638                         continue;
11639                     }
11640                     final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID);
11641                     final ComponentName cn = ComponentName.unflattenFromString(
11642                             XmlUtils.readStringAttribute(parser, ATT_COMPONENT));
11643                     int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING
11644                             | FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING;
11645 
11646                     ArraySet<VersionedPackage> disallowedPkgs = new ArraySet<>();
11647                     final int listenerOuterDepth = parser.getDepth();
11648                     while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) {
11649                         if (TAG_APPROVED.equals(parser.getName())) {
11650                             approved = XmlUtils.readIntAttribute(parser, ATT_TYPES);
11651                         } else if (TAG_DISALLOWED.equals(parser.getName())) {
11652                             String pkg = XmlUtils.readStringAttribute(parser, ATT_PKG);
11653                             int uid = XmlUtils.readIntAttribute(parser, ATT_UID);
11654                             if (!TextUtils.isEmpty(pkg)) {
11655                                 VersionedPackage ai = new VersionedPackage(pkg, uid);
11656                                 disallowedPkgs.add(ai);
11657                             }
11658                         }
11659                     }
11660                     NotificationListenerFilter nlf =
11661                             new NotificationListenerFilter(approved, disallowedPkgs);
11662                     synchronized (mRequestedNotificationListeners) {
11663                         mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf);
11664                     }
11665                 }
11666             }
11667         }
11668 
11669         @Override
11670         protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
11671             out.startTag(null, TAG_REQUESTED_LISTENERS);
11672             synchronized (mRequestedNotificationListeners) {
11673                 for (Pair<ComponentName, Integer> listener :
11674                         mRequestedNotificationListeners.keySet()) {
11675                     NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener);
11676                     out.startTag(null, TAG_REQUESTED_LISTENER);
11677                     XmlUtils.writeStringAttribute(
11678                             out, ATT_COMPONENT, listener.first.flattenToString());
11679                     XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second);
11680 
11681                     out.startTag(null, TAG_APPROVED);
11682                     XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes());
11683                     out.endTag(null, TAG_APPROVED);
11684 
11685                     for (VersionedPackage ai : nlf.getDisallowedPackages()) {
11686                         if (!TextUtils.isEmpty(ai.getPackageName())) {
11687                             out.startTag(null, TAG_DISALLOWED);
11688                             XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName());
11689                             XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode());
11690                             out.endTag(null, TAG_DISALLOWED);
11691                         }
11692                     }
11693 
11694                     out.endTag(null, TAG_REQUESTED_LISTENER);
11695                 }
11696             }
11697 
11698             out.endTag(null, TAG_REQUESTED_LISTENERS);
11699         }
11700 
11701         @Nullable protected NotificationListenerFilter getNotificationListenerFilter(
11702                 Pair<ComponentName, Integer> pair) {
11703             synchronized (mRequestedNotificationListeners) {
11704                 return mRequestedNotificationListeners.get(pair);
11705             }
11706         }
11707 
11708         protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair,
11709                 NotificationListenerFilter nlf) {
11710             synchronized (mRequestedNotificationListeners) {
11711                 mRequestedNotificationListeners.put(pair, nlf);
11712             }
11713         }
11714 
11715         @Override
11716         protected void ensureFilters(ServiceInfo si, int userId) {
11717             Pair<ComponentName, Integer> listener = Pair.create(si.getComponentName(), userId);
11718             synchronized (mRequestedNotificationListeners) {
11719                 NotificationListenerFilter existingNlf =
11720                         mRequestedNotificationListeners.get(listener);
11721                 if (si.metaData != null) {
11722                     if (existingNlf == null) {
11723                         // no stored filters for this listener; see if they provided a default
11724                         if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
11725                             String typeList =
11726                                     si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
11727                             if (typeList != null) {
11728                                 int types = getTypesFromStringList(typeList);
11729                                 NotificationListenerFilter nlf =
11730                                         new NotificationListenerFilter(types, new ArraySet<>());
11731                                 mRequestedNotificationListeners.put(listener, nlf);
11732                             }
11733                         }
11734                     }
11735 
11736                     // also check the types they never want bridged
11737                     if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
11738                         int neverBridge = getTypesFromStringList(si.metaData.get(
11739                                 META_DATA_DISABLED_FILTER_TYPES).toString());
11740                         if (neverBridge != 0) {
11741                             NotificationListenerFilter nlf =
11742                                     mRequestedNotificationListeners.getOrDefault(
11743                                             listener, new NotificationListenerFilter());
11744                             nlf.setTypes(nlf.getTypes() & ~neverBridge);
11745                             mRequestedNotificationListeners.put(listener, nlf);
11746                         }
11747                     }
11748                 }
11749             }
11750         }
11751 
11752         private int getTypesFromStringList(String typeList) {
11753             int types = 0;
11754             if (typeList != null) {
11755                 String[] typeStrings = typeList.split(FLAG_SEPARATOR);
11756                 for (int i = 0; i < typeStrings.length; i++) {
11757                     final String typeString = typeStrings[i];
11758                     if (TextUtils.isEmpty(typeString)) {
11759                         continue;
11760                     }
11761                     if (typeString.equalsIgnoreCase("ONGOING")) {
11762                         types |= FLAG_FILTER_TYPE_ONGOING;
11763                     } else if (typeString.equalsIgnoreCase("CONVERSATIONS")) {
11764                         types |= FLAG_FILTER_TYPE_CONVERSATIONS;
11765                     } else if (typeString.equalsIgnoreCase("SILENT")) {
11766                         types |= FLAG_FILTER_TYPE_SILENT;
11767                     } else if (typeString.equalsIgnoreCase("ALERTING")) {
11768                         types |= FLAG_FILTER_TYPE_ALERTING;
11769                     } else {
11770                         try {
11771                             types |= Integer.parseInt(typeString);
11772                         } catch (NumberFormatException e) {
11773                             // skip
11774                         }
11775                     }
11776                 }
11777             }
11778             return types;
11779         }
11780 
11781         @GuardedBy("mNotificationLock")
11782         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
11783             if (trim == TRIM_LIGHT) {
11784                 mLightTrimListeners.add(info);
11785             } else {
11786                 mLightTrimListeners.remove(info);
11787             }
11788         }
11789 
11790         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
11791             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
11792         }
11793 
11794         public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
11795             // send to all currently bounds NASes since notifications from both users will appear in
11796             // the status bar
11797             for (final ManagedServiceInfo info : getServices()) {
11798                 mHandler.post(() -> {
11799                     final INotificationListener listener = (INotificationListener) info.service;
11800                     try {
11801                         listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
11802                     } catch (RemoteException ex) {
11803                         Slog.e(TAG, "unable to notify listener "
11804                                 + "(hideSilentStatusIcons): " + info, ex);
11805                     }
11806                 });
11807             }
11808         }
11809 
11810         /**
11811          * Asynchronously notify all listeners about a new or updated notification. Note that the
11812          * notification is new or updated from the point of view of the NLS, but might not be
11813          * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method
11814          * is also invoked after exiting lockdown mode.
11815          *
11816          * <p>
11817          * Also takes care of removing a notification that has been visible to a listener before,
11818          * but isn't anymore.
11819          */
11820         @VisibleForTesting
11821         @GuardedBy("mNotificationLock")
11822         void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
11823             notifyPostedLocked(r, old, true);
11824         }
11825 
11826         /**
11827          * Asynchronously notify all listeners about a new or updated notification. Note that the
11828          * notification is new or updated from the point of view of the NLS, but might not be
11829          * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method
11830          * is invoked after exiting lockdown mode.
11831          *
11832          * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
11833          *                           targeting <= O_MR1
11834          */
11835         @VisibleForTesting
11836         @GuardedBy("mNotificationLock")
11837         void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
11838                 boolean notifyAllListeners) {
11839             for (Runnable listenerCall : prepareNotifyPostedLocked(r, old, notifyAllListeners)) {
11840                 mHandler.post(listenerCall);
11841             }
11842         }
11843 
11844         /**
11845          * "Prepares" to notify all listeners about the posted notification.
11846          *
11847          * <p>This method <em>does not invoke</em> the listeners; the caller should post each
11848          * returned {@link Runnable} on a suitable thread to do so.
11849          *
11850          * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
11851          *                           targeting <= O_MR1
11852          * @return A list of {@link Runnable} operations to notify all listeners about the posted
11853          * notification.
11854          */
11855         @VisibleForTesting
11856         @GuardedBy("mNotificationLock")
11857         List<Runnable> prepareNotifyPostedLocked(NotificationRecord r,
11858                 NotificationRecord old, boolean notifyAllListeners) {
11859             if (isInLockDownMode(r.getUser().getIdentifier())) {
11860                 return new ArrayList<>();
11861             }
11862 
11863             ArrayList<Runnable> listenerCalls = new ArrayList<>();
11864             try {
11865                 // Lazily initialized snapshots of the notification.
11866                 StatusBarNotification sbn = r.getSbn();
11867                 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
11868                 TrimCache trimCache = new TrimCache(sbn);
11869                 TrimCache redactedCache = null;
11870                 StatusBarNotification redactedSbn = null;
11871                 StatusBarNotification oldRedactedSbn = null;
11872                 boolean isNewSensitive = hasSensitiveContent(r);
11873                 boolean isOldSensitive = hasSensitiveContent(old);
11874 
11875                 for (final ManagedServiceInfo info : getServices()) {
11876                     boolean isTrusted = isUidTrusted(info.uid);
11877                     boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners()
11878                             && isNewSensitive && !isTrusted;
11879                     boolean sendOldRedacted = redactSensitiveNotificationsFromUntrustedListeners()
11880                             && isOldSensitive && !isTrusted;
11881                     boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info);
11882                     boolean oldSbnVisible = (oldSbn != null)
11883                             && isVisibleToListener(oldSbn, old.getNotificationType(), info);
11884                     // This notification hasn't been and still isn't visible -> ignore.
11885                     if (!oldSbnVisible && !sbnVisible) {
11886                         continue;
11887                     }
11888                     // If the notification is hidden, don't notifyPosted listeners targeting < P.
11889                     // Instead, those listeners will receive notifyPosted when the notification is
11890                     // unhidden.
11891                     if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
11892                         continue;
11893                     }
11894 
11895                     if (lifetimeExtensionRefactor()) {
11896                         if (sendRedacted && redactedSbn == null) {
11897                             redactedSbn = redactStatusBarNotification(sbn);
11898                             redactedCache = new TrimCache(redactedSbn);
11899                         }
11900                         final StatusBarNotification sbnToPost = sendRedacted
11901                                 ? redactedCache.ForListener(info) : trimCache.ForListener(info);
11902 
11903                         // Checks if this is a request to notify system UI about a notification that
11904                         // has been lifetime extended.
11905                         // (We only need to check old for the flag, because in both cancellation and
11906                         // update cases, old should have the flag, whereas in update cases the
11907                         // new will NOT have the flag.)
11908                         // If it is such a request, and this is system UI, we send the post request
11909                         // only to System UI, and break as we don't need to continue checking other
11910                         // Managed Services.
11911                         if (info.isSystemUi() && old != null && old.getNotification() != null
11912                                 && (old.getNotification().flags
11913                                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) {
11914                             final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
11915                             listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
11916                             break;
11917                         }
11918                     }
11919 
11920                     // If we shouldn't notify all listeners, this means the hidden state of
11921                     // a notification was changed.  Don't notifyPosted listeners targeting >= P.
11922                     // Instead, those listeners will receive notifyRankingUpdate.
11923                     if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
11924                         continue;
11925                     }
11926 
11927                     final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
11928 
11929                     // This notification became invisible -> remove the old one.
11930                     if (oldSbnVisible && !sbnVisible) {
11931                         if (sendOldRedacted && oldRedactedSbn == null) {
11932                             oldRedactedSbn = redactStatusBarNotification(oldSbn);
11933                         }
11934                         final StatusBarNotification oldSbnLightClone =
11935                                 sendOldRedacted ? oldRedactedSbn.cloneLight() : oldSbn.cloneLight();
11936                         listenerCalls.add(() -> notifyRemoved(
11937                                 info, oldSbnLightClone, update, null, REASON_USER_STOPPED));
11938 
11939                         continue;
11940                     }
11941                     // Grant access before listener is notified
11942                     final int targetUserId = (info.userid == USER_ALL)
11943                             ? USER_SYSTEM : info.userid;
11944                     updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
11945 
11946                     mPackageManagerInternal.grantImplicitAccess(
11947                             targetUserId, null /* intent */,
11948                             UserHandle.getAppId(info.uid),
11949                             sbn.getUid(),
11950                             false /* direct */, false /* retainOnUpdate */);
11951 
11952                     if (sendRedacted && redactedSbn == null) {
11953                         redactedSbn = redactStatusBarNotification(sbn);
11954                         redactedCache = new TrimCache(redactedSbn);
11955                     }
11956 
11957                     final StatusBarNotification sbnToPost = sendRedacted
11958                             ? redactedCache.ForListener(info) : trimCache.ForListener(info);
11959                     listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
11960                 }
11961             } catch (Exception e) {
11962                 Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e);
11963             }
11964             return listenerCalls;
11965         }
11966 
11967         boolean isAppTrustedNotificationListenerService(int uid, String pkg) {
11968             if (!redactSensitiveNotificationsFromUntrustedListeners()) {
11969                 return true;
11970             }
11971 
11972             long token = Binder.clearCallingIdentity();
11973             try {
11974                 if (mPackageManager.checkUidPermission(RECEIVE_SENSITIVE_NOTIFICATIONS, uid)
11975                         == PERMISSION_GRANTED || mPackageManagerInternal.isPlatformSigned(pkg)
11976                         || mAppOps
11977                         .noteOpNoThrow(OP_RECEIVE_SENSITIVE_NOTIFICATIONS, uid, pkg, null, null)
11978                         == MODE_ALLOWED) {
11979                     return true;
11980                 }
11981 
11982                 // check if there is a CDM association with the listener
11983                 // We don't listen for changes because if an association is lost, the app loses
11984                 // NLS access
11985                 List<AssociationInfo> cdmAssocs = new ArrayList<>();
11986                 if (mCompanionManager == null) {
11987                     mCompanionManager = getCompanionManager();
11988                 }
11989                 if (mCompanionManager != null) {
11990                     cdmAssocs =
11991                             mCompanionManager.getAllAssociationsForUser(UserHandle.getUserId(uid));
11992                 }
11993                 for (int i = 0; i < cdmAssocs.size(); i++) {
11994                     AssociationInfo assocInfo = cdmAssocs.get(i);
11995                     if (!assocInfo.isRevoked() && pkg.equals(assocInfo.getPackageName())
11996                             && assocInfo.getUserId() == UserHandle.getUserId(uid)) {
11997                         return true;
11998                     }
11999                 }
12000             } catch (RemoteException e) {
12001                 Slog.e(TAG, "Failed to check trusted status of listener", e);
12002             } finally {
12003                 Binder.restoreCallingIdentity(token);
12004             }
12005             return false;
12006         }
12007 
12008         StatusBarNotification redactStatusBarNotification(StatusBarNotification sbn) {
12009             if (!redactSensitiveNotificationsFromUntrustedListeners()) {
12010                 throw new RuntimeException("redactStatusBarNotification called while flag is off");
12011             }
12012 
12013             ApplicationInfo appInfo = sbn.getNotification().extras.getParcelable(
12014                     EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
12015             String pkgLabel;
12016             if (appInfo != null) {
12017                 pkgLabel = appInfo.loadLabel(mPackageManagerClient).toString();
12018             } else {
12019                 Slog.w(TAG, "StatusBarNotification " + sbn + " does not have ApplicationInfo."
12020                         + " Did you pass in a 'cloneLight' notification?");
12021                 pkgLabel = sbn.getPackageName();
12022             }
12023             String redactedText = mContext.getString(R.string.redacted_notification_message);
12024             Notification oldNotif = sbn.getNotification();
12025             Notification oldClone = new Notification();
12026             oldNotif.cloneInto(oldClone, false);
12027             Notification.Builder redactedNotifBuilder =
12028                     new Notification.Builder(getContext(), oldClone);
12029             redactedNotifBuilder.setContentTitle(pkgLabel);
12030             redactedNotifBuilder.setContentText(redactedText);
12031             redactedNotifBuilder.setSubText(null);
12032             redactedNotifBuilder.setActions();
12033             if (oldNotif.actions != null) {
12034                 for (int i = 0; i < oldNotif.actions.length; i++) {
12035                     Notification.Action act =
12036                             new Notification.Action.Builder(oldNotif.actions[i]).build();
12037                     act.title = mContext.getString(R.string.redacted_notification_action_title);
12038                     redactedNotifBuilder.addAction(act);
12039                 }
12040             }
12041 
12042             if (oldNotif.isStyle(MessagingStyle.class)) {
12043                 Person empty = new Person.Builder().setName("").build();
12044                 MessagingStyle messageStyle = new MessagingStyle(empty);
12045                 messageStyle.addMessage(new MessagingStyle.Message(
12046                         redactedText, System.currentTimeMillis(), empty));
12047                 redactedNotifBuilder.setStyle(messageStyle);
12048             }
12049             if (redactSensitiveNotificationsBigTextStyle()
12050                     && oldNotif.isStyle(Notification.BigTextStyle.class)) {
12051                 Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle();
12052                 bigTextStyle.bigText(mContext.getString(R.string.redacted_notification_message));
12053                 bigTextStyle.setBigContentTitle("");
12054                 bigTextStyle.setSummaryText("");
12055                 redactedNotifBuilder.setStyle(bigTextStyle);
12056             }
12057 
12058             Notification redacted = redactedNotifBuilder.build();
12059             // Notification extras can't always be overridden by a builder (configured by a system
12060             // property), so set them after building
12061             if (redacted.extras.containsKey(EXTRA_TITLE_BIG)) {
12062                 redacted.extras.putString(EXTRA_TITLE_BIG, pkgLabel);
12063             }
12064             redacted.extras.remove(EXTRA_SUB_TEXT);
12065             redacted.extras.remove(EXTRA_TEXT_LINES);
12066             redacted.extras.remove(EXTRA_LARGE_ICON_BIG);
12067             return sbn.cloneShallow(redacted);
12068         }
12069 
12070         boolean hasSensitiveContent(NotificationRecord r) {
12071             if (r == null || !redactSensitiveNotificationsFromUntrustedListeners()) {
12072                 return false;
12073             }
12074             return r.hasSensitiveContent();
12075         }
12076 
12077         boolean isUidTrusted(int uid) {
12078             synchronized (mTrustedListenerUids) {
12079                 return !redactSensitiveNotificationsFromUntrustedListeners()
12080                         || mTrustedListenerUids.contains(uid);
12081             }
12082         }
12083 
12084         /**
12085          * Synchronously grant or revoke permissions to Uris for all active and visible
12086          * notifications to just the NotificationListenerService provided.
12087          */
12088         @GuardedBy("mNotificationLock")
12089         private void updateUriPermissionsForActiveNotificationsLocked(
12090                 ManagedServiceInfo info, boolean grant) {
12091             try {
12092                 for (final NotificationRecord r : mNotificationList) {
12093                     // When granting permissions, ignore notifications which are invisible.
12094                     // When revoking permissions, all notifications are invisible, so process all.
12095                     if (grant && !isVisibleToListener(r.getSbn(), r.getNotificationType(), info)) {
12096                         continue;
12097                     }
12098                     // If the notification is hidden, permissions are not required by the listener.
12099                     if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
12100                         continue;
12101                     }
12102                     // Grant or revoke access synchronously
12103                     final int targetUserId = (info.userid == USER_ALL)
12104                             ? USER_SYSTEM : info.userid;
12105                     if (grant) {
12106                         // Grant permissions by passing arguments as if the notification is new.
12107                         updateUriPermissions(/* newRecord */ r, /* oldRecord */ null,
12108                                 info.component.getPackageName(), targetUserId);
12109                     } else {
12110                         // Revoke permissions by passing arguments as if the notification was
12111                         // removed, but set `onlyRevokeCurrentTarget` to avoid revoking permissions
12112                         // granted to *other* targets by this notification's URIs.
12113                         updateUriPermissions(/* newRecord */ null, /* oldRecord */ r,
12114                                 info.component.getPackageName(), targetUserId,
12115                                 /* onlyRevokeCurrentTarget */ true);
12116                     }
12117                 }
12118             } catch (Exception e) {
12119                 Slog.e(TAG, "Could not " + (grant ? "grant" : "revoke") + " Uri permissions to "
12120                         + info.component, e);
12121             }
12122         }
12123 
12124         /**
12125          * asynchronously notify all listeners about a removed notification
12126          */
12127         @GuardedBy("mNotificationLock")
12128         public void notifyRemovedLocked(NotificationRecord r, int reason,
12129                 NotificationStats notificationStats) {
12130             if (isInLockDownMode(r.getUser().getIdentifier())) {
12131                 return;
12132             }
12133 
12134             final StatusBarNotification sbn = r.getSbn();
12135 
12136             // make a copy in case changes are made to the underlying Notification object
12137             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
12138             // notification
12139             final StatusBarNotification sbnLight = sbn.cloneLight();
12140             StatusBarNotification redactedSbn = null;
12141             boolean hasSensitiveContent = hasSensitiveContent(r);
12142             for (final ManagedServiceInfo info : getServices()) {
12143                 if (!isVisibleToListener(sbn, r.getNotificationType(), info)) {
12144                     continue;
12145                 }
12146 
12147                 // don't notifyRemoved for listeners targeting < P
12148                 // if not for reason package suspended
12149                 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
12150                         && info.targetSdkVersion < Build.VERSION_CODES.P) {
12151                     continue;
12152                 }
12153 
12154                 // don't notifyRemoved for listeners targeting >= P
12155                 // if the reason is package suspended
12156                 if (reason == REASON_PACKAGE_SUSPENDED
12157                         && info.targetSdkVersion >= Build.VERSION_CODES.P) {
12158                     continue;
12159                 }
12160 
12161                 boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners()
12162                         && hasSensitiveContent && !isUidTrusted(info.uid);
12163                 if (sendRedacted && redactedSbn == null) {
12164                     redactedSbn = redactStatusBarNotification(sbn);
12165                 }
12166 
12167                 // Only assistants can get stats
12168                 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
12169                         ? notificationStats : null;
12170                 final StatusBarNotification sbnToSend = sendRedacted ? redactedSbn : sbnLight;
12171                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
12172                 mHandler.post(() -> notifyRemoved(info, sbnToSend, update, stats, reason));
12173             }
12174 
12175             // Revoke access after all listeners have been updated
12176             mHandler.post(() -> updateUriPermissions(null, r, null, USER_SYSTEM));
12177         }
12178 
12179         /**
12180          * Asynchronously notify all listeners about a reordering of notifications
12181          * unless changedHiddenNotifications is populated.
12182          * If changedHiddenNotifications is populated, there was a change in the hidden state
12183          * of the notifications.  In this case, we only send updates to listeners that
12184          * target >= P.
12185          */
12186         @GuardedBy("mNotificationLock")
12187         public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
12188             boolean isHiddenRankingUpdate = changedHiddenNotifications != null
12189                     && changedHiddenNotifications.size() > 0;
12190 
12191             // TODO (b/73052211): if the ranking update changed the notification type,
12192             // cancel notifications for NLSes that can't see them anymore
12193             for (final ManagedServiceInfo serviceInfo : getServices()) {
12194                 if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
12195                         serviceInfo, ActivityManager.getCurrentUser())) {
12196                     continue;
12197                 }
12198 
12199                 boolean notifyThisListener = false;
12200                 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
12201                         Build.VERSION_CODES.P) {
12202                     for (NotificationRecord rec : changedHiddenNotifications) {
12203                         if (isVisibleToListener(
12204                                 rec.getSbn(), rec.getNotificationType(), serviceInfo)) {
12205                             notifyThisListener = true;
12206                             break;
12207                         }
12208                     }
12209                 }
12210 
12211                 if (notifyThisListener || !isHiddenRankingUpdate) {
12212                     final NotificationRankingUpdate update = makeRankingUpdateLocked(
12213                             serviceInfo);
12214                     mHandler.post(() -> notifyRankingUpdate(serviceInfo, update));
12215                 }
12216             }
12217         }
12218 
12219         @GuardedBy("mNotificationLock")
12220         public void notifyListenerHintsChangedLocked(final int hints) {
12221             for (final ManagedServiceInfo serviceInfo : getServices()) {
12222                 if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
12223                         serviceInfo, ActivityManager.getCurrentUser())) {
12224                     continue;
12225                 }
12226                 mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints));
12227             }
12228         }
12229 
12230         /**
12231          * asynchronously notify relevant listeners their notification is hidden
12232          * NotificationListenerServices that target P+:
12233          *      NotificationListenerService#notifyRankingUpdateLocked()
12234          * NotificationListenerServices that target <= P:
12235          *      NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
12236          */
12237         @GuardedBy("mNotificationLock")
12238         public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
12239             if (changedNotifications == null || changedNotifications.size() == 0) {
12240                 return;
12241             }
12242 
12243             notifyRankingUpdateLocked(changedNotifications);
12244 
12245             // for listeners that target < P, notifyRemoveLocked
12246             int numChangedNotifications = changedNotifications.size();
12247             for (int i = 0; i < numChangedNotifications; i++) {
12248                 NotificationRecord rec = changedNotifications.get(i);
12249                 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
12250             }
12251         }
12252 
12253         /**
12254          * asynchronously notify relevant listeners their notification is unhidden
12255          * NotificationListenerServices that target P+:
12256          *      NotificationListenerService#notifyRankingUpdateLocked()
12257          * NotificationListenerServices that target <= P:
12258          *      NotificationListeners#notifyPostedLocked()
12259          */
12260         @GuardedBy("mNotificationLock")
12261         public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
12262             if (changedNotifications == null || changedNotifications.size() == 0) {
12263                 return;
12264             }
12265 
12266             notifyRankingUpdateLocked(changedNotifications);
12267 
12268             // for listeners that target < P, notifyPostedLocked
12269             int numChangedNotifications = changedNotifications.size();
12270             for (int i = 0; i < numChangedNotifications; i++) {
12271                 NotificationRecord rec = changedNotifications.get(i);
12272                 notifyPostedLocked(rec, rec, false);
12273             }
12274         }
12275 
12276         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
12277             for (final ManagedServiceInfo serviceInfo : getServices()) {
12278                 if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
12279                         serviceInfo, ActivityManager.getCurrentUser())) {
12280                     continue;
12281                 }
12282                 mHandler.post(
12283                         () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter));
12284             }
12285         }
12286 
12287         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
12288                 final NotificationChannel channel, final int modificationType) {
12289             if (channel == null) {
12290                 return;
12291             }
12292             for (final ManagedServiceInfo info : getServices()) {
12293                 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
12294                         || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
12295                     continue;
12296                 }
12297 
12298                 BackgroundThread.getHandler().post(() -> {
12299                     if (info.isSystem
12300                             || hasCompanionDevice(info)
12301                             || isServiceTokenValid(info.service)) {
12302                         notifyNotificationChannelChanged(
12303                                 info, pkg, user, channel, modificationType);
12304                     }
12305                 });
12306             }
12307         }
12308 
12309         protected void notifyNotificationChannelGroupChanged(
12310                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
12311                 final int modificationType) {
12312             if (group == null) {
12313                 return;
12314             }
12315             for (final ManagedServiceInfo info : getServices()) {
12316                 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
12317                         || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
12318                     continue;
12319                 }
12320 
12321                 BackgroundThread.getHandler().post(() -> {
12322                     if (info.isSystem() || hasCompanionDevice(info)) {
12323                         notifyNotificationChannelGroupChanged(
12324                                 info, pkg, user, group, modificationType);
12325                     }
12326                 });
12327             }
12328         }
12329 
12330         private void notifyPosted(final ManagedServiceInfo info,
12331                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
12332             final INotificationListener listener = (INotificationListener) info.service;
12333             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
12334             try {
12335                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
12336             } catch (DeadObjectException ex) {
12337                 Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex);
12338             } catch (RemoteException ex) {
12339                 Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
12340             }
12341         }
12342 
12343         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
12344                 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
12345             final INotificationListener listener = (INotificationListener) info.service;
12346             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
12347             try {
12348                 if (!CompatChanges.isChangeEnabled(NOTIFICATION_CANCELLATION_REASONS, info.uid)
12349                         && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
12350                     reason = REASON_CHANNEL_BANNED;
12351                 }
12352                 // apps before T don't know about REASON_ASSISTANT, so replace it with the
12353                 // previously-used case, REASON_LISTENER_CANCEL
12354                 if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid)
12355                         && reason == REASON_ASSISTANT_CANCEL) {
12356                     reason = REASON_LISTENER_CANCEL;
12357                 }
12358                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
12359             } catch (DeadObjectException ex) {
12360                 Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex);
12361             } catch (RemoteException ex) {
12362                 Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
12363             }
12364         }
12365 
12366         private void notifyRankingUpdate(ManagedServiceInfo info,
12367                                          NotificationRankingUpdate rankingUpdate) {
12368             final INotificationListener listener = (INotificationListener) info.service;
12369             try {
12370                 listener.onNotificationRankingUpdate(rankingUpdate);
12371             } catch (DeadObjectException ex) {
12372                 Slog.wtf(TAG, "unable to notify listener (ranking update): " + info, ex);
12373             } catch (RemoteException ex) {
12374                 Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
12375             }
12376         }
12377 
12378         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
12379             final INotificationListener listener = (INotificationListener) info.service;
12380             try {
12381                 listener.onListenerHintsChanged(hints);
12382             } catch (RemoteException ex) {
12383                 Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex);
12384             }
12385         }
12386 
12387         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
12388                 int interruptionFilter) {
12389             final INotificationListener listener = (INotificationListener) info.service;
12390             try {
12391                 listener.onInterruptionFilterChanged(interruptionFilter);
12392             } catch (RemoteException ex) {
12393                 Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex);
12394             }
12395         }
12396 
12397         void notifyNotificationChannelChanged(ManagedServiceInfo info,
12398                 final String pkg, final UserHandle user, final NotificationChannel channel,
12399                 final int modificationType) {
12400             final INotificationListener listener = (INotificationListener) info.service;
12401             try {
12402                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
12403             } catch (RemoteException ex) {
12404                 Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex);
12405             }
12406         }
12407 
12408         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
12409                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
12410                 final int modificationType) {
12411             final INotificationListener listener = (INotificationListener) info.getService();
12412             try {
12413                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
12414             } catch (RemoteException ex) {
12415                 Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex);
12416             }
12417         }
12418 
12419         public boolean isListenerPackage(String packageName) {
12420             if (packageName == null) {
12421                 return false;
12422             }
12423             // TODO: clean up locking object later
12424             synchronized (mNotificationLock) {
12425                 for (final ManagedServiceInfo serviceInfo : getServices()) {
12426                     if (packageName.equals(serviceInfo.component.getPackageName())) {
12427                         return true;
12428                     }
12429                 }
12430             }
12431             return false;
12432         }
12433 
12434         // Returns whether there is a component with listener access granted that is associated
12435         // with the given package name / user ID.
12436         boolean hasAllowedListener(String packageName, int userId) {
12437             if (packageName == null) {
12438                 return false;
12439             }
12440 
12441             // Loop through allowed components to compare package names
12442             List<ComponentName> allowedComponents = getAllowedComponents(userId);
12443             for (int i = 0; i < allowedComponents.size(); i++) {
12444                 if (allowedComponents.get(i).getPackageName().equals(packageName)) {
12445                     return true;
12446                 }
12447             }
12448             return false;
12449         }
12450     }
12451 
12452     @GuardedBy("mNotificationLock")
12453     private void broadcastToCallNotificationEventCallbacks(
12454             final RemoteCallbackList<ICallNotificationEventCallback> callbackList,
12455             final NotificationRecord r,
12456             boolean isPosted) {
12457         if (callbackList != null) {
12458             int numCallbacks = callbackList.beginBroadcast();
12459             try {
12460                 for (int i = 0; i < numCallbacks; i++) {
12461                     if (isPosted) {
12462                         callbackList.getBroadcastItem(i)
12463                                 .onCallNotificationPosted(r.getSbn().getPackageName(), r.getUser());
12464                     } else {
12465                         callbackList.getBroadcastItem(i)
12466                                 .onCallNotificationRemoved(r.getSbn().getPackageName(),
12467                                     r.getUser());
12468                     }
12469                 }
12470             } catch (RemoteException e) {
12471                 throw new RuntimeException(e);
12472             }
12473             callbackList.finishBroadcast();
12474         }
12475     }
12476 
12477     @GuardedBy("mNotificationLock")
12478     void notifyCallNotificationEventListenerOnPosted(final NotificationRecord r) {
12479         if (!r.getNotification().isStyle(Notification.CallStyle.class)) {
12480             return;
12481         }
12482 
12483         synchronized (mCallNotificationEventCallbacks) {
12484             ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
12485                     callbacksForPackage =
12486                     mCallNotificationEventCallbacks.get(r.getSbn().getPackageName());
12487             if (callbacksForPackage == null) {
12488                 return;
12489             }
12490 
12491             if (!r.getUser().equals(UserHandle.ALL)) {
12492                 broadcastToCallNotificationEventCallbacks(
12493                         callbacksForPackage.get(r.getUser().getIdentifier()), r, true);
12494                 // Also notify the listeners registered for USER_ALL
12495                 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r,
12496                         true);
12497             } else {
12498                 // Notify listeners registered for any userId
12499                 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList
12500                         : callbacksForPackage.values()) {
12501                     broadcastToCallNotificationEventCallbacks(callbackList, r, true);
12502                 }
12503             }
12504         }
12505     }
12506 
12507     @GuardedBy("mNotificationLock")
12508     void notifyCallNotificationEventListenerOnRemoved(final NotificationRecord r) {
12509         if (!r.getNotification().isStyle(Notification.CallStyle.class)) {
12510             return;
12511         }
12512 
12513         synchronized (mCallNotificationEventCallbacks) {
12514             ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
12515                     callbacksForPackage =
12516                     mCallNotificationEventCallbacks.get(r.getSbn().getPackageName());
12517             if (callbacksForPackage == null) {
12518                 return;
12519             }
12520 
12521             if (!r.getUser().equals(UserHandle.ALL)) {
12522                 broadcastToCallNotificationEventCallbacks(
12523                         callbacksForPackage.get(r.getUser().getIdentifier()), r, false);
12524                 // Also notify the listeners registered for USER_ALL
12525                 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r,
12526                         false);
12527             } else {
12528                 // Notify listeners registered for any userId
12529                 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList
12530                         : callbacksForPackage.values()) {
12531                     broadcastToCallNotificationEventCallbacks(callbackList, r, false);
12532                 }
12533             }
12534         }
12535     }
12536 
12537     // TODO (b/194833441): remove when we've fully migrated to a permission
12538     class RoleObserver implements OnRoleHoldersChangedListener {
12539         // Role name : user id : list of approved packages
12540         private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
12541 
12542         /**
12543          * Writes should be pretty rare (only when default browser changes) and reads are done
12544          * during activity start code-path, so we're optimizing for reads. This means this set is
12545          * immutable once written and we'll recreate the set every time there is a role change and
12546          * then assign that new set to the volatile below, so reads can be done without needing to
12547          * hold a lock. Every write is done on the main-thread, so write atomicity is guaranteed.
12548          *
12549          * Didn't use unmodifiable set to enforce immutability to avoid iterating via iterators.
12550          */
12551         private volatile ArraySet<Integer> mTrampolineExemptUids = new ArraySet<>();
12552 
12553         private final RoleManager mRm;
12554         private final IPackageManager mPm;
12555         private final Executor mExecutor;
12556         private final Looper mMainLooper;
12557 
12558         RoleObserver(Context context, @NonNull RoleManager roleManager,
12559                 @NonNull IPackageManager pkgMgr, @NonNull Looper mainLooper) {
12560             mRm = roleManager;
12561             mPm = pkgMgr;
12562             mExecutor = context.getMainExecutor();
12563             mMainLooper = mainLooper;
12564         }
12565 
12566         /** Should be called from the main-thread. */
12567         @MainThread
12568         public void init() {
12569             List<UserHandle> users = mUm.getUserHandles(/* excludeDying */ true);
12570             mNonBlockableDefaultApps = new ArrayMap<>();
12571             for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
12572                 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
12573                 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
12574                 for (int j = 0; j < users.size(); j++) {
12575                     Integer userId = users.get(j).getIdentifier();
12576                     ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
12577                             NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
12578                     ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
12579                     for (String pkg : approvedForUserId) {
12580                         approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
12581                     }
12582                     userToApprovedList.put(userId, approvedForUserId);
12583                     mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
12584                 }
12585             }
12586             updateTrampolineExemptUidsForUsers(users.toArray(new UserHandle[0]));
12587             mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
12588         }
12589 
12590         void destroy() {
12591             mRm.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.ALL);
12592         }
12593 
12594         @VisibleForTesting
12595         public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
12596             return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
12597         }
12598 
12599         @VisibleForTesting
12600         public boolean isUidExemptFromTrampolineRestrictions(int uid) {
12601             return mTrampolineExemptUids.contains(uid);
12602         }
12603 
12604         /**
12605          * Convert the assistant-role holder into settings. The rest of the system uses the
12606          * settings.
12607          *
12608          * @param roleName the name of the role whose holders are changed
12609          * @param user the user for this role holder change
12610          */
12611         @Override
12612         public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
12613             onRoleHoldersChangedForNonBlockableDefaultApps(roleName, user);
12614             onRoleHoldersChangedForTrampolines(roleName, user);
12615         }
12616 
12617         private void onRoleHoldersChangedForNonBlockableDefaultApps(@NonNull String roleName,
12618                 @NonNull UserHandle user) {
12619             // we only care about a couple of the roles they'll tell us about
12620             boolean relevantChange = false;
12621             for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
12622                 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
12623                     relevantChange = true;
12624                     break;
12625                 }
12626             }
12627 
12628             if (!relevantChange) {
12629                 return;
12630             }
12631 
12632             ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
12633 
12634             // find the diff
12635             ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
12636                     mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
12637             ArraySet<String> previouslyApproved =
12638                     prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
12639 
12640             ArraySet<String> toRemove = new ArraySet<>();
12641             ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
12642 
12643             for (String previous : previouslyApproved) {
12644                 if (!roleHolders.contains(previous)) {
12645                     toRemove.add(previous);
12646                 }
12647             }
12648             for (String nowApproved : roleHolders) {
12649                 if (!previouslyApproved.contains(nowApproved)) {
12650                     toAdd.add(new Pair(nowApproved,
12651                             getUidForPackage(nowApproved, user.getIdentifier())));
12652                 }
12653             }
12654 
12655             // store newly approved apps
12656             prevApprovedForRole.put(user.getIdentifier(), roleHolders);
12657             mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
12658 
12659             // update what apps can be blocked
12660             mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
12661 
12662             // RoleManager is the source of truth for this data so we don't need to trigger a
12663             // write of the notification policy xml for this change
12664         }
12665 
12666         private void onRoleHoldersChangedForTrampolines(@NonNull String roleName,
12667                 @NonNull UserHandle user) {
12668             if (!RoleManager.ROLE_BROWSER.equals(roleName)) {
12669                 return;
12670             }
12671             updateTrampolineExemptUidsForUsers(user);
12672         }
12673 
12674         private void updateTrampolineExemptUidsForUsers(UserHandle... users) {
12675             Preconditions.checkState(mMainLooper.isCurrentThread());
12676             ArraySet<Integer> oldUids = mTrampolineExemptUids;
12677             ArraySet<Integer> newUids = new ArraySet<>();
12678             // Add the uids from previous set for the users that we won't update.
12679             for (int i = 0, n = oldUids.size(); i < n; i++) {
12680                 int uid = oldUids.valueAt(i);
12681                 UserHandle user = UserHandle.of(UserHandle.getUserId(uid));
12682                 if (!ArrayUtils.contains(users, user)) {
12683                     newUids.add(uid);
12684                 }
12685             }
12686             // Now lookup the new uids for the users that we want to update.
12687             for (int i = 0, n = users.length; i < n; i++) {
12688                 UserHandle user = users[i];
12689                 for (String pkg : mRm.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, user)) {
12690                     int uid = getUidForPackage(pkg, user.getIdentifier());
12691                     if (uid != -1) {
12692                         newUids.add(uid);
12693                     } else {
12694                         Slog.e(TAG, "Bad uid (-1) for browser package " + pkg);
12695                     }
12696                 }
12697             }
12698             mTrampolineExemptUids = newUids;
12699         }
12700 
12701         private int getUidForPackage(String pkg, int userId) {
12702             try {
12703                 return mPm.getPackageUid(pkg, MATCH_ALL, userId);
12704             } catch (RemoteException e) {
12705                 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
12706             }
12707             return -1;
12708         }
12709     }
12710 
12711     public static final class DumpFilter {
12712         public boolean filtered = false;
12713         public String pkgFilter;
12714         public boolean zen;
12715         public long since;
12716         public boolean stats;
12717         public boolean rvStats;
12718         public boolean redact = true;
12719         public boolean proto = false;
12720         public boolean criticalPriority = false;
12721         public boolean normalPriority = false;
12722 
12723         @NonNull
12724         public static DumpFilter parseFromArguments(String[] args) {
12725             final DumpFilter filter = new DumpFilter();
12726             for (int ai = 0; ai < args.length; ai++) {
12727                 final String a = args[ai];
12728                 if ("--proto".equals(a)) {
12729                     filter.proto = true;
12730                 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
12731                     filter.redact = false;
12732                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
12733                     if (ai < args.length-1) {
12734                         ai++;
12735                         filter.pkgFilter = args[ai].trim().toLowerCase();
12736                         if (filter.pkgFilter.isEmpty()) {
12737                             filter.pkgFilter = null;
12738                         } else {
12739                             filter.filtered = true;
12740                         }
12741                     }
12742                 } else if ("--zen".equals(a) || "zen".equals(a)) {
12743                     filter.filtered = true;
12744                     filter.zen = true;
12745                 } else if ("--stats".equals(a)) {
12746                     filter.stats = true;
12747                     if (ai < args.length-1) {
12748                         ai++;
12749                         filter.since = Long.parseLong(args[ai]);
12750                     } else {
12751                         filter.since = 0;
12752                     }
12753                 } else if ("--remote-view-stats".equals(a)) {
12754                     filter.rvStats = true;
12755                     if (ai < args.length-1) {
12756                         ai++;
12757                         filter.since = Long.parseLong(args[ai]);
12758                     } else {
12759                         filter.since = 0;
12760                     }
12761                 } else if (PRIORITY_ARG.equals(a)) {
12762                     // Bugreport will call the service twice with priority arguments, first to dump
12763                     // critical sections and then non critical ones. Set appropriate filters
12764                     // to generate the desired data.
12765                     if (ai < args.length - 1) {
12766                         ai++;
12767                         switch (args[ai]) {
12768                             case PRIORITY_ARG_CRITICAL:
12769                                 filter.criticalPriority = true;
12770                                 break;
12771                             case PRIORITY_ARG_NORMAL:
12772                                 filter.normalPriority = true;
12773                                 break;
12774                         }
12775                     }
12776                 }
12777             }
12778             return filter;
12779         }
12780 
12781         public boolean matches(StatusBarNotification sbn) {
12782             if (!filtered) return true;
12783             return zen ? true : sbn != null
12784                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
12785         }
12786 
12787         public boolean matches(ComponentName component) {
12788             if (!filtered) return true;
12789             return zen ? true : component != null && matches(component.getPackageName());
12790         }
12791 
12792         public boolean matches(String pkg) {
12793             if (!filtered) return true;
12794             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
12795         }
12796 
12797         @Override
12798         public String toString() {
12799             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
12800         }
12801     }
12802 
12803     @VisibleForTesting
12804     void resetAssistantUserSet(int userId) {
12805         checkCallerIsSystemOrShell();
12806         mAssistants.setUserSet(userId, false);
12807         handleSavePolicyFile();
12808     }
12809 
12810     @VisibleForTesting
12811     @Nullable
12812     ComponentName getApprovedAssistant(int userId) {
12813         checkCallerIsSystemOrShell();
12814         List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
12815         return CollectionUtils.firstOrNull(allowedComponents);
12816     }
12817 
12818     /**
12819      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
12820      * binder without sending large amounts of data over a oneway transaction.
12821      */
12822     private static final class StatusBarNotificationHolder
12823             extends IStatusBarNotificationHolder.Stub {
12824         private StatusBarNotification mValue;
12825 
12826         public StatusBarNotificationHolder(StatusBarNotification value) {
12827             mValue = value;
12828         }
12829 
12830         /** Get the held value and clear it. This function should only be called once per holder */
12831         @Override
12832         public StatusBarNotification get() {
12833             StatusBarNotification value = mValue;
12834             mValue = null;
12835             return value;
12836         }
12837     }
12838 
12839     private void writeSecureNotificationsPolicy(TypedXmlSerializer out) throws IOException {
12840         out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
12841         out.attributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
12842                 mLockScreenAllowSecureNotifications);
12843         out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
12844     }
12845 
12846     // Creates a notification that informs the user about changes due to the migration to
12847     // use permissions for notifications.
12848     protected Notification createReviewPermissionsNotification() {
12849         int title = R.string.review_notification_settings_title;
12850         int content = R.string.review_notification_settings_text;
12851 
12852         // Tapping on the notification leads to the settings screen for managing app notifications,
12853         // using the intent reserved for system services to indicate it comes from this notification
12854         Intent tapIntent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS_FOR_REVIEW);
12855         Intent remindIntent = new Intent(REVIEW_NOTIF_ACTION_REMIND);
12856         Intent dismissIntent = new Intent(REVIEW_NOTIF_ACTION_DISMISS);
12857         Intent swipeIntent = new Intent(REVIEW_NOTIF_ACTION_CANCELED);
12858 
12859         // Both "remind me" and "dismiss" actions will be actions received by the BroadcastReceiver
12860         final Notification.Action remindMe = new Notification.Action.Builder(null,
12861                 getContext().getResources().getString(
12862                         R.string.review_notification_settings_remind_me_action),
12863                 PendingIntent.getBroadcast(
12864                         getContext(), 0, remindIntent,
12865                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
12866                 .build();
12867         final Notification.Action dismiss = new Notification.Action.Builder(null,
12868                 getContext().getResources().getString(
12869                         R.string.review_notification_settings_dismiss),
12870                 PendingIntent.getBroadcast(
12871                         getContext(), 0, dismissIntent,
12872                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
12873                 .build();
12874 
12875         return new Notification.Builder(getContext(), SystemNotificationChannels.SYSTEM_CHANGES)
12876                 .setSmallIcon(R.drawable.stat_sys_adb)
12877                 .setContentTitle(getContext().getResources().getString(title))
12878                 .setContentText(getContext().getResources().getString(content))
12879                 .setContentIntent(PendingIntent.getActivity(getContext(), 0, tapIntent,
12880                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
12881                 .setStyle(new Notification.BigTextStyle())
12882                 .setFlag(FLAG_NO_CLEAR, true)
12883                 .setAutoCancel(true)
12884                 .addAction(remindMe)
12885                 .addAction(dismiss)
12886                 .setDeleteIntent(PendingIntent.getBroadcast(getContext(), 0, swipeIntent,
12887                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
12888                 .build();
12889     }
12890 
12891     protected void maybeShowInitialReviewPermissionsNotification() {
12892         if (!mShowReviewPermissionsNotification) {
12893             // if this notification is disabled by settings do not ever show it
12894             return;
12895         }
12896 
12897         int currentState = Settings.Global.getInt(getContext().getContentResolver(),
12898                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
12899                 REVIEW_NOTIF_STATE_UNKNOWN);
12900 
12901         // now check the last known state of the notification -- this determination of whether the
12902         // user is in the correct target audience occurs elsewhere, and will have written the
12903         // REVIEW_NOTIF_STATE_SHOULD_SHOW to indicate it should be shown in the future.
12904         //
12905         // alternatively, if the user has rescheduled the notification (so it has been shown
12906         // again) but not yet interacted with the new notification, then show it again on boot,
12907         // as this state indicates that the user had the notification open before rebooting.
12908         //
12909         // sending the notification here does not record a new state for the notification;
12910         // that will be written by parts of the system further down the line if at any point
12911         // the user interacts with the notification.
12912         if (currentState == REVIEW_NOTIF_STATE_SHOULD_SHOW
12913                 || currentState == REVIEW_NOTIF_STATE_RESHOWN) {
12914             NotificationManager nm = getContext().getSystemService(NotificationManager.class);
12915             nm.notify(TAG,
12916                     SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS,
12917                     createReviewPermissionsNotification());
12918         }
12919     }
12920 
12921     /**
12922      * Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too
12923      * aggressive and annoying the user.
12924      *
12925      * TODO(b/161957908): Remove dogfooder toast.
12926      */
12927     private class NotificationTrampolineCallback implements BackgroundActivityStartCallback {
12928         @Override
12929         public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid,
12930                 String packageName) {
12931             checkArgument(!tokens.isEmpty());
12932             for (IBinder token : tokens) {
12933                 if (token != ALLOWLIST_TOKEN) {
12934                     // We only block or warn if the start is exclusively due to notification
12935                     return true;
12936                 }
12937             }
12938             String logcatMessage =
12939                     "Indirect notification activity start (trampoline) from " + packageName;
12940             if (blockTrampoline(uid)) {
12941                 Slog.e(TAG, logcatMessage + " blocked");
12942                 return false;
12943             } else {
12944                 Slog.w(TAG, logcatMessage + ", this should be avoided for performance reasons");
12945                 return true;
12946             }
12947         }
12948 
12949         private boolean blockTrampoline(int uid) {
12950             if (mRoleObserver != null && mRoleObserver.isUidExemptFromTrampolineRestrictions(uid)) {
12951                 return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES,
12952                         uid);
12953             }
12954             return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid);
12955         }
12956 
12957         @Override
12958         public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) {
12959             // If the start is allowed via notification, we allow the app to close system dialogs
12960             // only if their targetSdk < S, otherwise they have no valid reason to do this since
12961             // trampolines are blocked.
12962             return tokens.contains(ALLOWLIST_TOKEN)
12963                     && !CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid);
12964         }
12965     }
12966 
12967     interface PostNotificationTrackerFactory {
12968         default PostNotificationTracker newTracker(@Nullable WakeLock optionalWakelock) {
12969             return new PostNotificationTracker(optionalWakelock);
12970         }
12971     }
12972 
12973     static class PostNotificationTracker {
12974         @ElapsedRealtimeLong private final long mStartTime;
12975         @Nullable private final WakeLock mWakeLock;
12976         private boolean mOngoing;
12977 
12978         @VisibleForTesting
12979         PostNotificationTracker(@Nullable WakeLock wakeLock) {
12980             mStartTime = SystemClock.elapsedRealtime();
12981             mWakeLock = wakeLock;
12982             mOngoing = true;
12983             if (DBG) {
12984                 Slog.d(TAG, "PostNotification: Started");
12985             }
12986         }
12987 
12988         @ElapsedRealtimeLong
12989         long getStartTime() {
12990             return mStartTime;
12991         }
12992 
12993         @VisibleForTesting
12994         boolean isOngoing() {
12995             return mOngoing;
12996         }
12997 
12998         /**
12999          * Cancels the tracker (releasing the acquired WakeLock). Either {@link #finish} or
13000          * {@link #cancel} (exclusively) should be called on this object before it's discarded.
13001          */
13002         void cancel() {
13003             if (!isOngoing()) {
13004                 Log.wtfStack(TAG, "cancel() called on already-finished tracker");
13005                 return;
13006             }
13007             mOngoing = false;
13008             if (mWakeLock != null) {
13009                 Binder.withCleanCallingIdentity(() -> mWakeLock.release());
13010             }
13011             if (DBG) {
13012                 long elapsedTime = SystemClock.elapsedRealtime() - mStartTime;
13013                 Slog.d(TAG, TextUtils.formatSimple("PostNotification: Abandoned after %d ms",
13014                         elapsedTime));
13015             }
13016         }
13017 
13018         /**
13019          * Finishes the tracker (releasing the acquired WakeLock) and returns the time elapsed since
13020          * the operation started, in milliseconds. Either {@link #finish} or {@link #cancel}
13021          * (exclusively) should be called on this object before it's discarded.
13022          */
13023         @DurationMillisLong
13024         long finish() {
13025             long elapsedTime = SystemClock.elapsedRealtime() - mStartTime;
13026             if (!isOngoing()) {
13027                 Log.wtfStack(TAG, "finish() called on already-finished tracker");
13028                 return elapsedTime;
13029             }
13030             mOngoing = false;
13031             if (mWakeLock != null) {
13032                 Binder.withCleanCallingIdentity(() -> mWakeLock.release());
13033             }
13034             if (DBG) {
13035                 Slog.d(TAG,
13036                         TextUtils.formatSimple("PostNotification: Finished in %d ms", elapsedTime));
13037             }
13038             return elapsedTime;
13039         }
13040     }
13041 }
13042