• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.notification;
18 
19 import static android.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.nmSummarization;
30 import static android.app.Flags.nmSummarizationUi;
31 import static android.app.Flags.notificationClassificationUi;
32 import static android.app.Flags.sortSectionByTime;
33 import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
34 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
35 import static android.app.Notification.EXTRA_LARGE_ICON_BIG;
36 import static android.app.Notification.EXTRA_SUB_TEXT;
37 import static android.app.Notification.EXTRA_TEXT;
38 import static android.app.Notification.EXTRA_TEXT_LINES;
39 import static android.app.Notification.EXTRA_TITLE;
40 import static android.app.Notification.EXTRA_TITLE_BIG;
41 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
42 import static android.app.Notification.FLAG_AUTO_CANCEL;
43 import static android.app.Notification.FLAG_BUBBLE;
44 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
45 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
46 import static android.app.Notification.FLAG_GROUP_SUMMARY;
47 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
48 import static android.app.Notification.FLAG_NO_CLEAR;
49 import static android.app.Notification.FLAG_NO_DISMISS;
50 import static android.app.Notification.FLAG_ONGOING_EVENT;
51 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
52 import static android.app.Notification.FLAG_PROMOTED_ONGOING;
53 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
54 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
55 import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
56 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
57 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
58 import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED;
59 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
60 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL;
61 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
62 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
63 import static android.app.NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED;
64 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
65 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED;
66 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
67 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
68 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
69 import static android.app.NotificationManager.EXTRA_NOTIFICATION_POLICY;
70 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
71 import static android.app.NotificationManager.IMPORTANCE_LOW;
72 import static android.app.NotificationManager.IMPORTANCE_MIN;
73 import static android.app.NotificationManager.IMPORTANCE_NONE;
74 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
78 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
79 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
80 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
81 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
82 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
83 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
84 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
85 import static android.app.NotificationManager.zenModeFromInterruptionFilter;
86 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED;
87 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED;
88 import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
89 import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING;
90 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
91 import static android.content.Context.BIND_AUTO_CREATE;
92 import static android.content.Context.BIND_FOREGROUND_SERVICE;
93 import static android.content.Context.BIND_NOT_PERCEPTIBLE;
94 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
95 import static android.content.pm.PackageManager.FEATURE_TELECOM;
96 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
97 import static android.content.pm.PackageManager.MATCH_ALL;
98 import static android.content.pm.PackageManager.MATCH_ANY_USER;
99 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
100 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
101 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
102 import static android.os.Flags.allowPrivateProfile;
103 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
104 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
105 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
106 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
107 import static android.os.UserHandle.USER_ALL;
108 import static android.os.UserHandle.USER_NULL;
109 import static android.os.UserHandle.USER_SYSTEM;
110 import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
111 import static android.service.notification.Adjustment.KEY_TYPE;
112 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
113 import static android.service.notification.Adjustment.TYPE_NEWS;
114 import static android.service.notification.Adjustment.TYPE_PROMOTION;
115 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
116 import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT;
117 import static android.service.notification.Flags.callstyleCallbackApi;
118 import static android.service.notification.Flags.notificationClassification;
119 import static android.service.notification.Flags.notificationForceGrouping;
120 import static android.service.notification.Flags.notificationRegroupOnClassification;
121 import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle;
122 import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners;
123 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
124 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
125 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
126 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
127 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
128 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
129 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
130 import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES;
131 import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES;
132 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
133 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
134 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
135 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
136 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
137 import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
138 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
139 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
140 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
141 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_REMOVED;
142 import static android.service.notification.NotificationListenerService.REASON_CLEAR_DATA;
143 import static android.service.notification.NotificationListenerService.REASON_CLICK;
144 import static android.service.notification.NotificationListenerService.REASON_ERROR;
145 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
146 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
147 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
148 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
149 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
150 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
151 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
152 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
153 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
154 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
155 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
156 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
157 import static android.service.notification.NotificationListenerService.Ranking.RANKING_DEMOTED;
158 import static android.service.notification.NotificationListenerService.Ranking.RANKING_PROMOTED;
159 import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED;
160 import static android.service.notification.NotificationListenerService.TRIM_FULL;
161 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
162 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
163 import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
164 
165 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
166 import static com.android.internal.util.FrameworkStatsLog.NOTIFICATION_BUNDLE_PREFERENCES;
167 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
168 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
169 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
170 import static com.android.internal.util.Preconditions.checkArgument;
171 import static com.android.internal.util.Preconditions.checkNotNull;
172 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
173 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
174 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
175 import static com.android.server.notification.Flags.expireBitmaps;
176 import static com.android.server.notification.Flags.managedServicesConcurrentMultiuser;
177 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER;
178 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
179 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
180 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
181 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
182 
183 import android.Manifest;
184 import android.Manifest.permission;
185 import android.annotation.DurationMillisLong;
186 import android.annotation.ElapsedRealtimeLong;
187 import android.annotation.EnforcePermission;
188 import android.annotation.FlaggedApi;
189 import android.annotation.MainThread;
190 import android.annotation.NonNull;
191 import android.annotation.Nullable;
192 import android.annotation.RequiresPermission;
193 import android.annotation.UserIdInt;
194 import android.annotation.WorkerThread;
195 import android.app.ActivityManager;
196 import android.app.ActivityManagerInternal;
197 import android.app.ActivityManagerInternal.ServiceNotificationPolicy;
198 import android.app.ActivityTaskManager;
199 import android.app.AlarmManager;
200 import android.app.AppGlobals;
201 import android.app.AppOpsManager;
202 import android.app.AutomaticZenRule;
203 import android.app.IActivityManager;
204 import android.app.ICallNotificationEventCallback;
205 import android.app.INotificationManager;
206 import android.app.ITransientNotification;
207 import android.app.ITransientNotificationCallback;
208 import android.app.IUriGrantsManager;
209 import android.app.Notification;
210 import android.app.Notification.MessagingStyle;
211 import android.app.NotificationChannel;
212 import android.app.NotificationChannelGroup;
213 import android.app.NotificationHistory;
214 import android.app.NotificationHistory.HistoricalNotification;
215 import android.app.NotificationManager;
216 import android.app.NotificationManager.Policy;
217 import android.app.PendingIntent;
218 import android.app.Person;
219 import android.app.RemoteServiceException.BadForegroundServiceNotificationException;
220 import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException;
221 import android.app.StatsManager;
222 import android.app.UriGrantsManager;
223 import android.app.ZenBypassingApp;
224 import android.app.admin.DevicePolicyManagerInternal;
225 import android.app.backup.BackupManager;
226 import android.app.backup.BackupRestoreEventLogger;
227 import android.app.compat.CompatChanges;
228 import android.app.role.OnRoleHoldersChangedListener;
229 import android.app.role.RoleManager;
230 import android.app.usage.UsageEvents;
231 import android.app.usage.UsageStatsManagerInternal;
232 import android.companion.AssociationInfo;
233 import android.companion.AssociationRequest;
234 import android.companion.ICompanionDeviceManager;
235 import android.compat.annotation.ChangeId;
236 import android.compat.annotation.EnabledAfter;
237 import android.compat.annotation.EnabledSince;
238 import android.compat.annotation.LoggingOnly;
239 import android.content.AttributionSource;
240 import android.content.BroadcastReceiver;
241 import android.content.ComponentName;
242 import android.content.ContentProvider;
243 import android.content.ContentResolver;
244 import android.content.Context;
245 import android.content.Intent;
246 import android.content.IntentFilter;
247 import android.content.pm.ApplicationInfo;
248 import android.content.pm.IPackageManager;
249 import android.content.pm.LauncherApps;
250 import android.content.pm.ModuleInfo;
251 import android.content.pm.PackageManager;
252 import android.content.pm.PackageManager.NameNotFoundException;
253 import android.content.pm.PackageManagerInternal;
254 import android.content.pm.ParceledListSlice;
255 import android.content.pm.ServiceInfo;
256 import android.content.pm.ShortcutInfo;
257 import android.content.pm.ShortcutServiceInternal;
258 import android.content.pm.UserInfo;
259 import android.content.pm.VersionedPackage;
260 import android.content.res.Resources;
261 import android.database.ContentObserver;
262 import android.metrics.LogMaker;
263 import android.net.Uri;
264 import android.os.Binder;
265 import android.os.Build;
266 import android.os.Bundle;
267 import android.os.DeadObjectException;
268 import android.os.DeviceIdleManager;
269 import android.os.Environment;
270 import android.os.Handler;
271 import android.os.HandlerThread;
272 import android.os.IBinder;
273 import android.os.IInterface;
274 import android.os.Looper;
275 import android.os.Message;
276 import android.os.ParcelFileDescriptor;
277 import android.os.PowerManager;
278 import android.os.PowerManager.WakeLock;
279 import android.os.Process;
280 import android.os.RemoteCallbackList;
281 import android.os.RemoteException;
282 import android.os.ResultReceiver;
283 import android.os.ServiceManager;
284 import android.os.ShellCallback;
285 import android.os.SystemClock;
286 import android.os.SystemProperties;
287 import android.os.Trace;
288 import android.os.UserHandle;
289 import android.os.UserManager;
290 import android.os.WorkSource;
291 import android.permission.PermissionManager;
292 import android.provider.Settings;
293 import android.provider.Settings.Secure;
294 import android.service.notification.Adjustment;
295 import android.service.notification.Adjustment.Types;
296 import android.service.notification.Condition;
297 import android.service.notification.ConversationChannelWrapper;
298 import android.service.notification.DeviceEffectsApplier;
299 import android.service.notification.IConditionProvider;
300 import android.service.notification.INotificationListener;
301 import android.service.notification.IStatusBarNotificationHolder;
302 import android.service.notification.ListenersDisablingEffectsProto;
303 import android.service.notification.NotificationAssistantService;
304 import android.service.notification.NotificationListenerFilter;
305 import android.service.notification.NotificationListenerService;
306 import android.service.notification.NotificationRankingUpdate;
307 import android.service.notification.NotificationRecordProto;
308 import android.service.notification.NotificationServiceDumpProto;
309 import android.service.notification.NotificationStats;
310 import android.service.notification.StatusBarNotification;
311 import android.service.notification.ZenDeviceEffects;
312 import android.service.notification.ZenModeConfig;
313 import android.service.notification.ZenModeProto;
314 import android.service.notification.ZenPolicy;
315 import android.telecom.TelecomManager;
316 import android.telephony.TelephonyManager;
317 import android.text.TextUtils;
318 import android.text.format.DateUtils;
319 import android.util.ArrayMap;
320 import android.util.ArraySet;
321 import android.util.AtomicFile;
322 import android.util.IntArray;
323 import android.util.Log;
324 import android.util.Pair;
325 import android.util.Slog;
326 import android.util.SparseArray;
327 import android.util.SparseBooleanArray;
328 import android.util.StatsEvent;
329 import android.util.Xml;
330 import android.util.proto.ProtoOutputStream;
331 import android.view.Display;
332 import android.view.accessibility.AccessibilityManager;
333 import android.widget.RemoteViews;
334 import android.widget.Toast;
335 
336 import com.android.internal.R;
337 import com.android.internal.annotations.GuardedBy;
338 import com.android.internal.annotations.VisibleForTesting;
339 import com.android.internal.compat.IPlatformCompat;
340 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
341 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
342 import com.android.internal.logging.InstanceId;
343 import com.android.internal.logging.InstanceIdSequence;
344 import com.android.internal.logging.MetricsLogger;
345 import com.android.internal.logging.nano.MetricsProto;
346 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
347 import com.android.internal.messages.nano.SystemMessageProto;
348 import com.android.internal.notification.NotificationChannelGroupsHelper;
349 import com.android.internal.notification.SystemNotificationChannels;
350 import com.android.internal.os.BackgroundThread;
351 import com.android.internal.os.SomeArgs;
352 import com.android.internal.statusbar.NotificationVisibility;
353 import com.android.internal.util.ArrayUtils;
354 import com.android.internal.util.CollectionUtils;
355 import com.android.internal.util.ConcurrentUtils;
356 import com.android.internal.util.DumpUtils;
357 import com.android.internal.util.FrameworkStatsLog;
358 import com.android.internal.util.Preconditions;
359 import com.android.internal.util.XmlUtils;
360 import com.android.internal.util.function.TriPredicate;
361 import com.android.internal.widget.LockPatternUtils;
362 import com.android.modules.expresslog.Counter;
363 import com.android.modules.utils.TypedXmlPullParser;
364 import com.android.modules.utils.TypedXmlSerializer;
365 import com.android.server.DeviceIdleInternal;
366 import com.android.server.EventLogTags;
367 import com.android.server.IoThread;
368 import com.android.server.LocalServices;
369 import com.android.server.SystemService;
370 import com.android.server.job.JobSchedulerInternal;
371 import com.android.server.lights.LightsManager;
372 import com.android.server.notification.GroupHelper.NotificationAttributes;
373 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
374 import com.android.server.notification.ManagedServices.UserProfiles;
375 import com.android.server.notification.NotificationRecordLogger.NotificationPullStatsEvent;
376 import com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent;
377 import com.android.server.notification.toast.CustomToastRecord;
378 import com.android.server.notification.toast.TextToastRecord;
379 import com.android.server.notification.toast.ToastRecord;
380 import com.android.server.pm.PackageManagerService;
381 import com.android.server.pm.UserManagerInternal;
382 import com.android.server.policy.PermissionPolicyInternal;
383 import com.android.server.statusbar.StatusBarManagerInternal;
384 import com.android.server.uri.UriGrantsManagerInternal;
385 import com.android.server.utils.Slogf;
386 import com.android.server.utils.quota.MultiRateLimiter;
387 import com.android.server.wm.ActivityTaskManagerInternal;
388 import com.android.server.wm.BackgroundActivityStartCallback;
389 import com.android.server.wm.WindowManagerInternal;
390 
391 import libcore.io.IoUtils;
392 
393 import org.json.JSONException;
394 import org.json.JSONObject;
395 import org.xmlpull.v1.XmlPullParserException;
396 
397 import java.io.ByteArrayInputStream;
398 import java.io.ByteArrayOutputStream;
399 import java.io.File;
400 import java.io.FileDescriptor;
401 import java.io.FileNotFoundException;
402 import java.io.FileOutputStream;
403 import java.io.IOException;
404 import java.io.InputStream;
405 import java.io.OutputStream;
406 import java.io.PrintWriter;
407 import java.nio.charset.StandardCharsets;
408 import java.time.Clock;
409 import java.time.Duration;
410 import java.util.ArrayList;
411 import java.util.Arrays;
412 import java.util.Collection;
413 import java.util.HashSet;
414 import java.util.Iterator;
415 import java.util.LinkedList;
416 import java.util.List;
417 import java.util.Map;
418 import java.util.Map.Entry;
419 import java.util.Objects;
420 import java.util.Set;
421 import java.util.concurrent.Executor;
422 import java.util.concurrent.TimeUnit;
423 import java.util.function.BiConsumer;
424 import java.util.function.Predicate;
425 import java.util.stream.Collectors;
426 
427 /** {@hide} */
428 public class NotificationManagerService extends SystemService {
429     public static final String TAG = "NotificationService";
430     public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
431     public static final boolean ENABLE_CHILD_NOTIFICATIONS
432             = SystemProperties.getBoolean("debug.child_notifs", true);
433 
434     // pullStats report request: undecorated remote view stats
435     public static final int REPORT_REMOTE_VIEWS = 0x01;
436 
437     static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
438             "debug.notification.interruptiveness", false);
439 
440     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
441     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
442 
443     // To limit bad UX of seeing a toast many seconds after if was triggered.
444     static final int MAX_PACKAGE_TOASTS = 5;
445 
446     // message codes
447     static final int MESSAGE_DURATION_REACHED = 2;
448     // 3: removed to a different handler
449     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
450     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
451     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
452     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
453     static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
454 
455     static final Duration BITMAP_DURATION = Duration.ofHours(24);
456 
457     // ranking thread messages
458     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
459     private static final int MESSAGE_RANKING_SORT = 1001;
460 
461     static final int LONG_DELAY = TOAST_WINDOW_TIMEOUT - TOAST_WINDOW_ANIM_BUFFER; // 3.5 seconds
462     static final int SHORT_DELAY = 2000; // 2 seconds
463 
464     // 1 second past the ANR timeout.
465     static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
466 
467     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
468 
469     /**
470      *  The threshold, in milliseconds, to determine whether a notification has been
471      * cleared too quickly.
472      */
473     private static final int NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS = 5000;
474 
475     static final int INVALID_UID = -1;
476     static final String ROOT_PKG = "root";
477 
478     static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
479             Adjustment.KEY_PEOPLE,
480             Adjustment.KEY_SNOOZE_CRITERIA,
481             Adjustment.KEY_USER_SENTIMENT,
482             Adjustment.KEY_CONTEXTUAL_ACTIONS,
483             Adjustment.KEY_TEXT_REPLIES,
484             Adjustment.KEY_IMPORTANCE,
485             Adjustment.KEY_IMPORTANCE_PROPOSAL,
486             Adjustment.KEY_SENSITIVE_CONTENT,
487             Adjustment.KEY_RANKING_SCORE,
488             Adjustment.KEY_NOT_CONVERSATION,
489             Adjustment.KEY_TYPE,
490             Adjustment.KEY_SUMMARIZATION
491     };
492 
493     static final Integer[] DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES = new Integer[] {
494             TYPE_PROMOTION,
495             TYPE_NEWS,
496             TYPE_CONTENT_RECOMMENDATION,
497             TYPE_SOCIAL_MEDIA
498     };
499 
500     static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
501             RoleManager.ROLE_DIALER,
502             RoleManager.ROLE_EMERGENCY
503     };
504 
505     // Used for rate limiting toasts by package.
506     static final String TOAST_QUOTA_TAG = "toast_quota_tag";
507 
508     // This constant defines rate limits applied to showing toasts. The numbers are set in a way
509     // such that an aggressive toast showing strategy would result in a roughly 1.5x longer wait
510     // time (before the package is allowed to show toasts again) each time the toast rate limit is
511     // reached. It's meant to protect the user against apps spamming them with toasts (either
512     // accidentally or on purpose).
513     private static final MultiRateLimiter.RateLimit[] TOAST_RATE_LIMITS = {
514             MultiRateLimiter.RateLimit.create(3, Duration.ofSeconds(20)),
515             MultiRateLimiter.RateLimit.create(5, Duration.ofSeconds(42)),
516             MultiRateLimiter.RateLimit.create(6, Duration.ofSeconds(68)),
517     };
518 
519     // When #matchesCallFilter is called from the ringer, wait at most
520     // 3s to resolve the contacts. This timeout is required since
521     // ContactsProvider might take a long time to start up.
522     //
523     // Return STARRED_CONTACT when the timeout is hit in order to avoid
524     // missed calls in ZEN mode "Important".
525     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
526     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
527             ValidateNotificationPeople.STARRED_CONTACT;
528 
529     /** notification_enqueue status value for a newly enqueued notification. */
530     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
531 
532     /** notification_enqueue status value for an existing notification. */
533     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
534 
535     /** notification_enqueue status value for an ignored notification. */
536     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
537     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
538 
539     private static final long DELAY_FOR_ASSISTANT_TIME = 200;
540 
541     private static final long DELAY_FORCE_REGROUP_TIME = 3000;
542 
543 
544     private static final String ACTION_NOTIFICATION_TIMEOUT =
545             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
546     private static final int REQUEST_CODE_TIMEOUT = 1;
547     private static final String SCHEME_TIMEOUT = "timeout";
548     private static final String EXTRA_KEY = "key";
549 
550     private static final int NOTIFICATION_INSTANCE_ID_MAX = (1 << 13);
551 
552     // States for the review permissions notification
553     static final int REVIEW_NOTIF_STATE_UNKNOWN = -1;
554     static final int REVIEW_NOTIF_STATE_SHOULD_SHOW = 0;
555     static final int REVIEW_NOTIF_STATE_USER_INTERACTED = 1;
556     static final int REVIEW_NOTIF_STATE_DISMISSED = 2;
557     static final int REVIEW_NOTIF_STATE_RESHOWN = 3;
558 
559     // Action strings for review permissions notification
560     static final String REVIEW_NOTIF_ACTION_REMIND = "REVIEW_NOTIF_ACTION_REMIND";
561     static final String REVIEW_NOTIF_ACTION_DISMISS = "REVIEW_NOTIF_ACTION_DISMISS";
562     static final String REVIEW_NOTIF_ACTION_CANCELED = "REVIEW_NOTIF_ACTION_CANCELED";
563 
564     /**
565      * Apps that post custom toasts in the background will have those blocked. Apps can
566      * still post toasts created with
567      * {@link Toast#makeText(Context, CharSequence, int)} and its variants while
568      * in the background.
569      */
570     @ChangeId
571     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
572     private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L;
573 
574     /**
575      * Activity starts coming from broadcast receivers or services in response to notification and
576      * notification action clicks will be blocked for UX and performance reasons. Instead start the
577      * activity directly from the PendingIntent.
578      */
579     @ChangeId
580     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
581     private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L;
582 
583     /**
584      * Activity starts coming from broadcast receivers or services in response to notification and
585      * notification action clicks will be blocked for UX and performance reasons for previously
586      * exempt role holders (browser).
587      */
588     @ChangeId
589     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
590     private static final long NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES = 227752274L;
591 
592     /**
593      * Whether a notification listeners can understand new, more specific, cancellation reasons.
594      */
595     @ChangeId
596     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
597     private static final long NOTIFICATION_CANCELLATION_REASONS = 175319604L;
598 
599     /**
600      * Rate limit showing toasts, on a per package basis.
601      *
602      * It limits the number of {@link Toast#show()} calls to prevent overburdening
603      * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed
604      * in a certain time frame will result in the toast being discarded.
605      */
606     @ChangeId
607     @LoggingOnly
608     private static final long RATE_LIMIT_TOASTS = 174840628L;
609 
610     /**
611      * Whether listeners understand the more specific reason provided for notification
612      * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL.
613      */
614     @ChangeId
615     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
616     private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
617 
618     /**
619      * NO_CLEAR flag will be set for any media notification.
620      */
621     @ChangeId
622     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
623     static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L;
624 
625     /**
626      * App calls to {@link NotificationManager#setInterruptionFilter} and
627      * {@link NotificationManager#setNotificationPolicy} manage DND through the
628      * creation and activation of an implicit {@link AutomaticZenRule}.
629      */
630     @ChangeId
631     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
632     static final long MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES = 308670109L;
633 
634     private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
635 
636     static final long NOTIFICATION_TTL = Duration.ofDays(3).toMillis();
637 
638     static final long NOTIFICATION_MAX_AGE_AT_POST = Duration.ofDays(14).toMillis();
639 
640     // Minium number of sparse groups for a package before autogrouping them
641     private static final int AUTOGROUP_SPARSE_GROUPS_AT_COUNT = 6;
642 
643     private static final Duration ZEN_BROADCAST_DELAY = Duration.ofMillis(250);
644 
645     private IActivityManager mAm;
646     private ActivityTaskManagerInternal mAtm;
647     private ActivityManager mActivityManager;
648     private ActivityManagerInternal mAmi;
649     @VisibleForTesting
650     IPackageManager mPackageManager;
651     private PackageManager mPackageManagerClient;
652     PackageManagerInternal mPackageManagerInternal;
653     private PermissionManager mPermissionManager;
654     private PermissionPolicyInternal mPermissionPolicyInternal;
655 
656     // Can be null for wear
657     @Nullable StatusBarManagerInternal mStatusBar;
658     private WindowManagerInternal mWindowManagerInternal;
659     private AlarmManager mAlarmManager;
660     @VisibleForTesting
661     ICompanionDeviceManager mCompanionManager;
662     private AccessibilityManager mAccessibilityManager;
663     private DeviceIdleManager mDeviceIdleManager;
664     private IUriGrantsManager mUgm;
665     private UriGrantsManagerInternal mUgmInternal;
666     private volatile RoleObserver mRoleObserver;
667     private UserManager mUm;
668     private UserManagerInternal mUmInternal;
669     private IPlatformCompat mPlatformCompat;
670     private ShortcutHelper mShortcutHelper;
671     private PermissionHelper mPermissionHelper;
672     private UsageStatsManagerInternal mUsageStatsManagerInternal;
673     private TelecomManager mTelecomManager;
674     private PowerManager mPowerManager;
675     private PostNotificationTrackerFactory mPostNotificationTrackerFactory;
676 
677     private LockPatternUtils mLockUtils;
678 
679     final IBinder mForegroundToken = new Binder();
680     @VisibleForTesting
681     WorkerHandler mHandler;
682     private final HandlerThread mRankingThread = new HandlerThread("ranker",
683             Process.THREAD_PRIORITY_BACKGROUND);
684     @FlaggedApi(Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST)
685     private Handler mBroadcastsHandler;
686 
687     private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
688             new SparseArray<>();
689     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
690     private int mListenerHints;  // right now, all hints are global
691     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
692 
693     private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
694 
695     // used as a mutex for access to all active notifications & listeners
696     final Object mNotificationLock = new Object();
697     @GuardedBy("mNotificationLock")
698     final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
699     @GuardedBy("mNotificationLock")
700     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
701     @GuardedBy("mNotificationLock")
702     final ArrayMap<String, InlineReplyUriRecord> mInlineReplyRecordsByKey = new ArrayMap<>();
703     @GuardedBy("mNotificationLock")
704     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
705     @GuardedBy("mNotificationLock")
706     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
707     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
708     // set of uids for which toast rate limiting is disabled
709     @GuardedBy("mToastQueue")
710     private final Set<Integer> mToastRateLimitingDisabledUids = new ArraySet<>();
711     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
712 
713     // True if the toast that's on top of the queue is being shown at the moment.
714     @GuardedBy("mToastQueue")
715     private boolean mIsCurrentToastShown = false;
716 
717     // Used for rate limiting toasts by package.
718     private MultiRateLimiter mToastRateLimiter;
719 
720     private AppOpsManager mAppOps;
721     private UsageStatsManagerInternal mAppUsageStats;
722     private DevicePolicyManagerInternal mDpm;
723     private StatsManager mStatsManager;
724     private StatsPullAtomCallbackImpl mPullAtomCallback;
725 
726     private Archive mArchive;
727 
728     // Persistent storage for notification policy
729     private AtomicFile mPolicyFile;
730 
731     private static final int DB_VERSION = 1;
732 
733 
734     private static final String ADSERVICES_MODULE_PKG_NAME =
735             "com.android.adservices";
736 
737     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
738     private static final String ATTR_VERSION = "version";
739 
740     private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
741             "allow-secure-notifications-on-lockscreen";
742     private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
743 
744     @VisibleForTesting
745     RankingHelper mRankingHelper;
746     @VisibleForTesting
747     PreferencesHelper mPreferencesHelper;
748 
749     private final UserProfiles mUserProfiles = new UserProfiles();
750     private NotificationListeners mListeners;
751     @VisibleForTesting
752     NotificationAssistants mAssistants;
753     private ConditionProviders mConditionProviders;
754     private NotificationUsageStats mUsageStats;
755     private boolean mLockScreenAllowSecureNotifications = true;
756     final ArrayMap<String, ArrayMap<Integer,
757             RemoteCallbackList<ICallNotificationEventCallback>>>
758             mCallNotificationEventCallbacks = new ArrayMap<>();
759 
760     private static final int MY_UID = Process.myUid();
761     private static final int MY_PID = Process.myPid();
762     static final IBinder ALLOWLIST_TOKEN = new Binder();
763     protected RankingHandler mRankingHandler;
764     private long mLastOverRateLogTime;
765     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
766 
767     private boolean mRedactOtpNotifications = true;
768 
769     private NotificationHistoryManager mHistoryManager;
770     protected SnoozeHelper mSnoozeHelper;
771     private TimeToLiveHelper mTtlHelper;
772     private GroupHelper mGroupHelper;
773     private int mAutoGroupAtCount;
774     private boolean mIsTelevision;
775     protected NotificationAttentionHelper mAttentionHelper;
776 
777     private int mWarnRemoteViewsSizeBytes;
778     private int mStripRemoteViewsSizeBytes;
779     protected String[] mDefaultUnsupportedAdjustments;
780 
781     @VisibleForTesting
782     protected boolean mShowReviewPermissionsNotification;
783 
784     private MetricsLogger mMetricsLogger;
785     private NotificationChannelLogger mNotificationChannelLogger;
786     private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
787 
788     private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
789     private NotificationRecordLogger mNotificationRecordLogger;
790     private InstanceIdSequence mNotificationInstanceIdSequence;
791     private Set<String> mMsgPkgsAllowedAsConvos = new HashSet();
792     private String mDefaultSearchSelectorPkg;
793 
794     // Broadcast intent receiver for notification permissions review-related intents
795     private ReviewNotificationPermissionsReceiver mReviewNotificationPermissionsReceiver;
796 
797     private AppOpsManager.OnOpChangedListener mAppOpsListener;
798 
799     private ModuleInfo mAdservicesModuleInfo;
800 
801     static class Archive {
802         final SparseArray<Boolean> mEnabled;
803         final int mBufferSize;
804         final Object mBufferLock = new Object();
805         @GuardedBy("mBufferLock")
806         final LinkedList<Pair<StatusBarNotification, Integer>> mBuffer;
807 
Archive(int size)808         public Archive(int size) {
809             mBufferSize = size;
810             mBuffer = new LinkedList<>();
811             mEnabled = new SparseArray<>();
812         }
813 
toString()814         public String toString() {
815             final StringBuilder sb = new StringBuilder();
816             final int N = mBuffer.size();
817             sb.append("Archive (");
818             sb.append(N);
819             sb.append(" notification");
820             sb.append((N == 1) ? ")" : "s)");
821             return sb.toString();
822         }
823 
record(StatusBarNotification sbn, int reason)824         public void record(StatusBarNotification sbn, int reason) {
825             if (!mEnabled.get(sbn.getNormalizedUserId(), false)) {
826                 return;
827             }
828             synchronized (mBufferLock) {
829                 if (mBuffer.size() == mBufferSize) {
830                     mBuffer.removeFirst();
831                 }
832 
833                 // We don't want to store the heavy bits of the notification in the archive,
834                 // but other clients in the system process might be using the object, so we
835                 // store a (lightened) copy.
836                 mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason));
837             }
838         }
839 
descendingIterator()840         public Iterator<Pair<StatusBarNotification, Integer>> descendingIterator() {
841             return mBuffer.descendingIterator();
842         }
843 
getArray(UserManager um, int count, boolean includeSnoozed)844         public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) {
845             ArrayList<Integer> currentUsers = new ArrayList<>();
846             currentUsers.add(USER_ALL);
847             Binder.withCleanCallingIdentity(() -> {
848                 for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) {
849                     currentUsers.add(user);
850                 }
851             });
852             synchronized (mBufferLock) {
853                 if (count == 0) count = mBufferSize;
854                 List<StatusBarNotification> a = new ArrayList();
855                 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator();
856                 int i = 0;
857                 while (iter.hasNext() && i < count) {
858                     Pair<StatusBarNotification, Integer> pair = iter.next();
859                     if (pair.second != REASON_SNOOZED || includeSnoozed) {
860                         if (currentUsers.contains(pair.first.getUserId())) {
861                             i++;
862                             a.add(pair.first);
863                         }
864                     }
865                 }
866                 return a.toArray(new StatusBarNotification[a.size()]);
867             }
868         }
869 
updateHistoryEnabled(@serIdInt int userId, boolean enabled)870         public void updateHistoryEnabled(@UserIdInt int userId, boolean enabled) {
871             mEnabled.put(userId, enabled);
872 
873             if (!enabled) {
874                 synchronized (mBufferLock) {
875                     for (int i = mBuffer.size() - 1; i >= 0; i--) {
876                         if (userId == mBuffer.get(i).first.getNormalizedUserId()) {
877                             mBuffer.remove(i);
878                         }
879                     }
880                 }
881             }
882         }
883 
884         // Remove notifications with the specified user & channel ID.
removeChannelNotifications(String pkg, @UserIdInt int userId, String channelId)885         public void removeChannelNotifications(String pkg, @UserIdInt int userId,
886                 String channelId) {
887             synchronized (mBufferLock) {
888                 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator();
889                 while (bufferIter.hasNext()) {
890                     final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
891                     if (pair.first != null
892                             && userId == pair.first.getNormalizedUserId()
893                             && pkg != null && pkg.equals(pair.first.getPackageName())
894                             && pair.first.getNotification() != null
895                             && Objects.equals(channelId,
896                             pair.first.getNotification().getChannelId())) {
897                         bufferIter.remove();
898                     }
899                 }
900             }
901         }
902 
903         // Removes all notifications with the specified user & package.
removePackageNotifications(String pkg, @UserIdInt int userId)904         public void removePackageNotifications(String pkg, @UserIdInt int userId) {
905             synchronized (mBufferLock) {
906                 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator();
907                 while (bufferIter.hasNext()) {
908                     final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
909                     if (pair.first != null
910                             && userId == pair.first.getNormalizedUserId()
911                             && pkg != null && pkg.equals(pair.first.getPackageName())
912                             && pair.first.getNotification() != null) {
913                         bufferIter.remove();
914                     }
915                 }
916             }
917         }
918 
dumpImpl(PrintWriter pw, @NonNull DumpFilter filter)919         void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
920             synchronized (mBufferLock) {
921                 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator();
922                 int i = 0;
923                 while (iter.hasNext()) {
924                     final StatusBarNotification sbn = iter.next().first;
925                     if (filter != null && !filter.matches(sbn)) continue;
926                     pw.println("    " + sbn);
927                     if (++i >= 5) {
928                         if (iter.hasNext()) pw.println("    ...");
929                         break;
930                     }
931                 }
932             }
933         }
934     }
935 
loadDefaultApprovedServices(int userId)936     void loadDefaultApprovedServices(int userId) {
937         mListeners.loadDefaultsFromConfig();
938 
939         mConditionProviders.loadDefaultsFromConfig();
940 
941         mAssistants.loadDefaultsFromConfig();
942     }
943 
allowDefaultApprovedServices(int userId)944     protected void allowDefaultApprovedServices(int userId) {
945         ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents();
946         for (int i = 0; i < defaultListeners.size(); i++) {
947             ComponentName cn = defaultListeners.valueAt(i);
948             allowNotificationListener(userId, cn);
949         }
950 
951         allowDndPackages(userId);
952 
953         setDefaultAssistantForUser(userId);
954     }
955 
956     @VisibleForTesting
allowDndPackages(int userId)957     void allowDndPackages(int userId) {
958         ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages();
959         for (int i = 0; i < defaultDnds.size(); i++) {
960             allowDndPackage(userId, defaultDnds.valueAt(i));
961         }
962         if (!isDNDMigrationDone(userId)) {
963             setDNDMigrationDone(userId);
964         }
965     }
966 
967     @VisibleForTesting
isDNDMigrationDone(int userId)968     boolean isDNDMigrationDone(int userId) {
969         return Secure.getIntForUser(getContext().getContentResolver(),
970                 Secure.DND_CONFIGS_MIGRATED, 0, userId) == 1;
971     }
972 
973     @VisibleForTesting
setDNDMigrationDone(int userId)974     void setDNDMigrationDone(int userId) {
975         Secure.putIntForUser(getContext().getContentResolver(),
976                 Secure.DND_CONFIGS_MIGRATED, 1, userId);
977     }
978 
migrateDefaultNAS()979     protected void migrateDefaultNAS() {
980         final List<UserInfo> activeUsers = mUm.getUsers();
981         for (UserInfo userInfo : activeUsers) {
982             int userId = userInfo.getUserHandle().getIdentifier();
983             if (isNASMigrationDone(userId) || isProfileUser(userInfo)) {
984                 continue;
985             }
986             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
987             if (allowedComponents.size() == 0) { // user set to none
988                 Slog.d(TAG, "NAS Migration: user set to none, disable new NAS setting");
989                 setNASMigrationDone(userId);
990                 mAssistants.clearDefaults();
991             } else {
992                 Slog.d(TAG, "Reset NAS setting and migrate to new default");
993                 resetAssistantUserSet(userId);
994                 // migrate to new default and set migration done
995                 mAssistants.resetDefaultAssistantsIfNecessary();
996             }
997         }
998     }
999 
1000     @VisibleForTesting
setNASMigrationDone(int baseUserId)1001     void setNASMigrationDone(int baseUserId) {
1002         for (int profileId : mUm.getProfileIds(baseUserId, false)) {
1003             Secure.putIntForUser(getContext().getContentResolver(),
1004                     Secure.NAS_SETTINGS_UPDATED, 1, profileId);
1005         }
1006     }
1007 
1008     @VisibleForTesting
isNASMigrationDone(int userId)1009     boolean isNASMigrationDone(int userId) {
1010         return (Secure.getIntForUser(getContext().getContentResolver(),
1011                 Secure.NAS_SETTINGS_UPDATED, 0, userId) == 1);
1012     }
1013 
isProfileUser(UserInfo userInfo)1014     boolean isProfileUser(UserInfo userInfo) {
1015         if (privateSpaceFlagsEnabled()) {
1016             return userInfo.isProfile() && hasParent(userInfo);
1017         }
1018         return userInfo.isManagedProfile() || userInfo.isCloneProfile();
1019     }
1020 
hasParent(UserInfo profile)1021     boolean hasParent(UserInfo profile) {
1022         return mUmInternal.getProfileParentId(profile.id) != profile.id;
1023     }
1024 
setDefaultAssistantForUser(int userId)1025     protected void setDefaultAssistantForUser(int userId) {
1026         ArraySet<ComponentName> defaults = mAssistants.getDefaultComponents();
1027         // We should have only one default assistant by default
1028         // allowAssistant should execute once in practice
1029         for (int i = 0; i < defaults.size(); i++) {
1030             ComponentName cn = defaults.valueAt(i);
1031             if (allowAssistant(userId, cn)) return;
1032         }
1033     }
1034 
1035     /**
1036      * This method will update the flags and/or the icon of the summary.
1037      * It will set it to FLAG_ONGOING_EVENT if any of its group members
1038      * has the same flag. It will delete the flag otherwise.
1039      * It will update the summary notification icon if the group children's
1040      * icons are different.
1041      * @param userId user id of the autogroup summary
1042      * @param pkg package of the autogroup summary
1043      * @param groupKey group key of the autogroup summary
1044      * @param summaryAttr the new flags and/or icon & color for this summary
1045      * @param isAppForeground true if the app is currently in the foreground.
1046      */
1047     @GuardedBy("mNotificationLock")
updateAutobundledSummaryLocked(int userId, String pkg, String groupKey, NotificationAttributes summaryAttr, boolean isAppForeground)1048     protected void updateAutobundledSummaryLocked(int userId, String pkg, String groupKey,
1049                 NotificationAttributes summaryAttr, boolean isAppForeground) {
1050         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
1051         if (summaries == null) {
1052             return;
1053         }
1054         final String autbundledGroupKey;
1055         if (notificationForceGrouping()) {
1056             autbundledGroupKey = groupKey;
1057         } else {
1058             autbundledGroupKey = pkg;
1059         }
1060 
1061         String summaryKey = summaries.get(autbundledGroupKey);
1062         if (summaryKey == null) {
1063             return;
1064         }
1065         NotificationRecord summary = mNotificationsByKey.get(summaryKey);
1066         if (summary == null) {
1067             return;
1068         }
1069 
1070         int oldFlags = summary.getSbn().getNotification().flags;
1071 
1072         boolean attributesUpdated =
1073                 !summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon())
1074                 || summaryAttr.iconColor != summary.getSbn().getNotification().color
1075                 || summaryAttr.visibility != summary.getSbn().getNotification().visibility
1076                 || summaryAttr.groupAlertBehavior !=
1077                         summary.getSbn().getNotification().getGroupAlertBehavior();
1078 
1079         if (notificationForceGrouping()) {
1080             summary.getNotification().flags |= Notification.FLAG_SILENT;
1081             if (!summary.getChannel().getId().equals(summaryAttr.channelId)) {
1082                 NotificationChannel newChannel = mPreferencesHelper.getNotificationChannel(pkg,
1083                         summary.getUid(), summaryAttr.channelId, false);
1084                 if (newChannel != null) {
1085                     summary.updateNotificationChannel(newChannel);
1086                     attributesUpdated = true;
1087                 }
1088             }
1089         }
1090 
1091         if (oldFlags != summaryAttr.flags || attributesUpdated) {
1092             summary.getSbn().getNotification().flags =
1093                     summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags;
1094             summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon);
1095             summary.getSbn().getNotification().color = summaryAttr.iconColor;
1096             summary.getSbn().getNotification().visibility = summaryAttr.visibility;
1097             summary.getSbn().getNotification()
1098                     .setGroupAlertBehavior(summaryAttr.groupAlertBehavior);
1099             mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
1100                     /* isAppProvided= */ false, mPostNotificationTrackerFactory.newTracker(null)));
1101         }
1102     }
1103 
allowDndPackage(int userId, String packageName)1104     private void allowDndPackage(int userId, String packageName) {
1105         try {
1106             getBinderService().setNotificationPolicyAccessGrantedForUser(packageName, userId, true);
1107         } catch (RemoteException e) {
1108             e.printStackTrace();
1109         }
1110     }
1111 
allowNotificationListener(int userId, ComponentName cn)1112     private void allowNotificationListener(int userId, ComponentName cn) {
1113 
1114         try {
1115             getBinderService().setNotificationListenerAccessGrantedForUser(cn,
1116                         userId, true, true);
1117         } catch (RemoteException e) {
1118             e.printStackTrace();
1119         }
1120     }
1121 
allowAssistant(int userId, ComponentName candidate)1122     private boolean allowAssistant(int userId, ComponentName candidate) {
1123         Set<ComponentName> validAssistants =
1124                 mAssistants.queryPackageForServices(
1125                         null,
1126                         MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
1127         if (candidate != null && validAssistants.contains(candidate)) {
1128             setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true, false);
1129             return true;
1130         }
1131         return false;
1132     }
1133 
readPolicyXml(InputStream stream, boolean forRestore, int userId, @Nullable BackupRestoreEventLogger logger)1134     void readPolicyXml(InputStream stream, boolean forRestore, int userId,
1135             @Nullable BackupRestoreEventLogger logger)
1136             throws XmlPullParserException, NumberFormatException, IOException {
1137         final TypedXmlPullParser parser;
1138         if (forRestore) {
1139             parser = Xml.newFastPullParser();
1140             parser.setInput(stream, StandardCharsets.UTF_8.name());
1141         } else {
1142             parser = Xml.resolvePullParser(stream);
1143         }
1144         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
1145         boolean migratedManagedServices = false;
1146         UserInfo userInfo = mUmInternal.getUserInfo(userId);
1147         boolean ineligibleForManagedServices = forRestore && isProfileUser(userInfo);
1148         int outerDepth = parser.getDepth();
1149         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1150             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
1151                 int successfulReads = 0;
1152                 int unsuccessfulReads = 0;
1153                 try {
1154                     boolean loadedCorrectly =
1155                             mZenModeHelper.readXml(parser, forRestore, userId, logger);
1156                     if (loadedCorrectly)
1157                         successfulReads++;
1158                     else
1159                         unsuccessfulReads++;
1160                 } catch (Exception e) {
1161                     Slog.wtf(TAG, "failed to read config", e);
1162                     unsuccessfulReads++;
1163                 }
1164                 if (logger != null) {
1165                     logger.logItemsRestored(DATA_TYPE_ZEN_CONFIG, successfulReads);
1166                     if (unsuccessfulReads > 0) {
1167                         logger.logItemsRestoreFailed(
1168                                 DATA_TYPE_ZEN_CONFIG, unsuccessfulReads, ERROR_XML_PARSING);
1169                     }
1170                 }
1171 
1172             } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
1173                 mPreferencesHelper.readXml(parser, forRestore, userId);
1174             }
1175             if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
1176                 if (ineligibleForManagedServices) {
1177                     continue;
1178                 }
1179                 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
1180                 migratedManagedServices = true;
1181             } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
1182                 if (ineligibleForManagedServices) {
1183                     continue;
1184                 }
1185                 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
1186                 migratedManagedServices = true;
1187             } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
1188                 if (ineligibleForManagedServices) {
1189                     continue;
1190                 }
1191                 mConditionProviders.readXml(
1192                         parser, mAllowedManagedServicePackages, forRestore, userId);
1193                 migratedManagedServices = true;
1194             } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
1195                 mSnoozeHelper.readXml(parser, System.currentTimeMillis());
1196             }
1197             if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
1198                 if (forRestore && userId != USER_SYSTEM) {
1199                     continue;
1200                 }
1201                 mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null,
1202                         LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true);
1203             }
1204         }
1205 
1206         if (!migratedManagedServices) {
1207             mListeners.migrateToXml();
1208             mAssistants.migrateToXml();
1209             mConditionProviders.migrateToXml();
1210             handleSavePolicyFile();
1211         }
1212 
1213         mAssistants.resetDefaultAssistantsIfNecessary();
1214         mPreferencesHelper.syncHasPriorityChannels();
1215     }
1216 
1217     @VisibleForTesting
resetDefaultDndIfNecessary()1218     void resetDefaultDndIfNecessary() {
1219         boolean removed = false;
1220         final List<UserInfo> activeUsers = mUm.getAliveUsers();
1221         for (UserInfo userInfo : activeUsers) {
1222             int userId = userInfo.getUserHandle().getIdentifier();
1223             if (isDNDMigrationDone(userId)) {
1224                 continue;
1225             }
1226             removed |= mConditionProviders.removeDefaultFromConfig(userId);
1227             mConditionProviders.resetDefaultFromConfig();
1228             allowDndPackages(userId);
1229         }
1230         if (removed) {
1231             handleSavePolicyFile();
1232         }
1233     }
1234 
1235     @VisibleForTesting
loadPolicyFile()1236     protected void loadPolicyFile() {
1237         if (DBG) Slog.d(TAG, "loadPolicyFile");
1238         synchronized (mPolicyFile) {
1239             InputStream infile = null;
1240             try {
1241                 infile = mPolicyFile.openRead();
1242                 readPolicyXml(infile, false /*forRestore*/, USER_ALL, null);
1243 
1244                 // We re-load the default dnd packages to allow the newly added and denined.
1245                 final boolean isWatch = mPackageManagerClient.hasSystemFeature(
1246                         PackageManager.FEATURE_WATCH);
1247                 if (isWatch) {
1248                     resetDefaultDndIfNecessary();
1249                 }
1250             } catch (FileNotFoundException e) {
1251                 // No data yet
1252                 // Load default managed services approvals
1253                 loadDefaultApprovedServices(USER_SYSTEM);
1254                 allowDefaultApprovedServices(USER_SYSTEM);
1255             } catch (IOException e) {
1256                 Log.wtf(TAG, "Unable to read notification policy", e);
1257             } catch (NumberFormatException e) {
1258                 Log.wtf(TAG, "Unable to parse notification policy", e);
1259             } catch (XmlPullParserException e) {
1260                 Log.wtf(TAG, "Unable to parse notification policy", e);
1261             } finally {
1262                 IoUtils.closeQuietly(infile);
1263             }
1264         }
1265     }
1266 
1267     @VisibleForTesting
handleSavePolicyFile()1268     protected void handleSavePolicyFile() {
1269         if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
1270             IoThread.getHandler().postDelayed(mSavePolicyFile, 250);
1271         }
1272     }
1273 
privateSpaceFlagsEnabled()1274     protected static boolean privateSpaceFlagsEnabled() {
1275         return allowPrivateProfile() && android.multiuser.Flags.enablePrivateSpaceFeatures();
1276     }
1277 
1278     private final class SavePolicyFileRunnable implements Runnable {
1279         @Override
run()1280         public void run() {
1281             if (DBG) Slog.d(TAG, "handleSavePolicyFile");
1282             synchronized (mPolicyFile) {
1283                 final FileOutputStream stream;
1284                 try {
1285                     stream = mPolicyFile.startWrite();
1286                 } catch (IOException e) {
1287                     Slog.w(TAG, "Failed to save policy file", e);
1288                     return;
1289                 }
1290 
1291                 try {
1292                     writePolicyXml(stream, false /*forBackup*/, USER_ALL, null);
1293                     mPolicyFile.finishWrite(stream);
1294                 } catch (IOException e) {
1295                     Slog.w(TAG, "Failed to save policy file, restoring backup", e);
1296                     mPolicyFile.failWrite(stream);
1297                 }
1298             }
1299             BackupManager.dataChanged(getContext().getPackageName());
1300         }
1301     }
1302 
writePolicyXml(OutputStream stream, boolean forBackup, int userId, BackupRestoreEventLogger logger)1303     void writePolicyXml(OutputStream stream, boolean forBackup, int userId,
1304             BackupRestoreEventLogger logger)  throws IOException {
1305         final TypedXmlSerializer out;
1306         if (forBackup) {
1307             out = Xml.newFastSerializer();
1308             out.setOutput(stream, StandardCharsets.UTF_8.name());
1309         } else {
1310             out = Xml.resolveSerializer(stream);
1311         }
1312         out.startDocument(null, true);
1313         out.startTag(null, TAG_NOTIFICATION_POLICY);
1314         out.attributeInt(null, ATTR_VERSION, DB_VERSION);
1315         mZenModeHelper.writeXml(out, forBackup, null, userId, logger);
1316         mPreferencesHelper.writeXml(out, forBackup, userId);
1317         mListeners.writeXml(out, forBackup, userId);
1318         mAssistants.writeXml(out, forBackup, userId);
1319         mSnoozeHelper.writeXml(out);
1320         mConditionProviders.writeXml(out, forBackup, userId);
1321         if (!forBackup || userId == USER_SYSTEM) {
1322             writeSecureNotificationsPolicy(out);
1323         }
1324         out.endTag(null, TAG_NOTIFICATION_POLICY);
1325         out.endDocument();
1326     }
1327 
1328     @VisibleForTesting
1329     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
1330 
1331         @Override
1332         public void prepareForPossibleShutdown() {
1333             mHistoryManager.triggerWriteToDisk();
1334         }
1335 
1336         @Override
1337         public void onSetDisabled(int status) {
1338             synchronized (mNotificationLock) {
1339                 mAttentionHelper.updateDisableNotificationEffectsLocked(status);
1340             }
1341         }
1342 
1343         @Override
1344         public void onClearAll(int callingUid, int callingPid, int userId) {
1345             synchronized (mNotificationLock) {
1346                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
1347                         /*includeCurrentProfiles*/ true, FLAG_ONGOING_EVENT | FLAG_NO_CLEAR);
1348             }
1349         }
1350 
1351         @Override
1352         public void onNotificationClick(int callingUid, int callingPid, String key,
1353                 NotificationVisibility nv) {
1354             exitIdle();
1355             synchronized (mNotificationLock) {
1356                 NotificationRecord r = mNotificationsByKey.get(key);
1357                 if (r == null) {
1358                     Slog.w(TAG, "No notification with key: " + key);
1359                     return;
1360                 }
1361                 final long now = System.currentTimeMillis();
1362                 MetricsLogger.action(r.getItemLogMaker()
1363                         .setType(MetricsEvent.TYPE_ACTION)
1364                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
1365                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
1366                 mNotificationRecordLogger.log(
1367                         NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, r);
1368                 EventLogTags.writeNotificationClicked(key,
1369                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
1370                         nv.rank, nv.count);
1371 
1372                 StatusBarNotification sbn = r.getSbn();
1373                 // Notifications should be cancelled on click if they have been lifetime extended,
1374                 // regardless of presence or absence of FLAG_AUTO_CANCEL.
1375                 if (lifetimeExtensionRefactor()
1376                         && (sbn.getNotification().flags
1377                         & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) != 0) {
1378                     cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
1379                             sbn.getId(), FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
1380                             FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
1381                                     | FLAG_BUBBLE,
1382                             false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null);
1383 
1384                 } else {
1385                     // Otherwise, only FLAG_AUTO_CANCEL notifications should be canceled on click.
1386                     cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
1387                             sbn.getId(), FLAG_AUTO_CANCEL,
1388                             FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_BUBBLE,
1389                             false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null);
1390                 }
1391                 nv.recycle();
1392                 reportUserInteraction(r);
1393                 mAssistants.notifyAssistantNotificationClicked(r);
1394             }
1395         }
1396 
1397         @Override
1398         public void onNotificationActionClick(int callingUid, int callingPid, String key,
1399                 int actionIndex, Notification.Action action, NotificationVisibility nv,
1400                 boolean generatedByAssistant) {
1401             exitIdle();
1402             synchronized (mNotificationLock) {
1403                 NotificationRecord r = mNotificationsByKey.get(key);
1404                 if (r == null) {
1405                     Slog.w(TAG, "No notification with key: " + key);
1406                     return;
1407                 }
1408                 final long now = System.currentTimeMillis();
1409                 MetricsLogger.action(r.getLogMaker(now)
1410                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
1411                         .setType(MetricsEvent.TYPE_ACTION)
1412                         .setSubtype(actionIndex)
1413                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
1414                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)
1415                         .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART,
1416                                 action.isContextual() ? 1 : 0)
1417                         .addTaggedData(
1418                                 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1419                                 generatedByAssistant ? 1 : 0)
1420                         .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
1421                                 nv.location.toMetricsEventEnum()));
1422                 mNotificationRecordLogger.log(
1423                         NotificationRecordLogger.NotificationEvent.fromAction(actionIndex,
1424                                 generatedByAssistant, action.isContextual()), r);
1425                 EventLogTags.writeNotificationActionClicked(key,
1426                         action.actionIntent.getTarget().toString(),
1427                         action.actionIntent.getIntent().toString(), actionIndex,
1428                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
1429                         nv.rank, nv.count);
1430                 nv.recycle();
1431                 reportUserInteraction(r);
1432                 mAssistants.notifyAssistantActionClicked(r, action, generatedByAssistant);
1433                 // Notifications that have been interacted with should no longer be lifetime
1434                 // extended.
1435                 if (lifetimeExtensionRefactor()) {
1436                     // This cancellation should only work if
1437                     // the notification still has FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY
1438                     // We wait for 200 milliseconds before posting the cancel, to allow the app
1439                     // time to update the notification in response instead.
1440                     // If that update goes through, the notification won't have the lifetime
1441                     // extended flag, and this cancellation will be dropped.
1442                     mHandler.scheduleCancelNotification(
1443                             new CancelNotificationRunnable(
1444                                     callingUid,
1445                                     callingPid,
1446                                     r.getSbn().getPackageName(),
1447                                     r.getSbn().getTag(),
1448                                     r.getSbn().getId(),
1449                                     FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY /*=mustHaveFlags*/,
1450                                     FLAG_NO_DISMISS /*=mustNotHaveFlags*/,
1451                                     false /*=sendDelete*/,
1452                                     r.getUserId(),
1453                                     REASON_CLICK,
1454                                     -1 /*=rank*/,
1455                                     -1 /*=count*/,
1456                                     null /*=listener*/,
1457                                     SystemClock.elapsedRealtime()),
1458                             200);
1459                 }
1460             }
1461         }
1462 
1463         @Override
1464         public void onNotificationClear(int callingUid, int callingPid,
1465                 String pkg, int userId, String key,
1466                 @NotificationStats.DismissalSurface int dismissalSurface,
1467                 @NotificationStats.DismissalSentiment int dismissalSentiment,
1468                 NotificationVisibility nv) {
1469             String tag = null;
1470             int id = 0;
1471             synchronized (mNotificationLock) {
1472                 NotificationRecord r = mNotificationsByKey.get(key);
1473                 if (r != null) {
1474                     r.recordDismissalSurface(dismissalSurface);
1475                     r.recordDismissalSentiment(dismissalSentiment);
1476                     tag = r.getSbn().getTag();
1477                     id = r.getSbn().getId();
1478                 }
1479             }
1480 
1481             int mustNotHaveFlags = FLAG_NO_DISMISS;
1482             cancelNotification(callingUid, callingPid, pkg, tag, id,
1483                     /* mustHaveFlags= */ 0,
1484                     /* mustNotHaveFlags= */ mustNotHaveFlags,
1485                     /* sendDelete= */ true,
1486                     userId, REASON_CANCEL, nv.rank, nv.count, /* listener= */ null);
1487             nv.recycle();
1488         }
1489 
1490         @Override
1491         public void onPanelRevealed(boolean clearEffects, int items) {
1492             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
1493             MetricsLogger.histogram(getContext(), "note_load", items);
1494             mNotificationRecordLogger.log(
1495                     NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN);
1496             EventLogTags.writeNotificationPanelRevealed(items);
1497             if (clearEffects) {
1498                 clearEffects();
1499             }
1500             mAssistants.onPanelRevealed(items);
1501         }
1502 
1503         @Override
1504         public void onPanelHidden() {
1505             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
1506             mNotificationRecordLogger.log(
1507                     NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE);
1508             EventLogTags.writeNotificationPanelHidden();
1509             mAssistants.onPanelHidden();
1510         }
1511 
1512         @Override
1513         public void clearEffects() {
1514             synchronized (mNotificationLock) {
1515                 if (DBG) Slog.d(TAG, "clearEffects");
1516                 mAttentionHelper.clearAttentionEffects();
1517             }
1518         }
1519 
1520         @Override
1521         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
1522                 int id, int uid, int initialPid, String message, int userId) {
1523             final boolean fgService;
1524             final boolean uiJob;
1525             synchronized (mNotificationLock) {
1526                 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
1527                 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
1528                 uiJob = r != null && (r.getNotification().flags & FLAG_USER_INITIATED_JOB) != 0;
1529             }
1530             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
1531                     REASON_ERROR, null);
1532             if (fgService || uiJob) {
1533                 // Still crash for foreground services or user-initiated jobs, preventing the
1534                 // not-crash behaviour abused by apps to give us a garbage notification and
1535                 // silently start a fg service or user-initiated job.
1536                 final int exceptionTypeId = fgService
1537                         ? BadForegroundServiceNotificationException.TYPE_ID
1538                         : BadUserInitiatedJobNotificationException.TYPE_ID;
1539                 Binder.withCleanCallingIdentity(
1540                         () -> mAm.crashApplicationWithType(uid, initialPid, pkg, -1,
1541                             "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
1542                                 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
1543                                 + message, true /* force */, exceptionTypeId));
1544             }
1545         }
1546 
1547         @Override
1548         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
1549                 NotificationVisibility[] noLongerVisibleKeys) {
1550             synchronized (mNotificationLock) {
1551                 for (NotificationVisibility nv : newlyVisibleKeys) {
1552                     NotificationRecord r = mNotificationsByKey.get(nv.key);
1553                     if (r == null) continue;
1554                     if (!r.isSeen()) {
1555                         // Report to usage stats that notification was made visible
1556                         if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
1557                         reportSeen(r);
1558                     }
1559                     r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger);
1560                     mAssistants.notifyAssistantVisibilityChangedLocked(r, true);
1561                     boolean isHun = (nv.location
1562                             == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
1563                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
1564                     // the NotificationRecord to ensure the expansion state is up-to-date.
1565                     if (isHun || r.hasBeenVisiblyExpanded()) {
1566                         logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
1567                     }
1568                     maybeRecordInterruptionLocked(r);
1569                     nv.recycle();
1570                 }
1571                 // Note that we might receive this event after notifications
1572                 // have already left the system, e.g. after dismissing from the
1573                 // shade. Hence not finding notifications in
1574                 // mNotificationsByKey is not an exceptional condition.
1575                 for (NotificationVisibility nv : noLongerVisibleKeys) {
1576                     NotificationRecord r = mNotificationsByKey.get(nv.key);
1577                     if (r == null) continue;
1578                     r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger);
1579                     mAssistants.notifyAssistantVisibilityChangedLocked(r, false);
1580                     nv.recycle();
1581                 }
1582             }
1583         }
1584 
1585         @Override
1586         public void onNotificationExpansionChanged(String key,
1587                 boolean userAction, boolean expanded, int notificationLocation) {
1588             synchronized (mNotificationLock) {
1589                 NotificationRecord r = mNotificationsByKey.get(key);
1590                 if (r != null) {
1591                     r.stats.onExpansionChanged(userAction, expanded);
1592                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
1593                     // the NotificationRecord to ensure the expansion state is up-to-date.
1594                     if (r.hasBeenVisiblyExpanded()) {
1595                         logSmartSuggestionsVisible(r, notificationLocation);
1596                     }
1597                     if (userAction) {
1598                         MetricsLogger.action(r.getItemLogMaker()
1599                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
1600                                         : MetricsEvent.TYPE_COLLAPSE));
1601                         mNotificationRecordLogger.log(
1602                                 NotificationRecordLogger.NotificationEvent.fromExpanded(expanded,
1603                                         userAction),
1604                                 r);
1605                     }
1606                     if (expanded && userAction) {
1607                         r.recordExpanded();
1608                         reportUserInteraction(r);
1609                     }
1610                     mAssistants.notifyAssistantExpansionChangedLocked(
1611                             r.getSbn(), r.getNotificationType(), userAction, expanded);
1612                 }
1613             }
1614         }
1615 
1616         @Override
1617         public void onNotificationDirectReplied(String key) {
1618             exitIdle();
1619             String packageName = null;
1620             final int packageImportance;
1621             synchronized (mNotificationLock) {
1622                 NotificationRecord r = mNotificationsByKey.get(key);
1623                 if (r != null) {
1624                     packageName = r.getSbn().getPackageName();
1625                 }
1626             }
1627             if (lifetimeExtensionRefactor() && packageName != null) {
1628                 packageImportance = getPackageImportanceWithIdentity(packageName);
1629             } else {
1630                 packageImportance = IMPORTANCE_NONE;
1631             }
1632             synchronized (mNotificationLock) {
1633                 NotificationRecord r = mNotificationsByKey.get(key);
1634                 if (r != null) {
1635                     // If the notification is already marked as lifetime extended before we record
1636                     // the new direct reply, there must have been a previous lifetime extension
1637                     // event, and the app has already cancelled the notification, or does not
1638                     // respond to direct replies with updates. So we need to update System UI
1639                     // immediately.
1640                     if (lifetimeExtensionRefactor()) {
1641                         // We need to reset this to allow the notif to be updated again.
1642                         r.setCanceledAfterLifetimeExtension(false);
1643                         maybeNotifySystemUiListenerLifetimeExtendedLocked(r,
1644                                 r.getSbn().getPackageName(), packageImportance);
1645                     }
1646 
1647                     r.recordDirectReplied();
1648                     mMetricsLogger.write(r.getLogMaker()
1649                             .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
1650                             .setType(MetricsEvent.TYPE_ACTION));
1651                     mNotificationRecordLogger.log(
1652                             NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
1653                             r);
1654                     reportUserInteraction(r);
1655                     mAssistants.notifyAssistantNotificationDirectReplyLocked(r);
1656                 }
1657             }
1658         }
1659 
1660         @Override
1661         public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
1662                 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
1663             synchronized (mNotificationLock) {
1664                 NotificationRecord r = mNotificationsByKey.get(key);
1665                 if (r != null) {
1666                     r.setNumSmartRepliesAdded(smartReplyCount);
1667                     r.setNumSmartActionsAdded(smartActionCount);
1668                     r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
1669                     r.setEditChoicesBeforeSending(editBeforeSending);
1670                 }
1671             }
1672         }
1673 
1674         @Override
1675         public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
1676                 int notificationLocation, boolean modifiedBeforeSending) {
1677             String packageName = null;
1678             final int packageImportance;
1679             synchronized (mNotificationLock) {
1680                 NotificationRecord r = mNotificationsByKey.get(key);
1681                 if (r != null) {
1682                     packageName = r.getSbn().getPackageName();
1683                 }
1684             }
1685             if (lifetimeExtensionRefactor() && packageName != null) {
1686                 packageImportance = getPackageImportanceWithIdentity(packageName);
1687             } else {
1688                 packageImportance = IMPORTANCE_NONE;
1689             }
1690             synchronized (mNotificationLock) {
1691                 NotificationRecord r = mNotificationsByKey.get(key);
1692                 if (r != null) {
1693                     // If the notification is already marked as lifetime extended before we record
1694                     // the new direct reply, there must have been a previous lifetime extension
1695                     // event, and the app has already cancelled the notification, or does not
1696                     // respond to direct replies with updates. So we need to update System UI
1697                     // immediately.
1698                     if (lifetimeExtensionRefactor()) {
1699                         // We need to reset this to allow the notif to be updated again.
1700                         r.setCanceledAfterLifetimeExtension(false);
1701                         maybeNotifySystemUiListenerLifetimeExtendedLocked(r,
1702                                 r.getSbn().getPackageName(), packageImportance);
1703                     }
1704 
1705                     r.recordSmartReplied();
1706                     LogMaker logMaker = r.getLogMaker()
1707                             .setCategory(MetricsEvent.SMART_REPLY_ACTION)
1708                             .setSubtype(replyIndex)
1709                             .addTaggedData(
1710                                     MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1711                                     r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1712                             .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
1713                                     notificationLocation)
1714                             .addTaggedData(
1715                                     MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1716                                     r.getEditChoicesBeforeSending() ? 1 : 0)
1717                             .addTaggedData(
1718                                     MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
1719                                     modifiedBeforeSending ? 1 : 0);
1720                     mMetricsLogger.write(logMaker);
1721                     mNotificationRecordLogger.log(
1722                             NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
1723                             r);
1724                     // Treat clicking on a smart reply as a user interaction.
1725                     reportUserInteraction(r);
1726                     mAssistants.notifyAssistantSuggestedReplySent(
1727                             r.getSbn(), r.getNotificationType(), reply,
1728                             r.getSuggestionsGeneratedByAssistant());
1729                 }
1730             }
1731         }
1732 
1733         @Override
1734         public void onNotificationSettingsViewed(String key) {
1735             synchronized (mNotificationLock) {
1736                 NotificationRecord r = mNotificationsByKey.get(key);
1737                 if (r != null) {
1738                     r.recordViewedSettings();
1739                 }
1740             }
1741         }
1742 
1743         @Override
1744         public void onNotificationBubbleChanged(String key, boolean isBubble, int bubbleFlags) {
1745             synchronized (mNotificationLock) {
1746                 NotificationRecord r = mNotificationsByKey.get(key);
1747                 if (r != null) {
1748                     if (!isBubble) {
1749                         // This happens if the user has dismissed the bubble but the notification
1750                         // is still active in the shade, enqueuing would create a bubble since
1751                         // the notification is technically allowed. Flip the flag so that
1752                         // apps querying noMan will know that their notification is not showing
1753                         // as a bubble.
1754                         r.getNotification().flags &= ~FLAG_BUBBLE;
1755                         r.setFlagBubbleRemoved(true);
1756                     } else {
1757                         // Enqueue will trigger resort & if the flag is allowed to be true it'll
1758                         // be applied there.
1759                         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
1760                         r.setFlagBubbleRemoved(false);
1761                         if (r.getNotification().getBubbleMetadata() != null) {
1762                             r.getNotification().getBubbleMetadata().setFlags(bubbleFlags);
1763                         }
1764                         // Force isAppForeground true here, because for sysui's purposes we
1765                         // want to adjust the flag behaviour.
1766                         mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(),
1767                                 r, /* isAppForeground= */ true , /* isAppProvided= */ false,
1768                                 mPostNotificationTrackerFactory.newTracker(null)));
1769                     }
1770                 }
1771             }
1772         }
1773 
1774         @Override
1775         public void onBubbleMetadataFlagChanged(String key, int flags) {
1776             synchronized (mNotificationLock) {
1777                 NotificationRecord r = mNotificationsByKey.get(key);
1778                 if (r != null) {
1779                     Notification.BubbleMetadata data = r.getNotification().getBubbleMetadata();
1780                     if (data == null) {
1781                         // No data, do nothing
1782                         return;
1783                     }
1784 
1785                     if (flags != data.getFlags()) {
1786                         int changedFlags = data.getFlags() ^ flags;
1787                         if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) {
1788                             // Suppress notification flag changed, clear any effects
1789                             mAttentionHelper.clearEffectsLocked(key);
1790                         }
1791                         data.setFlags(flags);
1792                         // Shouldn't alert again just because of a flag change.
1793                         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
1794                         // Force isAppForeground true here, because for sysui's purposes we
1795                         // want to be able to adjust the flag behaviour.
1796                         mHandler.post(
1797                                 new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r,
1798                                         /* foreground= */ true, /* isAppProvided= */ false,
1799                                         mPostNotificationTrackerFactory.newTracker(null)));
1800                     }
1801                 }
1802             }
1803         }
1804 
1805         /**
1806          * Grant permission to read the specified URI to the package specified in the
1807          * NotificationRecord associated with the given key. The callingUid represents the UID of
1808          * SystemUI from which this method is being called.
1809          *
1810          * For this to work, SystemUI must have permission to read the URI when running under the
1811          * user associated with the NotificationRecord, and this grant will fail when trying
1812          * to grant URI permissions across users.
1813          */
1814         @Override
1815         public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
1816                 String packageName, int callingUid) {
1817             synchronized (mNotificationLock) {
1818                 InlineReplyUriRecord r = mInlineReplyRecordsByKey.get(key);
1819                 if (r == null) {
1820                     InlineReplyUriRecord newRecord = new InlineReplyUriRecord(
1821                             mUgmInternal.newUriPermissionOwner("INLINE_REPLY:" + key),
1822                             user,
1823                             packageName,
1824                             key);
1825                     r = newRecord;
1826                     mInlineReplyRecordsByKey.put(key, r);
1827                 }
1828                 IBinder owner = r.getPermissionOwner();
1829                 int uid = callingUid;
1830                 int userId = r.getUserId();
1831                 if (UserHandle.getUserId(uid) != userId) {
1832                     try {
1833                         final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
1834                         if (pkgs == null) {
1835                             Log.e(TAG, "Cannot grant uri permission to unknown UID: "
1836                                     + callingUid);
1837                         }
1838                         final String pkg = pkgs[0]; // Get the SystemUI package
1839                         // Find the UID for SystemUI for the correct user
1840                         uid =  mPackageManager.getPackageUid(pkg, 0, userId);
1841                     } catch (RemoteException re) {
1842                         Log.e(TAG, "Cannot talk to package manager", re);
1843                     }
1844                 }
1845                 r.addUri(uri);
1846                 grantUriPermission(owner, uri, uid, r.getPackageName(), userId);
1847             }
1848         }
1849 
1850         @Override
1851         /**
1852          * Clears inline URI permission grants by destroying the permission owner for the specified
1853          * notification.
1854          */
1855         public void clearInlineReplyUriPermissions(String key, int callingUid) {
1856             synchronized (mNotificationLock) {
1857                 InlineReplyUriRecord uriRecord = mInlineReplyRecordsByKey.get(key);
1858                 if (uriRecord != null) {
1859                     destroyPermissionOwner(uriRecord.getPermissionOwner(), uriRecord.getUserId(),
1860                             "INLINE_REPLY: " + uriRecord.getKey());
1861                     mInlineReplyRecordsByKey.remove(key);
1862                 }
1863             }
1864         }
1865 
1866         @Override
1867         public void onNotificationFeedbackReceived(String key, Bundle feedback) {
1868             exitIdle();
1869             synchronized (mNotificationLock) {
1870                 NotificationRecord r = mNotificationsByKey.get(key);
1871                 if (r == null) {
1872                     if (DBG) Slog.w(TAG, "No notification with key: " + key);
1873                     return;
1874                 }
1875                 mAssistants.notifyAssistantFeedbackReceived(r, feedback);
1876             }
1877         }
1878     };
1879 
applyNotificationUpdateForUser(final int userId, NotificationUpdate notificationUpdate)1880     private void applyNotificationUpdateForUser(final int userId,
1881             NotificationUpdate notificationUpdate) {
1882         applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId,
1883                 notificationUpdate);
1884     }
1885 
applyNotificationUpdateForUid(final int userId, @NonNull final String pkg, NotificationUpdate notificationUpdate)1886     private void applyNotificationUpdateForUid(final int userId, @NonNull final String pkg,
1887             NotificationUpdate notificationUpdate) {
1888         applyUpdateForNotificationsFiltered((r) ->
1889                 r.getUserId() == userId
1890                 && Objects.equals(r.getSbn().getPackageName(), pkg),
1891                 notificationUpdate);
1892     }
1893 
applyNotificationUpdateForUserAndChannelType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate)1894     private void applyNotificationUpdateForUserAndChannelType(final int userId,
1895             final @Types int bundleType, NotificationUpdate notificationUpdate) {
1896         final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType);
1897         applyUpdateForNotificationsFiltered((r) ->
1898                 r.getUserId() == userId
1899                 && r.getChannel() != null
1900                 && Objects.equals(bundleChannelId, r.getChannel().getId()),
1901                 notificationUpdate);
1902     }
1903 
applyNotificationUpdateForUserAndType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate)1904     private void applyNotificationUpdateForUserAndType(final int userId,
1905             final @Types int bundleType, NotificationUpdate notificationUpdate) {
1906         applyUpdateForNotificationsFiltered(
1907                 (r) -> r.getUserId() == userId && r.getBundleType() == bundleType,
1908                 notificationUpdate);
1909     }
1910 
1911     @VisibleForTesting
unclassifyNotification(final String key)1912     void unclassifyNotification(final String key) {
1913         if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
1914             return;
1915         }
1916         synchronized (mNotificationLock) {
1917             NotificationRecord r = mNotificationsByKey.get(key);
1918             if (r == null) {
1919                 return;
1920             }
1921             unclassifyNotificationLocked(r, true);
1922         }
1923     }
1924 
1925     @VisibleForTesting
reclassifyNotification(String key)1926     void reclassifyNotification(String key) {
1927         if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
1928             return;
1929         }
1930         synchronized (mNotificationLock) {
1931             NotificationRecord r = mNotificationsByKey.get(key);
1932             if (r == null) {
1933                 return;
1934             }
1935             reclassifyNotificationLocked(r, true);
1936         }
1937     }
1938 
1939     @GuardedBy("mNotificationLock")
unclassifyNotificationLocked(@onNull final NotificationRecord r, boolean isPosted)1940     private void unclassifyNotificationLocked(@NonNull final NotificationRecord r,
1941             boolean isPosted) {
1942         if (DBG) {
1943             Slog.v(TAG, "unclassifyNotification: " + r);
1944         }
1945         // Only NotificationRecord's mChannel is updated when bundled, the Notification
1946         // mChannelId will always be the original channel.
1947         String origChannelId = r.getNotification().getChannelId();
1948         NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
1949                 r.getSbn().getPackageName(), r.getUid(), origChannelId, false);
1950         String currChannelId = r.getChannel().getId();
1951         boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId);
1952         if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) {
1953             r.updateNotificationChannel(originalChannel);
1954             mGroupHelper.onNotificationUnbundled(r,
1955                     GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey));
1956         }
1957     }
1958 
1959     @GuardedBy("mNotificationLock")
unsummarizeNotificationLocked(@onNull final NotificationRecord r, boolean isPosted)1960     private void unsummarizeNotificationLocked(@NonNull final NotificationRecord r,
1961             boolean isPosted) {
1962         Bundle signals = new Bundle();
1963         signals.putString(KEY_SUMMARIZATION, null);
1964         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
1965                 r.getSbn().getUserId());
1966         r.addAdjustment(adjustment);
1967         mRankingHandler.requestSort();
1968 
1969     }
1970 
1971     @GuardedBy("mNotificationLock")
reclassifyNotificationLocked(@onNull final NotificationRecord r, final boolean isPosted)1972     private void reclassifyNotificationLocked(@NonNull final NotificationRecord r,
1973             final boolean isPosted) {
1974         if (DBG) {
1975             Slog.v(TAG, "reclassifyNotification: " + r);
1976         }
1977 
1978         boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(
1979                 r.getChannel().getId());
1980         if (r.getBundleType() != Adjustment.TYPE_OTHER && !isClassified) {
1981             final Bundle classifBundle = new Bundle();
1982             classifBundle.putInt(KEY_TYPE, r.getBundleType());
1983             Adjustment adj = new Adjustment(r.getSbn().getPackageName(), r.getKey(),
1984                     classifBundle, "reclassify", r.getUserId());
1985             applyAdjustmentLocked(r, adj, isPosted);
1986             mRankingHandler.requestSort();
1987         } else {
1988             if (DBG) {
1989                 Slog.w(TAG, "Can't reclassify. No valid bundle type or already bundled: " + r);
1990             }
1991         }
1992     }
1993 
1994     /**
1995      * Given a filter and a function to update a notification record, runs that function on all
1996      * enqueued and posted notifications that match the filter
1997      */
applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter, NotificationUpdate notificationUpdate)1998     private void applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter,
1999             NotificationUpdate notificationUpdate) {
2000         synchronized (mNotificationLock) {
2001             for (int i = 0; i < mEnqueuedNotifications.size(); i++) {
2002                 final NotificationRecord r = mEnqueuedNotifications.get(i);
2003                 if (filter.test(r)) {
2004                     notificationUpdate.apply(r, false);
2005                 }
2006             }
2007 
2008             for (int i = 0; i < mNotificationList.size(); i++) {
2009                 final NotificationRecord r = mNotificationList.get(i);
2010                 if (filter.test(r)) {
2011                     notificationUpdate.apply(r, true);
2012                 }
2013             }
2014         }
2015     }
2016 
2017     private interface NotificationUpdate {
apply(NotificationRecord r, boolean isPosted)2018         void apply(NotificationRecord r, boolean isPosted);
2019     }
2020 
2021     NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() {
2022         @Nullable
2023         @Override
2024         public NotificationRecord getNotificationByKey(String key) {
2025             synchronized (mNotificationLock) {
2026                 return mNotificationsByKey.get(key);
2027             }
2028         }
2029 
2030         @Override
2031         @FlaggedApi(Flags.FLAG_ALL_NOTIFS_NEED_TTL)
2032         public void timeoutNotification(String key) {
2033             boolean foundNotification = false;
2034             int uid = 0;
2035             int pid = 0;
2036             String packageName = null;
2037             String tag = null;
2038             int id = 0;
2039             int userId = 0;
2040 
2041             synchronized (mNotificationLock) {
2042                 NotificationRecord record = findNotificationByKeyLocked(key);
2043                 if (record != null) {
2044                     foundNotification = true;
2045                     uid = record.getUid();
2046                     pid = record.getSbn().getInitialPid();
2047                     packageName = record.getSbn().getPackageName();
2048                     tag = record.getSbn().getTag();
2049                     id = record.getSbn().getId();
2050                     userId = record.getUserId();
2051                 }
2052             }
2053             if (foundNotification) {
2054                 if (lifetimeExtensionRefactor()) {
2055                     cancelNotification(uid, pid, packageName, tag, id, 0,
2056                             FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
2057                                     | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
2058                             true, userId, REASON_TIMEOUT, null);
2059                 } else {
2060                     cancelNotification(uid, pid, packageName, tag, id, 0,
2061                             FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
2062                             true, userId, REASON_TIMEOUT, null);
2063                 }
2064             }
2065         }
2066     };
2067 
2068     @VisibleForTesting
logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)2069     void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
2070         // If the newly visible notification has smart suggestions
2071         // then log that the user has seen them.
2072         if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
2073                 && !r.hasSeenSmartReplies()) {
2074             r.setSeenSmartReplies(true);
2075             LogMaker logMaker = r.getLogMaker()
2076                     .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
2077                     .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
2078                             r.getNumSmartRepliesAdded())
2079                     .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
2080                             r.getNumSmartActionsAdded())
2081                     .addTaggedData(
2082                             MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
2083                             r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
2084                     // The fields in the NotificationVisibility.NotificationLocation enum map
2085                     // directly to the fields in the MetricsEvent.NotificationLocation enum.
2086                     .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
2087                     .addTaggedData(
2088                             MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
2089                             r.getEditChoicesBeforeSending() ? 1 : 0);
2090             mMetricsLogger.write(logMaker);
2091             mNotificationRecordLogger.log(
2092                     NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLY_VISIBLE,
2093                     r);
2094         }
2095     }
2096 
logSensitiveAdjustmentReceived(boolean hasPosted, boolean hasSensitiveContent, int lifespanMs)2097     protected void logSensitiveAdjustmentReceived(boolean hasPosted,
2098             boolean hasSensitiveContent, int lifespanMs) {
2099         FrameworkStatsLog.write(FrameworkStatsLog.SENSITIVE_NOTIFICATION_REDACTION, hasPosted,
2100                 hasSensitiveContent, lifespanMs);
2101     }
2102 
logClassificationChannelAdjustmentReceived(NotificationRecord r, boolean hasPosted, int classification)2103     protected void logClassificationChannelAdjustmentReceived(NotificationRecord r,
2104                                                               boolean hasPosted,
2105                                                               int classification) {
2106         // Note that this value of isAlerting does not fully indicate whether a notif
2107         // would make a sound or HUN on device; it is an approximation for metrics.
2108         boolean isAlerting = r.getChannel().getImportance() >= IMPORTANCE_DEFAULT;
2109         int instanceId = r.getSbn().getInstanceId() == null
2110                 ? 0 : r.getSbn().getInstanceId().getId();
2111 
2112         FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_CLASSIFICATION,
2113                 hasPosted, isAlerting, classification,
2114                 r.getLifespanMs(System.currentTimeMillis()),
2115                 NotificationReportedEvent.NOTIFICATION_ADJUSTED.getId(),
2116                 instanceId, r.getUid());
2117     }
2118 
2119     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
2120         @Override
2121         public void onReceive(Context context, Intent intent) {
2122             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
2123                 // update system notification channels
2124                 SystemNotificationChannels.createAll(context);
2125                 mZenModeHelper.updateZenRulesOnLocaleChange();
2126                 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
2127             }
2128         }
2129     };
2130 
2131     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
2132         @Override
2133         public void onReceive(Context context, Intent intent) {
2134             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
2135                 try {
2136                     String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
2137                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
2138                     int restoredFromSdkInt = intent.getIntExtra(
2139                             Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
2140                     mListeners.onSettingRestored(
2141                             element, newValue, restoredFromSdkInt, getSendingUserId());
2142                     mConditionProviders.onSettingRestored(
2143                             element, newValue, restoredFromSdkInt, getSendingUserId());
2144                 } catch (Exception e) {
2145                     Slog.wtf(TAG, "Cannot restore managed services from settings", e);
2146                 }
2147             }
2148         }
2149     };
2150 
2151     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
2152         @Override
2153         public void onReceive(Context context, Intent intent) {
2154             String action = intent.getAction();
2155             if (action == null) {
2156                 return;
2157             }
2158             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
2159                 final NotificationRecord record;
2160                 // TODO: b/323013410 - Record should be cloned instead of used directly.
2161                 synchronized (mNotificationLock) {
2162                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
2163                 }
2164                 if (record != null) {
2165                     if (lifetimeExtensionRefactor()) {
2166                         cancelNotification(record.getSbn().getUid(),
2167                                 record.getSbn().getInitialPid(),
2168                                 record.getSbn().getPackageName(), record.getSbn().getTag(),
2169                                 record.getSbn().getId(), 0,
2170                                 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
2171                                         | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
2172                                 true, record.getUserId(), REASON_TIMEOUT, null);
2173                     } else {
2174                         cancelNotification(record.getSbn().getUid(),
2175                                 record.getSbn().getInitialPid(),
2176                                 record.getSbn().getPackageName(), record.getSbn().getTag(),
2177                                 record.getSbn().getId(), 0,
2178                                 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
2179                                 true, record.getUserId(), REASON_TIMEOUT, null);
2180                     }
2181                 }
2182             }
2183         }
2184     };
2185 
2186     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
2187         @Override
2188         public void onReceive(Context context, Intent intent) {
2189             String action = intent.getAction();
2190             if (action == null) {
2191                 return;
2192             }
2193 
2194             boolean queryRemove = false;
2195             boolean packageChanged = false;
2196             boolean cancelNotifications = true;
2197             boolean hideNotifications = false;
2198             boolean unhideNotifications = false;
2199             int reason = REASON_PACKAGE_CHANGED;
2200 
2201             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
2202                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
2203                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
2204                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
2205                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
2206                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
2207                     || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
2208                     || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
2209                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
2210                         USER_ALL);
2211                 String pkgList[] = null;
2212                 int uidList[] = null;
2213                 boolean removingPackage = queryRemove &&
2214                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
2215                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
2216                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2217                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
2218                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
2219                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
2220                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
2221                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
2222                     cancelNotifications = false;
2223                     hideNotifications = true;
2224                 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
2225                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
2226                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
2227                     cancelNotifications = false;
2228                     unhideNotifications = true;
2229                 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
2230                     final int distractionRestrictions =
2231                             intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
2232                                     PackageManager.RESTRICTION_NONE);
2233                     if ((distractionRestrictions
2234                             & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
2235                         pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
2236                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
2237                         cancelNotifications = false;
2238                         hideNotifications = true;
2239                     } else {
2240                         pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
2241                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
2242                         cancelNotifications = false;
2243                         unhideNotifications = true;
2244                     }
2245                 } else {
2246                     Uri uri = intent.getData();
2247                     if (uri == null) {
2248                         return;
2249                     }
2250                     String pkgName = uri.getSchemeSpecificPart();
2251                     if (pkgName == null) {
2252                         return;
2253                     }
2254                     if (packageChanged) {
2255                         // We cancel notifications for packages which have just been disabled
2256                         try {
2257                             final int enabled = mPackageManager.getApplicationEnabledSetting(
2258                                     pkgName,
2259                                     changeUserId != USER_ALL ? changeUserId :
2260                                             USER_SYSTEM);
2261                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
2262                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
2263                                 cancelNotifications = false;
2264                             }
2265                         } catch (IllegalArgumentException e) {
2266                             // Package doesn't exist; probably racing with uninstall.
2267                             // cancelNotifications is already true, so nothing to do here.
2268                             if (DBG) {
2269                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
2270                             }
2271                         } catch (RemoteException e) {
2272                             // Failed to talk to PackageManagerService Should never happen!
2273                         }
2274                     }
2275                     pkgList = new String[]{pkgName};
2276                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
2277                 }
2278                 if (pkgList != null && (pkgList.length > 0)) {
2279                     if (cancelNotifications) {
2280                         for (String pkgName : pkgList) {
2281                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
2282                                     changeUserId, reason);
2283                         }
2284                     } else if (hideNotifications && uidList != null && (uidList.length > 0)) {
2285                         hideNotificationsForPackages(pkgList, uidList);
2286                     } else if (unhideNotifications && uidList != null && (uidList.length > 0)) {
2287                         unhideNotificationsForPackages(pkgList, uidList);
2288                     }
2289                 }
2290                 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
2291             }
2292         }
2293     };
2294 
2295     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
2296         @Override
2297         public void onReceive(Context context, Intent intent) {
2298             String action = intent.getAction();
2299 
2300             if (action.equals(Intent.ACTION_USER_STOPPED)) {
2301                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
2302                 if (userHandle >= 0) {
2303                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
2304                             REASON_USER_STOPPED);
2305                     mConditionProviders.onUserStopped(userHandle);
2306                     mListeners.onUserStopped(userHandle);
2307                     mAssistants.onUserStopped(userHandle);
2308                 }
2309             } else if (
2310                     isProfileUnavailable(action)) {
2311                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
2312                 if (userHandle >= 0) {
2313                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
2314                             REASON_PROFILE_TURNED_OFF);
2315                     mSnoozeHelper.clearData(userHandle);
2316                 }
2317             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
2318                 if (!Flags.useSsmUserSwitchSignal()) {
2319                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2320                     mUserProfiles.updateCache(context);
2321                     if (!mUserProfiles.isProfileUser(userId, context)) {
2322                         // reload per-user settings
2323                         mSettingsObserver.update(null);
2324                         // Refresh managed services
2325                         mConditionProviders.onUserSwitched(userId);
2326                         mListeners.onUserSwitched(userId);
2327                         mZenModeHelper.onUserSwitched(userId);
2328                         mPreferencesHelper.syncHasPriorityChannels();
2329                     }
2330                     // assistant is the only thing that cares about managed profiles specifically
2331                     mAssistants.onUserSwitched(userId);
2332                 }
2333             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
2334                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2335                 if (userId != USER_NULL) {
2336                     mUserProfiles.updateCache(context);
2337                     if (!mUserProfiles.isProfileUser(userId, context)) {
2338                         allowDefaultApprovedServices(userId);
2339                     }
2340                     mHistoryManager.onUserAdded(userId);
2341                     mSettingsObserver.update(null, userId);
2342                 }
2343             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
2344                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2345                 mUserProfiles.updateCache(context);
2346                 mZenModeHelper.onUserRemoved(userId);
2347                 mPreferencesHelper.onUserRemoved(userId);
2348                 mListeners.onUserRemoved(userId);
2349                 mConditionProviders.onUserRemoved(userId);
2350                 mAssistants.onUserRemoved(userId);
2351                 mHistoryManager.onUserRemoved(userId);
2352                 mPreferencesHelper.syncHasPriorityChannels();
2353                 handleSavePolicyFile();
2354             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
2355                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
2356                 mUserProfiles.updateCache(context);
2357                 mAssistants.onUserUnlocked(userId);
2358                 if (!mUserProfiles.isProfileUser(userId, context)) {
2359                     mConditionProviders.onUserUnlocked(userId);
2360                     mListeners.onUserUnlocked(userId);
2361                 }
2362             }
2363         }
2364 
2365         private boolean isProfileUnavailable(String action) {
2366             return privateSpaceFlagsEnabled() ?
2367                     action.equals(Intent.ACTION_PROFILE_UNAVAILABLE) :
2368                     action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
2369         }
2370     };
2371 
2372     private final class SettingsObserver extends ContentObserver {
2373         private final Uri NOTIFICATION_BADGING_URI
2374                 = Secure.getUriFor(Secure.NOTIFICATION_BADGING);
2375         private final Uri NOTIFICATION_BUBBLES_URI
2376                 = Secure.getUriFor(Secure.NOTIFICATION_BUBBLES);
2377         private final Uri NOTIFICATION_RATE_LIMIT_URI
2378                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
2379         private final Uri NOTIFICATION_HISTORY_ENABLED
2380                 = Secure.getUriFor(Secure.NOTIFICATION_HISTORY_ENABLED);
2381         private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI
2382                 = Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS);
2383         private final Uri LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
2384                 = Secure.getUriFor(
2385                         Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
2386         private final Uri LOCK_SCREEN_SHOW_NOTIFICATIONS
2387                 = Secure.getUriFor(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
2388         private final Uri SHOW_NOTIFICATION_SNOOZE
2389                 = Secure.getUriFor(Secure.SHOW_NOTIFICATION_SNOOZE);
2390         private final Uri REDACT_OTP_NOTIFICATIONS = Settings.Global.getUriFor(
2391                 Settings.Global.REDACT_OTP_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
2392 
SettingsObserver(Handler handler)2393         SettingsObserver(Handler handler) {
2394             super(handler);
2395         }
2396 
observe()2397         void observe() {
2398             ContentResolver resolver = getContext().getContentResolver();
2399             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
2400                     false, this, USER_ALL);
2401             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
2402                     false, this, USER_ALL);
2403             resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
2404                     false, this, USER_ALL);
2405             resolver.registerContentObserver(NOTIFICATION_HISTORY_ENABLED,
2406                     false, this, USER_ALL);
2407             resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI,
2408                     false, this, USER_ALL);
2409 
2410             resolver.registerContentObserver(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
2411                     false, this, USER_ALL);
2412             resolver.registerContentObserver(LOCK_SCREEN_SHOW_NOTIFICATIONS,
2413                     false, this, USER_ALL);
2414 
2415             resolver.registerContentObserver(SHOW_NOTIFICATION_SNOOZE,
2416                     false, this, USER_ALL);
2417             resolver.registerContentObserver(REDACT_OTP_NOTIFICATIONS,
2418                     false, this, USER_ALL);
2419 
2420             update(null);
2421         }
2422 
destroy()2423         void destroy() {
2424             getContext().getContentResolver().unregisterContentObserver(this);
2425         }
2426 
onChange(boolean selfChange, Uri uri, int userId)2427         @Override public void onChange(boolean selfChange, Uri uri, int userId) {
2428             update(uri);
2429         }
2430 
update(Uri uri)2431         public void update(Uri uri) {
2432             ContentResolver resolver = getContext().getContentResolver();
2433             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
2434                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
2435                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
2436             }
2437             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
2438                 mPreferencesHelper.updateBadgingEnabled();
2439             }
2440             if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
2441                 mPreferencesHelper.updateBubblesEnabled();
2442             }
2443             if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) {
2444                 for (UserInfo userInfo : mUm.getUsers()) {
2445                     update(uri, userInfo.id);
2446                 }
2447             }
2448             if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) {
2449                 mPreferencesHelper.updateMediaNotificationFilteringEnabled();
2450             }
2451             if (uri == null || LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS.equals(uri)) {
2452                 mPreferencesHelper.updateLockScreenPrivateNotifications();
2453             }
2454             if (uri == null || LOCK_SCREEN_SHOW_NOTIFICATIONS.equals(uri)) {
2455                 mPreferencesHelper.updateLockScreenShowNotifications();
2456             }
2457             if (SHOW_NOTIFICATION_SNOOZE.equals(uri)) {
2458                 final boolean snoozeEnabled = Secure.getIntForUser(resolver,
2459                         Secure.SHOW_NOTIFICATION_SNOOZE, 0, UserHandle.USER_CURRENT)
2460                         != 0;
2461                 if (!snoozeEnabled) {
2462                     unsnoozeAll();
2463                 }
2464             }
2465             if (REDACT_OTP_NOTIFICATIONS.equals(uri)) {
2466                 mRedactOtpNotifications = Settings.Global.getInt(resolver,
2467                         Settings.Global.REDACT_OTP_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS, 1) != 0;
2468             }
2469         }
2470 
update(Uri uri, int userId)2471         public void update(Uri uri, int userId) {
2472             ContentResolver resolver = getContext().getContentResolver();
2473             if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) {
2474                 mArchive.updateHistoryEnabled(userId,
2475                         Secure.getIntForUser(resolver,
2476                                 Secure.NOTIFICATION_HISTORY_ENABLED, 0,
2477                                 userId) == 1);
2478                 // note: this setting is also handled in NotificationHistoryManager
2479             }
2480         }
2481     }
2482 
2483     private SettingsObserver mSettingsObserver;
2484     protected ZenModeHelper mZenModeHelper;
2485 
2486     protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
2487 
2488         SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray();
2489 
StrongAuthTracker(Context context)2490         StrongAuthTracker(Context context) {
2491             super(context);
2492         }
2493 
containsFlag(int haystack, int needle)2494         private boolean containsFlag(int haystack, int needle) {
2495             return (haystack & needle) != 0;
2496         }
2497 
2498         // Return whether the user is in lockdown mode.
2499         // If the flag is not set, we assume the user is not in lockdown.
isInLockDownMode(int userId)2500         public boolean isInLockDownMode(int userId) {
2501             return mUserInLockDownMode.get(userId, false);
2502         }
2503 
2504         @Override
onStrongAuthRequiredChanged(int userId)2505         public synchronized void onStrongAuthRequiredChanged(int userId) {
2506             boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
2507                     STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
2508 
2509             // Nothing happens if the lockdown mode of userId keeps the same.
2510             if (userInLockDownModeNext == isInLockDownMode(userId)) {
2511                 return;
2512             }
2513 
2514             // When the lockdown mode is changed, we perform the following steps.
2515             // If the userInLockDownModeNext is true, all the function calls to
2516             // notifyPostedLocked and notifyRemovedLocked will not be executed.
2517             // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked
2518             // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked.
2519             // So we shall call cancelNotificationsWhenEnterLockDownMode before
2520             // we set mUserInLockDownMode as true.
2521             // On the other hand, if the userInLockDownModeNext is false, we shall call
2522             // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode
2523             if (userInLockDownModeNext) {
2524                 cancelNotificationsWhenEnterLockDownMode(userId);
2525             }
2526 
2527             mUserInLockDownMode.put(userId, userInLockDownModeNext);
2528 
2529             if (!userInLockDownModeNext) {
2530                 postNotificationsWhenExitLockDownMode(userId);
2531             }
2532         }
2533     }
2534 
2535     private StrongAuthTracker mStrongAuthTracker;
2536 
NotificationManagerService(Context context)2537     public NotificationManagerService(Context context) {
2538         this(context,
2539                 new NotificationRecordLoggerImpl(),
2540                 new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX));
2541     }
2542 
2543     @VisibleForTesting
NotificationManagerService(Context context, NotificationRecordLogger notificationRecordLogger, InstanceIdSequence notificationInstanceIdSequence)2544     public NotificationManagerService(Context context,
2545             NotificationRecordLogger notificationRecordLogger,
2546             InstanceIdSequence notificationInstanceIdSequence) {
2547         super(context);
2548         mNotificationRecordLogger = notificationRecordLogger;
2549         mNotificationInstanceIdSequence = notificationInstanceIdSequence;
2550         Notification.processAllowlistToken = ALLOWLIST_TOKEN;
2551     }
2552 
2553     // TODO - replace these methods with new fields in the VisibleForTesting constructor
2554     @VisibleForTesting
setStrongAuthTracker(StrongAuthTracker strongAuthTracker)2555     void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
2556         mStrongAuthTracker = strongAuthTracker;
2557     }
2558 
2559     @VisibleForTesting
setLockPatternUtils(LockPatternUtils lockUtils)2560     void setLockPatternUtils(LockPatternUtils lockUtils) {
2561         mLockUtils = lockUtils;
2562     }
2563 
2564     @VisibleForTesting
getShortcutHelper()2565     ShortcutHelper getShortcutHelper() {
2566         return mShortcutHelper;
2567     }
2568 
2569     @VisibleForTesting
setShortcutHelper(ShortcutHelper helper)2570     void setShortcutHelper(ShortcutHelper helper) {
2571         mShortcutHelper = helper;
2572     }
2573 
2574     @VisibleForTesting
getNotificationRecordCount()2575     int getNotificationRecordCount() {
2576         synchronized (mNotificationLock) {
2577             int count = mNotificationList.size() + mNotificationsByKey.size()
2578                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
2579             // subtract duplicates
2580             for (NotificationRecord posted : mNotificationList) {
2581                 if (mNotificationsByKey.containsKey(posted.getKey())) {
2582                     count--;
2583                 }
2584                 if (posted.getSbn().isGroup() && posted.getNotification().isGroupSummary()) {
2585                     count--;
2586                 }
2587             }
2588 
2589             return count;
2590         }
2591     }
2592 
2593     @VisibleForTesting
clearNotifications()2594     void clearNotifications() {
2595         synchronized (mNotificationLock) {
2596             mEnqueuedNotifications.clear();
2597             mNotificationList.clear();
2598             mNotificationsByKey.clear();
2599             mSummaryByGroupKey.clear();
2600         }
2601     }
2602 
2603     @VisibleForTesting
addNotification(NotificationRecord r)2604     void addNotification(NotificationRecord r) {
2605         synchronized (mNotificationLock) {
2606             mNotificationList.add(r);
2607             mNotificationsByKey.put(r.getSbn().getKey(), r);
2608             if (r.getSbn().isGroup()) {
2609                 mSummaryByGroupKey.put(r.getGroupKey(), r);
2610             }
2611         }
2612     }
2613 
2614     @VisibleForTesting
addEnqueuedNotification(NotificationRecord r)2615     void addEnqueuedNotification(NotificationRecord r) {
2616         synchronized (mNotificationLock) {
2617             mEnqueuedNotifications.add(r);
2618         }
2619     }
2620 
2621     @VisibleForTesting
getNotificationRecord(String key)2622     NotificationRecord getNotificationRecord(String key) {
2623         synchronized (mNotificationLock) {
2624             return mNotificationsByKey.get(key);
2625         }
2626     }
2627 
2628     @VisibleForTesting
setHandler(WorkerHandler handler)2629     void setHandler(WorkerHandler handler) {
2630         mHandler = handler;
2631     }
2632 
2633     @VisibleForTesting
setRankingHelper(RankingHelper rankingHelper)2634     void setRankingHelper(RankingHelper rankingHelper) {
2635         mRankingHelper = rankingHelper;
2636     }
2637 
2638     @VisibleForTesting
setPreferencesHelper(PreferencesHelper prefHelper)2639     void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
2640 
2641     @VisibleForTesting
setZenHelper(ZenModeHelper zenHelper)2642     void setZenHelper(ZenModeHelper zenHelper) {
2643         mZenModeHelper = zenHelper;
2644     }
2645 
2646     @VisibleForTesting
setAttentionHelper(NotificationAttentionHelper nah)2647     void setAttentionHelper(NotificationAttentionHelper nah) {
2648         mAttentionHelper = nah;
2649     }
2650 
2651     @VisibleForTesting
setIsTelevision(boolean isTelevision)2652     void setIsTelevision(boolean isTelevision) {
2653         mIsTelevision = isTelevision;
2654     }
2655 
2656     @VisibleForTesting
setTelecomManager(TelecomManager tm)2657     void setTelecomManager(TelecomManager tm) {
2658         mTelecomManager = tm;
2659     }
2660 
2661     // TODO: All tests should use this init instead of the one-off setters above.
2662     @VisibleForTesting
init(WorkerHandler handler, RankingHandler rankingHandler, Handler broadcastsHandler, 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)2663     void init(WorkerHandler handler, RankingHandler rankingHandler, Handler broadcastsHandler,
2664             IPackageManager packageManager, PackageManager packageManagerClient,
2665             LightsManager lightsManager, NotificationListeners notificationListeners,
2666             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
2667             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
2668             NotificationUsageStats usageStats, AtomicFile policyFile,
2669             ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
2670             ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats,
2671             DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
2672             UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
2673             NotificationHistoryManager historyManager, StatsManager statsManager,
2674             ActivityManagerInternal ami,
2675             MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
2676             UsageStatsManagerInternal usageStatsManagerInternal,
2677             TelecomManager telecomManager, NotificationChannelLogger channelLogger,
2678             SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
2679             PermissionManager permissionManager, PowerManager powerManager,
2680             PostNotificationTrackerFactory postNotificationTrackerFactory) {
2681         mHandler = handler;
2682         if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) {
2683             mBroadcastsHandler = broadcastsHandler;
2684         }
2685         Resources resources = getContext().getResources();
2686         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
2687                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
2688                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
2689 
2690         mAccessibilityManager =
2691                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2692         mAm = am;
2693         mAtm = atm;
2694         mAtm.setBackgroundActivityStartCallback(new NotificationTrampolineCallback());
2695         mUgm = ugm;
2696         mUgmInternal = ugmInternal;
2697         mPackageManager = packageManager;
2698         mPackageManagerClient = packageManagerClient;
2699         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
2700         mPermissionManager = permissionManager;
2701         mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
2702         mUmInternal = LocalServices.getService(UserManagerInternal.class);
2703         mUsageStatsManagerInternal = usageStatsManagerInternal;
2704         mAppOps = appOps;
2705         mAppUsageStats = appUsageStats;
2706         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
2707         mCompanionManager = companionManager;
2708         mActivityManager = activityManager;
2709         mAmi = ami;
2710         mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class);
2711         mDpm = dpm;
2712         mUm = userManager;
2713         mTelecomManager = telecomManager;
2714         mPowerManager = powerManager;
2715         mPostNotificationTrackerFactory = postNotificationTrackerFactory;
2716         mPlatformCompat = IPlatformCompat.Stub.asInterface(
2717                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
2718 
2719         mStrongAuthTracker = new StrongAuthTracker(getContext());
2720         String[] extractorNames;
2721         try {
2722             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
2723         } catch (Resources.NotFoundException e) {
2724             extractorNames = new String[0];
2725         }
2726         mUsageStats = usageStats;
2727         mMetricsLogger = new MetricsLogger();
2728         mRankingHandler = rankingHandler;
2729         mConditionProviders = conditionProviders;
2730         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(),
2731                 mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient));
2732         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
2733             @Override
2734             public void onConfigChanged() {
2735                 handleSavePolicyFile();
2736             }
2737 
2738             @Override
2739             void onZenModeChanged() {
2740                 Binder.withCleanCallingIdentity(() -> {
2741                     sendRegisteredOnlyBroadcast(ACTION_INTERRUPTION_FILTER_CHANGED);
2742                     getContext().sendBroadcastAsUser(
2743                             new Intent(ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
2744                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
2745                             UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
2746                     synchronized (mNotificationLock) {
2747                         updateInterruptionFilterLocked();
2748                     }
2749                     mRankingHandler.requestSort();
2750                 });
2751             }
2752 
2753             @Override
2754             void onPolicyChanged(Policy newPolicy) {
2755                 Binder.withCleanCallingIdentity(() -> {
2756                     Intent intent = new Intent(ACTION_NOTIFICATION_POLICY_CHANGED);
2757                     intent.putExtra(EXTRA_NOTIFICATION_POLICY, newPolicy);
2758                     sendRegisteredOnlyBroadcast(intent);
2759                     mRankingHandler.requestSort();
2760                 });
2761             }
2762 
2763             @Override
2764             void onConsolidatedPolicyChanged(Policy newConsolidatedPolicy) {
2765                 Binder.withCleanCallingIdentity(() -> {
2766                     Intent intent = new Intent(ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED);
2767                     intent.putExtra(EXTRA_NOTIFICATION_POLICY, newConsolidatedPolicy);
2768                     sendRegisteredOnlyBroadcast(intent);
2769 
2770                     mRankingHandler.requestSort();
2771                 });
2772             }
2773 
2774             @Override
2775             void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
2776                 Binder.withCleanCallingIdentity(() -> {
2777                     Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED);
2778                     intent.setPackage(pkg);
2779                     intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id);
2780                     intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status);
2781                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2782                     getContext().sendBroadcastAsUser(intent, UserHandle.of(userId));
2783                 });
2784             }
2785         });
2786         mPermissionHelper = permissionHelper;
2787         mNotificationChannelLogger = channelLogger;
2788         mUserProfiles.updateCache(getContext());
2789         mPreferencesHelper = new PreferencesHelper(getContext(),
2790                 mPackageManagerClient,
2791                 mRankingHandler,
2792                 mZenModeHelper,
2793                 mPermissionHelper,
2794                 mPermissionManager,
2795                 mNotificationChannelLogger,
2796                 mAppOps,
2797                 mUserProfiles,
2798                 mShowReviewPermissionsNotification,
2799                 Clock.systemUTC());
2800         mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper,
2801                 mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat, groupHelper);
2802         mSnoozeHelper = snoozeHelper;
2803         mGroupHelper = groupHelper;
2804         mHistoryManager = historyManager;
2805         if (Flags.allNotifsNeedTtl()) {
2806             mTtlHelper = new TimeToLiveHelper(mNotificationManagerPrivate, getContext());
2807         }
2808 
2809         // This is a ManagedServices object that keeps track of the listeners.
2810         mListeners = notificationListeners;
2811 
2812         // This is a MangedServices object that keeps track of the assistant.
2813         mAssistants = notificationAssistants;
2814 
2815         // Needs to be set before loadPolicyFile
2816         mAllowedManagedServicePackages = this::canUseManagedServices;
2817 
2818         mPolicyFile = policyFile;
2819         loadPolicyFile();
2820         mStatusBar = getLocalService(StatusBarManagerInternal.class);
2821         if (mStatusBar != null) {
2822             mStatusBar.setNotificationDelegate(mNotificationDelegate);
2823         }
2824 
2825         mZenModeHelper.initZenMode();
2826         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
2827 
2828         mSettingsObserver = new SettingsObserver(mHandler);
2829 
2830         mArchive = new Archive(resources.getInteger(
2831                 R.integer.config_notificationServiceArchiveSize));
2832 
2833         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
2834                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
2835 
2836         mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
2837                 com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
2838 
2839         mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger(
2840                 com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes);
2841         mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
2842                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
2843 
2844         mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
2845                 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
2846         mDefaultSearchSelectorPkg = getContext().getString(getContext().getResources()
2847                 .getIdentifier("config_defaultSearchSelectorPackageName", "string", "android"));
2848 
2849         mFlagResolver = flagResolver;
2850 
2851         mStatsManager = statsManager;
2852 
2853         mToastRateLimiter = toastRateLimiter;
2854 
2855         mAttentionHelper = new NotificationAttentionHelper(getContext(), mNotificationLock,
2856                 lightsManager, mAccessibilityManager, mPackageManagerClient, userManager,
2857                 usageStats, mNotificationManagerPrivate, mZenModeHelper, flagResolver);
2858 
2859         // register for various Intents.
2860         // If this is called within a test, make sure to unregister the intent receivers by
2861         // calling onDestroy()
2862         IntentFilter filter = new IntentFilter();
2863         filter.addAction(Intent.ACTION_USER_STOPPED);
2864         if (!Flags.useSsmUserSwitchSignal()) {
2865             filter.addAction(Intent.ACTION_USER_SWITCHED);
2866         }
2867         filter.addAction(Intent.ACTION_USER_ADDED);
2868         filter.addAction(Intent.ACTION_USER_REMOVED);
2869         filter.addAction(Intent.ACTION_USER_UNLOCKED);
2870         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
2871         if (privateSpaceFlagsEnabled()){
2872             filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE);
2873         }
2874         getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
2875 
2876         IntentFilter pkgFilter = new IntentFilter();
2877         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
2878         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
2879         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
2880         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
2881         pkgFilter.addDataScheme("package");
2882         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
2883                 null);
2884 
2885         IntentFilter suspendedPkgFilter = new IntentFilter();
2886         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
2887         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
2888         suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
2889         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
2890                 suspendedPkgFilter, null, null);
2891 
2892         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
2893         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
2894                 null);
2895 
2896         if (!Flags.allNotifsNeedTtl()) {
2897             IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
2898             timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
2899             getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter,
2900                     Context.RECEIVER_EXPORTED_UNAUDITED);
2901         }
2902 
2903         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
2904         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
2905 
2906         IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
2907         getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
2908 
2909         mReviewNotificationPermissionsReceiver = new ReviewNotificationPermissionsReceiver();
2910         getContext().registerReceiver(mReviewNotificationPermissionsReceiver,
2911                 ReviewNotificationPermissionsReceiver.getFilter(),
2912                 Context.RECEIVER_NOT_EXPORTED);
2913 
2914         mAppOpsListener = new AppOpsManager.OnOpChangedInternalListener() {
2915             @Override
2916             public void onOpChanged(@NonNull String op, @NonNull String packageName,
2917                     int userId) {
2918                 mHandler.post(
2919                         () -> handleNotificationPermissionChange(packageName, userId));
2920             }
2921         };
2922 
2923         mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsListener);
2924     }
2925 
2926     /**
2927      * Cleanup broadcast receivers change listeners.
2928      */
onDestroy()2929     public void onDestroy() {
2930         if (mIntentReceiver != null) {
2931             getContext().unregisterReceiver(mIntentReceiver);
2932         }
2933         if (mPackageIntentReceiver != null) {
2934             getContext().unregisterReceiver(mPackageIntentReceiver);
2935         }
2936         if (Flags.allNotifsNeedTtl()) {
2937             if (mTtlHelper != null) {
2938                 mTtlHelper.destroy();
2939             }
2940         } else {
2941             if (mNotificationTimeoutReceiver != null) {
2942                 getContext().unregisterReceiver(mNotificationTimeoutReceiver);
2943             }
2944         }
2945         if (mRestoreReceiver != null) {
2946             getContext().unregisterReceiver(mRestoreReceiver);
2947         }
2948         if (mLocaleChangeReceiver != null) {
2949             getContext().unregisterReceiver(mLocaleChangeReceiver);
2950         }
2951         if (mSettingsObserver != null) {
2952             mSettingsObserver.destroy();
2953         }
2954         if (mRoleObserver != null) {
2955             mRoleObserver.destroy();
2956         }
2957         if (mShortcutHelper != null) {
2958             mShortcutHelper.destroy();
2959         }
2960         if (mStatsManager != null) {
2961             mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES);
2962             mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
2963             mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
2964             mStatsManager.clearPullAtomCallback(NOTIFICATION_BUNDLE_PREFERENCES);
2965             mStatsManager.clearPullAtomCallback(DND_MODE_RULE);
2966         }
2967         if (mAppOps != null) {
2968             mAppOps.stopWatchingMode(mAppOpsListener);
2969         }
2970         if (mAlarmManager != null) {
2971             mAlarmManager.cancelAll();
2972         }
2973     }
2974 
getStringArrayResource(int key)2975     protected String[] getStringArrayResource(int key) {
2976         return getContext().getResources().getStringArray(key);
2977     }
2978 
2979     @Override
onStart()2980     public void onStart() {
2981         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
2982             try {
2983                 if (DBG) {
2984                     Slog.d(TAG, "Reposting " + r.getKey() + " " + muteOnReturn);
2985                 }
2986                 enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
2987                         r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
2988                         r.getSbn().getId(),  r.getSbn().getNotification(), userId, muteOnReturn,
2989                         /* byForegroundService= */ false, /* isAppProvided= */ false);
2990             } catch (Exception e) {
2991                 Slog.e(TAG, "Cannot un-snooze notification", e);
2992             }
2993         }, mUserProfiles);
2994 
2995         final File systemDir = new File(Environment.getDataDirectory(), "system");
2996         mRankingThread.start();
2997 
2998         WorkerHandler handler = new WorkerHandler(Looper.myLooper());
2999 
3000         Handler broadcastsHandler;
3001         if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) {
3002             HandlerThread broadcastsThread = new HandlerThread("NMS Broadcasts");
3003             broadcastsThread.start();
3004             broadcastsHandler = new Handler(broadcastsThread.getLooper());
3005         } else {
3006             broadcastsHandler = null;
3007         }
3008 
3009         mShowReviewPermissionsNotification = getContext().getResources().getBoolean(
3010                 R.bool.config_notificationReviewPermissions);
3011 
3012         mDefaultUnsupportedAdjustments = getContext().getResources().getStringArray(
3013                 R.array.config_notificationDefaultUnsupportedAdjustments);
3014 
3015         init(handler, new RankingHandlerWorker(mRankingThread.getLooper()), broadcastsHandler,
3016                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
3017                 getLocalService(LightsManager.class),
3018                 new NotificationListeners(getContext(), mNotificationLock, mUserProfiles,
3019                         AppGlobals.getPackageManager()),
3020                 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
3021                         AppGlobals.getPackageManager()),
3022                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
3023                 null /*CDM is not initialized yet*/, snoozeHelper,
3024                 new NotificationUsageStats(getContext()),
3025                 new AtomicFile(new File(
3026                         systemDir, "notification_policy.xml"), "notification-policy"),
3027                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
3028                 getGroupHelper(), ActivityManager.getService(),
3029                 LocalServices.getService(ActivityTaskManagerInternal.class),
3030                 LocalServices.getService(UsageStatsManagerInternal.class),
3031                 LocalServices.getService(DevicePolicyManagerInternal.class),
3032                 UriGrantsManager.getService(),
3033                 LocalServices.getService(UriGrantsManagerInternal.class),
3034                 getContext().getSystemService(AppOpsManager.class),
3035                 getContext().getSystemService(UserManager.class),
3036                 new NotificationHistoryManager(getContext(), handler),
3037                 mStatsManager = (StatsManager) getContext().getSystemService(
3038                         Context.STATS_MANAGER),
3039                 LocalServices.getService(ActivityManagerInternal.class),
3040                 createToastRateLimiter(), new PermissionHelper(getContext(),
3041                         AppGlobals.getPackageManager(),
3042                         AppGlobals.getPermissionManager()),
3043                 LocalServices.getService(UsageStatsManagerInternal.class),
3044                 getContext().getSystemService(TelecomManager.class),
3045                 new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(),
3046                 getContext().getSystemService(PermissionManager.class),
3047                 getContext().getSystemService(PowerManager.class),
3048                 new PostNotificationTrackerFactory() {});
3049 
3050         publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
3051                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
3052         publishLocalService(NotificationManagerInternal.class, mInternalService);
3053     }
3054 
registerNotificationPreferencesPullers()3055     private void registerNotificationPreferencesPullers() {
3056         mPullAtomCallback = new StatsPullAtomCallbackImpl();
3057         mStatsManager.setPullAtomCallback(
3058                 PACKAGE_NOTIFICATION_PREFERENCES,
3059                 null, // use default PullAtomMetadata values
3060                 ConcurrentUtils.DIRECT_EXECUTOR,
3061                 mPullAtomCallback
3062         );
3063         mStatsManager.setPullAtomCallback(
3064                 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
3065                 null, // use default PullAtomMetadata values
3066                 ConcurrentUtils.DIRECT_EXECUTOR,
3067                 mPullAtomCallback
3068         );
3069         mStatsManager.setPullAtomCallback(
3070                 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
3071                 null, // use default PullAtomMetadata values
3072                 ConcurrentUtils.DIRECT_EXECUTOR,
3073                 mPullAtomCallback
3074         );
3075         mStatsManager.setPullAtomCallback(
3076                 DND_MODE_RULE,
3077                 null, // use default PullAtomMetadata values
3078                 ConcurrentUtils.DIRECT_EXECUTOR,
3079                 mPullAtomCallback
3080         );
3081         mStatsManager.setPullAtomCallback(
3082                 NOTIFICATION_BUNDLE_PREFERENCES,
3083                 null, // use default PullAtomMetadata values
3084                 ConcurrentUtils.DIRECT_EXECUTOR,
3085                 mPullAtomCallback
3086         );
3087     }
3088 
3089     private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
3090         @Override
onPullAtom(int atomTag, List<StatsEvent> data)3091         public int onPullAtom(int atomTag, List<StatsEvent> data) {
3092             switch (atomTag) {
3093                 case PACKAGE_NOTIFICATION_PREFERENCES:
3094                 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
3095                 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
3096                 case NOTIFICATION_BUNDLE_PREFERENCES:
3097                 case DND_MODE_RULE:
3098                     return pullNotificationStates(atomTag, data);
3099                 default:
3100                     throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
3101             }
3102         }
3103     }
3104 
pullNotificationStates(int atomTag, List<StatsEvent> data)3105     private int pullNotificationStates(int atomTag, List<StatsEvent> data) {
3106         switch(atomTag) {
3107             case PACKAGE_NOTIFICATION_PREFERENCES:
3108                 if (notificationClassificationUi()) {
3109                     mPreferencesHelper.pullPackagePreferencesStats(data,
3110                             getAllUsersNotificationPermissions(),
3111                             new ArrayMap<>());
3112                 } else {
3113                     mPreferencesHelper.pullPackagePreferencesStats(data,
3114                             getAllUsersNotificationPermissions());
3115                 }
3116                 break;
3117             case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
3118                 mPreferencesHelper.pullPackageChannelPreferencesStats(data);
3119                 break;
3120             case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
3121                 mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data);
3122                 break;
3123             case NOTIFICATION_BUNDLE_PREFERENCES:
3124                 if (notificationClassification() && notificationClassificationUi()) {
3125                     mAssistants.pullBundlePreferencesStats(data);
3126                 }
3127                 break;
3128             case DND_MODE_RULE:
3129                 mZenModeHelper.pullRules(data);
3130                 break;
3131         }
3132         return StatsManager.PULL_SUCCESS;
3133     }
3134 
getGroupHelper()3135     private GroupHelper getGroupHelper() {
3136         mAutoGroupAtCount =
3137                 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
3138         return new GroupHelper(getContext(), getContext().getPackageManager(),
3139                 mAutoGroupAtCount, AUTOGROUP_SPARSE_GROUPS_AT_COUNT, new GroupHelper.Callback() {
3140             @Override
3141             public void addAutoGroup(String key, String groupName, boolean requestSort) {
3142                 synchronized (mNotificationLock) {
3143                     if (notificationForceGrouping()) {
3144                         convertSummaryToNotificationLocked(key);
3145                         addAutogroupKeyLocked(key, groupName, requestSort);
3146                     } else {
3147                         addAutogroupKeyLocked(key, groupName, requestSort);
3148                     }
3149                 }
3150             }
3151 
3152             @Override
3153             public void removeAutoGroup(String key) {
3154                 synchronized (mNotificationLock) {
3155                     removeAutogroupKeyLocked(key);
3156                 }
3157             }
3158 
3159             @Override
3160             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
3161                     String groupName, int summaryId, NotificationAttributes summaryAttr) {
3162                 NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey,
3163                         groupName, summaryId, summaryAttr);
3164                 if (r != null) {
3165                     final boolean isAppForeground =
3166                             mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
3167                     mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
3168                             /* isAppProvided= */ false,
3169                             mPostNotificationTrackerFactory.newTracker(null)));
3170                 }
3171             }
3172 
3173             @Override
3174             public void removeAutoGroupSummary(int userId, String pkg, String groupKey) {
3175                 synchronized (mNotificationLock) {
3176                     clearAutogroupSummaryLocked(userId, pkg, groupKey);
3177                 }
3178             }
3179 
3180             @Override
3181             public void updateAutogroupSummary(int userId, String pkg, String groupKey,
3182                     NotificationAttributes summaryAttr) {
3183                 boolean isAppForeground = pkg != null
3184                         && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
3185                 synchronized (mNotificationLock) {
3186                     updateAutobundledSummaryLocked(userId, pkg, groupKey, summaryAttr,
3187                             isAppForeground);
3188                 }
3189             }
3190 
3191             @Override
3192             public void removeAppProvidedSummary(String key) {
3193                 synchronized (mNotificationLock) {
3194                     removeAppSummaryLocked(key);
3195                 }
3196             }
3197 
3198             @Override
3199             public void sendAppProvidedSummaryDeleteIntent(String pkg, PendingIntent deleteIntent) {
3200                 sendDeleteIntent(deleteIntent, pkg);
3201             }
3202 
3203             @Override
3204             public void removeNotificationFromCanceledGroup(int userId, String pkg,
3205                     String groupKey, int cancelReason) {
3206                 synchronized (mNotificationLock) {
3207                     final int mustNotHaveFlags;
3208                     if (lifetimeExtensionRefactor()) {
3209                         // Also don't allow client apps to cancel lifetime extended notifs.
3210                         mustNotHaveFlags = (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
3211                                 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3212                     } else {
3213                         mustNotHaveFlags = (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB);
3214                     }
3215                     FlagChecker childrenFlagChecker = (flags) -> {
3216                             if (cancelReason == REASON_CANCEL
3217                                 || cancelReason == REASON_CLICK
3218                                 || cancelReason == REASON_CANCEL_ALL) {
3219                                 if ((flags & FLAG_BUBBLE) != 0) {
3220                                     return false;
3221                                 }
3222                             }
3223                             return (flags & mustNotHaveFlags) == 0;
3224                     };
3225                     cancelGroupChildrenLocked(userId, pkg, Binder.getCallingUid(),
3226                             Binder.getCallingPid(), null,
3227                             false, childrenFlagChecker,
3228                             NotificationManagerService::wasChildOfForceRegroupedGroupChecker,
3229                             groupKey, REASON_APP_CANCEL, SystemClock.elapsedRealtime());
3230                 }
3231             }
3232 
3233             @Override
3234             @Nullable
3235             public NotificationRecord removeAppProvidedSummaryOnClassification(String triggeringKey,
3236                     @Nullable String oldGroupKey) {
3237                 synchronized (mNotificationLock) {
3238                     return removeAppProvidedSummaryOnClassificationLocked(triggeringKey,
3239                             oldGroupKey);
3240                 }
3241             }
3242         });
3243     }
3244 
3245     //Enables tests running in TH mode to be exempted from forced grouping of notifications
3246     void setTestHarnessExempted(boolean isExempted) {
3247         mGroupHelper.setTestHarnessExempted(isExempted);
3248     }
3249 
3250     private void sendRegisteredOnlyBroadcast(String action) {
3251         sendRegisteredOnlyBroadcast(new Intent(action));
3252     }
3253 
3254     /**
3255      * Schedules a broadcast to be sent to runtime receivers and DND-policy-access packages. The
3256      * broadcast will be sent after {@link #ZEN_BROADCAST_DELAY}, unless a new broadcast is
3257      * scheduled in the interim, in which case the previous one is dropped and the waiting period
3258      * is <em>restarted</em>.
3259      *
3260      * <p>Note that this uses <em>equality of the {@link Intent#getAction}</em> as the criteria for
3261      * deduplicating pending broadcasts, ignoring the extras and anything else. This is intentional
3262      * so that e.g. rapidly changing some value A -> B -> C will only produce a broadcast for C
3263      * (instead of every time because the extras are different).
3264      */
3265     @FlaggedApi(Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST)
3266     private void sendZenBroadcastWithDelay(Intent intent) {
3267         String token = "zen_broadcast:" + intent.getAction();
3268         mBroadcastsHandler.removeCallbacksAndEqualMessages(token);
3269         mBroadcastsHandler.postDelayed(() -> sendRegisteredOnlyBroadcast(intent), token,
3270                 ZEN_BROADCAST_DELAY.toMillis());
3271     }
3272 
3273     private void sendRegisteredOnlyBroadcast(Intent baseIntent) {
3274         int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true);
3275         if (Flags.nmBinderPerfReduceZenBroadcasts()) {
3276             for (int userId : userIds) {
3277                 Context userContext = getContext().createContextAsUser(UserHandle.of(userId), 0);
3278                 String[] dndPackages = mConditionProviders.getAllowedPackages(userId)
3279                         .toArray(new String[0]);
3280 
3281                 // We send the broadcast to all DND packages in the second step, so leave them out
3282                 // of this first broadcast for *running* receivers. That ensures each package only
3283                 // receives it once.
3284                 Intent registeredOnlyIntent = new Intent(baseIntent)
3285                         .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3286                 userContext.sendBroadcastMultiplePermissions(registeredOnlyIntent,
3287                         /* receiverPermissions= */ new String[0],
3288                         /* excludedPermissions= */ new String[0],
3289                         /* excludedPackages= */ dndPackages);
3290 
3291                 for (String pkg : dndPackages) {
3292                     Intent pkgIntent = new Intent(baseIntent).setPackage(pkg)
3293                             .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3294                     userContext.sendBroadcast(pkgIntent);
3295                 }
3296             }
3297         } else {
3298             Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3299             for (int userId : userIds) {
3300                 getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
3301             }
3302 
3303             // explicitly send the broadcast to all DND packages, even if they aren't currently
3304             // running
3305             for (int userId : userIds) {
3306                 for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
3307                     Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags(
3308                             Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3309                     getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
3310                 }
3311             }
3312         }
3313     }
3314 
3315     @Override
3316     public void onBootPhase(int phase) {
3317         onBootPhase(phase, Looper.getMainLooper());
3318     }
3319 
3320     @VisibleForTesting
3321     void onBootPhase(int phase, Looper mainLooper) {
3322         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
3323             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
3324             mZenModeHelper.onSystemReady();
3325             RoleObserver roleObserver = new RoleObserver(getContext(),
3326                     getContext().getSystemService(RoleManager.class),
3327                     mPackageManager, mainLooper);
3328             roleObserver.init();
3329             mRoleObserver = roleObserver;
3330             LauncherApps launcherApps =
3331                     (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
3332             UserManager userManager = (UserManager) getContext().getSystemService(
3333                     Context.USER_SERVICE);
3334             mShortcutHelper = new ShortcutHelper(launcherApps, mShortcutListener, getLocalService(
3335                     ShortcutServiceInternal.class), userManager);
3336             BubbleExtractor bubbsExtractor = mRankingHelper.findExtractor(BubbleExtractor.class);
3337             if (bubbsExtractor != null) {
3338                 bubbsExtractor.setShortcutHelper(mShortcutHelper);
3339                 bubbsExtractor.setPackageManager(mPackageManagerClient);
3340             }
3341             registerNotificationPreferencesPullers();
3342             if (mLockUtils == null) {
3343                 mLockUtils = new LockPatternUtils(getContext());
3344             }
3345             mLockUtils.registerStrongAuthTracker(mStrongAuthTracker);
3346             mAttentionHelper.onSystemReady();
3347         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
3348             // This observer will force an update when observe is called, causing us to
3349             // bind to listener services.
3350             mSettingsObserver.observe();
3351             mListeners.onBootPhaseAppsCanStart();
3352             mAssistants.onBootPhaseAppsCanStart();
3353             mConditionProviders.onBootPhaseAppsCanStart();
3354             mHistoryManager.onBootPhaseAppsCanStart();
3355             mPreferencesHelper.onBootPhaseAppsCanStart();
3356             migrateDefaultNAS();
3357             maybeShowInitialReviewPermissionsNotification();
3358 
3359             if (!mZenModeHelper.hasDeviceEffectsApplier()) {
3360                 // Cannot be done earlier, as some services aren't ready until this point.
3361                 mZenModeHelper.setDeviceEffectsApplier(
3362                         new DefaultDeviceEffectsApplier(getContext()));
3363             }
3364             List<ModuleInfo> moduleInfoList =
3365             mPackageManagerClient.getInstalledModules(
3366                 PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
3367             // Cache adservices module info
3368             for (ModuleInfo mi : moduleInfoList) {
3369                 if (Objects.equals(mi.getApexModuleName(), ADSERVICES_MODULE_PKG_NAME)) {
3370                     mAdservicesModuleInfo = mi;
3371                 }
3372             }
3373         } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
3374             mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
3375         } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
3376             mPreferencesHelper.updateFixedImportance(mUm.getUsers());
3377             mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers());
3378         } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
3379             if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) {
3380                 new Thread(() -> {
3381                     while (true) {
3382                         try {
3383                             Thread.sleep(5000);
3384                         } catch (InterruptedException e) { }
3385                         mInternalService.removeBitmaps();
3386                     }
3387                 }).start();
3388             } else if (expireBitmaps()) {
3389                 NotificationBitmapJobService.scheduleJob(getContext());
3390             }
3391         }
3392     }
3393 
3394     @Override
3395     public void onUserUnlocked(@NonNull TargetUser user) {
3396         mHandler.post(() -> {
3397             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser");
3398             try {
3399                 mHistoryManager.onUserUnlocked(user.getUserIdentifier());
3400             } finally {
3401                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
3402             }
3403         });
3404     }
3405 
3406     private void sendAppBlockStateChangedBroadcast(String pkg, int uid, boolean blocked) {
3407         // From Android T, revoking the notification permission will cause the app to be killed.
3408         // delay this broadcast so it doesn't race with that process death
3409         mHandler.postDelayed(() -> {
3410             try {
3411                 getContext().sendBroadcastAsUser(
3412                         new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
3413                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, blocked)
3414                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3415                                 .setPackage(pkg),
3416                         UserHandle.of(UserHandle.getUserId(uid)), null);
3417             } catch (SecurityException e) {
3418                 Slog.w(TAG, "Can't notify app about app block change", e);
3419             }
3420         }, 500);
3421     }
3422 
3423     @Override
3424     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
3425         if (!Flags.useSsmUserSwitchSignal()) {
3426             return;
3427         }
3428         final int userId = to.getUserIdentifier();
3429         mUserProfiles.updateCache(getContext());
3430         if (!mUserProfiles.isProfileUser(userId, getContext())) {
3431             // reload per-user settings
3432             mSettingsObserver.update(null);
3433             // Refresh managed services
3434             mConditionProviders.onUserSwitched(userId);
3435             mListeners.onUserSwitched(userId);
3436             mZenModeHelper.onUserSwitched(userId);
3437             mPreferencesHelper.syncHasPriorityChannels();
3438         }
3439         // assistant is the only thing that cares about managed profiles specifically
3440         mAssistants.onUserSwitched(userId);
3441     }
3442 
3443     @Override
3444     public void onUserStopping(@NonNull TargetUser user) {
3445         mHandler.post(() -> {
3446             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser");
3447             try {
3448                 mHistoryManager.onUserStopped(user.getUserIdentifier());
3449             } finally {
3450                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
3451             }
3452         });
3453     }
3454 
3455     @GuardedBy("mNotificationLock")
3456     private void updateListenerHintsLocked() {
3457         final int hints = calculateHints();
3458         if (hints == mListenerHints) return;
3459         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
3460         mListenerHints = hints;
3461         scheduleListenerHintsChanged(hints);
3462     }
3463 
3464     @GuardedBy("mNotificationLock")
3465     private void updateEffectsSuppressorLocked() {
3466         final long oldSuppressedEffects = mZenModeHelper.getSuppressedEffects();
3467         final long updatedSuppressedEffects = calculateSuppressedEffects();
3468         if (updatedSuppressedEffects == oldSuppressedEffects) return;
3469 
3470         final List<ComponentName> suppressors = getSuppressors();
3471         ZenLog.traceEffectsSuppressorChanged(
3472                 mEffectsSuppressors, suppressors, oldSuppressedEffects, updatedSuppressedEffects);
3473         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
3474 
3475         if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) {
3476             if (!suppressors.equals(mEffectsSuppressors)) {
3477                 mEffectsSuppressors = suppressors;
3478                 sendZenBroadcastWithDelay(
3479                         new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED));
3480             }
3481         } else {
3482             mEffectsSuppressors = suppressors;
3483             sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
3484         }
3485     }
3486 
3487     private void exitIdle() {
3488         if (mDeviceIdleManager != null) {
3489             mDeviceIdleManager.endIdle("notification interaction");
3490         }
3491     }
3492 
3493     void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
3494             boolean fromListener) {
3495         if (channel.getImportance() == IMPORTANCE_NONE) {
3496             // cancel
3497             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0,
3498                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED
3499             );
3500             if (isUidSystemOrPhone(uid)) {
3501                 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
3502                 int N = profileIds.size();
3503                 for (int i = 0; i < N; i++) {
3504                     int profileId = profileIds.get(i);
3505                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0,
3506                             profileId, REASON_CHANNEL_BANNED
3507                     );
3508                 }
3509             }
3510         }
3511         final NotificationChannel preUpdate =
3512                 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
3513 
3514         mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true,
3515                 Binder.getCallingUid(), isCallerSystemOrSystemUi());
3516         if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
3517             mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
3518                     channel.getImportance() != IMPORTANCE_NONE, true);
3519         }
3520         maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
3521 
3522         if (!fromListener) {
3523             final NotificationChannel modifiedChannel = mPreferencesHelper.getNotificationChannel(
3524                     pkg, uid, channel.getId(), false);
3525             mListeners.notifyNotificationChannelChanged(
3526                     pkg, UserHandle.getUserHandleForUid(uid),
3527                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
3528         }
3529 
3530         if (notificationForceGrouping()) {
3531             final NotificationChannel updatedChannel = mPreferencesHelper.getNotificationChannel(
3532                     pkg, uid, channel.getId(), false);
3533             mHandler.postDelayed(() -> {
3534                 synchronized (mNotificationLock) {
3535                     mGroupHelper.onChannelUpdated(
3536                             UserHandle.getUserHandleForUid(uid).getIdentifier(), pkg,
3537                             updatedChannel, mNotificationList, mSummaryByGroupKey);
3538                 }
3539             }, DELAY_FORCE_REGROUP_TIME);
3540         }
3541 
3542         handleSavePolicyFile();
3543     }
3544 
3545     private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
3546             NotificationChannel update) {
3547         try {
3548             if ((preUpdate.getImportance() == IMPORTANCE_NONE
3549                     && update.getImportance() != IMPORTANCE_NONE)
3550                     || (preUpdate.getImportance() != IMPORTANCE_NONE
3551                     && update.getImportance() == IMPORTANCE_NONE)) {
3552                 getContext().sendBroadcastAsUser(
3553                         new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
3554                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
3555                                         update.getId())
3556                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
3557                                         update.getImportance() == IMPORTANCE_NONE)
3558                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3559                                 .setPackage(pkg),
3560                         UserHandle.of(UserHandle.getUserId(uid)), null);
3561             }
3562         } catch (SecurityException e) {
3563             Slog.w(TAG, "Can't notify app about channel change", e);
3564         }
3565     }
3566 
3567     void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
3568             boolean fromApp, boolean fromListener) {
3569         Objects.requireNonNull(group);
3570         Objects.requireNonNull(pkg);
3571 
3572         final NotificationChannelGroup preUpdate =
3573                 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
3574         mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
3575                 fromApp, Binder.getCallingUid(), isCallerSystemOrSystemUi());
3576         if (!fromApp) {
3577             maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
3578         }
3579         if (!fromListener) {
3580             mListeners.notifyNotificationChannelGroupChanged(pkg,
3581                     UserHandle.of(UserHandle.getCallingUserId()), group,
3582                     NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
3583         }
3584     }
3585 
3586     private void maybeNotifyChannelGroupOwner(String pkg, int uid,
3587             NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
3588         try {
3589             if (preUpdate.isBlocked() != update.isBlocked()) {
3590                 getContext().sendBroadcastAsUser(
3591                         new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
3592                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
3593                                         update.getId())
3594                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
3595                                         update.isBlocked())
3596                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3597                                 .setPackage(pkg),
3598                         UserHandle.of(UserHandle.getUserId(uid)), null);
3599             }
3600         } catch (SecurityException e) {
3601             Slog.w(TAG, "Can't notify app about group change", e);
3602         }
3603     }
3604 
3605     private ArrayList<ComponentName> getSuppressors() {
3606         ArrayList<ComponentName> names = new ArrayList<>();
3607         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
3608             ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
3609 
3610             for (ComponentName info : serviceInfoList) {
3611                 if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) {
3612                     if (!names.contains(info)) {
3613                         names.add(info);
3614                     }
3615                 } else {
3616                     names.add(info);
3617                 }
3618             }
3619         }
3620 
3621         return names;
3622     }
3623 
3624     private boolean removeDisabledHints(ManagedServiceInfo info) {
3625         return removeDisabledHints(info, 0);
3626     }
3627 
3628     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
3629         boolean removed = false;
3630 
3631         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
3632             final int hint = mListenersDisablingEffects.keyAt(i);
3633             final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
3634 
3635             if (hints == 0 || (hint & hints) == hint) {
3636                 removed |= listeners.remove(info.component);
3637             }
3638         }
3639 
3640         return removed;
3641     }
3642 
3643     private void addDisabledHints(ManagedServiceInfo info, int hints) {
3644         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3645             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
3646         }
3647 
3648         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
3649             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
3650         }
3651 
3652         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
3653             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
3654         }
3655     }
3656 
3657     private void addDisabledHint(ManagedServiceInfo info, int hint) {
3658         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
3659             mListenersDisablingEffects.put(hint, new ArraySet<>());
3660         }
3661 
3662         ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
3663         hintListeners.add(info.component);
3664     }
3665 
3666     private int calculateHints() {
3667         int hints = 0;
3668         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
3669             int hint = mListenersDisablingEffects.keyAt(i);
3670             ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
3671 
3672             if (!serviceInfoList.isEmpty()) {
3673                 hints |= hint;
3674             }
3675         }
3676 
3677         return hints;
3678     }
3679 
3680     private long calculateSuppressedEffects() {
3681         int hints = calculateHints();
3682         long suppressedEffects = 0;
3683 
3684         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3685             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
3686         }
3687 
3688         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
3689             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
3690         }
3691 
3692         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
3693             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
3694         }
3695 
3696         return suppressedEffects;
3697     }
3698 
3699     @GuardedBy("mNotificationLock")
3700     private void updateInterruptionFilterLocked() {
3701         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
3702         if (interruptionFilter == mInterruptionFilter) return;
3703         mInterruptionFilter = interruptionFilter;
3704         scheduleInterruptionFilterChanged(interruptionFilter);
3705     }
3706 
3707     int correctCategory(int requestedCategoryList, int categoryType,
3708             int currentCategoryList) {
3709         if ((requestedCategoryList & categoryType) != 0
3710                 && (currentCategoryList & categoryType) == 0) {
3711             requestedCategoryList &= ~categoryType;
3712         } else if ((requestedCategoryList & categoryType) == 0
3713                 && (currentCategoryList & categoryType) != 0){
3714             requestedCategoryList |= categoryType;
3715         }
3716         return requestedCategoryList;
3717     }
3718 
3719     @VisibleForTesting
3720     INotificationManager getBinderService() {
3721         return INotificationManager.Stub.asInterface(mService);
3722     }
3723 
3724     /**
3725      * Report to usage stats that the notification was seen.
3726      * @param r notification record
3727      */
3728     @GuardedBy("mNotificationLock")
3729     protected void reportSeen(NotificationRecord r) {
3730         if (!r.isProxied()) {
3731             mAppUsageStats.reportEvent(r.getSbn().getPackageName(),
3732                     getRealUserId(r.getSbn().getUserId()),
3733                     UsageEvents.Event.NOTIFICATION_SEEN);
3734         }
3735     }
3736 
3737     protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
3738             int targetSdkVersion) {
3739         if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
3740             return incomingPolicy.suppressedVisualEffects;
3741         }
3742         final int[] effectsIntroducedInP = {
3743                 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
3744                 SUPPRESSED_EFFECT_LIGHTS,
3745                 SUPPRESSED_EFFECT_PEEK,
3746                 SUPPRESSED_EFFECT_STATUS_BAR,
3747                 SUPPRESSED_EFFECT_BADGE,
3748                 SUPPRESSED_EFFECT_AMBIENT,
3749                 SUPPRESSED_EFFECT_NOTIFICATION_LIST
3750         };
3751 
3752         int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
3753         if (targetSdkVersion < Build.VERSION_CODES.P) {
3754             // unset higher order bits introduced in P, maintain the user's higher order bits
3755             for (int i = 0; i < effectsIntroducedInP.length ; i++) {
3756                 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
3757                 newSuppressedVisualEffects |=
3758                         (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
3759             }
3760             // set higher order bits according to lower order bits
3761             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
3762                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
3763                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
3764             }
3765             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
3766                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
3767             }
3768         } else {
3769             boolean hasNewEffects = (newSuppressedVisualEffects
3770                     - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
3771             // if any of the new effects introduced in P are set
3772             if (hasNewEffects) {
3773                 // clear out the deprecated effects
3774                 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
3775                         | SUPPRESSED_EFFECT_SCREEN_OFF);
3776 
3777                 // set the deprecated effects according to the new more specific effects
3778                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) != 0) {
3779                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
3780                 }
3781                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) != 0
3782                         && (newSuppressedVisualEffects
3783                         & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
3784                         && (newSuppressedVisualEffects
3785                         & SUPPRESSED_EFFECT_AMBIENT) != 0) {
3786                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
3787                 }
3788             } else {
3789                 // set higher order bits according to lower order bits
3790                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
3791                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
3792                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
3793                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
3794                 }
3795                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
3796                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
3797                 }
3798             }
3799         }
3800 
3801         return newSuppressedVisualEffects;
3802     }
3803 
3804     @GuardedBy("mNotificationLock")
3805     protected void maybeRecordInterruptionLocked(NotificationRecord r) {
3806         if (r.isInterruptive() && !r.hasRecordedInterruption()) {
3807             mAppUsageStats.reportInterruptiveNotification(r.getSbn().getPackageName(),
3808                     r.getChannel().getId(),
3809                     getRealUserId(r.getSbn().getUserId()));
3810             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryAddItem");
3811             try {
3812                 if (r.getNotification().getSmallIcon() != null) {
3813                     mHistoryManager.addNotification(new HistoricalNotification.Builder()
3814                             .setPackage(r.getSbn().getPackageName())
3815                             .setUid(r.getSbn().getUid())
3816                             .setUserId(r.getSbn().getNormalizedUserId())
3817                             .setChannelId(r.getChannel().getId())
3818                             .setChannelName(r.getChannel().getName().toString())
3819                             .setPostedTimeMs(System.currentTimeMillis())
3820                             .setTitle(getHistoryTitle(r.getNotification()))
3821                             .setText(getHistoryText(r.getNotification()))
3822                             .setIcon(r.getNotification().getSmallIcon())
3823                             .build());
3824                 }
3825             } finally {
3826                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
3827             }
3828             r.setRecordedInterruption(true);
3829         }
3830     }
3831 
3832     protected void reportForegroundServiceUpdate(boolean shown,
3833             final Notification notification, final int id, final String pkg, final int userId) {
3834         mHandler.post(() -> {
3835             mAmi.onForegroundServiceNotificationUpdate(shown, notification, id, pkg, userId);
3836         });
3837     }
3838 
3839     protected void maybeReportForegroundServiceUpdate(final NotificationRecord r, boolean shown) {
3840         if (r.isForegroundService()) {
3841             // snapshot live state for the asynchronous operation
3842             final StatusBarNotification sbn = r.getSbn();
3843             reportForegroundServiceUpdate(shown, sbn.getNotification(), sbn.getId(),
3844                     sbn.getPackageName(), sbn.getUser().getIdentifier());
3845         }
3846     }
3847 
3848     private String getHistoryTitle(Notification n) {
3849         CharSequence title = null;
3850         if (n.extras != null) {
3851             title = n.extras.getCharSequence(EXTRA_TITLE);
3852             if (title == null) {
3853                 title = n.extras.getCharSequence(EXTRA_TITLE_BIG);
3854             }
3855         }
3856         return title == null ? getContext().getResources().getString(
3857             com.android.internal.R.string.notification_history_title_placeholder)
3858             : String.valueOf(title);
3859     }
3860 
3861     /**
3862      * Returns the appropriate substring for this notification based on the style of notification.
3863      */
3864     private String getHistoryText(Notification n) {
3865         CharSequence text = null;
3866         if (n.extras != null) {
3867             text = n.extras.getCharSequence(EXTRA_TEXT);
3868             Notification.Builder nb = Notification.Builder.recoverBuilder(getContext(), n);
3869 
3870             if (nb.getStyle() instanceof Notification.BigTextStyle) {
3871                 text = ((Notification.BigTextStyle) nb.getStyle()).getBigText();
3872             } else if (nb.getStyle() instanceof MessagingStyle) {
3873                 MessagingStyle ms = (MessagingStyle) nb.getStyle();
3874                 final List<MessagingStyle.Message> messages = ms.getMessages();
3875                 if (messages != null && messages.size() > 0) {
3876                     text = messages.get(messages.size() - 1).getText();
3877                 }
3878             }
3879 
3880             if (TextUtils.isEmpty(text)) {
3881                 text = n.extras.getCharSequence(EXTRA_TEXT);
3882             }
3883         }
3884         return text == null ? null : String.valueOf(text);
3885     }
3886 
3887     protected void maybeRegisterMessageSent(NotificationRecord r) {
3888         if (r.isConversation()) {
3889             if (r.getShortcutInfo() != null) {
3890                 if (mPreferencesHelper.setValidMessageSent(
3891                         r.getSbn().getPackageName(), r.getUid())) {
3892                     handleSavePolicyFile();
3893                 } else if (r.getNotification().getBubbleMetadata() != null) {
3894                     // If bubble metadata is present it is valid (if invalid it's removed
3895                     // via BubbleExtractor).
3896                     if (mPreferencesHelper.setValidBubbleSent(
3897                             r.getSbn().getPackageName(), r.getUid())) {
3898                         handleSavePolicyFile();
3899                     }
3900                 }
3901             } else {
3902                 if (mPreferencesHelper.setInvalidMessageSent(
3903                         r.getSbn().getPackageName(), r.getUid())) {
3904                     handleSavePolicyFile();
3905                 }
3906             }
3907         }
3908     }
3909 
3910     /**
3911      * Report to usage stats that the user interacted with the notification.
3912      * @param r notification record
3913      */
3914     protected void reportUserInteraction(NotificationRecord r) {
3915         mAppUsageStats.reportEvent(r.getSbn().getPackageName(),
3916                 getRealUserId(r.getSbn().getUserId()),
3917                 UsageEvents.Event.USER_INTERACTION);
3918 
3919         if (Flags.politeNotifications()) {
3920             mAttentionHelper.onUserInteraction(r);
3921         }
3922     }
3923 
3924     private int getRealUserId(int userId) {
3925         return userId == USER_ALL ? USER_SYSTEM : userId;
3926     }
3927 
3928     private ToastRecord getToastRecord(int uid, int pid, String packageName, boolean isSystemToast,
3929             IBinder token, @Nullable CharSequence text, @Nullable ITransientNotification callback,
3930             int duration, Binder windowToken, int displayId,
3931             @Nullable ITransientNotificationCallback textCallback) {
3932         if (callback == null) {
3933             return new TextToastRecord(this, mStatusBar, uid, pid, packageName,
3934                     isSystemToast, token, text, duration, windowToken, displayId, textCallback);
3935         } else {
3936             return new CustomToastRecord(this, uid, pid, packageName,
3937                     isSystemToast, token, callback, duration, windowToken, displayId);
3938         }
3939     }
3940 
3941     @VisibleForTesting
3942     NotificationManagerInternal getInternalService() {
3943         return mInternalService;
3944     }
3945 
3946     private MultiRateLimiter createToastRateLimiter() {
3947         return new MultiRateLimiter.Builder(getContext()).addRateLimits(TOAST_RATE_LIMITS).build();
3948     }
3949 
3950     protected int checkComponentPermission(String permission, int uid, int owningUid,
3951             boolean exported) {
3952         return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
3953     }
3954 
3955     @VisibleForTesting
3956     final IBinder mService = new INotificationManager.Stub() {
3957         // Toasts
3958         // ============================================================================
3959 
3960         @Override
3961         public boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
3962                 boolean isUiContext, int displayId,
3963                 @Nullable ITransientNotificationCallback textCallback) {
3964             return enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext,
3965                     displayId, textCallback);
3966         }
3967 
3968         @Override
3969         public boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback,
3970                 int duration, boolean isUiContext, int displayId) {
3971             return enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext,
3972                     displayId, /* textCallback= */ null);
3973         }
3974 
3975         private boolean enqueueToast(String pkg, IBinder token, @Nullable CharSequence text,
3976                 @Nullable ITransientNotification callback, int duration, boolean isUiContext,
3977                 int displayId, @Nullable ITransientNotificationCallback textCallback) {
3978             if (DBG) {
3979                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration
3980                         + " isUiContext=" + isUiContext + " displayId=" + displayId);
3981             }
3982 
3983             if (pkg == null || (text == null && callback == null)
3984                     || (text != null && callback != null) || token == null) {
3985                 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback="
3986                         + " token=" + token);
3987                 return false;
3988             }
3989 
3990             final int callingUid = Binder.getCallingUid();
3991             if (!isUiContext && displayId == Display.DEFAULT_DISPLAY
3992                     && mUm.isVisibleBackgroundUsersSupported()) {
3993                 // When the caller is a visible background user using a non-UI context (like the
3994                 // application context), the Toast must be displayed in the display the user was
3995                 // started visible on.
3996                 int userId = UserHandle.getUserId(callingUid);
3997                 int userDisplayId = mUmInternal.getMainDisplayAssignedToUser(userId);
3998                 if (displayId != userDisplayId) {
3999                     if (DBG) {
4000                         Slogf.d(TAG, "Changing display id from %d to %d on user %d", displayId,
4001                                 userDisplayId, userId);
4002                     }
4003                     displayId = userDisplayId;
4004                 }
4005             }
4006 
4007             checkCallerIsSameApp(pkg);
4008             final boolean isSystemToast = isCallerSystemOrSystemUi()
4009                     || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
4010             boolean isAppRenderedToast = (callback != null);
4011             if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast,
4012                     isSystemToast)) {
4013                 return false;
4014             }
4015 
4016             synchronized (mToastQueue) {
4017                 int callingPid = Binder.getCallingPid();
4018                 final long callingId = Binder.clearCallingIdentity();
4019                 try {
4020                     ToastRecord record;
4021                     int index = indexOfToastLocked(pkg, token);
4022                     // If it's already in the queue, we update it in place, we don't
4023                     // move it to the end of the queue.
4024                     if (index >= 0) {
4025                         record = mToastQueue.get(index);
4026                         record.update(duration);
4027                     } else {
4028                         // Limit the number of toasts that any given package can enqueue.
4029                         // Prevents DOS attacks and deals with leaks.
4030                         int count = 0;
4031                         final int N = mToastQueue.size();
4032                         for (int i = 0; i < N; i++) {
4033                             final ToastRecord r = mToastQueue.get(i);
4034                             if (r.pkg.equals(pkg)) {
4035                                 count++;
4036                                 if (count >= MAX_PACKAGE_TOASTS) {
4037                                     Slog.e(TAG, "Package has already queued " + count
4038                                             + " toasts. Not showing more. Package=" + pkg);
4039                                     return false;
4040                                 }
4041                             }
4042                         }
4043 
4044                         Binder windowToken = new Binder();
4045                         mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId,
4046                                 null /* options */);
4047                         record = getToastRecord(callingUid, callingPid, pkg, isSystemToast, token,
4048                                 text, callback, duration, windowToken, displayId, textCallback);
4049 
4050                         // Insert system toasts at the front of the queue
4051                         int systemToastInsertIdx = mToastQueue.size();
4052                         if (isSystemToast) {
4053                             systemToastInsertIdx = getInsertIndexForSystemToastLocked();
4054                         }
4055                         if (systemToastInsertIdx < mToastQueue.size()) {
4056                             index = systemToastInsertIdx;
4057                             mToastQueue.add(index, record);
4058                         } else {
4059                             mToastQueue.add(record);
4060                             index = mToastQueue.size() - 1;
4061                         }
4062                         keepProcessAliveForToastIfNeededLocked(callingPid);
4063                     }
4064                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
4065                     // new or just been updated, show it.
4066                     // If the callback fails, this will remove it from the list, so don't
4067                     // assume that it's valid after this.
4068                     if (index == 0) {
4069                         showNextToastLocked(false);
4070                     }
4071                 } finally {
4072                     Binder.restoreCallingIdentity(callingId);
4073                 }
4074             }
4075             return true;
4076         }
4077 
4078         @GuardedBy("mToastQueue")
4079         private int getInsertIndexForSystemToastLocked() {
4080             // If there are other system toasts: insert after the last one
4081             int idx = 0;
4082             for (ToastRecord r : mToastQueue) {
4083                 if (idx == 0 && mIsCurrentToastShown) {
4084                     idx++;
4085                     continue;
4086                 }
4087                 if (!r.isSystemToast) {
4088                     return idx;
4089                 }
4090                 idx++;
4091             }
4092             return idx;
4093         }
4094 
4095         private boolean checkCanEnqueueToast(String pkg, int callingUid, int displayId,
4096                 boolean isAppRenderedToast, boolean isSystemToast) {
4097             final boolean isPackageSuspended = isPackagePaused(pkg);
4098             final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
4099                     callingUid);
4100 
4101             final boolean appIsForeground;
4102             final long callingIdentity = Binder.clearCallingIdentity();
4103             try {
4104                 appIsForeground = mActivityManager.getUidImportance(callingUid)
4105                         == IMPORTANCE_FOREGROUND;
4106             } finally {
4107                 Binder.restoreCallingIdentity(callingIdentity);
4108             }
4109 
4110             if (!isSystemToast && ((notificationsDisabledForPackage && !appIsForeground)
4111                     || isPackageSuspended)) {
4112                 Slog.e(TAG, "Suppressing toast from package " + pkg
4113                         + (isPackageSuspended ? " due to package suspended."
4114                         : " by user request."));
4115                 return false;
4116             }
4117 
4118             if (blockToast(callingUid, isSystemToast, isAppRenderedToast,
4119                     isPackageInForegroundForToast(callingUid))) {
4120                 Slog.w(TAG, "Blocking custom toast from package " + pkg
4121                         + " due to package not in the foreground at time the toast was posted");
4122                 return false;
4123             }
4124 
4125             int userId = UserHandle.getUserId(callingUid);
4126             if (!isSystemToast && !mUmInternal.isUserVisible(userId, displayId)) {
4127                 Slog.e(TAG, "Suppressing toast from package " + pkg + "/" + callingUid + " as user "
4128                         + userId + " is not visible on display " + displayId);
4129                 return false;
4130             }
4131 
4132             return true;
4133         }
4134 
4135         @Override
4136         public void cancelToast(String pkg, IBinder token) {
4137             Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token);
4138 
4139             if (pkg == null || token == null) {
4140                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token);
4141                 return;
4142             }
4143 
4144             synchronized (mToastQueue) {
4145                 final long callingId = Binder.clearCallingIdentity();
4146                 try {
4147                     int index = indexOfToastLocked(pkg, token);
4148                     if (index >= 0) {
4149                         cancelToastLocked(index);
4150                     } else {
4151                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
4152                                 + " token=" + token);
4153                     }
4154                 } finally {
4155                     Binder.restoreCallingIdentity(callingId);
4156                 }
4157             }
4158         }
4159 
4160         @Override
4161         @EnforcePermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING)
4162         public void setToastRateLimitingEnabled(boolean enable) {
4163 
4164             super.setToastRateLimitingEnabled_enforcePermission();
4165 
4166             synchronized (mToastQueue) {
4167                 int uid = Binder.getCallingUid();
4168                 int userId = UserHandle.getUserId(uid);
4169                 if (enable) {
4170                     mToastRateLimitingDisabledUids.remove(uid);
4171                     try {
4172                         String[] packages = mPackageManager.getPackagesForUid(uid);
4173                         if (packages == null) {
4174                             Slog.e(TAG, "setToastRateLimitingEnabled method haven't found any "
4175                                     + "packages for the  given uid: " + uid + ", toast rate "
4176                                     + "limiter not reset for that uid.");
4177                             return;
4178                         }
4179                         for (String pkg : packages) {
4180                             mToastRateLimiter.clear(userId, pkg);
4181                         }
4182                     } catch (RemoteException e) {
4183                         Slog.e(TAG, "Failed to reset toast rate limiter for given uid", e);
4184                     }
4185                 } else {
4186                     mToastRateLimitingDisabledUids.add(uid);
4187                 }
4188             }
4189         }
4190 
4191         @Override
4192         public void finishToken(String pkg, IBinder token) {
4193             synchronized (mToastQueue) {
4194                 final long callingId = Binder.clearCallingIdentity();
4195                 try {
4196                     int index = indexOfToastLocked(pkg, token);
4197                     if (index >= 0) {
4198                         ToastRecord record = mToastQueue.get(index);
4199                         finishWindowTokenLocked(record.windowToken, record.displayId);
4200                     } else {
4201                         Slog.w(TAG, "Toast already killed. pkg=" + pkg
4202                                 + " token=" + token);
4203                     }
4204                 } finally {
4205                     Binder.restoreCallingIdentity(callingId);
4206                 }
4207             }
4208         }
4209 
4210         @Override
4211         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
4212                 Notification notification, int userId) throws RemoteException {
4213             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
4214                     Binder.getCallingPid(), tag, id, notification, userId,
4215                     /* byForegroundService= */ false, /* isAppProvided= */ true);
4216         }
4217 
4218         @Override
4219         public void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id,
4220                 int userId) {
4221             // Don't allow client applications to cancel foreground service notifs, user-initiated
4222             // job notifs, autobundled summaries, or notifs that have been replied to.
4223             int mustNotHaveFlags = isCallingUidSystem() ? 0 :
4224                     (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
4225             if (lifetimeExtensionRefactor()) {
4226                 // Also don't allow client apps to cancel lifetime extended notifs.
4227                 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
4228             }
4229 
4230             cancelNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(),
4231                     tag, id, userId, mustNotHaveFlags);
4232         }
4233 
4234         @Override
4235         public void cancelAllNotifications(String pkg, int userId) {
4236             checkCallerIsSystemOrSameApp(pkg);
4237 
4238             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
4239                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
4240 
4241             // Don't allow the app to cancel active FGS or UIJ notifications
4242             if (lifetimeExtensionRefactor()) {
4243                 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
4244                         pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
4245                                 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
4246                         userId, REASON_APP_CANCEL_ALL);
4247                 final int packageImportance = getPackageImportanceWithIdentity(pkg);
4248                 // If cancellation will be prevented due to lifetime extension, we send updates
4249                 // to system UI.
4250                 synchronized (mNotificationLock) {
4251                     maybeNotifySystemUiListenerLifetimeExtendedListLocked(mNotificationList,
4252                             packageImportance);
4253                     maybeNotifySystemUiListenerLifetimeExtendedListLocked(mEnqueuedNotifications,
4254                             packageImportance);
4255                 }
4256             } else {
4257                 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
4258                         pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
4259                         userId, REASON_APP_CANCEL_ALL);
4260             }
4261         }
4262 
4263         @Override
4264         public void silenceNotificationSound() {
4265             checkCallerIsSystem();
4266 
4267             mNotificationDelegate.clearEffects();
4268         }
4269 
4270         @Override
4271         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
4272             enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
4273             boolean wasEnabled = mPermissionHelper.hasPermission(uid);
4274             if (wasEnabled == enabled) {
4275                 return;
4276             }
4277             mPermissionHelper.setNotificationPermission(
4278                     pkg, UserHandle.getUserId(uid), enabled, true);
4279             sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
4280 
4281             mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
4282                     .setType(MetricsEvent.TYPE_ACTION)
4283                     .setPackageName(pkg)
4284                     .setSubtype(enabled ? 1 : 0));
4285             mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled);
4286 
4287             // Outstanding notifications from this package will be cancelled as soon as we get the
4288             // callback from AppOpsManager.
4289         }
4290 
4291         /**
4292          * Updates the enabled state for notifications for the given package (and uid).
4293          * Additionally, this method marks the app importance as locked by the user, which
4294          * means
4295          * that notifications from the app will <b>not</b> be considered for showing a
4296          * blocking helper.
4297          *
4298          * @param pkg     package that owns the notifications to update
4299          * @param uid     uid of the app providing notifications
4300          * @param enabled whether notifications should be enabled for the app
4301          * @see #setNotificationsEnabledForPackage(String, int, boolean)
4302          */
4303         @Override
4304         public void setNotificationsEnabledWithImportanceLockForPackage(
4305                 String pkg, int uid, boolean enabled) {
4306             setNotificationsEnabledForPackage(pkg, uid, enabled);
4307         }
4308 
4309         /**
4310          * Use this when you just want to know if notifications are OK for this package.
4311          */
4312         @Override
4313         public boolean areNotificationsEnabled(String pkg) {
4314             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
4315         }
4316 
4317         /**
4318          * Use this when you just want to know if notifications are OK for this package.
4319          */
4320         @Override
4321         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
4322             enforceSystemOrSystemUIOrSamePackage(pkg,
4323                     "Caller not system or systemui or same package");
4324             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
4325                 getContext().enforceCallingPermission(
4326                         android.Manifest.permission.INTERACT_ACROSS_USERS,
4327                         "canNotifyAsPackage for uid " + uid);
4328             }
4329 
4330             return areNotificationsEnabledForPackageInt(uid);
4331         }
4332 
4333         /**
4334          * @return true if and only if "all" bubbles are allowed from the provided package.
4335          */
4336         @Override
4337         public boolean areBubblesAllowed(String pkg) {
4338             return getBubblePreferenceForPackage(pkg, Binder.getCallingUid())
4339                     == BUBBLE_PREFERENCE_ALL;
4340         }
4341 
4342         /**
4343          * @return true if this user has bubbles enabled at the feature-level.
4344          */
4345         @Override
4346         public boolean areBubblesEnabled(UserHandle user) {
4347             if (UserHandle.getCallingUserId() != user.getIdentifier()) {
4348                 getContext().enforceCallingPermission(
4349                         android.Manifest.permission.INTERACT_ACROSS_USERS,
4350                         "areBubblesEnabled for user " + user.getIdentifier());
4351             }
4352             return mPreferencesHelper.bubblesEnabled(user);
4353         }
4354 
4355         @Override
4356         public int getBubblePreferenceForPackage(String pkg, int uid) {
4357             enforceSystemOrSystemUIOrSamePackage(pkg,
4358                     "Caller not system or systemui or same package");
4359 
4360             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
4361                 getContext().enforceCallingPermission(
4362                         android.Manifest.permission.INTERACT_ACROSS_USERS,
4363                         "getBubblePreferenceForPackage for uid " + uid);
4364             }
4365 
4366             return mPreferencesHelper.getBubblePreference(pkg, uid);
4367         }
4368 
4369         @Override
4370         public void setBubblesAllowed(String pkg, int uid, int bubblePreference) {
4371             checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
4372             mPreferencesHelper.setBubblesAllowed(pkg, uid, bubblePreference);
4373             handleSavePolicyFile();
4374         }
4375 
4376         @Override
4377         public boolean shouldHideSilentStatusIcons(String callingPkg) {
4378             checkCallerIsSameApp(callingPkg);
4379 
4380             if (isCallerSystemOrPhone()
4381                     || mListeners.isListenerPackage(callingPkg)) {
4382                 return mPreferencesHelper.shouldHideSilentStatusIcons();
4383             } else {
4384                 throw new SecurityException("Only available for notification listeners");
4385             }
4386         }
4387 
4388         @Override
4389         public void setHideSilentStatusIcons(boolean hide) {
4390             checkCallerIsSystem();
4391 
4392             mPreferencesHelper.setHideSilentStatusIcons(hide);
4393             handleSavePolicyFile();
4394 
4395             mListeners.onStatusBarIconsBehaviorChanged(hide);
4396         }
4397 
4398         @Override
4399         public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) {
4400             checkCallerIsSystem();
4401             mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime);
4402         }
4403 
4404         @Override
4405         public NotificationListenerFilter getListenerFilter(ComponentName cn, int userId) {
4406             checkCallerIsSystem();
4407             return mListeners.getNotificationListenerFilter(Pair.create(cn, userId));
4408         }
4409 
4410         @Override
4411         public void setListenerFilter(ComponentName cn, int userId,
4412                 NotificationListenerFilter nlf) {
4413             checkCallerIsSystem();
4414             mListeners.setNotificationListenerFilter(Pair.create(cn, userId), nlf);
4415             // TODO (b/173052211): cancel notifications for listeners that can no longer see them
4416             handleSavePolicyFile();
4417         }
4418 
4419         @Override
4420         public int getPackageImportance(String pkg) {
4421             checkCallerIsSystemOrSameApp(pkg);
4422             if (mPermissionHelper.hasPermission(Binder.getCallingUid())) {
4423                 return IMPORTANCE_DEFAULT;
4424             } else {
4425                 return IMPORTANCE_NONE;
4426             }
4427         }
4428 
4429         @Override
4430         public boolean isImportanceLocked(String pkg, int uid) {
4431             checkCallerIsSystem();
4432             return mPreferencesHelper.isImportanceLocked(pkg, uid);
4433         }
4434 
4435         @Override
4436         public boolean canShowBadge(String pkg, int uid) {
4437             checkCallerIsSystem();
4438             return mPreferencesHelper.canShowBadge(pkg, uid);
4439         }
4440 
4441         @Override
4442         public void setShowBadge(String pkg, int uid, boolean showBadge) {
4443             checkCallerIsSystem();
4444             mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
4445             handleSavePolicyFile();
4446         }
4447 
4448         @Override
4449         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
4450         public void allowAssistantAdjustment(String adjustmentType) {
4451             checkCallerIsSystemOrSystemUiOrShell();
4452             mAssistants.allowAdjustmentType(adjustmentType);
4453             int userId = UserHandle.getUserId(Binder.getCallingUid());
4454             if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
4455                 if (KEY_TYPE.equals(adjustmentType)) {
4456                     applyNotificationUpdateForUser(userId,
4457                             NotificationManagerService.this::reclassifyNotificationLocked);
4458                 }
4459             }
4460             handleSavePolicyFile();
4461         }
4462 
4463         @Override
4464         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
4465         public void disallowAssistantAdjustment(String adjustmentType) {
4466             checkCallerIsSystemOrSystemUiOrShell();
4467             mAssistants.disallowAdjustmentType(adjustmentType);
4468             int userId = UserHandle.getUserId(Binder.getCallingUid());
4469             if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
4470                 if (KEY_TYPE.equals(adjustmentType)) {
4471                     applyNotificationUpdateForUser(userId,
4472                             NotificationManagerService.this::unclassifyNotificationLocked);
4473                 }
4474             }
4475             if (nmSummarizationUi() || nmSummarization()) {
4476                 if (KEY_SUMMARIZATION.equals(adjustmentType)) {
4477                     applyNotificationUpdateForUser(userId,
4478                             NotificationManagerService.this::unsummarizeNotificationLocked);
4479                 }
4480             }
4481             handleSavePolicyFile();
4482         }
4483 
4484         @Override
4485         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
4486         public void setAdjustmentTypeSupportedState(INotificationListener token,
4487                 @Adjustment.Keys String key, boolean supported) {
4488             final long identity = Binder.clearCallingIdentity();
4489             try {
4490                 synchronized (mNotificationLock) {
4491                     final ManagedServiceInfo info = mAssistants.checkServiceTokenLocked(token);
4492                     if (key == null) {
4493                         return;
4494                     }
4495                     mAssistants.setAdjustmentTypeSupportedState(info.userid,  key, supported);
4496                 }
4497             } finally {
4498                 Binder.restoreCallingIdentity(identity);
4499             }
4500             handleSavePolicyFile();
4501         }
4502 
4503         @Override
4504         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
4505         public @NonNull List<String> getUnsupportedAdjustmentTypes() {
4506             checkCallerIsSystemOrSystemUiOrShell();
4507             synchronized (mNotificationLock) {
4508                 return new ArrayList(mAssistants.getUnsupportedAdjustments(
4509                         UserHandle.getUserId(Binder.getCallingUid())));
4510             }
4511         }
4512 
4513         @Override
4514         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
4515         public @NonNull int[] getAllowedAdjustmentKeyTypes() {
4516             checkCallerIsSystemOrSystemUiOrShell();
4517             return mAssistants.getAllowedClassificationTypes();
4518         }
4519 
4520         @Override
4521         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
4522         public void setAssistantAdjustmentKeyTypeState(int type, boolean enabled) {
4523             checkCallerIsSystemOrSystemUiOrShell();
4524             mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled);
4525             if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
4526                 if (enabled) {
4527                     applyNotificationUpdateForUserAndType(
4528                             UserHandle.getUserId(Binder.getCallingUid()), type,
4529                             NotificationManagerService.this::reclassifyNotificationLocked);
4530                 } else {
4531                     applyNotificationUpdateForUserAndChannelType(
4532                             UserHandle.getUserId(Binder.getCallingUid()), type,
4533                             NotificationManagerService.this::unclassifyNotificationLocked);
4534                 }
4535             }
4536             handleSavePolicyFile();
4537         }
4538 
4539         @Override
4540         public String[] getAdjustmentDeniedPackages(String key) {
4541             checkCallerIsSystemOrSystemUiOrShell();
4542             return mAssistants.getAdjustmentDeniedPackages(key);
4543         }
4544 
4545         @Override
4546         public boolean isAdjustmentSupportedForPackage(String key, String pkg) {
4547             checkCallerIsSystemOrSystemUiOrShell();
4548             return mAssistants.isAdjustmentAllowedForPackage(key, pkg);
4549         }
4550 
4551         @Override
4552         public void setAdjustmentSupportedForPackage(@Adjustment.Keys String key, String pkg,
4553                 boolean enabled) {
4554             checkCallerIsSystemOrSystemUiOrShell();
4555             mAssistants.setAdjustmentSupportedForPackage(key, pkg, enabled);
4556             if (notificationClassificationUi() && notificationRegroupOnClassification()
4557                     && key.equals(KEY_TYPE)) {
4558                 if (enabled) {
4559                     applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()),
4560                             pkg, NotificationManagerService.this::reclassifyNotificationLocked);
4561                 } else {
4562                     applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()),
4563                             pkg, NotificationManagerService.this::unclassifyNotificationLocked);
4564                 }
4565             }
4566             if (nmSummarization() || nmSummarizationUi()) {
4567                 if (KEY_SUMMARIZATION.equals(key) && !enabled) {
4568                     applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()),
4569                             pkg, NotificationManagerService.this::unsummarizeNotificationLocked);
4570                 }
4571             }
4572             handleSavePolicyFile();
4573         }
4574 
4575         @Override
4576         @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
4577         public boolean appCanBePromoted(String pkg, int uid) {
4578             checkCallerIsSystemOrSystemUiOrShell();
4579             if (!android.app.Flags.apiRichOngoing()) {
4580                 return false;
4581             }
4582             return mPreferencesHelper.canBePromoted(pkg, uid);
4583         }
4584 
4585         @Override
4586         @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
4587         public boolean canBePromoted(String callingPkg) {
4588             checkCallerIsSameApp(callingPkg);
4589             if (!android.app.Flags.apiRichOngoing()) {
4590                 return false;
4591             }
4592             return mPreferencesHelper.canBePromoted(callingPkg, Binder.getCallingUid());
4593         }
4594 
4595 
4596         /**
4597          * Any changes from SystemUI or Settings should be fromUser == true. Any changes the
4598          * allowlist should be fromUser == false.
4599          */
4600         @Override
4601         @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
4602         public void setCanBePromoted(String pkg, int uid, boolean promote, boolean fromUser) {
4603             checkCallerIsSystemOrSystemUiOrShell();
4604             if (!android.app.Flags.apiRichOngoing()) {
4605                 return;
4606             }
4607             boolean changed = mPreferencesHelper.setCanBePromoted(pkg, uid, promote, fromUser);
4608             if (changed) {
4609                 // check for pending/posted notifs from this app and update the flag
4610                 synchronized (mNotificationLock) {
4611                     // for enqueued we just need to update the flag
4612                     List<NotificationRecord> enqueued = findAppNotificationByListLocked(
4613                             mEnqueuedNotifications, pkg, UserHandle.getUserId(uid));
4614                     for (NotificationRecord r : enqueued) {
4615                         if (promote
4616                                 && r.getNotification().hasPromotableCharacteristics()
4617                                 && r.getImportance() > IMPORTANCE_MIN) {
4618                             r.getNotification().flags |= FLAG_PROMOTED_ONGOING;
4619                         } else if (!promote) {
4620                             r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING;
4621                         }
4622                     }
4623                     // if the notification is posted we need to update the flag and tell listeners
4624                     List<NotificationRecord> posted = findAppNotificationByListLocked(
4625                             mNotificationList, pkg, UserHandle.getUserId(uid));
4626                     for (NotificationRecord r : posted) {
4627                         if (promote
4628                                 && !hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING)
4629                                 && r.getNotification().hasPromotableCharacteristics()
4630                                 && r.getImportance() > IMPORTANCE_MIN) {
4631                             r.getNotification().flags |= FLAG_PROMOTED_ONGOING;
4632                             // we could set a wake lock here but this value should only change
4633                             // in response to user action, so the device should be awake long enough
4634                             // to post
4635                             PostNotificationTracker tracker =
4636                                     mPostNotificationTrackerFactory.newTracker(null);
4637                             // Set false for isAppForeground because that field is only used
4638                             // for bubbles and messagingstyle can not be promoted
4639                             mHandler.post(new EnqueueNotificationRunnable(
4640                                     r.getUser().getIdentifier(),
4641                                     r, /* isAppForeground */ false, /* isAppProvided= */ false,
4642                                     tracker));
4643                         } else if (!promote
4644                                 && hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING)){
4645                             r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING;
4646                             PostNotificationTracker tracker =
4647                                     mPostNotificationTrackerFactory.newTracker(null);
4648                             mHandler.post(new EnqueueNotificationRunnable(
4649                                     r.getUser().getIdentifier(),
4650                                     r, /* isAppForeground */ false, /* isAppProvided= */ false,
4651                                     tracker));
4652                         }
4653                     }
4654                 }
4655                 handleSavePolicyFile();
4656             }
4657         }
4658 
4659         @Override
4660         public boolean hasSentValidMsg(String pkg, int uid) {
4661             checkCallerIsSystem();
4662             return mPreferencesHelper.hasSentValidMsg(pkg, uid);
4663         }
4664 
4665         @Override
4666         public boolean isInInvalidMsgState(String pkg, int uid) {
4667             checkCallerIsSystem();
4668             return mPreferencesHelper.isInInvalidMsgState(pkg, uid);
4669         }
4670 
4671         @Override
4672         public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) {
4673             checkCallerIsSystem();
4674             return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid);
4675         }
4676 
4677         @Override
4678         public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) {
4679             checkCallerIsSystem();
4680             mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted);
4681             handleSavePolicyFile();
4682         }
4683 
4684         @Override
4685         public boolean hasSentValidBubble(String pkg, int uid) {
4686             checkCallerIsSystem();
4687             return mPreferencesHelper.hasSentValidBubble(pkg, uid);
4688         }
4689 
4690         @Override
4691         public void setNotificationDelegate(String callingPkg, String delegate) {
4692             checkCallerIsSameApp(callingPkg);
4693             final int callingUid = Binder.getCallingUid();
4694             UserHandle user = UserHandle.getUserHandleForUid(callingUid);
4695             if (delegate == null) {
4696                 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
4697                 handleSavePolicyFile();
4698             } else {
4699                 try {
4700                     ApplicationInfo info =
4701                             mPackageManager.getApplicationInfo(delegate,
4702                                     MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
4703                                     user.getIdentifier());
4704                     if (info != null) {
4705                         mPreferencesHelper.setNotificationDelegate(
4706                                 callingPkg, callingUid, delegate, info.uid);
4707                         handleSavePolicyFile();
4708                     }
4709                 } catch (RemoteException e) {
4710                     e.rethrowFromSystemServer();
4711                 }
4712             }
4713         }
4714 
4715         @Override
4716         public String getNotificationDelegate(String callingPkg) {
4717             // callable by Settings also
4718             checkCallerIsSystemOrSameApp(callingPkg);
4719             return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
4720         }
4721 
4722         @Override
4723         public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) {
4724             checkCallerIsSameApp(callingPkg);
4725             final int callingUid = Binder.getCallingUid();
4726             UserHandle user = UserHandle.getUserHandleForUid(callingUid);
4727             if (user.getIdentifier() != userId) {
4728                 getContext().enforceCallingPermission(
4729                         android.Manifest.permission.INTERACT_ACROSS_USERS,
4730                         "canNotifyAsPackage for user " + userId);
4731             }
4732             if (callingPkg.equals(targetPkg)) {
4733                 return true;
4734             }
4735             try {
4736                 ApplicationInfo info =
4737                         mPackageManager.getApplicationInfo(targetPkg,
4738                                 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
4739                                 userId);
4740                 if (info != null) {
4741                     return mPreferencesHelper.isDelegateAllowed(
4742                             targetPkg, info.uid, callingPkg, callingUid);
4743                 }
4744             } catch (RemoteException e) {
4745                 // :(
4746             }
4747             return false;
4748         }
4749 
4750         @Override
4751         public boolean canUseFullScreenIntent(@NonNull AttributionSource attributionSource) {
4752             final String packageName = attributionSource.getPackageName();
4753             final int uid = attributionSource.getUid();
4754             final int userId = UserHandle.getUserId(uid);
4755             checkCallerIsSameApp(packageName, uid, userId);
4756 
4757             final ApplicationInfo applicationInfo;
4758             try {
4759                 applicationInfo = mPackageManagerClient.getApplicationInfoAsUser(
4760                         packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
4761             } catch (NameNotFoundException e) {
4762                 Slog.e(TAG, "Failed to getApplicationInfo() in canUseFullScreenIntent()", e);
4763                 return false;
4764             }
4765             return checkUseFullScreenIntentPermission(attributionSource, applicationInfo,
4766                     false /* forDataDelivery */);
4767         }
4768 
4769         @Override
4770         public void updateNotificationChannelGroupForPackage(String pkg, int uid,
4771                 NotificationChannelGroup group) throws RemoteException {
4772             enforceSystemOrSystemUI("Caller not system or systemui");
4773             createNotificationChannelGroup(pkg, uid, group, false, false);
4774             handleSavePolicyFile();
4775         }
4776 
4777         @Override
4778         public void createNotificationChannelGroups(String pkg,
4779                 ParceledListSlice channelGroupList) throws RemoteException {
4780             checkCallerIsSystemOrSameApp(pkg);
4781             List<NotificationChannelGroup> groups = channelGroupList.getList();
4782             final int groupSize = groups.size();
4783             for (int i = 0; i < groupSize; i++) {
4784                 final NotificationChannelGroup group = groups.get(i);
4785                 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
4786             }
4787             handleSavePolicyFile();
4788         }
4789 
4790         private void createNotificationChannelsImpl(String pkg, int uid,
4791                 ParceledListSlice channelsList) {
4792             createNotificationChannelsImpl(pkg, uid, channelsList,
4793                     ActivityTaskManager.INVALID_TASK_ID);
4794         }
4795 
4796         private void createNotificationChannelsImpl(String pkg, int uid,
4797                 ParceledListSlice channelsList, int startingTaskId) {
4798             List<NotificationChannel> channels = channelsList.getList();
4799             final int channelsSize = channels.size();
4800             ParceledListSlice<NotificationChannel> oldChannels =
4801                     mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
4802             final boolean hadNonBundleChannel =
4803                     oldChannels != null && !oldChannels.getList().isEmpty();
4804             boolean needsPolicyFileChange = false;
4805             boolean hasRequestedNotificationPermission = false;
4806             for (int i = 0; i < channelsSize; i++) {
4807                 final NotificationChannel channel = channels.get(i);
4808                 Objects.requireNonNull(channel, "channel in list is null");
4809                 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid,
4810                         channel, true /* fromTargetApp */,
4811                         mConditionProviders.isPackageOrComponentAllowed(
4812                                 pkg, UserHandle.getUserId(uid)), Binder.getCallingUid(),
4813                         isCallerSystemOrSystemUi());
4814                 if (needsPolicyFileChange) {
4815                     mListeners.notifyNotificationChannelChanged(pkg,
4816                             UserHandle.getUserHandleForUid(uid),
4817                             mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
4818                                     false),
4819                             NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
4820                     boolean hasNonBundleChannel =
4821                             hadNonBundleChannel || hasRequestedNotificationPermission;
4822                     if (!hasNonBundleChannel) {
4823                         ParceledListSlice<NotificationChannel> currChannels =
4824                                 mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
4825                         hasNonBundleChannel =
4826                                 currChannels != null && !currChannels.getList().isEmpty();
4827                     }
4828                     // show perm prompt if new non-bundle channel added and the user has not
4829                     // seen the prompt
4830                     if (!hadNonBundleChannel && hasNonBundleChannel
4831                             && !hasRequestedNotificationPermission
4832                             && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
4833                         hasRequestedNotificationPermission = true;
4834                         if (mPermissionPolicyInternal == null) {
4835                             mPermissionPolicyInternal =
4836                                     LocalServices.getService(PermissionPolicyInternal.class);
4837                         }
4838                         mHandler.post(new ShowNotificationPermissionPromptRunnable(pkg,
4839                                 UserHandle.getUserId(uid), startingTaskId,
4840                                 mPermissionPolicyInternal));
4841                     }
4842                 }
4843             }
4844             if (needsPolicyFileChange) {
4845                 handleSavePolicyFile();
4846             }
4847         }
4848 
4849         @Override
4850         public void createNotificationChannels(String pkg, ParceledListSlice channelsList) {
4851             checkCallerIsSystemOrSameApp(pkg);
4852             int taskId = ActivityTaskManager.INVALID_TASK_ID;
4853             try {
4854                 int uid = mPackageManager.getPackageUid(pkg, 0,
4855                         UserHandle.getUserId(Binder.getCallingUid()));
4856                 taskId = mAtm.getTaskToShowPermissionDialogOn(pkg, uid);
4857             } catch (RemoteException e) {
4858                 // Do nothing
4859             }
4860             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList, taskId);
4861         }
4862 
4863         @Override
4864         public void createNotificationChannelsForPackage(String pkg, int uid,
4865                 ParceledListSlice channelsList) {
4866             enforceSystemOrSystemUI("only system can call this");
4867             createNotificationChannelsImpl(pkg, uid, channelsList);
4868         }
4869 
4870         @Override
4871         public void createConversationNotificationChannelForPackage(String pkg, int uid,
4872                 NotificationChannel parentChannel, String conversationId) {
4873             enforceSystemOrSystemUI("only system can call this");
4874             checkNotNull(parentChannel);
4875             checkNotNull(conversationId);
4876             String parentId = parentChannel.getId();
4877             NotificationChannel conversationChannel = parentChannel;
4878             conversationChannel.setId(String.format(
4879                     CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId));
4880             conversationChannel.setConversationId(parentId, conversationId);
4881             createNotificationChannelsImpl(
4882                     pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel)));
4883             mRankingHandler.requestSort();
4884             handleSavePolicyFile();
4885         }
4886 
4887         @Override
4888         public NotificationChannel getNotificationChannel(String callingPkg, int userId,
4889                 String targetPkg, String channelId) {
4890             return getConversationNotificationChannel(
4891                     callingPkg, userId, targetPkg, channelId, true, null);
4892         }
4893 
4894         @Override
4895         public NotificationChannel getConversationNotificationChannel(String callingPkg, int userId,
4896                 String targetPkg, String channelId, boolean returnParentIfNoConversationChannel,
4897                 String conversationId) {
4898             if (canNotifyAsPackage(callingPkg, targetPkg, userId)
4899                     || isCallerSystemOrSystemUiOrShell()) {
4900                 int targetUid = -1;
4901                 try {
4902                     targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4903                 } catch (NameNotFoundException e) {
4904                     /* ignore */
4905                 }
4906                 return mPreferencesHelper.getConversationNotificationChannel(
4907                         targetPkg, targetUid, channelId, conversationId,
4908                         returnParentIfNoConversationChannel, false /* includeDeleted */);
4909             }
4910             throw new SecurityException("Pkg " + callingPkg
4911                     + " cannot read channels for " + targetPkg + " in " + userId);
4912         }
4913 
4914         @Override
4915         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
4916                 String channelId, String conversationId, boolean includeDeleted) {
4917             checkCallerIsSystem();
4918             return mPreferencesHelper.getConversationNotificationChannel(
4919                     pkg, uid, channelId, conversationId, true, includeDeleted);
4920         }
4921 
4922         // Returns 'true' if the given channel has a notification associated
4923         // with an active foreground service.
4924         private void enforceDeletingChannelHasNoFgService(String pkg, int userId,
4925                 String channelId) {
4926             if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) {
4927                 Slog.w(TAG, "Package u" + userId + "/" + pkg
4928                         + " may not delete notification channel '"
4929                         + channelId + "' with fg service");
4930                 throw new SecurityException("Not allowed to delete channel " + channelId
4931                         + " with a foreground service");
4932             }
4933         }
4934 
4935         // Throws a security exception if the given channel has a notification associated
4936         // with an active user-initiated job.
4937         private void enforceDeletingChannelHasNoUserInitiatedJob(String pkg, int userId,
4938                 String channelId) {
4939             final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
4940             if (js != null && js.isNotificationChannelAssociatedWithAnyUserInitiatedJobs(
4941                     channelId, userId, pkg)) {
4942                 Slog.w(TAG, "Package u" + userId + "/" + pkg
4943                         + " may not delete notification channel '"
4944                         + channelId + "' with user-initiated job");
4945                 throw new SecurityException("Not allowed to delete channel " + channelId
4946                         + " with a user-initiated job");
4947             }
4948         }
4949 
4950         @Override
4951         public void deleteNotificationChannel(String pkg, String channelId) {
4952             checkCallerIsSystemOrSameApp(pkg);
4953             final int callingUid = Binder.getCallingUid();
4954             final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
4955             final int callingUser = UserHandle.getUserId(callingUid);
4956             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4957                 throw new IllegalArgumentException("Cannot delete default channel");
4958             }
4959             if (notificationClassification()) {
4960                 // Check for all reserved channels, but do not throw because it's a common
4961                 // preexisting pattern for apps to (try to) delete all channels that don't match
4962                 //  their current desired channel structure
4963                 if (SYSTEM_RESERVED_IDS.contains(channelId)) {
4964                     Log.v(TAG, "Package " + pkg + " cannot delete a reserved channel");
4965                     return;
4966                 }
4967             }
4968             enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
4969             enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId);
4970             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
4971                     callingUser, REASON_CHANNEL_REMOVED);
4972             boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
4973                     pkg, callingUid, channelId, callingUid, isSystemOrSystemUi);
4974             if (previouslyExisted) {
4975                 // Remove from both recent notification archive (recently dismissed notifications)
4976                 // and notification history
4977                 mArchive.removeChannelNotifications(pkg, callingUser, channelId);
4978                 mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
4979                 mListeners.notifyNotificationChannelChanged(pkg,
4980                         UserHandle.getUserHandleForUid(callingUid),
4981                         mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
4982                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
4983                 handleSavePolicyFile();
4984             }
4985         }
4986 
4987         @Override
4988         public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
4989             checkCallerIsSystemOrSameApp(pkg);
4990             return mPreferencesHelper.getNotificationChannelGroupWithChannels(
4991                     pkg, Binder.getCallingUid(), groupId, false);
4992         }
4993 
4994         @Override
4995         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
4996                 String pkg) {
4997             checkCallerIsSystemOrSameApp(pkg);
4998             return mPreferencesHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid(),
4999                     NotificationChannelGroupsHelper.Params.forAllGroups());
5000         }
5001 
5002         @Override
5003         public ParceledListSlice<NotificationChannelGroup>
5004                 getNotificationChannelGroupsWithoutChannels(String pkg) {
5005             checkCallerIsSystemOrSameApp(pkg);
5006             List<NotificationChannelGroup> groups = new ArrayList<>();
5007             groups.addAll(mPreferencesHelper.getNotificationChannelGroupsWithoutChannels(pkg,
5008                     Binder.getCallingUid()));
5009             return new ParceledListSlice<>(groups);
5010         }
5011 
5012         @Override
5013         public void deleteNotificationChannelGroup(String pkg, String groupId) {
5014             checkCallerIsSystemOrSameApp(pkg);
5015 
5016             final int callingUid = Binder.getCallingUid();
5017             final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
5018             NotificationChannelGroup groupToDelete =
5019                     mPreferencesHelper.getNotificationChannelGroupWithChannels(
5020                             pkg, callingUid, groupId, false);
5021             if (groupToDelete != null) {
5022                 // Preflight for allowability
5023                 final int userId = UserHandle.getUserId(callingUid);
5024                 List<NotificationChannel> groupChannels = groupToDelete.getChannels();
5025                 for (int i = 0; i < groupChannels.size(); i++) {
5026                     final String channelId = groupChannels.get(i).getId();
5027                     enforceDeletingChannelHasNoFgService(pkg, userId, channelId);
5028                     enforceDeletingChannelHasNoUserInitiatedJob(pkg, userId, channelId);
5029                 }
5030                 List<NotificationChannel> deletedChannels =
5031                         mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId,
5032                                 callingUid, isSystemOrSystemUi);
5033                 for (int i = 0; i < deletedChannels.size(); i++) {
5034                     final NotificationChannel deletedChannel = deletedChannels.get(i);
5035                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
5036                             userId, REASON_CHANNEL_REMOVED
5037                     );
5038                     mListeners.notifyNotificationChannelChanged(pkg,
5039                             UserHandle.getUserHandleForUid(callingUid),
5040                             deletedChannel,
5041                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
5042                 }
5043                 mListeners.notifyNotificationChannelGroupChanged(
5044                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
5045                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
5046                 handleSavePolicyFile();
5047             }
5048         }
5049 
5050         @Override
5051         public void updateNotificationChannelForPackage(String pkg, int uid,
5052                 NotificationChannel channel) {
5053             checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
5054             Objects.requireNonNull(channel);
5055             updateNotificationChannelInt(pkg, uid, channel, false);
5056         }
5057 
5058         @Override
5059         public void unlockNotificationChannel(String pkg, int uid, String channelId) {
5060             checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
5061             mPreferencesHelper.unlockNotificationChannelImportance(pkg, uid, channelId);
5062             handleSavePolicyFile();
5063         }
5064 
5065         @Override
5066         public void unlockAllNotificationChannels() {
5067             checkCallerIsSystem();
5068             mPreferencesHelper.unlockAllNotificationChannels();
5069             handleSavePolicyFile();
5070         }
5071 
5072         @Override
5073         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
5074                 int uid, boolean includeDeleted) {
5075             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
5076             return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted, true);
5077         }
5078 
5079         @Override
5080         public int getNumNotificationChannelsForPackage(String pkg, int uid,
5081                 boolean includeDeleted) {
5082             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
5083             return NotificationManagerService.this
5084                     .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted);
5085         }
5086 
5087         @Override
5088         public boolean onlyHasDefaultChannel(String pkg, int uid) {
5089             enforceSystemOrSystemUI("onlyHasDefaultChannel");
5090             return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
5091         }
5092 
5093         @Override
5094         public int getDeletedChannelCount(String pkg, int uid) {
5095             enforceSystemOrSystemUI("getDeletedChannelCount");
5096             return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
5097         }
5098 
5099         @Override
5100         public int getBlockedChannelCount(String pkg, int uid) {
5101             enforceSystemOrSystemUI("getBlockedChannelCount");
5102             return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
5103         }
5104 
5105         @Override
5106         public ParceledListSlice<ConversationChannelWrapper> getConversations(
5107                 boolean onlyImportant) {
5108             enforceSystemOrSystemUI("getConversations");
5109             IntArray userIds = mUserProfiles.getCurrentProfileIds();
5110             ArrayList<ConversationChannelWrapper> conversations =
5111                     mPreferencesHelper.getConversations(userIds, onlyImportant);
5112             for (ConversationChannelWrapper conversation : conversations) {
5113                 if (mShortcutHelper == null) {
5114                     conversation.setShortcutInfo(null);
5115                 } else {
5116                     conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
5117                             conversation.getNotificationChannel().getConversationId(),
5118                             conversation.getPkg(),
5119                             UserHandle.of(UserHandle.getUserId(conversation.getUid()))));
5120                 }
5121             }
5122             return new ParceledListSlice<>(conversations);
5123         }
5124 
5125         @Override
5126         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
5127                 String pkg, int uid, boolean includeDeleted) {
5128             enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
5129             return mPreferencesHelper.getNotificationChannelGroups(pkg, uid,
5130                     new NotificationChannelGroupsHelper.Params(includeDeleted, true, false, true,
5131                             null));
5132         }
5133 
5134         @Override
5135         public ParceledListSlice<NotificationChannelGroup>
5136                 getRecentBlockedNotificationChannelGroupsForPackage(String pkg, int uid) {
5137             enforceSystemOrSystemUI("getRecentBlockedNotificationChannelGroupsForPackage");
5138             Set<String> recentlySentChannels = new HashSet<>();
5139             long now = System.currentTimeMillis();
5140             long startTime = now - (DateUtils.DAY_IN_MILLIS * 14);
5141             UsageEvents events = mUsageStatsManagerInternal.queryEventsForUser(
5142                 UserHandle.getUserId(uid),  startTime, now, UsageEvents.SHOW_ALL_EVENT_DATA);
5143             // get all channelids that sent notifs in the past 2 weeks
5144             if (events != null) {
5145                 UsageEvents.Event event = new UsageEvents.Event();
5146                 while (events.hasNextEvent()) {
5147                     events.getNextEvent(event);
5148                     if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) {
5149                         if (pkg.equals(event.mPackage)) {
5150                             String channelId = event.mNotificationChannelId;
5151                             if (channelId != null) {
5152                                 recentlySentChannels.add(channelId);
5153                             }
5154                         }
5155                     }
5156                 }
5157             }
5158 
5159             return mPreferencesHelper.getNotificationChannelGroups(pkg, uid,
5160                     NotificationChannelGroupsHelper.Params.onlySpecifiedOrBlockedChannels(
5161                             recentlySentChannels));
5162         }
5163 
5164         @Override
5165         public ParceledListSlice<ConversationChannelWrapper> getConversationsForPackage(String pkg,
5166                 int uid) {
5167             enforceSystemOrSystemUI("getConversationsForPackage");
5168             ArrayList<ConversationChannelWrapper> conversations =
5169                     mPreferencesHelper.getConversations(pkg, uid);
5170             for (ConversationChannelWrapper conversation : conversations) {
5171                 if (mShortcutHelper == null) {
5172                     conversation.setShortcutInfo(null);
5173                 } else {
5174                     conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo(
5175                             conversation.getNotificationChannel().getConversationId(),
5176                             pkg,
5177                             UserHandle.of(UserHandle.getUserId(uid))));
5178                 }
5179             }
5180             return new ParceledListSlice<>(conversations);
5181         }
5182 
5183         @Override
5184         public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
5185                 String pkg, int uid, String groupId, boolean includeDeleted) {
5186             enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
5187             return mPreferencesHelper.getNotificationChannelGroupWithChannels(
5188                     pkg, uid, groupId, includeDeleted);
5189         }
5190 
5191         @Override
5192         public NotificationChannelGroup getNotificationChannelGroupForPackage(
5193                 String groupId, String pkg, int uid) {
5194             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
5195             return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
5196         }
5197 
5198         @Override
5199         public ParceledListSlice<NotificationChannel> getNotificationChannels(String callingPkg,
5200                 String targetPkg, int userId) {
5201             if (canNotifyAsPackage(callingPkg, targetPkg, userId)
5202                 || isCallingUidSystem()) {
5203                 int targetUid = -1;
5204                 try {
5205                     targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
5206                 } catch (NameNotFoundException e) {
5207                     /* ignore */
5208                 }
5209                 return mPreferencesHelper.getNotificationChannels(
5210                         targetPkg, targetUid, false /* includeDeleted */, true);
5211             }
5212             throw new SecurityException("Pkg " + callingPkg
5213                     + " cannot read channels for " + targetPkg + " in " + userId);
5214         }
5215 
5216         @Override
5217         public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
5218                 String pkg, int uid) {
5219             checkCallerIsSystem();
5220             if (!areNotificationsEnabledForPackage(pkg, uid)) {
5221                 return ParceledListSlice.emptyList();
5222             }
5223             return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid);
5224         }
5225 
5226         @Override
5227         public ParceledListSlice<ZenBypassingApp> getPackagesBypassingDnd(int userId)
5228                 throws RemoteException {
5229             checkCallerIsSystem();
5230 
5231             UserHandle user = UserHandle.of(userId);
5232             ArrayList<ZenBypassingApp> bypassing =
5233                     mPreferencesHelper.getPackagesBypassingDnd(userId);
5234             for (int i = bypassing.size() - 1; i >= 0; i--) {
5235                 String pkg = bypassing.get(i).getPkg();
5236                 if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) {
5237                     bypassing.remove(i);
5238                 }
5239             }
5240             return new ParceledListSlice<>(bypassing);
5241         }
5242 
5243         @Override
5244         public boolean areChannelsBypassingDnd() {
5245             return mZenModeHelper.getConsolidatedNotificationPolicy().allowPriorityChannels()
5246                     && mPreferencesHelper.hasPriorityChannels();
5247         }
5248 
5249         @Override
5250         @FlaggedApi(android.app.Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS)
5251         public List<String> getPackagesWithAnyChannels(int userId) throws RemoteException {
5252             checkCallerIsSystem();
5253             UserHandle user = UserHandle.of(userId);
5254             List<String> packages = mPreferencesHelper.getPackagesWithAnyChannels(userId);
5255             for (int i = packages.size() - 1; i >= 0; i--) {
5256                 String pkg = packages.get(i);
5257                 if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) {
5258                     packages.remove(i);
5259                 }
5260             }
5261             return packages;
5262         }
5263 
5264         @Override
5265         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
5266             boolean packagesChanged = false;
5267             checkCallerIsSystem();
5268             // Cancel posted notifications
5269             final int userId = UserHandle.getUserId(uid);
5270             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0,
5271                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CLEAR_DATA);
5272 
5273             // Zen
5274             packagesChanged |=
5275                     mConditionProviders.resetPackage(packageName, userId);
5276 
5277             // Listener
5278             ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
5279                     mListeners.resetComponents(packageName, userId);
5280             packagesChanged |= changedListeners.get(true).size() > 0
5281                     || changedListeners.get(false).size() > 0;
5282 
5283             // When a listener is enabled, we enable the dnd package as a secondary
5284             for (int i = 0; i < changedListeners.get(true).size(); i++) {
5285                 mConditionProviders.setPackageOrComponentEnabled(
5286                         changedListeners.get(true).get(i).getPackageName(),
5287                         userId, false, true);
5288             }
5289 
5290             // Assistant
5291             ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants =
5292                     mAssistants.resetComponents(packageName, userId);
5293             packagesChanged |= changedAssistants.get(true).size() > 0
5294                     || changedAssistants.get(false).size() > 0;
5295 
5296             // we want only one assistant enabled
5297             for (int i = 1; i < changedAssistants.get(true).size(); i++) {
5298                 mAssistants.setPackageOrComponentEnabled(
5299                         changedAssistants.get(true).get(i).flattenToString(),
5300                         userId, true, false);
5301             }
5302 
5303             // When the default assistant is enabled, we enable the dnd package as a secondary
5304             if (changedAssistants.get(true).size() > 0) {
5305                 //we want only one assistant active
5306                 mConditionProviders
5307                         .setPackageOrComponentEnabled(
5308                                 changedAssistants.get(true).get(0).getPackageName(),
5309                                 userId, false, true);
5310 
5311             }
5312 
5313             // Snoozing
5314             mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
5315 
5316             // Reset notification preferences
5317             if (!fromApp) {
5318                 mPreferencesHelper.clearData(packageName, uid);
5319             }
5320 
5321             if (packagesChanged) {
5322                 getContext().sendBroadcastAsUser(new Intent(
5323                                 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5324                                 .setPackage(packageName)
5325                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
5326                         UserHandle.of(userId), null);
5327             }
5328 
5329             handleSavePolicyFile();
5330         }
5331 
5332         @Override
5333         public List<String> getAllowedAssistantAdjustments(String pkg) {
5334             checkCallerIsSystemOrSameApp(pkg);
5335 
5336             if (!isCallerSystemOrPhone()
5337                     && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
5338                     throw new SecurityException("Not currently an assistant");
5339             }
5340 
5341             return new ArrayList<>(mAssistants.getAllowedAssistantAdjustments());
5342         }
5343 
5344         /**
5345          * @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead.
5346          */
5347         @Deprecated
5348         @Override
5349         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
5350             return getActiveNotificationsWithAttribution(callingPkg, null);
5351         }
5352 
5353         /**
5354          * System-only API for getting a list of current (i.e. not cleared) notifications.
5355          *
5356          * Requires ACCESS_NOTIFICATIONS which is signature|system.
5357          * @returns A list of all the notifications, in natural order.
5358          */
5359         @Override
5360         @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
5361         public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg,
5362                 String callingAttributionTag) {
5363             // enforce() will ensure the calling uid has the correct permission
5364             getActiveNotificationsWithAttribution_enforcePermission();
5365 
5366             ArrayList<StatusBarNotification> tmp = new ArrayList<>();
5367             int uid = Binder.getCallingUid();
5368 
5369             ArrayList<Integer> currentUsers = new ArrayList<>();
5370             currentUsers.add(USER_ALL);
5371             Binder.withCleanCallingIdentity(() -> {
5372                 for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) {
5373                     currentUsers.add(user);
5374                 }
5375             });
5376 
5377             // noteOp will check to make sure the callingPkg matches the uid
5378             int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
5379                         callingAttributionTag, null);
5380             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
5381                 synchronized (mNotificationLock) {
5382                     final int N = mNotificationList.size();
5383                     for (int i = 0; i < N; i++) {
5384                         final StatusBarNotification sbn = mNotificationList.get(i).getSbn();
5385                         if (currentUsers.contains(sbn.getUserId())) {
5386                             tmp.add(sbn);
5387                         }
5388                     }
5389                 }
5390             }
5391             return tmp.toArray(new StatusBarNotification[tmp.size()]);
5392         }
5393 
5394         /**
5395          * Public API for getting a list of current notifications for the calling package/uid.
5396          *
5397          * Note that since notification posting is done asynchronously, this will not return
5398          * notifications that are in the process of being posted.
5399          *
5400          * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as
5401          * an app's notification delegate via
5402          * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}.
5403          *
5404          * @returns A list of all the package's notifications, in natural order.
5405          */
5406         @Override
5407         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
5408                 int incomingUserId) {
5409             checkCallerIsSystemOrSameApp(pkg);
5410             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
5411                     Binder.getCallingUid(), incomingUserId, true, false,
5412                     "getAppActiveNotifications", pkg);
5413             synchronized (mNotificationLock) {
5414                 final ArrayMap<String, StatusBarNotification> map
5415                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
5416                 final int N = mNotificationList.size();
5417                 for (int i = 0; i < N; i++) {
5418                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
5419                             mNotificationList.get(i).getSbn());
5420                     if (sbn != null) {
5421                         map.put(sbn.getKey(), sbn);
5422                     }
5423                 }
5424                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
5425                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.getSbn());
5426                     if (sbn != null) {
5427                         map.put(sbn.getKey(), sbn);
5428                     }
5429                 }
5430                 final int M = mEnqueuedNotifications.size();
5431                 for (int i = 0; i < M; i++) {
5432                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
5433                             mEnqueuedNotifications.get(i).getSbn());
5434                     if (sbn != null) {
5435                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
5436                     }
5437                 }
5438                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
5439                 list.addAll(map.values());
5440                 return new ParceledListSlice<StatusBarNotification>(list);
5441             }
5442         }
5443 
5444         /** Notifications returned here will have allowlistToken stripped from them. */
5445         private StatusBarNotification sanitizeSbn(String pkg, int userId,
5446                 StatusBarNotification sbn) {
5447             if (sbn.getUserId() == userId) {
5448                 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) {
5449                     // We could pass back a cloneLight() but clients might get confused and
5450                     // try to send this thing back to notify() again, which would not work
5451                     // very well.
5452                     Notification notification = sbn.getNotification().clone();
5453                     // Remove background token before returning notification to untrusted app, this
5454                     // ensures the app isn't able to perform background operations that are
5455                     // associated with notification interactions.
5456                     notification.overrideAllowlistToken(null);
5457                     return new StatusBarNotification(
5458                             sbn.getPackageName(),
5459                             sbn.getOpPkg(),
5460                             sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
5461                             notification,
5462                             sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
5463                 }
5464             }
5465             return null;
5466         }
5467 
5468         /**
5469          * @deprecated Use {@link #getHistoricalNotificationsWithAttribution} instead.
5470          */
5471         @Deprecated
5472         @Override
5473         @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
5474         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count,
5475                 boolean includeSnoozed) {
5476             return getHistoricalNotificationsWithAttribution(callingPkg, null, count,
5477                     includeSnoozed);
5478         }
5479 
5480         /**
5481          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
5482          */
5483         @Override
5484         @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
5485         @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
5486         public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg,
5487                 String callingAttributionTag, int count, boolean includeSnoozed) {
5488             // enforce() will ensure the calling uid has the correct permission
5489             getHistoricalNotificationsWithAttribution_enforcePermission();
5490 
5491             StatusBarNotification[] tmp = null;
5492             int uid = Binder.getCallingUid();
5493 
5494             // noteOp will check to make sure the callingPkg matches the uid
5495             int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
5496                         callingAttributionTag, null);
5497             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
5498                 synchronized (mArchive) {
5499                     tmp = mArchive.getArray(mUm, count, includeSnoozed);
5500                 }
5501             }
5502             return tmp;
5503         }
5504 
5505         /**
5506          * System-only API for getting a list of historical notifications. May contain multiple days
5507          * of notifications.
5508          */
5509         @Override
5510         @WorkerThread
5511         @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
5512         @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
5513         public NotificationHistory getNotificationHistory(String callingPkg,
5514                 String callingAttributionTag) {
5515             // enforce() will ensure the calling uid has the correct permission
5516             getNotificationHistory_enforcePermission();
5517             int uid = Binder.getCallingUid();
5518 
5519             // noteOp will check to make sure the callingPkg matches the uid
5520             int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
5521                         callingAttributionTag, null);
5522             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
5523                 IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();
5524                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory");
5525                 try {
5526                     return mHistoryManager.readNotificationHistory(currentUserIds.toArray());
5527                 } finally {
5528                     Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
5529                 }
5530             }
5531             return new NotificationHistory();
5532         }
5533 
5534         /**
5535          * Register a listener to be notified when a call notification is posted or removed
5536          * for a specific package and user.
5537          * @param packageName Which package to monitor
5538          * @param userHandle Which user to monitor
5539          * @param listener Listener to register
5540          */
5541         @Override
5542         @EnforcePermission(allOf = {
5543                 android.Manifest.permission.INTERACT_ACROSS_USERS,
5544                 android.Manifest.permission.ACCESS_NOTIFICATIONS})
5545         public void registerCallNotificationEventListener(String packageName, UserHandle userHandle,
5546                 ICallNotificationEventCallback listener) {
5547             registerCallNotificationEventListener_enforcePermission();
5548 
5549             final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT
5550                     ? userHandle.getIdentifier() : mAmi.getCurrentUserId();
5551 
5552             synchronized (mCallNotificationEventCallbacks) {
5553                 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
5554                         callbacksForPackage =
5555                         mCallNotificationEventCallbacks.getOrDefault(packageName, new ArrayMap<>());
5556                 RemoteCallbackList<ICallNotificationEventCallback> callbackList =
5557                         callbacksForPackage.getOrDefault(userId, new RemoteCallbackList<>());
5558 
5559                 if (callbackList.register(listener)) {
5560                     callbacksForPackage.put(userId, callbackList);
5561                     mCallNotificationEventCallbacks.put(packageName, callbacksForPackage);
5562                 } else {
5563                     Log.e(TAG,
5564                             "registerCallNotificationEventListener failed to register listener: "
5565                                 + packageName + " " + userHandle + " " + listener);
5566                     return;
5567                 }
5568             }
5569 
5570             synchronized (mNotificationLock) {
5571                 for (NotificationRecord r : mNotificationList) {
5572                     if (r.getNotification().isStyle(Notification.CallStyle.class)
5573                             && notificationMatchesUserId(r, userId, false)
5574                             && r.getSbn().getPackageName().equals(packageName)) {
5575                         try {
5576                             listener.onCallNotificationPosted(packageName, r.getUser());
5577                         } catch (RemoteException e) {
5578                             throw new RuntimeException(e);
5579                         }
5580                     }
5581                 }
5582             }
5583         }
5584 
5585         /**
5586          * Unregister a listener that was previously
5587          * registered with {@link #registerCallNotificationEventListener}
5588          *
5589          * @param packageName Which package to stop monitoring
5590          * @param userHandle Which user to stop monitoring
5591          * @param listener Listener to unregister
5592          */
5593         @Override
5594         @EnforcePermission(allOf = {
5595             android.Manifest.permission.INTERACT_ACROSS_USERS,
5596             android.Manifest.permission.ACCESS_NOTIFICATIONS})
5597         public void unregisterCallNotificationEventListener(String packageName,
5598                     UserHandle userHandle, ICallNotificationEventCallback listener) {
5599             unregisterCallNotificationEventListener_enforcePermission();
5600             synchronized (mCallNotificationEventCallbacks) {
5601                 final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT
5602                         ? userHandle.getIdentifier() : mAmi.getCurrentUserId();
5603 
5604                 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
5605                         callbacksForPackage = mCallNotificationEventCallbacks.get(packageName);
5606                 if (callbacksForPackage == null) {
5607                     return;
5608                 }
5609                 RemoteCallbackList<ICallNotificationEventCallback> callbackList =
5610                         callbacksForPackage.get(userId);
5611                 if (callbackList == null) {
5612                     return;
5613                 }
5614                 if (!callbackList.unregister(listener)) {
5615                     Log.e(TAG,
5616                             "unregisterCallNotificationEventListener listener not found for: "
5617                             + packageName + " " + userHandle + " " + listener);
5618                 }
5619             }
5620         }
5621 
5622         /**
5623          * Register a listener binder directly with the notification manager.
5624          *
5625          * Only works with system callers. Apps should extend
5626          * {@link NotificationListenerService}.
5627          */
5628         @Override
5629         public void registerListener(final INotificationListener listener,
5630                 final ComponentName component, final int userid) {
5631             enforceSystemOrSystemUI("INotificationManager.registerListener");
5632             mListeners.registerSystemService(listener, component, userid, Binder.getCallingUid());
5633         }
5634 
5635         /**
5636          * Remove a listener binder directly
5637          */
5638         @Override
5639         public void unregisterListener(INotificationListener token, int userid) {
5640             mListeners.unregisterService(token, userid);
5641         }
5642 
5643         /**
5644          * Allow an INotificationListener to simulate a "clear all" operation.
5645          *
5646          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
5647          *
5648          * @param token The binder for the listener, to check that the caller is allowed
5649          */
5650         @Override
5651         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
5652             final int callingUid = Binder.getCallingUid();
5653             final int callingPid = Binder.getCallingPid();
5654             final long identity = Binder.clearCallingIdentity();
5655             boolean notificationsRapidlyCleared = false;
5656             final String pkg;
5657             final int packageImportance;
5658             final ManagedServiceInfo info;
5659             try {
5660                 synchronized (mNotificationLock) {
5661                     info = mListeners.checkServiceTokenLocked(token);
5662                     pkg = info.component.getPackageName();
5663                 }
5664                 if (lifetimeExtensionRefactor()) {
5665                     packageImportance = getPackageImportanceWithIdentity(pkg);
5666                 } else {
5667                     packageImportance = IMPORTANCE_NONE;
5668                 }
5669                 synchronized (mNotificationLock) {
5670                     // Cancellation reason. If the token comes from assistant, label the
5671                     // cancellation as coming from the assistant; default to LISTENER_CANCEL.
5672                     int reason = REASON_LISTENER_CANCEL;
5673                     if (mAssistants.isServiceTokenValidLocked(token)) {
5674                         reason = REASON_ASSISTANT_CANCEL;
5675                     }
5676 
5677                     if (keys != null) {
5678                         final int N = keys.length;
5679                         for (int i = 0; i < N; i++) {
5680                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
5681                             if (r == null) continue;
5682                             final int userId = r.getSbn().getUserId();
5683                             if (userId != info.userid && userId != USER_ALL &&
5684                                     !mUserProfiles.isCurrentProfile(userId)) {
5685                                 continue;
5686                             }
5687                             notificationsRapidlyCleared = notificationsRapidlyCleared
5688                                     || isNotificationRecent(r.getUpdateTimeMs());
5689                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
5690                                     r.getSbn().getPackageName(), r.getSbn().getTag(),
5691                                     r.getSbn().getId(), userId, reason);
5692                         }
5693                     } else {
5694                         for (NotificationRecord notificationRecord : mNotificationList) {
5695                             if (isNotificationRecent(notificationRecord.getUpdateTimeMs())) {
5696                                 notificationsRapidlyCleared = true;
5697                                 break;
5698                             }
5699                         }
5700                         if (lifetimeExtensionRefactor()) {
5701                             cancelAllLocked(callingUid, callingPid, info.userid,
5702                                     REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
5703                                     FLAG_ONGOING_EVENT | FLAG_NO_CLEAR
5704                                             | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
5705                             // If cancellation will be prevented due to lifetime extension, we send
5706                             // an update to system UI.
5707                             maybeNotifySystemUiListenerLifetimeExtendedListLocked(
5708                                     mNotificationList, packageImportance);
5709                             maybeNotifySystemUiListenerLifetimeExtendedListLocked(
5710                                     mEnqueuedNotifications, packageImportance);
5711                         } else {
5712                             cancelAllLocked(callingUid, callingPid, info.userid,
5713                                     REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
5714                                     FLAG_ONGOING_EVENT | FLAG_NO_CLEAR);
5715                         }
5716                     }
5717                 }
5718                 if (notificationsRapidlyCleared) {
5719                     mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
5720                             callingUid, pkg, /* attributionTag= */ null, /* message= */ null);
5721                 }
5722             } finally {
5723                 Binder.restoreCallingIdentity(identity);
5724             }
5725         }
5726 
5727         /**
5728          * Handle request from an approved listener to re-enable itself.
5729          *
5730          * @param component The componenet to be re-enabled, caller must match package.
5731          */
5732         @Override
5733         public void requestBindListener(ComponentName component) {
5734             checkCallerIsSystemOrSameApp(component.getPackageName());
5735             int uid = Binder.getCallingUid();
5736             int userId = UserHandle.getUserId(uid);
5737             final long identity = Binder.clearCallingIdentity();
5738             try {
5739                 boolean isAssistantEnabled = managedServicesConcurrentMultiuser()
5740                         ? mAssistants.isComponentEnabledForUser(component, userId)
5741                         : mAssistants.isComponentEnabledForCurrentProfiles(component);
5742                 ManagedServices manager = isAssistantEnabled ? mAssistants : mListeners;
5743                 manager.setComponentState(component, UserHandle.getUserId(uid), true);
5744             } finally {
5745                 Binder.restoreCallingIdentity(identity);
5746             }
5747         }
5748 
5749         @Override
5750         public void requestUnbindListener(INotificationListener token) {
5751             int uid = Binder.getCallingUid();
5752             final long identity = Binder.clearCallingIdentity();
5753             try {
5754                 // allow bound services to disable themselves
5755                 synchronized (mNotificationLock) {
5756                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5757                     info.getOwner().setComponentState(
5758                             info.component, UserHandle.getUserId(uid), false);
5759                 }
5760             } finally {
5761                 Binder.restoreCallingIdentity(identity);
5762             }
5763         }
5764 
5765         @Override
5766         public void requestUnbindListenerComponent(ComponentName component) {
5767             checkCallerIsSameApp(component.getPackageName());
5768             int uid = Binder.getCallingUid();
5769             int userId = UserHandle.getUserId(uid);
5770             final long identity = Binder.clearCallingIdentity();
5771             try {
5772                 synchronized (mNotificationLock) {
5773                     boolean isAssistantEnabled = managedServicesConcurrentMultiuser()
5774                             ? mAssistants.isComponentEnabledForUser(component, userId)
5775                             : mAssistants.isComponentEnabledForCurrentProfiles(component);
5776                     ManagedServices manager = isAssistantEnabled ? mAssistants : mListeners;
5777                     if (manager.isPackageOrComponentAllowed(component.flattenToString(), userId)) {
5778                         manager.setComponentState(component, userId, false);
5779                     }
5780                 }
5781             } finally {
5782                 Binder.restoreCallingIdentity(identity);
5783             }
5784         }
5785 
5786         @Override
5787         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
5788             final long identity = Binder.clearCallingIdentity();
5789             try {
5790                 synchronized (mNotificationLock) {
5791                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5792                     if (keys == null) {
5793                         return;
5794                     }
5795                     ArrayList<NotificationRecord> seen = new ArrayList<>();
5796                     final int n = keys.length;
5797                     for (int i = 0; i < n; i++) {
5798                         NotificationRecord r = mNotificationsByKey.get(keys[i]);
5799                         if (r == null) continue;
5800                         final int userId = r.getSbn().getUserId();
5801                         if (userId != info.userid && userId != USER_ALL
5802                                 && !mUserProfiles.isCurrentProfile(userId)) {
5803                             continue;
5804                         }
5805                         seen.add(r);
5806                         if (!r.isSeen()) {
5807                             if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
5808                             reportSeen(r);
5809                             r.setSeen();
5810                             maybeRecordInterruptionLocked(r);
5811                         }
5812                     }
5813                     if (!seen.isEmpty()) {
5814                         mAssistants.onNotificationsSeenLocked(seen);
5815                     }
5816                 }
5817             } finally {
5818                 Binder.restoreCallingIdentity(identity);
5819             }
5820         }
5821 
5822         /**
5823          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
5824          *
5825          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
5826          *
5827          * @param info The binder for the listener, to check that the caller is allowed
5828          */
5829         @GuardedBy("mNotificationLock")
5830         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
5831                 int callingUid, int callingPid, String pkg, String tag, int id, int userId,
5832                 int reason) {
5833             int mustNotHaveFlags = FLAG_ONGOING_EVENT;
5834             if (lifetimeExtensionRefactor()) {
5835                 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
5836             }
5837             cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */,
5838                     mustNotHaveFlags,
5839                     true,
5840                     userId, reason, info);
5841         }
5842 
5843         /**
5844          * Allow an INotificationListener to snooze a single notification until a context.
5845          *
5846          * @param token The binder for the listener, to check that the caller is allowed
5847          */
5848         @Override
5849         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
5850                 String key, String snoozeCriterionId) {
5851             final int callingUid = Binder.getCallingUid();
5852             final long identity = Binder.clearCallingIdentity();
5853             try {
5854                 snoozeNotificationInt(callingUid, token, key, SNOOZE_UNTIL_UNSPECIFIED,
5855                         snoozeCriterionId);
5856             } finally {
5857                 Binder.restoreCallingIdentity(identity);
5858             }
5859         }
5860 
5861         /**
5862          * Allow an INotificationListener to snooze a single notification until a time.
5863          *
5864          * @param token The binder for the listener, to check that the caller is allowed
5865          */
5866         @Override
5867         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
5868                 long duration) {
5869             final int callingUid = Binder.getCallingUid();
5870             final long identity = Binder.clearCallingIdentity();
5871             try {
5872                 snoozeNotificationInt(callingUid, token, key, duration, null);
5873             } finally {
5874                 Binder.restoreCallingIdentity(identity);
5875             }
5876         }
5877 
5878         /**
5879          * Allows the notification assistant to un-snooze a single notification.
5880          *
5881          * @param token The binder for the assistant, to check that the caller is allowed
5882          */
5883         @Override
5884         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
5885             final long identity = Binder.clearCallingIdentity();
5886             try {
5887                 synchronized (mNotificationLock) {
5888                     final ManagedServiceInfo info =
5889                             mAssistants.checkServiceTokenLocked(token);
5890                     unsnoozeNotificationInt(key, info, false);
5891                 }
5892             } finally {
5893                 Binder.restoreCallingIdentity(identity);
5894             }
5895         }
5896 
5897         /**
5898          * Allows the notification assistant to un-snooze a single notification.
5899          *
5900          * @param token The binder for the listener, to check that the caller is allowed
5901          */
5902         @Override
5903         public void unsnoozeNotificationFromSystemListener(INotificationListener token,
5904                 String key) {
5905             final long identity = Binder.clearCallingIdentity();
5906             try {
5907                 synchronized (mNotificationLock) {
5908                     final ManagedServiceInfo info =
5909                             mListeners.checkServiceTokenLocked(token);
5910                     if (!info.isSystem) {
5911                         throw new SecurityException("Not allowed to unsnooze before deadline");
5912                     }
5913                     unsnoozeNotificationInt(key, info, true);
5914                 }
5915             } finally {
5916                 Binder.restoreCallingIdentity(identity);
5917             }
5918         }
5919 
5920         /**
5921          * Allows an app to set an initial notification listener filter
5922          *
5923          * @param token The binder for the listener, to check that the caller is allowed
5924          */
5925         @Override
5926         public void migrateNotificationFilter(INotificationListener token, int defaultTypes,
5927                 List<String> disallowedApps) {
5928             final long identity = Binder.clearCallingIdentity();
5929             try {
5930                 synchronized (mNotificationLock) {
5931                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5932 
5933                     Pair key = Pair.create(info.component, info.userid);
5934 
5935                     NotificationListenerFilter nlf = mListeners.getNotificationListenerFilter(key);
5936                     if (nlf == null) {
5937                         nlf = new NotificationListenerFilter();
5938                     }
5939                     if (nlf.getDisallowedPackages().isEmpty() && disallowedApps != null) {
5940                         for (String pkg : disallowedApps) {
5941                             // block the current user's version and any work profile versions
5942                             for (int userId : mUm.getProfileIds(info.userid, false)) {
5943                                 try {
5944                                     int uid = getUidForPackageAndUser(pkg, UserHandle.of(userId));
5945                                     if (uid != INVALID_UID) {
5946                                         VersionedPackage vp = new VersionedPackage(pkg, uid);
5947                                         nlf.addPackage(vp);
5948                                     }
5949                                 } catch (Exception e) {
5950                                     // pkg doesn't exist on that user; skip
5951                                 }
5952                             }
5953                         }
5954                     }
5955                     if (nlf.areAllTypesAllowed()) {
5956                         nlf.setTypes(defaultTypes);
5957                     }
5958                     mListeners.setNotificationListenerFilter(key, nlf);
5959                 }
5960             } finally {
5961                 Binder.restoreCallingIdentity(identity);
5962             }
5963         }
5964 
5965         /**
5966          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
5967          *
5968          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
5969          *
5970          * @param token The binder for the listener, to check that the caller is allowed
5971          */
5972         @Override
5973         public void cancelNotificationFromListener(INotificationListener token, String pkg,
5974                 String tag, int id) {
5975             Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) use " +
5976                     "cancelNotification(key) instead.");
5977         }
5978 
5979         /**
5980          * Allow an INotificationListener to request the list of outstanding notifications seen by
5981          * the current user. Useful when starting up, after which point the listener callbacks
5982          * should be used.
5983          *
5984          * @param token The binder for the listener, to check that the caller is allowed
5985          * @param keys An array of notification keys to fetch, or null to fetch everything
5986          * @returns The return value will contain the notifications specified in keys, in that
5987          *      order, or if keys is null, all the notifications, in natural order.
5988          */
5989         @Override
5990         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
5991                 INotificationListener token, String[] keys, int trim) {
5992             synchronized (mNotificationLock) {
5993                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
5994                 final boolean getKeys = keys != null;
5995                 final int N = getKeys ? keys.length : mNotificationList.size();
5996                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
5997                 for (int i=0; i<N; i++) {
5998                     final NotificationRecord r = getKeys
5999                             ? mNotificationsByKey.get(keys[i])
6000                             : mNotificationList.get(i);
6001                     addToListIfNeeded(r, info, list, trim);
6002                 }
6003                 return new ParceledListSlice<>(list);
6004             }
6005         }
6006 
6007         /**
6008          * Allow an INotificationListener to request the list of outstanding snoozed notifications
6009          * seen by the current user. Useful when starting up, after which point the listener
6010          * callbacks should be used.
6011          *
6012          * @param token The binder for the listener, to check that the caller is allowed
6013          * @returns The return value will contain the notifications specified in keys, in that
6014          *      order, or if keys is null, all the notifications, in natural order.
6015          */
6016         @Override
6017         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
6018                 INotificationListener token, int trim) {
6019             synchronized (mNotificationLock) {
6020                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
6021                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
6022                 final int N = snoozedRecords.size();
6023                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
6024                 for (int i=0; i < N; i++) {
6025                     addToListIfNeeded(snoozedRecords.get(i), info, list, trim);
6026                 }
6027                 return new ParceledListSlice<>(list);
6028             }
6029         }
6030 
6031         private void addToListIfNeeded(NotificationRecord r, ManagedServiceInfo info,
6032                 ArrayList<StatusBarNotification> notifications, int trim) {
6033             if (r == null) return;
6034             StatusBarNotification sbn = r.getSbn();
6035             if (!isVisibleToListener(sbn, r.getNotificationType(), info)) return;
6036             if (mListeners.hasSensitiveContent(r) && !mListeners.isUidTrusted(info.uid)) {
6037                 notifications.add(mListeners.redactStatusBarNotification(sbn));
6038             } else {
6039                 notifications.add((trim == TRIM_FULL) ? sbn : sbn.cloneLight());
6040             }
6041 
6042         }
6043 
6044         @Override
6045         public void clearRequestedListenerHints(INotificationListener token) {
6046             final long identity = Binder.clearCallingIdentity();
6047             try {
6048                 synchronized (mNotificationLock) {
6049                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
6050                     removeDisabledHints(info);
6051                     updateListenerHintsLocked();
6052                     updateEffectsSuppressorLocked();
6053                 }
6054             } finally {
6055                 Binder.restoreCallingIdentity(identity);
6056             }
6057         }
6058 
6059         @Override
6060         public void requestHintsFromListener(INotificationListener token, int hints) {
6061             final long identity = Binder.clearCallingIdentity();
6062             try {
6063                 synchronized (mNotificationLock) {
6064                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
6065                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
6066                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
6067                             | HINT_HOST_DISABLE_CALL_EFFECTS;
6068                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
6069                     if (disableEffects) {
6070                         addDisabledHints(info, hints);
6071                     } else {
6072                         removeDisabledHints(info, hints);
6073                     }
6074                     updateListenerHintsLocked();
6075                     updateEffectsSuppressorLocked();
6076                 }
6077             } finally {
6078                 Binder.restoreCallingIdentity(identity);
6079             }
6080         }
6081 
6082         @Override
6083         public int getHintsFromListener(INotificationListener token) {
6084             synchronized (mNotificationLock) {
6085                 return mListenerHints;
6086             }
6087         }
6088 
6089         @Override
6090         public int getHintsFromListenerNoToken() {
6091             synchronized (mNotificationLock) {
6092                 return mListenerHints;
6093             }
6094         }
6095 
6096         @Override
6097         public void requestInterruptionFilterFromListener(INotificationListener token,
6098                 int interruptionFilter) throws RemoteException {
6099             final int callingUid = Binder.getCallingUid();
6100             ManagedServiceInfo info;
6101             synchronized (mNotificationLock) {
6102                 info = mListeners.checkServiceTokenLocked(token);
6103             }
6104 
6105             final int zenMode = zenModeFromInterruptionFilter(interruptionFilter, -1);
6106             if (zenMode == -1) return;
6107 
6108             UserHandle zenUser = getCallingZenUser();
6109             if (!canManageGlobalZenPolicy(info.component.getPackageName(), callingUid)) {
6110                 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(
6111                         zenUser, info.component.getPackageName(), callingUid, zenMode);
6112             } else {
6113                 int origin = computeZenOrigin(/* fromUser= */ false);
6114                 Binder.withCleanCallingIdentity(() -> {
6115                     mZenModeHelper.setManualZenMode(zenUser, zenMode, /* conditionId= */ null,
6116                             origin, "listener:" + info.component.flattenToShortString(),
6117                             /* caller= */ info.component.getPackageName(),
6118                             callingUid);
6119                 });
6120             }
6121         }
6122 
6123         @Override
6124         public int getInterruptionFilterFromListener(INotificationListener token)
6125                 throws RemoteException {
6126             synchronized (mNotificationLock) {
6127                 return mInterruptionFilter;
6128             }
6129         }
6130 
6131         @Override
6132         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
6133                 throws RemoteException {
6134             synchronized (mNotificationLock) {
6135                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
6136                 if (info == null) return;
6137                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
6138             }
6139         }
6140 
6141         @Override
6142         public int getZenMode() {
6143             return mZenModeHelper.getZenMode();
6144         }
6145 
6146         @Override
6147         public ZenModeConfig getZenModeConfig() {
6148             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
6149             return mZenModeHelper.getConfig();
6150         }
6151 
6152         @Override
6153         public void setZenMode(int mode, Uri conditionId, String reason, boolean fromUser) {
6154             enforceSystemOrSystemUI("INotificationManager.setZenMode");
6155             enforceUserOriginOnlyFromSystem(fromUser, "setZenMode");
6156             UserHandle zenUser = getCallingZenUser();
6157 
6158             final int callingUid = Binder.getCallingUid();
6159             final long identity = Binder.clearCallingIdentity();
6160             try {
6161                 mZenModeHelper.setManualZenMode(zenUser, mode, conditionId,
6162                         computeZenOrigin(fromUser), reason, /* caller= */ null, callingUid);
6163             } finally {
6164                 Binder.restoreCallingIdentity(identity);
6165             }
6166         }
6167 
6168         @Override
6169         public ParceledListSlice getAutomaticZenRules() {
6170             int callingUid = Binder.getCallingUid();
6171             enforcePolicyAccess(callingUid, "getAutomaticZenRules");
6172             List<AutomaticZenRule.AzrWithId> ruleList = new ArrayList<>();
6173             for (Map.Entry<String, AutomaticZenRule> rule : mZenModeHelper.getAutomaticZenRules(
6174                     getCallingZenUser(), callingUid).entrySet()) {
6175                 ruleList.add(new AutomaticZenRule.AzrWithId(rule.getKey(), rule.getValue()));
6176             }
6177             return new ParceledListSlice<>(ruleList);
6178         }
6179 
6180         @Override
6181         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
6182             Objects.requireNonNull(id, "Id is null");
6183             int callingUid = Binder.getCallingUid();
6184             enforcePolicyAccess(callingUid, "getAutomaticZenRule");
6185             return mZenModeHelper.getAutomaticZenRule(getCallingZenUser(), id, callingUid);
6186         }
6187 
6188         @Override
6189         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg,
6190                 boolean fromUser) {
6191             validateAutomaticZenRule(/* updateId= */ null, automaticZenRule);
6192             checkCallerIsSameApp(pkg);
6193             if (automaticZenRule.getZenPolicy() != null
6194                     && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
6195                 throw new IllegalArgumentException("ZenPolicy is only applicable to "
6196                         + "INTERRUPTION_FILTER_PRIORITY filters");
6197             }
6198             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
6199             enforceUserOriginOnlyFromSystem(fromUser, "addAutomaticZenRule");
6200             UserHandle zenUser = getCallingZenUser();
6201 
6202             // If the calling app is the system (from any user), take the package name from the
6203             // rule's owner rather than from the caller's package.
6204             String rulePkg = pkg;
6205             if (isCallingAppIdSystem()) {
6206                 if (automaticZenRule.getOwner() != null) {
6207                     rulePkg = automaticZenRule.getOwner().getPackageName();
6208                 }
6209             }
6210 
6211             return mZenModeHelper.addAutomaticZenRule(zenUser, rulePkg, automaticZenRule,
6212                     computeZenOrigin(fromUser), "addAutomaticZenRule", Binder.getCallingUid());
6213         }
6214 
6215         @Override
6216         public void setManualZenRuleDeviceEffects(ZenDeviceEffects effects) throws RemoteException {
6217             checkCallerIsSystem();
6218             UserHandle zenUser = getCallingZenUser();
6219 
6220             mZenModeHelper.setManualZenRuleDeviceEffects(zenUser, effects,
6221                     computeZenOrigin(true), "Update manual mode non-policy settings",
6222                     Binder.getCallingUid());
6223         }
6224 
6225         @Override
6226         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule,
6227                 boolean fromUser) throws RemoteException {
6228             validateAutomaticZenRule(id, automaticZenRule);
6229             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
6230             enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule");
6231             UserHandle zenUser = getCallingZenUser();
6232 
6233             return mZenModeHelper.updateAutomaticZenRule(zenUser, id, automaticZenRule,
6234                     computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid());
6235         }
6236 
6237         private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) {
6238             Objects.requireNonNull(rule, "automaticZenRule is null");
6239             Objects.requireNonNull(rule.getName(), "Name is null");
6240             rule.validate();
6241 
6242             // Implicit rules have no ConditionProvider or Activity. We allow the user to customize
6243             // them (via Settings), but not the owner app. Should the app want to start using it as
6244             // a "normal" rule, it must provide a CP/ConfigActivity too.
6245             boolean isImplicitRuleUpdateFromSystem = updateId != null
6246                     && ZenModeConfig.isImplicitRuleId(updateId)
6247                     && isCallerSystemOrSystemUi();
6248             if (!isImplicitRuleUpdateFromSystem
6249                     && rule.getOwner() == null
6250                     && rule.getConfigurationActivity() == null) {
6251                 throw new NullPointerException(
6252                         "Rule must have a ConditionProviderService and/or configuration "
6253                                 + "activity");
6254             }
6255             Objects.requireNonNull(rule.getConditionId(), "ConditionId is null");
6256 
6257             if (isCallerSystemOrSystemUi()) {
6258                 return; // System callers can use any type.
6259             }
6260             int uid = Binder.getCallingUid();
6261             int userId = UserHandle.getUserId(uid);
6262 
6263             if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) {
6264                 boolean isDeviceOwner = Binder.withCleanCallingIdentity(
6265                         () -> mDpm.isActiveDeviceOwner(uid));
6266                 if (!isDeviceOwner) {
6267                     throw new IllegalArgumentException(
6268                             "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED");
6269                 }
6270             } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) {
6271                 String wellbeingPackage = getContext().getResources().getString(
6272                         com.android.internal.R.string.config_systemWellbeing);
6273                 boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage)
6274                         && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId);
6275                 if (!isCallerWellbeing) {
6276                     throw new IllegalArgumentException(
6277                             "Only the 'Wellbeing' package can use AutomaticZenRules with "
6278                                     + "TYPE_BEDTIME");
6279                 }
6280             }
6281         }
6282 
6283         @Override
6284         public boolean removeAutomaticZenRule(String id, boolean fromUser) throws RemoteException {
6285             Objects.requireNonNull(id, "Id is null");
6286             // Verify that they can modify zen rules.
6287             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
6288             enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRule");
6289             UserHandle zenUser = getCallingZenUser();
6290 
6291             return mZenModeHelper.removeAutomaticZenRule(zenUser, id, computeZenOrigin(fromUser),
6292                     "removeAutomaticZenRule", Binder.getCallingUid());
6293         }
6294 
6295         @Override
6296         public boolean removeAutomaticZenRules(String packageName, boolean fromUser)
6297                 throws RemoteException {
6298             Objects.requireNonNull(packageName, "Package name is null");
6299             enforceSystemOrSystemUI("removeAutomaticZenRules");
6300             enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRules");
6301             UserHandle zenUser = getCallingZenUser();
6302 
6303             return mZenModeHelper.removeAutomaticZenRules(zenUser, packageName,
6304                     computeZenOrigin(fromUser), packageName + "|removeAutomaticZenRules",
6305                     Binder.getCallingUid());
6306         }
6307 
6308         @Override
6309         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
6310             Objects.requireNonNull(owner, "Owner is null");
6311             enforceSystemOrSystemUI("getRuleInstanceCount");
6312 
6313             return mZenModeHelper.getCurrentInstanceCount(getCallingZenUser(), owner);
6314         }
6315 
6316         @Override
6317         @Condition.State
6318         public int getAutomaticZenRuleState(@NonNull String id) {
6319             Objects.requireNonNull(id, "id is null");
6320             int callingUid = Binder.getCallingUid();
6321             enforcePolicyAccess(callingUid, "getAutomaticZenRuleState");
6322             return mZenModeHelper.getAutomaticZenRuleState(getCallingZenUser(), id, callingUid);
6323         }
6324 
6325         @Override
6326         public void setAutomaticZenRuleState(String id, Condition condition) {
6327             Objects.requireNonNull(id, "id is null");
6328             Objects.requireNonNull(condition, "Condition is null");
6329             condition.validate();
6330 
6331             enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
6332             boolean fromUser = (condition.source == Condition.SOURCE_USER_ACTION);
6333             UserHandle zenUser = getCallingZenUser();
6334 
6335             mZenModeHelper.setAutomaticZenRuleState(zenUser, id, condition,
6336                     computeZenOrigin(fromUser), Binder.getCallingUid());
6337         }
6338 
6339         /**
6340          * Returns the {@link UserHandle} corresponding to the caller that is performing a
6341          * zen-related operation (such as {@link #setInterruptionFilter},
6342          * {@link #addAutomaticZenRule}, {@link #setAutomaticZenRuleState}, etc). The user is
6343          * {@link UserHandle#USER_CURRENT} if the caller is the system or SystemUI (assuming
6344          * that all interactions in SystemUI are for the "current" user); otherwise it's the user
6345          * associated to the binder call.
6346          */
6347         private UserHandle getCallingZenUser() {
6348             if (android.app.Flags.modesMultiuser()) {
6349                 if (isCallerSystemOrSystemUiOrShell()) {
6350                     return UserHandle.CURRENT;
6351                 } else {
6352                     return Binder.getCallingUserHandle();
6353                 }
6354             } else {
6355                 return UserHandle.CURRENT;
6356             }
6357         }
6358 
6359         @ZenModeConfig.ConfigOrigin
6360         private int computeZenOrigin(boolean fromUser) {
6361             if (fromUser) {
6362                 if (isCallerSystemOrSystemUi()) {
6363                     return ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI;
6364                 } else {
6365                     return ZenModeConfig.ORIGIN_USER_IN_APP;
6366                 }
6367             } else if (isCallerSystemOrSystemUi()) {
6368                 return ZenModeConfig.ORIGIN_SYSTEM;
6369             } else {
6370                 return ZenModeConfig.ORIGIN_APP;
6371             }
6372         }
6373 
6374         private void enforceUserOriginOnlyFromSystem(boolean fromUser, String method) {
6375             if (fromUser && !isCallerSystemOrSystemUiOrShell()) {
6376                 throw new SecurityException(TextUtils.formatSimple(
6377                         "Calling %s with fromUser == true is only allowed for system", method));
6378             }
6379         }
6380 
6381         @Override
6382         public void setInterruptionFilter(String pkg, int filter, boolean fromUser) {
6383             enforcePolicyAccess(pkg, "setInterruptionFilter");
6384             final int zen = zenModeFromInterruptionFilter(filter, -1);
6385             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
6386             final int callingUid = Binder.getCallingUid();
6387             enforceUserOriginOnlyFromSystem(fromUser, "setInterruptionFilter");
6388             UserHandle zenUser = getCallingZenUser();
6389 
6390             if (!canManageGlobalZenPolicy(pkg, callingUid)) {
6391                 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(zenUser, pkg, callingUid, zen);
6392                 return;
6393             }
6394 
6395             final long identity = Binder.clearCallingIdentity();
6396             try {
6397                 mZenModeHelper.setManualZenMode(zenUser, zen, null, computeZenOrigin(fromUser),
6398                         /* reason= */ "setInterruptionFilter", /* caller= */ pkg,
6399                         callingUid);
6400             } finally {
6401                 Binder.restoreCallingIdentity(identity);
6402             }
6403         }
6404 
6405         @Override
6406         public void notifyConditions(final String pkg, IConditionProvider provider,
6407                 final Condition[] conditions) {
6408             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
6409             checkCallerIsSystemOrSameApp(pkg);
6410             mHandler.post(new Runnable() {
6411                 @Override
6412                 public void run() {
6413                     mConditionProviders.notifyConditions(pkg, info, conditions);
6414                 }
6415             });
6416         }
6417 
6418         @Override
6419         public void requestUnbindProvider(IConditionProvider provider) {
6420             int uid = Binder.getCallingUid();
6421             final long identity = Binder.clearCallingIdentity();
6422             try {
6423                 // allow bound services to disable themselves
6424                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
6425                 info.getOwner().setComponentState(info.component, UserHandle.getUserId(uid), false);
6426             } finally {
6427                 Binder.restoreCallingIdentity(identity);
6428             }
6429         }
6430 
6431         @Override
6432         public void requestBindProvider(ComponentName component) {
6433             checkCallerIsSystemOrSameApp(component.getPackageName());
6434             int uid = Binder.getCallingUid();
6435             final long identity = Binder.clearCallingIdentity();
6436             try {
6437                 mConditionProviders.setComponentState(component, UserHandle.getUserId(uid), true);
6438             } finally {
6439                 Binder.restoreCallingIdentity(identity);
6440             }
6441         }
6442 
6443         private void enforceSystemOrSystemUI(String message) {
6444             if (isCallerSystemOrPhone()) return;
6445             getContext().enforceCallingPermission(STATUS_BAR_SERVICE,
6446                     message);
6447         }
6448 
6449         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
6450             try {
6451                 checkCallerIsSystemOrSameApp(pkg);
6452             } catch (SecurityException e) {
6453                 getContext().enforceCallingPermission(
6454                         STATUS_BAR_SERVICE,
6455                         message);
6456             }
6457         }
6458 
6459         private void enforcePolicyAccess(int uid, String method) {
6460             if (PERMISSION_GRANTED == getContext().checkCallingOrSelfPermission(
6461                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
6462                 return;
6463             }
6464             boolean accessAllowed = false;
6465             String[] packages = mPackageManagerClient.getPackagesForUid(uid);
6466             final int packageCount = packages.length;
6467             for (int i = 0; i < packageCount; i++) {
6468                 if (mConditionProviders.isPackageOrComponentAllowed(
6469                         packages[i], UserHandle.getUserId(uid))) {
6470                     accessAllowed = true;
6471                 }
6472             }
6473             if (!accessAllowed) {
6474                 Slog.w(TAG, "Notification policy access denied calling " + method);
6475                 throw new SecurityException("Notification policy access denied");
6476             }
6477         }
6478 
6479         private boolean canManageGlobalZenPolicy(String callingPkg, int callingUid) {
6480             boolean isCompatChangeEnabled = Binder.withCleanCallingIdentity(
6481                     () -> CompatChanges.isChangeEnabled(MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES,
6482                             callingUid));
6483             return !isCompatChangeEnabled
6484                     || isCallerSystemOrSystemUi()
6485                     || hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid),
6486                             Set.of(AssociationRequest.DEVICE_PROFILE_WATCH,
6487                                     AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION));
6488         }
6489 
6490         private void enforcePolicyAccess(String pkg, String method) {
6491             if (PERMISSION_GRANTED == getContext().checkCallingOrSelfPermission(
6492                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
6493                 return;
6494             }
6495             checkCallerIsSameApp(pkg);
6496             if (!checkPolicyAccess(pkg)) {
6497                 Slog.w(TAG, "Notification policy access denied calling " + method);
6498                 throw new SecurityException("Notification policy access denied");
6499             }
6500         }
6501 
6502         private boolean checkPackagePolicyAccess(String pkg) {
6503             return mConditionProviders.isPackageOrComponentAllowed(
6504                     pkg, getCallingUserHandle().getIdentifier());
6505         }
6506 
6507         private boolean checkPolicyAccess(String pkg) {
6508             final int uid;
6509             try {
6510                 uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
6511                         UserHandle.getCallingUserId());
6512                 if (PERMISSION_GRANTED == checkComponentPermission(
6513                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
6514                         -1, true)) {
6515                     return true;
6516                 }
6517             } catch (NameNotFoundException e) {
6518                 return false;
6519             }
6520             if (managedServicesConcurrentMultiuser()) {
6521                 return checkPackagePolicyAccess(pkg)
6522                         || mListeners.isComponentEnabledForPackage(pkg,
6523                             UserHandle.getCallingUserId())
6524                         || (mDpm != null
6525                             && (mDpm.isActiveProfileOwner(uid) || mDpm.isActiveDeviceOwner(uid)));
6526             }
6527             //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
6528             return checkPackagePolicyAccess(pkg)
6529                     || mListeners.isComponentEnabledForPackage(pkg)
6530                     || (mDpm != null && (mDpm.isActiveProfileOwner(uid)
6531                                 || mDpm.isActiveDeviceOwner(uid)));
6532         }
6533 
6534         @Override
6535         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
6536             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
6537             final DumpFilter filter = DumpFilter.parseFromArguments(args);
6538             final long token = Binder.clearCallingIdentity();
6539             try {
6540                 final ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions =
6541                         getAllUsersNotificationPermissions();
6542                 if (filter.stats) {
6543                     dumpJson(pw, filter, pkgPermissions);
6544                 } else if (filter.rvStats) {
6545                     dumpRemoteViewStats(pw, filter);
6546                 } else if (filter.proto) {
6547                     dumpProto(fd, filter, pkgPermissions);
6548                 } else if (filter.criticalPriority) {
6549                     dumpNotificationRecords(pw, filter);
6550                 } else {
6551                     dumpImpl(pw, filter, pkgPermissions);
6552                 }
6553             } finally {
6554                 Binder.restoreCallingIdentity(token);
6555             }
6556         }
6557 
6558         @Override
6559         public ComponentName getEffectsSuppressor() {
6560             ComponentName suppressor = !mEffectsSuppressors.isEmpty()
6561                     ? mEffectsSuppressors.get(0)
6562                     : null;
6563             if (isCallerSystemOrSystemUiOrShell() || suppressor == null
6564                     || mPackageManagerInternal.isSameApp(suppressor.getPackageName(),
6565                     Binder.getCallingUid(), UserHandle.getUserId(Binder.getCallingUid()))) {
6566                 return suppressor;
6567             }
6568 
6569             return null;
6570         }
6571 
6572         @Override
6573         public boolean matchesCallFilter(Bundle extras) {
6574             // Because matchesCallFilter may use contact data to filter calls, the callers of this
6575             // method need to either have notification listener access or permission to read
6576             // contacts.
6577             boolean systemAccess = false;
6578             try {
6579                 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
6580                 systemAccess = true;
6581             } catch (SecurityException e) {
6582             }
6583 
6584             boolean listenerAccess = false;
6585             try {
6586                 String[] pkgNames = mPackageManager.getPackagesForUid(Binder.getCallingUid());
6587                 for (int i = 0; i < pkgNames.length; i++) {
6588                     // in most cases there should only be one package here
6589                     listenerAccess |= mListeners.hasAllowedListener(pkgNames[i],
6590                             Binder.getCallingUserHandle().getIdentifier());
6591                 }
6592             } catch (RemoteException e) {
6593             } finally {
6594                 if (!systemAccess && !listenerAccess) {
6595                     getContext().enforceCallingPermission(Manifest.permission.READ_CONTACTS,
6596                             "matchesCallFilter requires listener permission, contacts read access,"
6597                             + " or system level access");
6598                 }
6599             }
6600 
6601             return mZenModeHelper.matchesCallFilter(
6602                     Binder.getCallingUserHandle(),
6603                     extras,
6604                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
6605                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
6606                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY,
6607                     Binder.getCallingUid());
6608         }
6609 
6610         @Override
6611         public void cleanUpCallersAfter(long timeThreshold) {
6612             enforceSystemOrSystemUI("INotificationManager.cleanUpCallersAfter");
6613             mZenModeHelper.cleanUpCallersAfter(timeThreshold);
6614         }
6615 
6616         @Override
6617         public boolean isSystemConditionProviderEnabled(String path) {
6618             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
6619             return mConditionProviders.isSystemProviderEnabled(path);
6620         }
6621 
6622         // Backup/restore interface
6623         @Override
6624         public byte[] getBackupPayload(int user) {
6625             checkCallerIsSystem();
6626             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
6627             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
6628             try {
6629                 writePolicyXml(baos, true /*forBackup*/, user, null);
6630                 return baos.toByteArray();
6631             } catch (IOException e) {
6632                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
6633             }
6634             return null;
6635         }
6636 
6637         @Override
6638         public void applyRestore(byte[] payload, int user) {
6639             checkCallerIsSystem();
6640             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
6641                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
6642             if (payload == null) {
6643                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
6644                 return;
6645             }
6646             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
6647             try {
6648                 readPolicyXml(bais, true /*forRestore*/, user, null);
6649                 handleSavePolicyFile();
6650             } catch (NumberFormatException | XmlPullParserException | IOException e) {
6651                 Slog.w(TAG, "applyRestore: error reading payload", e);
6652             }
6653         }
6654 
6655         @Override
6656         public boolean isNotificationPolicyAccessGranted(String pkg) {
6657             return checkPolicyAccess(pkg);
6658         }
6659 
6660         @Override
6661         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
6662             enforceSystemOrSystemUIOrSamePackage(pkg,
6663                     "request policy access status for another package");
6664             return checkPolicyAccess(pkg);
6665         }
6666 
6667         @Override
6668         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
6669                 throws RemoteException {
6670             setNotificationPolicyAccessGrantedForUser(
6671                     pkg, getCallingUserHandle().getIdentifier(), granted);
6672         }
6673 
6674         @Override
6675         public void setNotificationPolicyAccessGrantedForUser(
6676                 String pkg, int userId, boolean granted) {
6677             checkCallerIsSystemOrShell();
6678             final long identity = Binder.clearCallingIdentity();
6679             try {
6680                 if (mAllowedManagedServicePackages.test(
6681                         pkg, userId, mConditionProviders.getRequiredPermission())) {
6682                     mConditionProviders.setPackageOrComponentEnabled(
6683                             pkg, userId, true, granted);
6684 
6685                     getContext().sendBroadcastAsUser(new Intent(
6686                             ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
6687                                     .setPackage(pkg)
6688                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
6689                             UserHandle.of(userId), null);
6690                     handleSavePolicyFile();
6691                 }
6692             } finally {
6693                 Binder.restoreCallingIdentity(identity);
6694             }
6695         }
6696 
6697         @Override
6698         public Policy getNotificationPolicy(String pkg) {
6699             final int callingUid = Binder.getCallingUid();
6700             UserHandle zenUser = getCallingZenUser();
6701             if (!canManageGlobalZenPolicy(pkg, callingUid)) {
6702                 return mZenModeHelper.getNotificationPolicyFromImplicitZenRule(zenUser, pkg);
6703             }
6704             final long identity = Binder.clearCallingIdentity();
6705             try {
6706                 return mZenModeHelper.getNotificationPolicy(zenUser);
6707             } finally {
6708                 Binder.restoreCallingIdentity(identity);
6709             }
6710         }
6711 
6712         @Override
6713         public Policy getConsolidatedNotificationPolicy() {
6714             final long identity = Binder.clearCallingIdentity();
6715             try {
6716                 return mZenModeHelper.getConsolidatedNotificationPolicy();
6717             } finally {
6718                 Binder.restoreCallingIdentity(identity);
6719             }
6720         }
6721 
6722         /**
6723          * Sets the notification policy.  Apps that target API levels below
6724          * {@link Build.VERSION_CODES#P} cannot change user-designated values to
6725          * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
6726          * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
6727          * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
6728          */
6729         @Override
6730         public void setNotificationPolicy(String pkg, Policy policy, boolean fromUser) {
6731             enforcePolicyAccess(pkg, "setNotificationPolicy");
6732             enforceUserOriginOnlyFromSystem(fromUser, "setNotificationPolicy");
6733             int callingUid = Binder.getCallingUid();
6734             @ZenModeConfig.ConfigOrigin int origin = computeZenOrigin(fromUser);
6735             UserHandle zenUser = getCallingZenUser();
6736 
6737             boolean isSystemCaller = isCallerSystemOrSystemUiOrShell();
6738             boolean shouldApplyAsImplicitRule = !canManageGlobalZenPolicy(pkg, callingUid);
6739 
6740             final long identity = Binder.clearCallingIdentity();
6741             try {
6742                 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
6743                         0, UserHandle.getUserId(callingUid));
6744                 Policy currPolicy = mZenModeHelper.getNotificationPolicy(zenUser);
6745 
6746                 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
6747                     int priorityCategories = policy.priorityCategories;
6748                     // ignore alarm and media values from new policy
6749                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
6750                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
6751                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
6752                     // use user-designated values
6753                     priorityCategories |= currPolicy.priorityCategories
6754                             & Policy.PRIORITY_CATEGORY_ALARMS;
6755                     priorityCategories |= currPolicy.priorityCategories
6756                             & Policy.PRIORITY_CATEGORY_MEDIA;
6757                     priorityCategories |= currPolicy.priorityCategories
6758                             & Policy.PRIORITY_CATEGORY_SYSTEM;
6759 
6760                     policy = new Policy(priorityCategories,
6761                             policy.priorityCallSenders, policy.priorityMessageSenders,
6762                             policy.suppressedVisualEffects);
6763                 }
6764                 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
6765                     int priorityCategories = correctCategory(policy.priorityCategories,
6766                             Policy.PRIORITY_CATEGORY_CONVERSATIONS,
6767                             currPolicy.priorityCategories);
6768 
6769                     policy = new Policy(priorityCategories,
6770                             policy.priorityCallSenders, policy.priorityMessageSenders,
6771                             policy.suppressedVisualEffects, currPolicy.priorityConversationSenders);
6772                 }
6773 
6774                 int newVisualEffects = calculateSuppressedVisualEffects(
6775                             policy, currPolicy, applicationInfo.targetSdkVersion);
6776 
6777                 if (android.app.Flags.modesUi()) {
6778                     // 1. Callers should not modify STATE_CHANNELS_BYPASSING_DND, which is
6779                     // internally calculated and only indicates whether channels that want to bypass
6780                     // DND _exist_.
6781                     // 2. Only system callers should modify STATE_PRIORITY_CHANNELS_BLOCKED because
6782                     // it is @hide.
6783                     // 3. If the policy has been modified by the targetSdkVersion checks above then
6784                     // it has lost its state flags and that's fine (STATE_PRIORITY_CHANNELS_BLOCKED
6785                     // didn't exist until V).
6786                     int newState = Policy.STATE_UNSET;
6787                     if (isSystemCaller && policy.state != Policy.STATE_UNSET) {
6788                         newState = Policy.policyState(
6789                                 currPolicy.hasPriorityChannels(),
6790                                 policy.allowPriorityChannels());
6791                     }
6792                     policy = new Policy(policy.priorityCategories,
6793                             policy.priorityCallSenders, policy.priorityMessageSenders,
6794                             newVisualEffects, newState, policy.priorityConversationSenders);
6795                 } else {
6796                     policy = new Policy(policy.priorityCategories,
6797                             policy.priorityCallSenders, policy.priorityMessageSenders,
6798                             newVisualEffects, policy.priorityConversationSenders);
6799                 }
6800 
6801                 if (shouldApplyAsImplicitRule) {
6802                     mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(zenUser, pkg, callingUid,
6803                             policy);
6804                 } else {
6805                     ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion,
6806                             policy);
6807                     mZenModeHelper.setNotificationPolicy(zenUser, policy, origin, callingUid);
6808                 }
6809             } catch (RemoteException e) {
6810                 Slog.e(TAG, "Failed to set notification policy", e);
6811             } finally {
6812                 Binder.restoreCallingIdentity(identity);
6813             }
6814         }
6815 
6816         /**
6817          * Gets the device-default zen policy as a ZenPolicy.
6818          */
6819         @Override
6820         public ZenPolicy getDefaultZenPolicy() {
6821             enforceSystemOrSystemUI("INotificationManager.getDefaultZenPolicy");
6822             final long identity = Binder.clearCallingIdentity();
6823             try {
6824                 return mZenModeHelper.getDefaultZenPolicy();
6825             } finally {
6826                 Binder.restoreCallingIdentity(identity);
6827             }
6828         }
6829 
6830         @Override
6831         public List<String> getEnabledNotificationListenerPackages() {
6832             checkCallerIsSystem();
6833             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
6834         }
6835 
6836         @Override
6837         public List<ComponentName> getEnabledNotificationListeners(int userId) {
6838             checkNotificationListenerAccess();
6839             return mListeners.getAllowedComponents(userId);
6840         }
6841 
6842         @Override
6843         public ComponentName getAllowedNotificationAssistantForUser(int userId) {
6844             checkCallerIsSystemOrSystemUiOrShell();
6845             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
6846             if (allowedComponents.size() > 1) {
6847                 throw new IllegalStateException(
6848                         "At most one NotificationAssistant: " + allowedComponents.size());
6849             }
6850             return CollectionUtils.firstOrNull(allowedComponents);
6851         }
6852 
6853         @Override
6854         public ComponentName getAllowedNotificationAssistant() {
6855             return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier());
6856         }
6857 
6858         @Override
6859         public ComponentName getDefaultNotificationAssistant() {
6860             checkCallerIsSystem();
6861             return mAssistants.getDefaultFromConfig();
6862         }
6863 
6864         @Override
6865         public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) {
6866             checkCallerIsSystem();
6867             setNASMigrationDone(userId);
6868             if (loadFromConfig) {
6869                 mAssistants.resetDefaultFromConfig();
6870             } else {
6871                 mAssistants.clearDefaults();
6872             }
6873         }
6874 
6875 
6876         @Override
6877         public boolean hasEnabledNotificationListener(String packageName, int userId) {
6878             checkCallerIsSystem();
6879             return mListeners.isPackageAllowed(packageName, userId);
6880         }
6881 
6882         @Override
6883         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
6884             Objects.requireNonNull(listener);
6885             checkCallerIsSystemOrSameApp(listener.getPackageName());
6886             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
6887                     getCallingUserHandle().getIdentifier());
6888         }
6889 
6890         @Override
6891         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
6892                 int userId) {
6893             Objects.requireNonNull(listener);
6894             checkCallerIsSystem();
6895             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
6896                     userId);
6897         }
6898 
6899         @Override
6900         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
6901             Objects.requireNonNull(assistant);
6902             checkCallerIsSystemOrSameApp(assistant.getPackageName());
6903             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
6904                     getCallingUserHandle().getIdentifier());
6905         }
6906 
6907         @Override
6908         public void setNotificationListenerAccessGranted(ComponentName listener,
6909                 boolean granted, boolean userSet) throws RemoteException {
6910             setNotificationListenerAccessGrantedForUser(
6911                     listener, getCallingUserHandle().getIdentifier(), granted, userSet);
6912         }
6913 
6914         @Override
6915         public void setNotificationAssistantAccessGranted(ComponentName assistant,
6916                 boolean granted) {
6917             setNotificationAssistantAccessGrantedForUser(
6918                     assistant, getCallingUserHandle().getIdentifier(), granted);
6919         }
6920 
6921         @Override
6922         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
6923                 boolean granted, boolean userSet) {
6924             Objects.requireNonNull(listener);
6925             if (UserHandle.getCallingUserId() != userId) {
6926                 getContext().enforceCallingOrSelfPermission(
6927                         android.Manifest.permission.INTERACT_ACROSS_USERS,
6928                         "setNotificationListenerAccessGrantedForUser for user " + userId);
6929             }
6930             if (!managedServicesConcurrentMultiuser()
6931                     && mUmInternal.isVisibleBackgroundFullUser(userId)) {
6932                 // The main use case for visible background users is the Automotive multi-display
6933                 // configuration where a passenger can use a secondary display while the driver is
6934                 // using the main display. NotificationListeners is designed only for the current
6935                 // user and work profile. We added a condition to prevent visible background users
6936                 // from updating the data managed within the NotificationListeners object.
6937                 return;
6938             }
6939             checkNotificationListenerAccess();
6940             if (granted && listener.flattenToString().length()
6941                     > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
6942                 throw new IllegalArgumentException(
6943                         "Component name too long: " + listener.flattenToString());
6944             }
6945             if (!userSet && isNotificationListenerAccessUserSet(listener, userId)) {
6946                 // Don't override user's choice
6947                 return;
6948             }
6949             final long identity = Binder.clearCallingIdentity();
6950             try {
6951                 if (mAllowedManagedServicePackages.test(
6952                         listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
6953                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
6954                             userId, false, granted, userSet);
6955                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
6956                             userId, true, granted, userSet);
6957 
6958                     getContext().sendBroadcastAsUser(new Intent(
6959                             ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
6960                                     .setPackage(listener.getPackageName())
6961                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
6962                             UserHandle.of(userId), null);
6963 
6964                     handleSavePolicyFile();
6965                 }
6966             } finally {
6967                 Binder.restoreCallingIdentity(identity);
6968             }
6969         }
6970 
6971         private boolean isNotificationListenerAccessUserSet(ComponentName listener, int userId) {
6972             return mListeners.isPackageOrComponentUserSet(listener.flattenToString(), userId);
6973         }
6974 
6975         @Override
6976         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
6977                 int userId, boolean granted) {
6978             checkCallerIsSystemOrSystemUiOrShell();
6979             for (UserInfo ui : mUm.getEnabledProfiles(userId)) {
6980                 mAssistants.setUserSet(ui.id, true);
6981             }
6982             final long identity = Binder.clearCallingIdentity();
6983             try {
6984                 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
6985                         true);
6986             } finally {
6987                 Binder.restoreCallingIdentity(identity);
6988             }
6989         }
6990 
6991         @Override
6992         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
6993                 Adjustment adjustment) {
6994             boolean foundEnqueued = false;
6995             final long identity = Binder.clearCallingIdentity();
6996             try {
6997                 synchronized (mNotificationLock) {
6998                     ManagedServiceInfo info = mAssistants.checkServiceTokenLocked(token);
6999                     int N = mEnqueuedNotifications.size();
7000                     for (int i = 0; i < N; i++) {
7001                         final NotificationRecord r = mEnqueuedNotifications.get(i);
7002                         if (Objects.equals(adjustment.getKey(), r.getKey())
7003                                 && Objects.equals(adjustment.getUser(), r.getUserId())
7004                                 && mAssistants.isSameUser(token, r.getUserId())) {
7005                             applyAdjustmentLocked(r, adjustment, false);
7006                             r.applyAdjustments();
7007                             // importance is checked at the beginning of the
7008                             // PostNotificationRunnable, before the signal extractors are run, so
7009                             // calculate the final importance here
7010                             r.calculateImportance();
7011                             foundEnqueued = true;
7012                         }
7013                     }
7014                     if (!foundEnqueued) {
7015                         applyAdjustmentsFromAssistant(token, List.of(adjustment));
7016                     }
7017                 }
7018             } finally {
7019                 Binder.restoreCallingIdentity(identity);
7020             }
7021         }
7022 
7023         @Override
7024         public void applyAdjustmentFromAssistant(INotificationListener token,
7025                 Adjustment adjustment) {
7026             List<Adjustment> adjustments = new ArrayList<>();
7027             adjustments.add(adjustment);
7028             applyAdjustmentsFromAssistant(token, adjustments);
7029         }
7030 
7031         @Override
7032         public void applyAdjustmentsFromAssistant(INotificationListener token,
7033                 List<Adjustment> adjustments) {
7034 
7035             boolean needsSort = false;
7036             final long identity = Binder.clearCallingIdentity();
7037             try {
7038                 synchronized (mNotificationLock) {
7039                     mAssistants.checkServiceTokenLocked(token);
7040                     for (Adjustment adjustment : adjustments) {
7041                         NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
7042                         if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
7043                             applyAdjustmentLocked(r, adjustment, true);
7044                             // If the assistant has blocked the notification, cancel it
7045                             // This will trigger a sort, so we don't have to explicitly ask for
7046                             // one here.
7047                             if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
7048                                     && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
7049                                     == IMPORTANCE_NONE) {
7050                                 cancelNotificationsFromListener(token, new String[]{r.getKey()});
7051                             } else {
7052                                 r.setPendingLogUpdate(true);
7053                                 needsSort = true;
7054                             }
7055                         }
7056                     }
7057                 }
7058                 if (needsSort) {
7059                     mRankingHandler.requestSort();
7060                 }
7061             } finally {
7062                 Binder.restoreCallingIdentity(identity);
7063             }
7064         }
7065 
7066         @Override
7067         @FlaggedApi(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
7068         public NotificationChannel createConversationNotificationChannelForPackageFromPrivilegedListener(
7069                 INotificationListener token, String pkg, UserHandle user,
7070                 String parentId, String conversationId) throws RemoteException {
7071             Objects.requireNonNull(pkg);
7072             Objects.requireNonNull(user);
7073             Objects.requireNonNull(parentId);
7074             Objects.requireNonNull(conversationId);
7075 
7076             verifyPrivilegedListener(token, user, true);
7077 
7078             int uid = getUidForPackageAndUser(pkg, user);
7079             NotificationChannel conversationChannel =
7080                     mPreferencesHelper.getNotificationChannel(pkg, uid, parentId, false).copy();
7081             String conversationChannelId = String.format(
7082                     CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId);
7083             conversationChannel.setId(conversationChannelId);
7084             conversationChannel.setConversationId(parentId, conversationId);
7085             createNotificationChannelsImpl(
7086                     pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel)));
7087             handleSavePolicyFile();
7088 
7089             return mPreferencesHelper.getConversationNotificationChannel(
7090                     pkg, uid, parentId, conversationId, false, false).copy();
7091         }
7092 
7093         @Override
7094         public void updateNotificationChannelGroupFromPrivilegedListener(
7095                 INotificationListener token, String pkg, UserHandle user,
7096                 NotificationChannelGroup group) throws RemoteException {
7097             Objects.requireNonNull(user);
7098             verifyPrivilegedListener(token, user, false);
7099             createNotificationChannelGroup(
7100                     pkg, getUidForPackageAndUser(pkg, user), group, false, true);
7101             handleSavePolicyFile();
7102         }
7103 
7104         @Override
7105         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
7106                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
7107             Objects.requireNonNull(channel);
7108             Objects.requireNonNull(pkg);
7109             Objects.requireNonNull(user);
7110 
7111             verifyPrivilegedListener(token, user, true);
7112 
7113             final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
7114                     pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true);
7115             verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel);
7116             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
7117         }
7118 
7119         @Override
7120         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
7121                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
7122             Objects.requireNonNull(pkg);
7123             Objects.requireNonNull(user);
7124             verifyPrivilegedListener(token, user, true);
7125 
7126             return mPreferencesHelper.getNotificationChannels(pkg,
7127                     getUidForPackageAndUser(pkg, user), false /* includeDeleted */, true);
7128         }
7129 
7130         @Override
7131         public ParceledListSlice<NotificationChannelGroup>
7132                 getNotificationChannelGroupsFromPrivilegedListener(
7133                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
7134             Objects.requireNonNull(pkg);
7135             Objects.requireNonNull(user);
7136             verifyPrivilegedListener(token, user, true);
7137 
7138             List<NotificationChannelGroup> groups = new ArrayList<>();
7139             groups.addAll(mPreferencesHelper.getNotificationChannelGroupsWithoutChannels(
7140                     pkg, getUidForPackageAndUser(pkg, user)));
7141             return new ParceledListSlice<>(groups);
7142         }
7143 
7144         @Override
7145         public boolean isInCall(String pkg, int uid) {
7146             checkCallerIsSystemOrSystemUiOrShell();
7147             return isCallNotification(pkg, uid);
7148         }
7149 
7150         @Override
7151         public void setPrivateNotificationsAllowed(boolean allow) {
7152             if (PERMISSION_GRANTED
7153                     != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
7154                 throw new SecurityException(
7155                         "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
7156             }
7157             if (allow != mLockScreenAllowSecureNotifications) {
7158                 mLockScreenAllowSecureNotifications = allow;
7159                 if (android.app.Flags.keyguardPrivateNotifications()) {
7160                     getContext().sendBroadcast(
7161                             new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED)
7162                                     .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED,
7163                                             mLockScreenAllowSecureNotifications),
7164                             STATUS_BAR_SERVICE);
7165                 }
7166 
7167                 handleSavePolicyFile();
7168             }
7169         }
7170 
7171         @Override
7172         public boolean getPrivateNotificationsAllowed() {
7173             if (PERMISSION_GRANTED
7174                     != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
7175                 throw new SecurityException(
7176                         "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
7177             }
7178             return mLockScreenAllowSecureNotifications;
7179         }
7180 
7181         @Override
7182         public boolean isPackagePaused(String pkg) {
7183             Objects.requireNonNull(pkg);
7184             checkCallerIsSameApp(pkg);
7185 
7186             return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
7187         }
7188 
7189         @Override
7190         public boolean isPermissionFixed(String pkg, @UserIdInt int userId) {
7191             enforceSystemOrSystemUI("isPermissionFixed");
7192             return mPermissionHelper.isPermissionFixed(pkg, userId);
7193         }
7194 
7195         private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
7196                 boolean assistantAllowed) {
7197             ManagedServiceInfo info;
7198             synchronized (mNotificationLock) {
7199                 info = mListeners.checkServiceTokenLocked(token);
7200             }
7201             if (!hasCompanionDevice(info)) {
7202                 synchronized (mNotificationLock) {
7203                     if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
7204                         throw new SecurityException(info + " does not have access");
7205                     }
7206                 }
7207             }
7208             if (!info.enabledAndUserMatches(user.getIdentifier())) {
7209                 throw new SecurityException(info + " does not have access");
7210             }
7211         }
7212 
7213         private void verifyPrivilegedListenerUriPermission(int sourceUid,
7214                 @NonNull NotificationChannel updateChannel,
7215                 @Nullable NotificationChannel originalChannel) {
7216             // Check that the NLS has the required permissions to access the channel
7217             final Uri soundUri = updateChannel.getSound();
7218             final Uri originalSoundUri =
7219                     (originalChannel != null) ? originalChannel.getSound() : null;
7220             if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) {
7221                 Binder.withCleanCallingIdentity(() -> {
7222                     mUgmInternal.checkGrantUriPermission(sourceUid, null,
7223                             ContentProvider.getUriWithoutUserId(soundUri),
7224                             Intent.FLAG_GRANT_READ_URI_PERMISSION,
7225                             ContentProvider.getUserIdFromUri(soundUri,
7226                             UserHandle.getUserId(sourceUid)));
7227                 });
7228             }
7229         }
7230 
7231         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
7232             int uid = INVALID_UID;
7233             final long identity = Binder.clearCallingIdentity();
7234             try {
7235                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
7236             } finally {
7237                 Binder.restoreCallingIdentity(identity);
7238             }
7239             return uid;
7240         }
7241 
7242         @Override
7243         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
7244                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
7245                 throws RemoteException {
7246             new NotificationShellCmd(NotificationManagerService.this)
7247                     .exec(this, in, out, err, args, callback, resultReceiver);
7248         }
7249 
7250         /**
7251          * Get stats committed after startNs
7252          *
7253          * @param startNs Report stats committed after this time in nanoseconds.
7254          * @param report  Indicatess which section to include in the stats.
7255          * @param doAgg   Whether to aggregate the stats or keep them separated.
7256          * @param out   List of protos of individual commits or one representing the
7257          *                aggregate.
7258          * @return the report time in nanoseconds, or 0 on error.
7259          */
7260         @Override
7261         public long pullStats(long startNs, int report, boolean doAgg,
7262                 List<ParcelFileDescriptor> out) {
7263             checkCallerIsSystemOrShell();
7264             long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS);
7265 
7266             final long identity = Binder.clearCallingIdentity();
7267             try {
7268                 switch (report) {
7269                     case REPORT_REMOTE_VIEWS:
7270                         Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: "
7271                                 + startMs + "  with " + doAgg);
7272                         PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg);
7273                         if (stats != null) {
7274                             out.add(stats.toParcelFileDescriptor(report));
7275                             Slog.e(TAG, "exiting pullStats with: " + out.size());
7276                             long endNs = TimeUnit.NANOSECONDS
7277                                     .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS);
7278                             return endNs;
7279                         }
7280                         Slog.e(TAG, "null stats for: " + report);
7281                 }
7282             } catch (IOException e) {
7283 
7284                 Slog.e(TAG, "exiting pullStats: on error", e);
7285                 return 0;
7286             } finally {
7287                 Binder.restoreCallingIdentity(identity);
7288             }
7289             Slog.e(TAG, "exiting pullStats: bad request");
7290             return 0;
7291         }
7292 
7293         @Override
7294         public void incrementCounter(String metricId) {
7295             if (android.app.Flags.nmBinderPerfLogNmThrottling() && metricId != null) {
7296                 Counter.logIncrementWithUid(metricId, Binder.getCallingUid());
7297             }
7298         }
7299     };
7300 
7301     private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) {
7302         if (!mUmInternal.isUserInitialized(userId)) {
7303             return; // App-op "updates" are sent when starting a new user the first time.
7304         }
7305         int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId);
7306         if (uid == INVALID_UID) {
7307             Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId));
7308             return;
7309         }
7310         boolean hasPermission = mPermissionHelper.hasPermission(uid);
7311         if (!hasPermission) {
7312             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null,
7313                     /* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId,
7314                     REASON_PACKAGE_BANNED);
7315         }
7316     }
7317 
7318     protected void checkNotificationListenerAccess() {
7319         if (!isCallerSystemOrPhone()) {
7320             // Safe to check calling permission as caller is already not system or phone
7321             getContext().enforceCallingPermission(
7322                     permission.MANAGE_NOTIFICATION_LISTENERS,
7323                     "Caller must hold " + permission.MANAGE_NOTIFICATION_LISTENERS);
7324         }
7325     }
7326 
7327     @VisibleForTesting
7328     protected void setNotificationAssistantAccessGrantedForUserInternal(
7329             ComponentName assistant, int baseUserId, boolean granted, boolean userSet) {
7330         List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
7331         if (users != null) {
7332             for (UserInfo user : users) {
7333                 int userId = user.id;
7334                 if (assistant == null) {
7335                     ComponentName allowedAssistant = CollectionUtils.firstOrNull(
7336                             mAssistants.getAllowedComponents(userId));
7337                     if (allowedAssistant != null) {
7338                         setNotificationAssistantAccessGrantedForUserInternal(
7339                                 allowedAssistant, userId, false, userSet);
7340                     }
7341                     continue;
7342                 }
7343                 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
7344                         userId, mAssistants.getRequiredPermission())) {
7345                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
7346                             userId, false, granted);
7347                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
7348                             userId, true, granted, userSet);
7349 
7350                     if (android.service.notification.Flags.notificationClassification()) {
7351                         mAssistants.setNasUnsupportedDefaults(userId);
7352                     }
7353 
7354                     getContext().sendBroadcastAsUser(
7355                             new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
7356                                     .setPackage(assistant.getPackageName())
7357                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
7358                             UserHandle.of(userId), null);
7359 
7360                     handleSavePolicyFile();
7361                 }
7362             }
7363         }
7364     }
7365 
7366     @GuardedBy("mNotificationLock")
7367     private void applyAdjustmentLocked(NotificationRecord r, Adjustment adjustment,
7368             boolean isPosted) {
7369         if (r == null) {
7370             return;
7371         }
7372         if (adjustment.getSignals() != null) {
7373             final Bundle adjustments = adjustment.getSignals();
7374             Bundle.setDefusable(adjustments, true);
7375             // Save classification even if the adjustment is disabled, in case user enables it later
7376             if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
7377                 r.setBundleType(adjustments.getInt(KEY_TYPE));
7378             }
7379             List<String> toRemove = new ArrayList<>();
7380             for (String potentialKey : adjustments.keySet()) {
7381                 if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
7382                     toRemove.add(potentialKey);
7383                 }
7384                 if (notificationClassification() && potentialKey.equals(KEY_TYPE)) {
7385                     mAssistants.setAdjustmentTypeSupportedState(
7386                             r.getSbn().getNormalizedUserId(), potentialKey, true);
7387                     if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) {
7388                         toRemove.add(potentialKey);
7389                     } else if (notificationClassificationUi()
7390                             && !mAssistants.isAdjustmentAllowedForPackage(KEY_TYPE,
7391                             r.getSbn().getPackageName())) {
7392                         toRemove.add(potentialKey);
7393                     }
7394                 }
7395                 if ((nmSummarization() || nmSummarizationUi())
7396                         && potentialKey.equals(KEY_SUMMARIZATION)) {
7397                     mAssistants.setAdjustmentTypeSupportedState(
7398                             r.getSbn().getNormalizedUserId(), potentialKey, true);
7399                     if (!mAssistants.isAdjustmentAllowedForPackage(KEY_SUMMARIZATION,
7400                             r.getSbn().getPackageName())) {
7401                         toRemove.add(potentialKey);
7402                     }
7403                 }
7404             }
7405             for (String removeKey : toRemove) {
7406                 adjustments.remove(removeKey);
7407             }
7408             if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
7409                 final NotificationChannel newChannel = getClassificationChannelLocked(r,
7410                         adjustments);
7411                 if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) {
7412                     adjustments.remove(KEY_TYPE);
7413                 } else if (android.app.Flags.apiRichOngoing() && hasFlag(r.getNotification().flags,
7414                         FLAG_PROMOTED_ONGOING)) {
7415                     // Don't bundle any promoted ongoing notifications
7416                     adjustments.remove(KEY_TYPE);
7417                 } else {
7418                     // Save the app-provided type for logging.
7419                     int classification = adjustments.getInt(KEY_TYPE);
7420                     // swap app provided type with the real thing
7421                     adjustments.putParcelable(KEY_TYPE, newChannel);
7422                     logClassificationChannelAdjustmentReceived(r, isPosted, classification);
7423                 }
7424             }
7425             r.addAdjustment(adjustment);
7426             if (adjustment.getSignals().containsKey(Adjustment.KEY_SENSITIVE_CONTENT)) {
7427                 logSensitiveAdjustmentReceived(isPosted,
7428                         adjustment.getSignals().getBoolean(Adjustment.KEY_SENSITIVE_CONTENT),
7429                         r.getLifespanMs(System.currentTimeMillis()));
7430             }
7431         }
7432     }
7433 
7434     @GuardedBy("mNotificationLock")
7435     @Nullable
7436     @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
7437     private NotificationChannel getClassificationChannelLocked(NotificationRecord r,
7438             Bundle adjustments) {
7439         int type = adjustments.getInt(KEY_TYPE);
7440         if (type >= TYPE_PROMOTION && type <= TYPE_CONTENT_RECOMMENDATION) {
7441             NotificationChannel channel = mPreferencesHelper.getReservedChannel(
7442                     r.getSbn().getPackageName(), r.getUid(), type);
7443             if (channel == null) {
7444                 channel = mPreferencesHelper.createReservedChannel(
7445                         r.getSbn().getPackageName(), r.getUid(), type);
7446                 handleSavePolicyFile();
7447             }
7448             return channel;
7449         }
7450         return null;
7451     }
7452 
7453     @SuppressWarnings("GuardedBy")
7454     @GuardedBy("mNotificationLock")
7455     void addAutogroupKeyLocked(String key, String groupName, boolean requestSort) {
7456         NotificationRecord r = mNotificationsByKey.get(key);
7457         if (r == null) {
7458             return;
7459         }
7460         if (r.getSbn().getOverrideGroupKey() == null) {
7461             if (notificationForceGrouping()) {
7462                 if (r.getSbn().isAppGroup()) {
7463                     // Override group key early for forced grouped notifications
7464                     r.setOverrideGroupKey(groupName);
7465                 }
7466                 r.getNotification().flags |= Notification.FLAG_SILENT;
7467             }
7468 
7469             addAutoGroupAdjustment(r, groupName);
7470             EventLogTags.writeNotificationAutogrouped(key);
7471 
7472             if (!android.app.Flags.checkAutogroupBeforePost() || requestSort) {
7473                 mRankingHandler.requestSort();
7474             }
7475 
7476             if (notificationForceGrouping()) {
7477                 if (r.getSbn().isAppGroup()) {
7478                     mListeners.notifyPostedLocked(r, r);
7479 
7480                     mNotificationRecordLogger.log(
7481                         NotificationRecordLogger.NotificationEvent.NOTIFICATION_FORCE_GROUP, r);
7482                 }
7483             }
7484         }
7485     }
7486 
7487     @GuardedBy("mNotificationLock")
7488     void removeAutogroupKeyLocked(String key) {
7489         NotificationRecord r = mNotificationsByKey.get(key);
7490         if (r == null) {
7491             Slog.w(TAG, "Failed to remove autogroup " + key);
7492             return;
7493         }
7494         if (r.getSbn().getOverrideGroupKey() != null) {
7495             addAutoGroupAdjustment(r, null);
7496             EventLogTags.writeNotificationUnautogrouped(key);
7497             mRankingHandler.requestSort();
7498         }
7499     }
7500 
7501     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
7502         Bundle signals = new Bundle();
7503         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
7504         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
7505                 r.getSbn().getUserId());
7506         r.addAdjustment(adjustment);
7507     }
7508 
7509     // Clears the 'fake' auto-group summary.
7510     @VisibleForTesting
7511     @GuardedBy("mNotificationLock")
7512     void clearAutogroupSummaryLocked(int userId, String pkg, String groupKey) {
7513         final String autbundledGroupKey;
7514         if (notificationForceGrouping()) {
7515             autbundledGroupKey = groupKey;
7516         } else {
7517             autbundledGroupKey = pkg;
7518         }
7519         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
7520         if (summaries != null && summaries.containsKey(autbundledGroupKey)) {
7521             final NotificationRecord removed = findNotificationByKeyLocked(
7522                     summaries.remove(autbundledGroupKey));
7523             if (removed != null) {
7524                 final StatusBarNotification sbn = removed.getSbn();
7525                 cancelNotification(MY_UID, MY_PID, pkg, sbn.getTag(), sbn.getId(), 0, 0, false,
7526                     userId, REASON_UNAUTOBUNDLED, null);
7527             }
7528         }
7529     }
7530 
7531     @GuardedBy("mNotificationLock")
7532     void removeAppSummaryLocked(String key) {
7533         NotificationRecord r = mNotificationsByKey.get(key);
7534         if (r == null) {
7535             return;
7536         }
7537         if (convertSummaryToNotificationLocked(key)) {
7538             r.isCanceled = true;
7539             cancelNotification(Binder.getCallingUid(),
7540                     Binder.getCallingPid(), r.getSbn().getPackageName(),
7541                     r.getSbn().getTag(), r.getSbn().getId(), 0, 0,
7542                     false, r.getUserId(),
7543                     NotificationListenerService.REASON_GROUP_OPTIMIZATION, null);
7544         }
7545     }
7546 
7547     @GuardedBy("mNotificationLock")
7548     @Nullable
7549     NotificationRecord removeAppProvidedSummaryOnClassificationLocked(String triggeringKey,
7550             @Nullable String oldGroupKey) {
7551         NotificationRecord canceledSummary = null;
7552         NotificationRecord r = mNotificationsByKey.get(triggeringKey);
7553         if (r == null || oldGroupKey == null) {
7554             return null;
7555         }
7556 
7557         if (r.getSbn().isAppGroup() && r.getNotification().isGroupChild()) {
7558             NotificationRecord groupSummary = mSummaryByGroupKey.get(oldGroupKey);
7559             // We only care about app-provided valid groups
7560             if (groupSummary != null && !GroupHelper.isAggregatedGroup(groupSummary)) {
7561                 List<NotificationRecord> notificationsInGroup =
7562                         findGroupNotificationsLocked(r.getSbn().getPackageName(),
7563                             oldGroupKey, r.getUserId());
7564                 // Remove the app-provided summary if only the summary is left in the
7565                 // original group, or summary + triggering notification that will be
7566                 // regrouped
7567                 boolean isOnlySummaryLeft =
7568                         (notificationsInGroup.size() <= 1)
7569                             || (notificationsInGroup.size() == 2
7570                             && notificationsInGroup.contains(r)
7571                             && notificationsInGroup.contains(groupSummary));
7572                 if (isOnlySummaryLeft) {
7573                     if (DBG) {
7574                         Slog.i(TAG, "Removing app summary (all children bundled): "
7575                                 + groupSummary);
7576                     }
7577                     if (convertSummaryToNotificationLocked(groupSummary.getKey())) {
7578                         groupSummary.isCanceled = true;
7579                         canceledSummary = groupSummary;
7580                         mSummaryByGroupKey.remove(oldGroupKey);
7581                         cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(),
7582                             groupSummary.getSbn().getPackageName(),
7583                             groupSummary.getSbn().getTag(),
7584                             groupSummary.getSbn().getId(), 0, 0, false, groupSummary.getUserId(),
7585                             NotificationListenerService.REASON_GROUP_OPTIMIZATION, null);
7586                     }
7587                 }
7588             }
7589         }
7590 
7591         return canceledSummary;
7592     }
7593 
7594     @GuardedBy("mNotificationLock")
7595     private boolean hasAutoGroupSummaryLocked(NotificationRecord record) {
7596         final String autbundledGroupKey;
7597         if (notificationForceGrouping()) {
7598             autbundledGroupKey = GroupHelper.getFullAggregateGroupKey(record);
7599         } else {
7600             autbundledGroupKey = record.getSbn().getPackageName();
7601         }
7602 
7603         ArrayMap<String, String> summaries = mAutobundledSummaries.get(record.getUserId());
7604         return summaries != null && summaries.containsKey(autbundledGroupKey);
7605     }
7606 
7607     // Creates a 'fake' summary for a package that has exceeded the solo-notification limit.
7608     NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
7609             String groupKey, int summaryId, NotificationAttributes summaryAttr) {
7610         NotificationRecord summaryRecord = null;
7611         boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
7612         synchronized (mNotificationLock) {
7613             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
7614             if (notificationRecord == null) {
7615                 // The notification could have been cancelled again already. A successive
7616                 // adjustment will post a summary if needed.
7617                 return null;
7618             }
7619             final StatusBarNotification adjustedSbn = notificationRecord.getSbn();
7620             userId = adjustedSbn.getUser().getIdentifier();
7621             int uid =  adjustedSbn.getUid();
7622             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
7623             if (summaries == null) {
7624                 summaries = new ArrayMap<>();
7625             }
7626             mAutobundledSummaries.put(userId, summaries);
7627 
7628             boolean hasSummary;
7629             String channelId;
7630             if (notificationForceGrouping()) {
7631                 hasSummary = summaries.containsKey(groupKey);
7632                 channelId = summaryAttr.channelId;
7633             } else {
7634                 hasSummary = summaries.containsKey(pkg);
7635                 channelId = notificationRecord.getChannel().getId();
7636             }
7637 
7638             if (!hasSummary) {
7639                 // Add summary
7640                 final ApplicationInfo appInfo =
7641                         adjustedSbn.getNotification().extras.getParcelable(
7642                                 EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
7643                 final Bundle extras = new Bundle();
7644                 extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, appInfo);
7645 
7646 
7647                 final Notification summaryNotification =
7648                                 new Notification.Builder(getContext(), channelId)
7649                                 .setSmallIcon(summaryAttr.icon)
7650                                 .setGroupSummary(true)
7651                                 .setGroupAlertBehavior(summaryAttr.groupAlertBehavior)
7652                                 .setGroup(groupKey)
7653                                 .setFlag(summaryAttr.flags, true)
7654                                 .setColor(summaryAttr.iconColor)
7655                                 .setVisibility(summaryAttr.visibility)
7656                                 .build();
7657                 summaryNotification.extras.putAll(extras);
7658                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
7659                 if (appIntent != null) {
7660                     summaryNotification.contentIntent = mAmi.getPendingIntentActivityAsApp(
7661                             0, appIntent, PendingIntent.FLAG_IMMUTABLE, null,
7662                             pkg, appInfo.uid);
7663                 }
7664                 final StatusBarNotification summarySbn =
7665                         new StatusBarNotification(adjustedSbn.getPackageName(),
7666                                 adjustedSbn.getOpPkg(),
7667                                 summaryId,
7668                                 groupKey, adjustedSbn.getUid(),
7669                                 adjustedSbn.getInitialPid(), summaryNotification,
7670                                 adjustedSbn.getUser(), groupKey,
7671                                 System.currentTimeMillis());
7672                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
7673                         notificationRecord.getChannel());
7674                 summaryRecord.setImportanceFixed(isPermissionFixed);
7675                 summaryRecord.setIsAppImportanceLocked(
7676                         notificationRecord.getIsAppImportanceLocked());
7677 
7678                 if (notificationForceGrouping()) {
7679                     summaries.put(summarySbn.getGroupKey(), summarySbn.getKey());
7680                 } else {
7681                     summaries.put(pkg, summarySbn.getKey());
7682                 }
7683             }
7684             if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
7685                     summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
7686                     true, false)) {
7687                 return summaryRecord;
7688             }
7689         }
7690         return null;
7691     }
7692 
7693     @GuardedBy("mNotificationLock")
7694     boolean convertSummaryToNotificationLocked(final String key) {
7695         NotificationRecord r = mNotificationsByKey.get(key);
7696         if (r == null) {
7697             return false;
7698         }
7699         // Convert summary to regular notification
7700         if (r.getSbn().isAppGroup() && r.getNotification().isGroupSummary()) {
7701             String oldGroupKey = r.getGroupKey();
7702             NotificationRecord groupSummary = mSummaryByGroupKey.get(oldGroupKey);
7703             if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
7704                 mSummaryByGroupKey.remove(oldGroupKey);
7705             }
7706             // Clear summary flag
7707             StatusBarNotification sbn = r.getSbn();
7708             sbn.getNotification().flags = (r.mOriginalFlags & ~FLAG_GROUP_SUMMARY);
7709 
7710             EventLogTags.writeNotificationSummaryConverted(key);
7711             mNotificationRecordLogger.log(
7712                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_FORCE_GROUP_SUMMARY, r);
7713             return true;
7714         }
7715         return false;
7716     }
7717 
7718     // Gets packages that have requested notification permission, and whether that has been
7719     // allowed/denied, for all users on the device.
7720     // Returns a single map containing that info keyed by (uid, package name) for all users.
7721     // Because this calls into mPermissionHelper, this method must never be called with a lock held.
7722     @VisibleForTesting
7723     protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
7724             getAllUsersNotificationPermissions() {
7725         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>();
7726         final List<UserInfo> allUsers = mUm.getUsers();
7727         // for each of these, get the package notification permissions that are associated
7728         // with this user and add it to the map
7729         for (UserInfo ui : allUsers) {
7730             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> userPermissions =
7731                     mPermissionHelper.getNotificationPermissionValues(
7732                             ui.getUserHandle().getIdentifier());
7733             for (Pair<Integer, String> pair : userPermissions.keySet()) {
7734                 allPermissions.put(pair, userPermissions.get(pair));
7735             }
7736         }
7737         return allPermissions;
7738     }
7739 
7740     private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter,
7741             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
7742         JSONObject dump = new JSONObject();
7743         try {
7744             dump.put("service", "Notification Manager");
7745             dump.put("bans", mPreferencesHelper.dumpBansJson(filter, pkgPermissions));
7746             dump.put("ranking", mPreferencesHelper.dumpJson(filter, pkgPermissions));
7747             dump.put("stats", mUsageStats.dumpJson(filter));
7748             dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
7749         } catch (JSONException e) {
7750             e.printStackTrace();
7751         }
7752         pw.println(dump);
7753     }
7754 
7755     private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) {
7756         PulledStats stats = mUsageStats.remoteViewStats(filter.since, true);
7757         if (stats == null) {
7758             pw.println("no remote view stats reported.");
7759             return;
7760         }
7761         stats.dump(REPORT_REMOTE_VIEWS, pw, filter);
7762     }
7763 
7764     private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter,
7765             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
7766         final ProtoOutputStream proto = new ProtoOutputStream(fd);
7767         synchronized (mNotificationLock) {
7768             int N = mNotificationList.size();
7769             for (int i = 0; i < N; i++) {
7770                 final NotificationRecord nr = mNotificationList.get(i);
7771                 if (filter.filtered && !filter.matches(nr.getSbn())) continue;
7772                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
7773                         NotificationRecordProto.POSTED);
7774             }
7775             N = mEnqueuedNotifications.size();
7776             for (int i = 0; i < N; i++) {
7777                 final NotificationRecord nr = mEnqueuedNotifications.get(i);
7778                 if (filter.filtered && !filter.matches(nr.getSbn())) continue;
7779                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
7780                         NotificationRecordProto.ENQUEUED);
7781             }
7782             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
7783             N = snoozed.size();
7784             for (int i = 0; i < N; i++) {
7785                 final NotificationRecord nr = snoozed.get(i);
7786                 if (filter.filtered && !filter.matches(nr.getSbn())) continue;
7787                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
7788                         NotificationRecordProto.SNOOZED);
7789             }
7790 
7791             long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
7792             mZenModeHelper.dump(proto);
7793             for (ComponentName suppressor : mEffectsSuppressors) {
7794                 suppressor.dumpDebug(proto, ZenModeProto.SUPPRESSORS);
7795             }
7796             proto.end(zenLog);
7797 
7798             long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
7799             mListeners.dump(proto, filter);
7800             proto.end(listenersToken);
7801 
7802             proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
7803 
7804             for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
7805                 long effectsToken = proto.start(
7806                     NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
7807 
7808                 proto.write(
7809                     ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
7810                 final ArraySet<ComponentName> listeners =
7811                     mListenersDisablingEffects.valueAt(i);
7812                 for (int j = 0; j < listeners.size(); j++) {
7813                     final ComponentName componentName = listeners.valueAt(j);
7814                     componentName.dumpDebug(proto,
7815                             ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
7816                 }
7817 
7818                 proto.end(effectsToken);
7819             }
7820 
7821             long assistantsToken = proto.start(
7822                 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
7823             mAssistants.dump(proto, filter);
7824             proto.end(assistantsToken);
7825 
7826             long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
7827             mConditionProviders.dump(proto, filter);
7828             proto.end(conditionsToken);
7829 
7830             long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
7831             mRankingHelper.dump(proto, filter);
7832             mPreferencesHelper.dump(proto, filter, pkgPermissions);
7833             proto.end(rankingToken);
7834         }
7835 
7836         proto.flush();
7837     }
7838 
7839     private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
7840         synchronized (mNotificationLock) {
7841             int N;
7842             N = mNotificationList.size();
7843             if (N > 0) {
7844                 pw.println("  Notification List:");
7845                 for (int i = 0; i < N; i++) {
7846                     final NotificationRecord nr = mNotificationList.get(i);
7847                     if (filter.filtered && !filter.matches(nr.getSbn())) continue;
7848                     nr.dump(pw, "    ", getContext(), filter.redact);
7849                 }
7850                 pw.println("  ");
7851             }
7852         }
7853     }
7854 
7855     void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter,
7856             ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
7857         pw.print("Current Notification Manager state");
7858         if (filter.filtered) {
7859             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
7860         }
7861         pw.println(':');
7862         int N;
7863         final boolean zenOnly = filter.filtered && filter.zen;
7864 
7865         if (!zenOnly) {
7866             synchronized (mToastQueue) {
7867                 N = mToastQueue.size();
7868                 if (N > 0) {
7869                     pw.println("  Toast Queue:");
7870                     for (int i=0; i<N; i++) {
7871                         mToastQueue.get(i).dump(pw, "    ", filter);
7872                     }
7873                     pw.println("  ");
7874                 }
7875             }
7876         }
7877 
7878         synchronized (mNotificationLock) {
7879             if (!zenOnly) {
7880                 // Priority filters are only set when called via bugreport. If set
7881                 // skip sections that are part of the critical section.
7882                 if (!filter.normalPriority) {
7883                     dumpNotificationRecords(pw, filter);
7884                 }
7885                 if (!filter.filtered) {
7886                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
7887                     pw.println("  hideSilentStatusBar="
7888                             + mPreferencesHelper.shouldHideSilentStatusIcons());
7889                     mAttentionHelper.dumpLocked(pw, "    ", filter);
7890                 }
7891                 pw.println("  mArchive=" + mArchive.toString());
7892                 mArchive.dumpImpl(pw, filter);
7893 
7894                 if (!zenOnly) {
7895                     N = mEnqueuedNotifications.size();
7896                     if (N > 0) {
7897                         pw.println("  Enqueued Notification List:");
7898                         for (int i = 0; i < N; i++) {
7899                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
7900                             if (filter.filtered && !filter.matches(nr.getSbn())) continue;
7901                             nr.dump(pw, "    ", getContext(), filter.redact);
7902                         }
7903                         pw.println("  ");
7904                     }
7905 
7906                     mSnoozeHelper.dump(pw, filter);
7907                 }
7908             }
7909 
7910             if (!zenOnly) {
7911                 pw.println("\n  Ranking Config:");
7912                 mRankingHelper.dump(pw, "    ", filter);
7913 
7914                 pw.println("\n Notification Preferences:");
7915                 mPreferencesHelper.dump(pw, "    ", filter, pkgPermissions);
7916 
7917                 pw.println("\n  Notification listeners:");
7918                 mListeners.dump(pw, filter);
7919                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
7920                 pw.print("    mListenersDisablingEffects: (");
7921                 N = mListenersDisablingEffects.size();
7922                 for (int i = 0; i < N; i++) {
7923                     final int hint = mListenersDisablingEffects.keyAt(i);
7924                     if (i > 0) pw.print(';');
7925                     pw.print("hint[" + hint + "]:");
7926 
7927                     final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
7928                     final int listenerSize = listeners.size();
7929 
7930                     for (int j = 0; j < listenerSize; j++) {
7931                         if (j > 0) pw.print(',');
7932                         final ComponentName listener = listeners.valueAt(j);
7933                         if (listener != null) {
7934                             pw.print(listener);
7935                         }
7936                     }
7937                 }
7938                 pw.println(')');
7939                 pw.println("\n  Notification assistant services:");
7940                 mAssistants.dump(pw, filter);
7941             }
7942 
7943             if (!filter.filtered || zenOnly) {
7944                 pw.println("\n  Zen Mode:");
7945                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
7946                 mZenModeHelper.dump(pw, "    ");
7947 
7948                 pw.println("\n  Zen Log:");
7949                 ZenLog.dump(pw, "    ");
7950             }
7951 
7952             pw.println("\n  Condition providers:");
7953             mConditionProviders.dump(pw, filter);
7954 
7955             pw.println("\n  Group summaries:");
7956             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
7957                 NotificationRecord r = entry.getValue();
7958                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
7959                 if (mNotificationsByKey.get(r.getKey()) != r) {
7960                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
7961                     r.dump(pw, "      ", getContext(), filter.redact);
7962                 }
7963             }
7964 
7965             if (!zenOnly) {
7966                 pw.println("\n  Usage Stats:");
7967                 mUsageStats.dump(pw, "    ", filter);
7968 
7969                 if (Flags.allNotifsNeedTtl()) {
7970                     pw.println("\n  TimeToLive alarms:");
7971                     mTtlHelper.dump(pw, "    ");
7972                 }
7973             }
7974 
7975             if (notificationForceGrouping()) {
7976                 pw.println("\n  GroupHelper:");
7977                 mGroupHelper.dump(pw, "    ");
7978             }
7979         }
7980     }
7981 
7982     /**
7983      * The private API only accessible to the system process.
7984      */
7985     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
7986 
7987         public byte[] getBackupPayload(int user, BackupRestoreEventLogger logger) {
7988             checkCallerIsSystem();
7989             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
7990             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
7991             try {
7992                 writePolicyXml(baos, true /*forBackup*/, user, logger);
7993                 return baos.toByteArray();
7994             } catch (IOException e) {
7995                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
7996             }
7997             return null;
7998         }
7999 
8000         @Override
8001         public void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger) {
8002             checkCallerIsSystem();
8003             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
8004                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
8005             if (payload == null) {
8006                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
8007                 return;
8008             }
8009             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
8010             try {
8011                 readPolicyXml(bais, true /*forRestore*/, user, logger);
8012                 handleSavePolicyFile();
8013             } catch (NumberFormatException | XmlPullParserException | IOException e) {
8014                 Slog.w(TAG, "applyRestore: error reading payload", e);
8015             }
8016         }
8017 
8018         @Override
8019         public NotificationChannel getNotificationChannel(String pkg, int uid, String
8020                 channelId) {
8021             return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
8022         }
8023 
8024         @Override
8025         public NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String
8026                 channelId) {
8027             return mPreferencesHelper.getGroupForChannel(pkg, uid, channelId);
8028         }
8029 
8030         @Override
8031         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
8032                 String tag, int id, Notification notification, int userId) {
8033             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
8034                     userId, /* byForegroundService= */ false , /* isAppProvided= */ true);
8035         }
8036 
8037         @Override
8038         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
8039                 String tag, int id, Notification notification, int userId,
8040                 boolean byForegroundService) {
8041             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
8042                     userId, byForegroundService, /* isAppProvided= */ true);
8043         }
8044 
8045         @Override
8046         public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid,
8047                 String tag, int id, int userId) {
8048             // Don't allow client applications to cancel foreground service notifs,
8049             // user-initiated job notifs or autobundled summaries.
8050             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
8051                     (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
8052             cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId,
8053                     mustNotHaveFlags);
8054         }
8055 
8056         @Override
8057         public boolean isNotificationShown(String pkg, String tag, int notificationId, int userId) {
8058             return isNotificationShownInternal(pkg, tag, notificationId, userId);
8059         }
8060 
8061         @Override
8062         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
8063                 int userId) {
8064             checkCallerIsSystem();
8065             mHandler.post(() -> {
8066                 synchronized (mNotificationLock) {
8067                     removeFlagFromNotificationLocked(pkg, notificationId, userId,
8068                             FLAG_FOREGROUND_SERVICE);
8069                 }
8070             });
8071         }
8072 
8073         @Override
8074         public void removeUserInitiatedJobFlagFromNotification(String pkg, int notificationId,
8075                 int userId) {
8076             checkCallerIsSystem();
8077             mHandler.post(() -> {
8078                 synchronized (mNotificationLock) {
8079                     removeFlagFromNotificationLocked(pkg, notificationId, userId,
8080                             FLAG_USER_INITIATED_JOB);
8081                 }
8082             });
8083         }
8084 
8085         @GuardedBy("mNotificationLock")
8086         private void removeFlagFromNotificationLocked(String pkg, int notificationId, int userId,
8087                 int flag) {
8088             int count = getNotificationCount(pkg, userId);
8089             boolean removeFlagFromNotification = false;
8090             if (count > MAX_PACKAGE_NOTIFICATIONS) {
8091                 mUsageStats.registerOverCountQuota(pkg);
8092                 removeFlagFromNotification = true;
8093             }
8094             if (removeFlagFromNotification) {
8095                 NotificationRecord r = findNotificationLocked(pkg, null, notificationId, userId);
8096                 if (r != null) {
8097                     if (DBG) {
8098                         final String type = (flag == FLAG_FOREGROUND_SERVICE) ? "FGS" : "UIJ";
8099                         Slog.d(TAG, "Remove " + type + " flag not allow. "
8100                                 + "Cancel " + type + " notification");
8101                     }
8102                     removeFromNotificationListsLocked(r);
8103                     cancelNotificationLocked(r, false, REASON_APP_CANCEL, true,
8104                             null, SystemClock.elapsedRealtime());
8105                 }
8106             } else {
8107                 List<NotificationRecord> enqueued = findNotificationsByListLocked(
8108                         mEnqueuedNotifications, pkg, null, notificationId, userId);
8109                 for (int i = 0; i < enqueued.size(); i++) {
8110                     final NotificationRecord r = enqueued.get(i);
8111                     if (r != null) {
8112                         // strip flag from all enqueued notifications. listeners will be informed
8113                         // in post runnable.
8114                         StatusBarNotification sbn = r.getSbn();
8115                         if (notificationForceGrouping()) {
8116                             sbn.getNotification().flags = (r.getFlags() & ~flag);
8117                         } else {
8118                             sbn.getNotification().flags = (r.mOriginalFlags & ~flag);
8119                         }
8120                     }
8121                 }
8122 
8123                 NotificationRecord r = findNotificationByListLocked(
8124                         mNotificationList, pkg, null, notificationId, userId);
8125                 if (r != null) {
8126                     // if posted notification exists, strip its flag and tell listeners
8127                     StatusBarNotification sbn = r.getSbn();
8128                     if (notificationForceGrouping()) {
8129                         sbn.getNotification().flags = (r.getFlags() & ~flag);
8130                     } else {
8131                         sbn.getNotification().flags = (r.mOriginalFlags & ~flag);
8132                     }
8133                     mRankingHelper.sort(mNotificationList);
8134                     mListeners.notifyPostedLocked(r, r);
8135                 }
8136             }
8137         }
8138 
8139         @Override
8140         public void onConversationRemoved(String pkg, int uid, Set<String> shortcuts) {
8141             onConversationRemovedInternal(pkg, uid, shortcuts);
8142         }
8143 
8144         @Override
8145         public int getNumNotificationChannelsForPackage(String pkg, int uid,
8146                 boolean includeDeleted) {
8147             return NotificationManagerService.this
8148                     .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted);
8149         }
8150 
8151         @Override
8152         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
8153             return areNotificationsEnabledForPackageInt(uid);
8154         }
8155 
8156         @Override
8157         public void sendReviewPermissionsNotification() {
8158             if (!mShowReviewPermissionsNotification) {
8159                 // don't show if this notification is turned off
8160                 return;
8161             }
8162 
8163             // This method is meant to be called from the JobService upon running the job for this
8164             // notification having been rescheduled; so without checking any other state, it will
8165             // send the notification.
8166             checkCallerIsSystem();
8167             NotificationManager nm = getContext().getSystemService(NotificationManager.class);
8168             nm.notify(TAG,
8169                     SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS,
8170                     createReviewPermissionsNotification());
8171             Settings.Global.putInt(getContext().getContentResolver(),
8172                     Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
8173                     NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN);
8174         }
8175 
8176         @Override
8177         public void cleanupHistoryFiles() {
8178             checkCallerIsSystem();
8179             mHistoryManager.cleanupHistoryFiles();
8180         }
8181 
8182         @Override
8183         public void removeBitmaps() {
8184             // Check all NotificationRecords, remove expired bitmaps and icon URIs, repost silently.
8185             synchronized (mNotificationLock) {
8186                 for (NotificationRecord r: mNotificationList) {
8187 
8188                     // System#currentTimeMillis when posted
8189                     final long timePostedMs = r.getSbn().getPostTime();
8190                     final long timeNowMs = System.currentTimeMillis();
8191 
8192                     final long bitmapDuration;
8193                     if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) {
8194                         bitmapDuration = Duration.ofSeconds(5).toMillis();
8195                     } else {
8196                         bitmapDuration = BITMAP_DURATION.toMillis();
8197                     }
8198 
8199                     if (isBitmapExpired(timePostedMs, timeNowMs, bitmapDuration)) {
8200                         removeBitmapAndRepost(r);
8201                     }
8202                 }
8203             }
8204         }
8205 
8206         @Override
8207         public void setDeviceEffectsApplier(DeviceEffectsApplier applier) {
8208             if (mZenModeHelper == null) {
8209                 throw new IllegalStateException("ZenModeHelper is not yet ready!");
8210             }
8211             // This can also throw IllegalStateException if called too late.
8212             mZenModeHelper.setDeviceEffectsApplier(applier);
8213         }
8214 
8215         @Override
8216         public void onDisplayRemoveSystemDecorations(int displayId) {
8217             synchronized (mToastQueue) {
8218                 for (int i = mToastQueue.size() - 1; i >= 0; i--) {
8219                     final ToastRecord toast = mToastQueue.get(i);
8220                     if (toast.displayId == displayId) {
8221                         cancelToastLocked(i);
8222                     }
8223                 }
8224             }
8225         }
8226     };
8227 
8228     private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
8229         final boolean isBigPicture = n.isStyle(Notification.BigPictureStyle.class);
8230         if (!isBigPicture) {
8231             return false;
8232         }
8233 
8234         final boolean hasBitmap = n.extras.containsKey(Notification.EXTRA_PICTURE)
8235                 && n.extras.getParcelable(Notification.EXTRA_PICTURE) != null;
8236         if (hasBitmap) {
8237             return true;
8238         }
8239 
8240         final boolean hasIcon = n.extras.containsKey(Notification.EXTRA_PICTURE_ICON)
8241                 && n.extras.getParcelable(Notification.EXTRA_PICTURE_ICON) != null;
8242         if (hasIcon) {
8243             return true;
8244         }
8245         return false;
8246     }
8247 
8248     private static boolean isBitmapExpired(long timePostedMs, long timeNowMs, long timeToLiveMs) {
8249         final long timeDiff = timeNowMs - timePostedMs;
8250         return timeDiff > timeToLiveMs;
8251     }
8252 
8253     private void removeBitmapAndRepost(NotificationRecord r) {
8254         if (!isBigPictureWithBitmapOrIcon(r.getNotification())) {
8255             return;
8256         }
8257         // Remove Notification object's reference to picture bitmap or URI. Leave the extras set to
8258         // null to avoid crashing apps that came to expect them to be present but null.
8259         r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE, null);
8260         r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE_ICON, null);
8261 
8262         // Make Notification silent
8263         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
8264 
8265         // Repost as the original app (even if it was posted by a delegate originally
8266         // because the delegate may now be revoked)
8267         enqueueNotificationInternal(r.getSbn().getPackageName(),
8268                 r.getSbn().getPackageName(), r.getSbn().getUid(),
8269                 MY_PID, r.getSbn().getTag(),
8270                 r.getSbn().getId(), r.getNotification(),
8271                 r.getSbn().getUserId(), /* postSilently= */ true,
8272                 /* byForegroundService= */ false,
8273                 /* isAppProvided= */ false);
8274     }
8275 
8276     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
8277         // don't show perm prompt if the only channels are bundle channels
8278         return mPreferencesHelper.getNotificationChannels(
8279                 pkg, uid, includeDeleted, false).getList().size();
8280     }
8281 
8282     void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid,
8283             String tag, int id, int userId, int mustNotHaveFlags) {
8284         userId = ActivityManager.handleIncomingUser(callingPid,
8285                 callingUid, userId, true, false, "cancelNotificationWithTag", pkg);
8286 
8287         // ensure opPkg is delegate if does not match pkg
8288 
8289         int uid = INVALID_UID;
8290 
8291         try {
8292             uid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
8293         } catch (NameNotFoundException e) {
8294             // package either never existed so there's no posted notification or it's being
8295             // uninstalled so we'll be cleaning it up soon. log and return immediately below.
8296         }
8297 
8298         if (uid == INVALID_UID) {
8299             Slog.w(TAG, opPkg + ":" + callingUid + " trying to cancel notification "
8300                     + "for nonexistent pkg " + pkg + " in user " + userId);
8301             return;
8302         }
8303 
8304         // if opPkg is not the same as pkg, make sure the notification given was posted
8305         // by opPkg
8306         if (!Objects.equals(pkg, opPkg)) {
8307             synchronized (mNotificationLock) {
8308                 // Look for the notification, searching both the posted and enqueued lists.
8309                 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
8310                 if (r != null) {
8311                     if (!Objects.equals(opPkg, r.getSbn().getOpPkg())) {
8312                         throw new SecurityException(opPkg + " does not have permission to "
8313                                 + "cancel a notification they did not post " + tag + " " + id);
8314                     }
8315                 }
8316             }
8317         }
8318         if (Flags.traceCancelEvents()) {
8319             Trace.instant(Trace.TRACE_TAG_SYSTEM_SERVER, "cancelNotificationInternal: " +
8320                     SmallHash.hash(Objects.hashCode(tag) ^ id));
8321         }
8322 
8323         cancelNotification(uid, callingPid, pkg, tag, id, 0,
8324                 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
8325     }
8326 
8327     boolean isNotificationShownInternal(String pkg, String tag, int notificationId, int userId) {
8328         synchronized (mNotificationLock) {
8329             return findNotificationLocked(pkg, tag, notificationId, userId) != null;
8330         }
8331     }
8332 
8333     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
8334             final int callingPid, final String tag, final int id, final Notification notification,
8335             int incomingUserId, boolean byForegroundService, boolean isAppProvided) {
8336         enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
8337                 incomingUserId, false /* postSilently */, byForegroundService, isAppProvided);
8338     }
8339 
8340     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
8341             final int callingPid, final String tag, final int id, final Notification notification,
8342             int incomingUserId, boolean postSilently, boolean byForegroundService,
8343             boolean isAppProvided) {
8344         PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
8345         boolean enqueued = false;
8346         try {
8347             enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
8348                     notification, incomingUserId, postSilently, tracker, byForegroundService,
8349                     isAppProvided);
8350         } finally {
8351             if (!enqueued) {
8352                 tracker.cancel();
8353             }
8354         }
8355     }
8356 
8357     private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) {
8358         // The package probably doesn't have WAKE_LOCK permission and should not require it.
8359         return Binder.withCleanCallingIdentity(() -> {
8360             WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
8361                     "NotificationManagerService:post:" + pkg);
8362             wakeLock.setWorkSource(new WorkSource(uid, pkg));
8363             wakeLock.acquire(POST_WAKE_LOCK_TIMEOUT.toMillis());
8364             return mPostNotificationTrackerFactory.newTracker(wakeLock);
8365         });
8366     }
8367 
8368     /**
8369      * @return True if we successfully processed the notification and handed off the task of
8370      * enqueueing it to a background thread; false otherwise.
8371      */
8372     private boolean enqueueNotificationInternal(final String pkg, final String opPkg,  //HUI
8373             final int callingUid, final int callingPid, final String tag, final int id,
8374             final Notification notification, int incomingUserId, boolean postSilently,
8375             PostNotificationTracker tracker, boolean byForegroundService, boolean isAppProvided) {
8376         if (DBG) {
8377             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
8378                     + " notification=" + notification);
8379         }
8380 
8381         if (pkg == null || notification == null) {
8382             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
8383                     + " id=" + id + " notification=" + notification);
8384         }
8385 
8386         final int userId = ActivityManager.handleIncomingUser(callingPid,
8387                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
8388         final UserHandle user = UserHandle.of(userId);
8389 
8390         // Can throw a SecurityException if the calling uid doesn't have permission to post
8391         // as "pkg"
8392         int notificationUid = INVALID_UID;
8393 
8394         try {
8395             notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
8396         } catch (NameNotFoundException e) {
8397             // not great -  throw immediately below
8398         }
8399 
8400         if (notificationUid == INVALID_UID) {
8401             throw new SecurityException("Caller " + opPkg + ":" + callingUid
8402                     + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
8403         }
8404 
8405         IBinder allowlistToken = notification.getAllowlistToken();
8406         if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) {
8407             throw new SecurityException(
8408                     "Unexpected allowlist token received from " + callingUid);
8409         }
8410         // allowlistToken is populated by unparceling, so it can be null if the notification was
8411         // posted from inside system_server. Ensure it's the expected value.
8412         notification.overrideAllowlistToken(ALLOWLIST_TOKEN);
8413 
8414         checkRestrictedCategories(notification);
8415 
8416         // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
8417         // but it's also possible that the app has called notify() with an update to an
8418         // FGS notification that hasn't yet been displayed.  Make sure we check for any
8419         // FGS-related situation up front, outside of any locks so it's safe to call into
8420         // the Activity Manager.
8421         final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
8422                 notification, tag, id, pkg, userId);
8423 
8424         boolean stripUijFlag = true;
8425         final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
8426         if (js != null) {
8427             stripUijFlag = !js.isNotificationAssociatedWithAnyUserInitiatedJobs(id, userId, pkg);
8428         }
8429 
8430         // Fix the notification as best we can.
8431         try {
8432             fixNotification(notification, pkg, tag, id, userId, notificationUid,
8433                     policy, stripUijFlag);
8434         } catch (Exception e) {
8435             if (notification.isForegroundService()) {
8436                 throw new SecurityException("Invalid FGS notification", e);
8437             }
8438             Slog.e(TAG, "Cannot fix notification", e);
8439             return false;
8440         }
8441 
8442         if (policy == ServiceNotificationPolicy.UPDATE_ONLY) {
8443             // Proceed if the notification is already showing/known, otherwise ignore
8444             // because the service lifecycle logic has retained responsibility for its
8445             // handling.
8446             if (!isNotificationShownInternal(pkg, tag, id, userId)) {
8447                 reportForegroundServiceUpdate(false, notification, id, pkg, userId);
8448                 return false;
8449             }
8450         }
8451 
8452         mUsageStats.registerEnqueuedByApp(pkg);
8453 
8454         final StatusBarNotification n = new StatusBarNotification(
8455                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
8456                 user, null, System.currentTimeMillis());
8457 
8458         // setup local book-keeping
8459         String channelId = notification.getChannelId();
8460         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
8461             channelId = (new Notification.TvExtender(notification)).getChannelId();
8462         }
8463         String shortcutId = n.getShortcutId();
8464         final NotificationChannel channel = getNotificationChannelRestoreDeleted(pkg,
8465                 callingUid, notificationUid, channelId, shortcutId);
8466         if (channel == null) {
8467             final String noChannelStr = "No Channel found for "
8468                     + "pkg=" + pkg
8469                     + ", channelId=" + channelId
8470                     + ", id=" + id
8471                     + ", tag=" + tag
8472                     + ", opPkg=" + opPkg
8473                     + ", callingUid=" + callingUid
8474                     + ", userId=" + userId
8475                     + ", incomingUserId=" + incomingUserId
8476                     + ", notificationUid=" + notificationUid
8477                     + ", notification=" + notification;
8478             Slog.e(TAG, noChannelStr);
8479             boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
8480 
8481 
8482             if (!appNotificationsOff) {
8483                 doChannelWarningToast(notificationUid,
8484                         "Developer warning for package \"" + pkg + "\"\n" +
8485                         "Failed to post notification on channel \"" + channelId + "\"\n" +
8486                         "See log for more details");
8487             }
8488             return false;
8489         }
8490 
8491         if (android.app.Flags.apiRichOngoing()) {
8492             // This would normally be done in fixNotification(), but we need the channel info so
8493             // it's done a little late
8494             if (mPreferencesHelper.canBePromoted(pkg, notificationUid)
8495                     && notification.hasPromotableCharacteristics()
8496                     && channel.getImportance() > IMPORTANCE_MIN) {
8497                 notification.flags |= FLAG_PROMOTED_ONGOING;
8498             }
8499         }
8500 
8501         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
8502         r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
8503         r.setPostSilently(postSilently);
8504         r.setFlagBubbleRemoved(false);
8505         r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
8506         boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
8507         r.setImportanceFixed(isImportanceFixed);
8508         if (notification.isFgsOrUij()) {
8509             if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
8510                         || !channel.isUserVisibleTaskShown())
8511                     && (r.getImportance() == IMPORTANCE_MIN
8512                             || r.getImportance() == IMPORTANCE_NONE)) {
8513                 // Increase the importance of fgs/uij notifications unless the user had
8514                 // an opinion otherwise (and the channel hasn't yet shown a fgs/uij).
8515                 channel.setImportance(IMPORTANCE_LOW);
8516                 r.setSystemImportance(IMPORTANCE_LOW);
8517                 if (!channel.isUserVisibleTaskShown()) {
8518                     channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
8519                     channel.setUserVisibleTaskShown(true);
8520                 }
8521                 mPreferencesHelper.updateNotificationChannel(
8522                         pkg, notificationUid, channel, false, callingUid,
8523                         isCallerSystemOrSystemUi());
8524                 r.updateNotificationChannel(channel);
8525             } else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId)
8526                     && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
8527                 channel.setUserVisibleTaskShown(true);
8528                 r.updateNotificationChannel(channel);
8529             }
8530         }
8531 
8532         ShortcutInfo info = mShortcutHelper != null
8533                 ? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user)
8534                 : null;
8535         if (notification.getShortcutId() != null && info == null) {
8536             Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut");
8537         }
8538         r.setShortcutInfo(info);
8539         r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid));
8540         r.userDemotedAppFromConvoSpace(
8541                 mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
8542 
8543         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
8544                 r.getSbn().getOverrideGroupKey() != null, byForegroundService)) {
8545             return false;
8546         }
8547 
8548         mUsageStats.registerEnqueuedByAppAndAccepted(pkg);
8549 
8550         if (info != null) {
8551             // Cache the shortcut synchronously after the associated notification is posted in case
8552             // the app unpublishes this shortcut immediately after posting the notification. If the
8553             // user does not modify the notification settings on this conversation, the shortcut
8554             // will be uncached by People Service when all the associated notifications are removed.
8555             mShortcutHelper.cacheShortcut(info, user);
8556         }
8557 
8558         // temporarily allow apps to perform extra work when their pending intents are launched
8559         if (notification.allPendingIntents != null) {
8560             final int intentCount = notification.allPendingIntents.size();
8561             if (intentCount > 0) {
8562                 final long duration = LocalServices.getService(
8563                         DeviceIdleInternal.class).getNotificationAllowlistDuration();
8564                 for (int i = 0; i < intentCount; i++) {
8565                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
8566                     if (pendingIntent != null) {
8567                         mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
8568                                 ALLOWLIST_TOKEN, duration,
8569                                 TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
8570                                 REASON_NOTIFICATION_SERVICE,
8571                                 "NotificationManagerService");
8572                         mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
8573                                 ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
8574                                         | FLAG_SERVICE_SENDER));
8575                     }
8576                 }
8577             }
8578         }
8579 
8580         // Need escalated privileges to get package importance.
8581         final int packageImportance = getPackageImportanceWithIdentity(pkg);
8582         boolean isAppForeground = packageImportance == IMPORTANCE_FOREGROUND;
8583         mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
8584                 /* isAppProvided= */ isAppProvided, tracker));
8585         return true;
8586     }
8587 
8588     /**
8589      * Returns a channel, if exists and is not a bundle channel, and restores deleted
8590      * conversation channels.
8591      */
8592     @Nullable
8593     private NotificationChannel getNotificationChannelRestoreDeleted(String pkg,
8594             int callingUid, int notificationUid, String channelId, String conversationId) {
8595         if (SYSTEM_RESERVED_IDS.contains(channelId)) {
8596             // apps cannot post to these channels directly, in case they post incorrect content
8597             return null;
8598         }
8599         // Restore a deleted conversation channel, if exists. Otherwise use the parent channel.
8600         NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
8601                 pkg, notificationUid, channelId, conversationId,
8602                 true /* parent ok */, !TextUtils.isEmpty(conversationId) /* includeDeleted */);
8603         // Restore deleted conversation channel
8604         if (channel != null && channel.isDeleted()) {
8605             if (Objects.equals(conversationId, channel.getConversationId())) {
8606                 boolean needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(
8607                         pkg, notificationUid, channel, true /* fromTargetApp */,
8608                         mConditionProviders.isPackageOrComponentAllowed(pkg,
8609                         UserHandle.getUserId(notificationUid)), callingUid, true);
8610                 // Update policy file if the conversation channel was restored
8611                 if (needsPolicyFileChange) {
8612                     handleSavePolicyFile();
8613                 }
8614             } else {
8615                 // Do not restore parent channel
8616                 channel = null;
8617             }
8618         }
8619         return channel;
8620     }
8621 
8622     private void onConversationRemovedInternal(String pkg, int uid, Set<String> shortcuts) {
8623         checkCallerIsSystem();
8624         Preconditions.checkStringNotEmpty(pkg);
8625 
8626         mHistoryManager.deleteConversations(pkg, uid, shortcuts);
8627         List<String> deletedChannelIds =
8628                 mPreferencesHelper.deleteConversations(pkg, uid, shortcuts,
8629                         /* callingUid */ Process.SYSTEM_UID, /* is system */ true);
8630         for (String channelId : deletedChannelIds) {
8631             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
8632                     UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED
8633             );
8634         }
8635         handleSavePolicyFile();
8636     }
8637 
8638     private void makeStickyHun(Notification notification, String pkg, @UserIdInt int userId) {
8639         if (mPermissionHelper.hasRequestedPermission(
8640                 Manifest.permission.USE_FULL_SCREEN_INTENT, pkg, userId)) {
8641             notification.flags |= FLAG_FSI_REQUESTED_BUT_DENIED;
8642         }
8643         if (notification.contentIntent == null) {
8644             // On notification click, if contentIntent is null, SystemUI launches the
8645             // fullScreenIntent instead.
8646             notification.contentIntent = notification.fullScreenIntent;
8647         }
8648         notification.fullScreenIntent = null;
8649     }
8650 
8651     @VisibleForTesting
8652     protected void fixNotification(Notification notification, String pkg, String tag, int id,
8653             @UserIdInt int userId, int notificationUid,
8654             ServiceNotificationPolicy fgsPolicy, boolean stripUijFlag)
8655             throws NameNotFoundException, RemoteException {
8656         final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
8657                 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
8658                 (userId == USER_ALL) ? USER_SYSTEM : userId);
8659         Notification.addFieldsFromContext(ai, notification);
8660 
8661         // can't be set by an app
8662         notification.extras.remove(Notification.EXTRA_SUMMARIZED_CONTENT);
8663 
8664         if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) {
8665             notification.flags &= ~FLAG_FOREGROUND_SERVICE;
8666         }
8667         if (notification.isUserInitiatedJob() && stripUijFlag) {
8668             notification.flags &= ~FLAG_USER_INITIATED_JOB;
8669         }
8670 
8671         // Remove FLAG_AUTO_CANCEL from notifications that are associated with a FGS or UIJ.
8672         if (notification.isFgsOrUij()) {
8673             notification.flags &= ~FLAG_AUTO_CANCEL;
8674         }
8675 
8676         // Only notifications that can be non-dismissible can have the flag FLAG_NO_DISMISS
8677         if (((notification.flags & FLAG_ONGOING_EVENT) > 0)
8678                 && canBeNonDismissible(ai, notification)) {
8679             notification.flags |= FLAG_NO_DISMISS;
8680         } else {
8681             notification.flags &= ~FLAG_NO_DISMISS;
8682         }
8683 
8684         int canColorize = getContext().checkPermission(
8685                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, -1, notificationUid);
8686 
8687         if (canColorize == PERMISSION_GRANTED) {
8688             notification.flags |= Notification.FLAG_CAN_COLORIZE;
8689         } else {
8690             notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
8691         }
8692 
8693         if (notification.extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, false)) {
8694             int hasShowDuringSetupPerm = getContext().checkPermission(
8695                     android.Manifest.permission.NOTIFICATION_DURING_SETUP, -1, notificationUid);
8696             if (hasShowDuringSetupPerm != PERMISSION_GRANTED) {
8697                 notification.extras.remove(Notification.EXTRA_ALLOW_DURING_SETUP);
8698                 if (DBG) {
8699                     Slog.w(TAG, "warning: pkg " + pkg + " attempting to show during setup"
8700                             + " without holding perm "
8701                             + Manifest.permission.NOTIFICATION_DURING_SETUP);
8702                 }
8703             }
8704         }
8705 
8706         notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED;
8707 
8708         // Apps cannot post notifications that are lifetime extended.
8709         if (lifetimeExtensionRefactor()) {
8710             notification.flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
8711         }
8712 
8713         if (notification.fullScreenIntent != null) {
8714             final AttributionSource attributionSource =
8715                     new AttributionSource.Builder(notificationUid).setPackageName(pkg).build();
8716             final boolean canUseFullScreenIntent = checkUseFullScreenIntentPermission(
8717                     attributionSource, ai, true /* forDataDelivery */);
8718             if (!canUseFullScreenIntent) {
8719                 makeStickyHun(notification, pkg, userId);
8720             }
8721         }
8722 
8723         // Ensure all actions are present
8724         if (notification.actions != null) {
8725             boolean hasNullActions = false;
8726             int nActions = notification.actions.length;
8727             for (int i = 0; i < nActions; i++) {
8728                 if (notification.actions[i] == null) {
8729                     hasNullActions = true;
8730                     break;
8731                 }
8732             }
8733             if (hasNullActions) {
8734                 ArrayList<Notification.Action> nonNullActions = new ArrayList<>();
8735                 for (int i = 0; i < nActions; i++) {
8736                     if (notification.actions[i] != null) {
8737                         nonNullActions.add(notification.actions[i]);
8738                     }
8739                 }
8740                 if (nonNullActions.size() != 0) {
8741                     notification.actions = nonNullActions.toArray(new Notification.Action[0]);
8742                 } else {
8743                     notification.actions = null;
8744                 }
8745             }
8746         }
8747 
8748         // Apps cannot set this flag
8749          notification.flags &= ~FLAG_PROMOTED_ONGOING;
8750 
8751         // Ensure CallStyle has all the correct actions
8752         if (notification.isStyle(Notification.CallStyle.class)) {
8753             Notification.Builder builder =
8754                     Notification.Builder.recoverBuilder(getContext(), notification);
8755             Notification.CallStyle style = (Notification.CallStyle) builder.getStyle();
8756             List<Notification.Action> actions = style.getActionsListWithSystemActions();
8757             notification.actions = new Notification.Action[actions.size()];
8758             actions.toArray(notification.actions);
8759         }
8760 
8761         // Ensure MediaStyle has correct permissions for remote device extras
8762         if (notification.isStyle(Notification.MediaStyle.class)
8763                 || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) {
8764             int hasMediaContentControlPermission = getContext().checkPermission(
8765                     android.Manifest.permission.MEDIA_CONTENT_CONTROL, -1, notificationUid);
8766             if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
8767                 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE);
8768                 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON);
8769                 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT);
8770                 if (DBG) {
8771                     Slog.w(TAG, "Package " + pkg + ": Use of setRemotePlayback requires the "
8772                             + "MEDIA_CONTENT_CONTROL permission");
8773                 }
8774             }
8775 
8776             // Enforce NO_CLEAR flag on MediaStyle notification for apps with targetSdk >= V.
8777             if (CompatChanges.isChangeEnabled(ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION,
8778                     notificationUid)) {
8779                 notification.flags |= FLAG_NO_CLEAR;
8780             }
8781         }
8782 
8783         // Ensure only allowed packages have a substitute app name
8784         if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
8785             int hasSubstituteAppNamePermission = getContext().checkPermission(
8786                     permission.SUBSTITUTE_NOTIFICATION_APP_NAME, -1, notificationUid);
8787             if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
8788                 notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
8789                 if (DBG) {
8790                     Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name"
8791                             + " without holding perm "
8792                             + Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
8793                 }
8794             }
8795         }
8796 
8797         // Remote views? Are they too big?
8798         checkRemoteViews(pkg, tag, id, notification);
8799 
8800         if (Flags.allNotifsNeedTtl()) {
8801             if (notification.getTimeoutAfter() == 0) {
8802                 notification.setTimeoutAfter(NOTIFICATION_TTL);
8803             }
8804         }
8805 
8806         if (notificationForceGrouping()) {
8807             notification.fixSilentGroup();
8808         }
8809     }
8810 
8811     /**
8812      * Whether a notification can be non-dismissible.
8813      * A notification should be dismissible, unless it's exempted for some reason.
8814      */
8815     private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) {
8816         return notification.isMediaNotification() || isEnterpriseExempted(ai)
8817                 || notification.isStyle(Notification.CallStyle.class)
8818                 || isDefaultSearchSelectorPackage(ai.packageName)
8819                 || isDefaultAdservicesPackage(ai.packageName);
8820     }
8821 
8822     private boolean isDefaultSearchSelectorPackage(String pkg) {
8823         return Objects.equals(mDefaultSearchSelectorPkg, pkg);
8824     }
8825 
8826     private boolean isDefaultAdservicesPackage(String pkg) {
8827         if (mAdservicesModuleInfo == null) {
8828             return false;
8829         }
8830         // Handles the special package structure for mainline modules
8831         for (String apkName : mAdservicesModuleInfo.getApkInApexPackageNames()) {
8832             if (Objects.equals(apkName, pkg)) {
8833                 return true;
8834             }
8835         }
8836         return false;
8837     }
8838 
8839     private boolean isEnterpriseExempted(ApplicationInfo ai) {
8840         // Check if the app is an organization admin app
8841         // TODO(b/234609037): Replace with new DPM APIs to check if organization admin
8842         if (mDpm != null && (mDpm.isActiveProfileOwner(ai.uid)
8843                 || mDpm.isActiveDeviceOwner(ai.uid))) {
8844             return true;
8845         }
8846         // Check if an app has been given system exemption
8847         if (ai.uid == Process.SYSTEM_UID) {
8848             return false;
8849         }
8850         return mAppOps.checkOpNoThrow(
8851                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
8852                 ai.packageName) == MODE_ALLOWED;
8853     }
8854 
8855     private boolean checkUseFullScreenIntentPermission(@NonNull AttributionSource attributionSource,
8856             @NonNull ApplicationInfo applicationInfo,
8857             boolean forDataDelivery) {
8858         if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
8859             return true;
8860         }
8861         final int permissionResult;
8862         if (forDataDelivery) {
8863             permissionResult = mPermissionManager.checkPermissionForDataDelivery(
8864                     permission.USE_FULL_SCREEN_INTENT, attributionSource, /* message= */ null);
8865         } else {
8866             permissionResult = mPermissionManager.checkPermissionForPreflight(
8867                     permission.USE_FULL_SCREEN_INTENT, attributionSource);
8868         }
8869         return permissionResult == PermissionManager.PERMISSION_GRANTED;
8870     }
8871 
8872     private void checkRemoteViews(String pkg, String tag, int id, Notification notification) {
8873         if (android.app.Flags.removeRemoteViews()) {
8874             if (notification.containsCustomViews()) {
8875                 Slog.i(TAG, "Removed customViews for " + pkg);
8876                 mUsageStats.registerImageRemoved(pkg);
8877             }
8878             notification.contentView = null;
8879             notification.bigContentView = null;
8880             notification.headsUpContentView = null;
8881             if (notification.publicVersion != null) {
8882                 notification.publicVersion.contentView = null;
8883                 notification.publicVersion.bigContentView = null;
8884                 notification.publicVersion.headsUpContentView = null;
8885             }
8886         } else {
8887             if (removeRemoteView(pkg, tag, id, notification.contentView)) {
8888                 notification.contentView = null;
8889             }
8890             if (removeRemoteView(pkg, tag, id, notification.bigContentView)) {
8891                 notification.bigContentView = null;
8892             }
8893             if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) {
8894                 notification.headsUpContentView = null;
8895             }
8896             if (notification.publicVersion != null) {
8897                 if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) {
8898                     notification.publicVersion.contentView = null;
8899                 }
8900                 if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) {
8901                     notification.publicVersion.bigContentView = null;
8902                 }
8903                 if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) {
8904                     notification.publicVersion.headsUpContentView = null;
8905                 }
8906             }
8907         }
8908     }
8909 
8910     private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) {
8911         if (contentView == null) {
8912             return false;
8913         }
8914         final long contentViewSize = contentView.estimateMemoryUsage();
8915         if (contentViewSize > mWarnRemoteViewsSizeBytes
8916                 && contentViewSize < mStripRemoteViewsSizeBytes) {
8917             Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id
8918                     + " this might be stripped in a future release");
8919         }
8920         if (contentViewSize >= mStripRemoteViewsSizeBytes) {
8921             mUsageStats.registerImageRemoved(pkg);
8922             Slog.w(TAG, "Removed too large RemoteViews (" + contentViewSize + " bytes) on pkg: "
8923                     + pkg + " tag: " + tag + " id: " + id);
8924             return true;
8925         }
8926         return false;
8927     }
8928 
8929     /**
8930      * Strips any flags from BubbleMetadata that wouldn't apply (e.g. app not foreground).
8931      */
8932     private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) {
8933         Notification notification = r.getNotification();
8934         Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
8935         if (metadata == null) {
8936             // Nothing to update
8937             return;
8938         }
8939         if (!isAppForeground) {
8940             // Auto expand only works if foreground
8941             int flags = metadata.getFlags();
8942             flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
8943             metadata.setFlags(flags);
8944         }
8945         if (!metadata.isBubbleSuppressable()) {
8946             // If it's not suppressable remove the suppress flag
8947             int flags = metadata.getFlags();
8948             flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
8949             metadata.setFlags(flags);
8950         }
8951     }
8952 
8953     private ShortcutHelper.ShortcutListener mShortcutListener =
8954             new ShortcutHelper.ShortcutListener() {
8955                 @Override
8956                 public void onShortcutRemoved(String key) {
8957                     String packageName;
8958                     synchronized (mNotificationLock) {
8959                         NotificationRecord r = mNotificationsByKey.get(key);
8960                         packageName = r != null ? r.getSbn().getPackageName() : null;
8961                     }
8962                     final int packageImportance = getPackageImportanceWithIdentity(packageName);
8963                     boolean isAppForeground = packageName != null
8964                             && packageImportance == IMPORTANCE_FOREGROUND;
8965                     synchronized (mNotificationLock) {
8966                         NotificationRecord r = mNotificationsByKey.get(key);
8967                         if (r != null) {
8968                             r.setShortcutInfo(null);
8969                             // Enqueue will trigger resort & flag is updated that way.
8970                             r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
8971                             mHandler.post(
8972                                     new EnqueueNotificationRunnable(
8973                                             r.getUser().getIdentifier(), r, isAppForeground,
8974                                             /* isAppProvided= */ false,
8975                                             mPostNotificationTrackerFactory.newTracker(null)));
8976                         }
8977                     }
8978                 }
8979             };
8980 
8981     protected void doChannelWarningToast(int forUid, CharSequence toastText) {
8982         Binder.withCleanCallingIdentity(() -> {
8983             final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
8984                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0) != 0;
8985             if (warningEnabled) {
8986                 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
8987                         Toast.LENGTH_SHORT);
8988                 toast.show();
8989             }
8990         });
8991     }
8992 
8993     @VisibleForTesting
8994     int resolveNotificationUid(String callingPkg, String targetPkg, int callingUid, int userId)
8995             throws NameNotFoundException {
8996         if (userId == USER_ALL) {
8997             userId = USER_SYSTEM;
8998         }
8999         // posted from app A on behalf of app A
9000         if (isCallerSameApp(targetPkg, callingUid, userId)
9001                 && (TextUtils.equals(callingPkg, targetPkg)
9002                 || isCallerSameApp(callingPkg, callingUid, userId))) {
9003             return callingUid;
9004         }
9005 
9006         int targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
9007 
9008         // posted from app A on behalf of app B
9009         if (isCallerAndroid(callingPkg, callingUid)
9010                 || mPreferencesHelper.isDelegateAllowed(
9011                         targetPkg, targetUid, callingPkg, callingUid)) {
9012             return targetUid;
9013         }
9014 
9015         throw new SecurityException("Caller " + callingPkg + ":" + callingUid
9016                 + " cannot post for pkg " + targetPkg + " in user " + userId);
9017     }
9018 
9019     public boolean hasFlag(final int flags, final int flag) {
9020         return (flags & flag) != 0;
9021     }
9022     /**
9023      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
9024      *
9025      * Has side effects.
9026      */
9027     boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
9028             NotificationRecord r, boolean isAutogroup, boolean byForegroundService) {
9029         Notification n = r.getNotification();
9030         final String pkg = r.getSbn().getPackageName();
9031         final boolean isSystemNotification =
9032                 isUidSystemOrPhone(uid) || ("android".equals(pkg));
9033         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
9034 
9035         // Limit the number of notifications that any given package except the android
9036         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
9037         if (!isSystemNotification && !isNotificationFromListener) {
9038             final int callingUid = Binder.getCallingUid();
9039             synchronized (mNotificationLock) {
9040                 if (mNotificationsByKey.get(r.getSbn().getKey()) == null
9041                         && isCallerInstantApp(callingUid, userId)) {
9042                     // Ephemeral apps have some special constraints for notifications.
9043                     // They are not allowed to create new notifications however they are allowed to
9044                     // update notifications created by the system (e.g. a foreground service
9045                     // notification).
9046                     throw new SecurityException("Instant app " + pkg
9047                             + " cannot create notifications");
9048                 }
9049 
9050                 // Rate limit updates that aren't completed progress notifications
9051                 // Search for the original one in the posted and not-yet-posted (enqueued) lists.
9052                 boolean isUpdate = mNotificationsByKey.get(r.getSbn().getKey()) != null
9053                         || findNotificationByListLocked(mEnqueuedNotifications, r.getSbn().getKey())
9054                         != null;
9055                 if (isUpdate && !r.getNotification().hasCompletedProgress() && !isAutogroup) {
9056                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
9057                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
9058                         mUsageStats.registerOverRateQuota(pkg);
9059                         final long now = SystemClock.elapsedRealtime();
9060                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
9061                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
9062                                     + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg);
9063                             mLastOverRateLogTime = now;
9064                         }
9065                         return false;
9066                     }
9067                 }
9068             }
9069 
9070             // limit the number of non-fgs/uij outstanding notificationrecords an app can have
9071             if (!n.isFgsOrUij()) {
9072                 int count = getNotificationCount(pkg, userId, id, tag);
9073                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
9074                     mUsageStats.registerOverCountQuota(pkg);
9075                     Slog.e(TAG, "Package has already posted or enqueued " + count
9076                             + " notifications.  Not showing more.  package=" + pkg);
9077                     return false;
9078                 }
9079             }
9080         }
9081 
9082         // bubble or inline reply that's immutable?
9083         if (n.getBubbleMetadata() != null
9084                 && n.getBubbleMetadata().getIntent() != null
9085                 && hasFlag(mAmi.getPendingIntentFlags(
9086                         n.getBubbleMetadata().getIntent().getTarget()),
9087                         PendingIntent.FLAG_IMMUTABLE)) {
9088             throw new IllegalArgumentException(r.getKey() + " Not posted."
9089                     + " PendingIntents attached to bubbles must be mutable");
9090         }
9091 
9092         if (n.actions != null) {
9093             for (Notification.Action action : n.actions) {
9094                 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null)
9095                         && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()),
9096                         PendingIntent.FLAG_IMMUTABLE)) {
9097                     throw new IllegalArgumentException(r.getKey() + " Not posted."
9098                             + " PendingIntents attached to actions with remote"
9099                             + " inputs must be mutable");
9100                 }
9101             }
9102         }
9103 
9104         if (r.getSystemGeneratedSmartActions() != null) {
9105             for (Notification.Action action : r.getSystemGeneratedSmartActions()) {
9106                 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null)
9107                         && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()),
9108                         PendingIntent.FLAG_IMMUTABLE)) {
9109                     throw new IllegalArgumentException(r.getKey() + " Not posted."
9110                             + " PendingIntents attached to contextual actions with remote inputs"
9111                             + " must be mutable");
9112                 }
9113             }
9114         }
9115 
9116         if (n.isStyle(Notification.CallStyle.class)) {
9117             boolean hasFullScreenIntent = n.fullScreenIntent != null;
9118             boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
9119             if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent
9120                     && !byForegroundService) {
9121                 throw new IllegalArgumentException(r.getKey() + " Not posted."
9122                         + " CallStyle notifications must be for a foreground service or"
9123                         + " user initated job or use a fullScreenIntent.");
9124             }
9125         }
9126 
9127         // snoozed apps
9128         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
9129             MetricsLogger.action(r.getLogMaker()
9130                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
9131                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
9132             mNotificationRecordLogger.log(
9133                     NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED,
9134                     r);
9135             if (DBG) {
9136                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
9137             }
9138             mSnoozeHelper.update(userId, r);
9139             handleSavePolicyFile();
9140             return false;
9141         }
9142 
9143         // blocked apps
9144         boolean isBlocked = !areNotificationsEnabledForPackageInt(uid);
9145         synchronized (mNotificationLock) {
9146             isBlocked |= isRecordBlockedLocked(r);
9147         }
9148         if (isBlocked && !(n.isMediaNotification() || isCallNotification(pkg, uid, n))) {
9149             if (DBG) {
9150                 Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
9151                         + " by user request.");
9152             }
9153             mUsageStats.registerBlocked(r);
9154             return false;
9155         }
9156 
9157         if (Flags.rejectOldNotifications() && n.hasAppProvidedWhen() && n.getWhen() > 0
9158                 && (System.currentTimeMillis() - n.getWhen()) > NOTIFICATION_MAX_AGE_AT_POST) {
9159             Slog.d(TAG, "Ignored enqueue for old " + n.getWhen() + " notification " + r.getKey());
9160             mUsageStats.registerTooOldBlocked(r);
9161             return false;
9162         }
9163 
9164         return true;
9165     }
9166 
9167     private boolean isCallNotification(String pkg, int uid, Notification n) {
9168         if (n.isStyle(Notification.CallStyle.class)) {
9169             return isCallNotification(pkg, uid);
9170         }
9171         return false;
9172     }
9173 
9174     private boolean isCallNotification(String pkg, int uid) {
9175         final long identity = Binder.clearCallingIdentity();
9176         try {
9177             if (mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)
9178                     && mTelecomManager != null) {
9179                 try {
9180                     return mTelecomManager.isInManagedCall()
9181                             || mTelecomManager.isInSelfManagedCall(pkg,
9182                             UserHandle.ALL);
9183                 } catch (IllegalStateException ise) {
9184                     // Telecom is not ready (this is likely early boot), so there are no calls.
9185                     return false;
9186                 }
9187             }
9188             return false;
9189         } finally {
9190             Binder.restoreCallingIdentity(identity);
9191         }
9192     }
9193 
9194     private boolean areNotificationsEnabledForPackageInt(int uid) {
9195         return mPermissionHelper.hasPermission(uid);
9196     }
9197 
9198     private int getNotificationCount(String pkg, int userId) {
9199         int count = 0;
9200         synchronized (mNotificationLock) {
9201             final int numListSize = mNotificationList.size();
9202             for (int i = 0; i < numListSize; i++) {
9203                 final NotificationRecord existing = mNotificationList.get(i);
9204                 if (existing.getSbn().getPackageName().equals(pkg)
9205                         && existing.getSbn().getUserId() == userId) {
9206                     count++;
9207                 }
9208             }
9209             final int numEnqSize = mEnqueuedNotifications.size();
9210             for (int i = 0; i < numEnqSize; i++) {
9211                 final NotificationRecord existing = mEnqueuedNotifications.get(i);
9212                 if (existing.getSbn().getPackageName().equals(pkg)
9213                         && existing.getSbn().getUserId() == userId) {
9214                     count++;
9215                 }
9216             }
9217         }
9218         return count;
9219     }
9220 
9221     protected int getNotificationCount(String pkg, int userId, int excludedId,
9222             String excludedTag) {
9223         int count = 0;
9224         synchronized (mNotificationLock) {
9225             final int N = mNotificationList.size();
9226             for (int i = 0; i < N; i++) {
9227                 final NotificationRecord existing = mNotificationList.get(i);
9228                 if (existing.getSbn().getPackageName().equals(pkg)
9229                         && existing.getSbn().getUserId() == userId) {
9230                     if (existing.getSbn().getId() == excludedId
9231                             && TextUtils.equals(existing.getSbn().getTag(), excludedTag)) {
9232                         continue;
9233                     }
9234                     count++;
9235                 }
9236             }
9237             final int M = mEnqueuedNotifications.size();
9238             for (int i = 0; i < M; i++) {
9239                 final NotificationRecord existing = mEnqueuedNotifications.get(i);
9240                 if (existing.getSbn().getPackageName().equals(pkg)
9241                         && existing.getSbn().getUserId() == userId) {
9242                     count++;
9243                 }
9244             }
9245         }
9246         return count;
9247     }
9248 
9249     /**
9250      * Checks whether a notification is banned at a group or channel level or if the NAS or system
9251      * has blocked the notification.
9252      */
9253     @GuardedBy("mNotificationLock")
9254     boolean isRecordBlockedLocked(NotificationRecord r) {
9255         final String pkg = r.getSbn().getPackageName();
9256         final int callingUid = r.getSbn().getUid();
9257         return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
9258                 || r.getImportance() == IMPORTANCE_NONE;
9259     }
9260 
9261     protected class SnoozeNotificationRunnable implements Runnable {
9262         private final String mKey;
9263         private final long mDuration;
9264         private final String mSnoozeCriterionId;
9265 
9266         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
9267             mKey = key;
9268             mDuration = duration;
9269             mSnoozeCriterionId = snoozeCriterionId;
9270         }
9271 
9272         @Override
9273         public void run() {
9274             synchronized (mNotificationLock) {
9275                 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey);
9276                 if (r != null) {
9277                     snoozeLocked(r);
9278                 }
9279             }
9280         }
9281 
9282         @GuardedBy("mNotificationLock")
9283         void snoozeLocked(NotificationRecord r) {
9284             final List<NotificationRecord> recordsToSnooze = new ArrayList<>();
9285             if (r.getSbn().isGroup()) {
9286                 final List<NotificationRecord> groupNotifications =
9287                         findCurrentAndSnoozedGroupNotificationsLocked(
9288                         r.getSbn().getPackageName(),
9289                                 r.getSbn().getGroupKey(), r.getSbn().getUserId());
9290                 if (r.getNotification().isGroupSummary()) {
9291                     // snooze all children
9292                     for (int i = 0; i < groupNotifications.size(); i++) {
9293                         if (!mKey.equals(groupNotifications.get(i).getKey())) {
9294                             recordsToSnooze.add(groupNotifications.get(i));
9295                         }
9296                     }
9297                 } else {
9298                     // if there is a valid summary for this group, and we are snoozing the only
9299                     // child, also snooze the summary
9300                     if (mSummaryByGroupKey.containsKey(r.getSbn().getGroupKey())) {
9301                         if (groupNotifications.size() == 2) {
9302                             // snooze summary and the one child
9303                             for (int i = 0; i < groupNotifications.size(); i++) {
9304                                 if (!mKey.equals(groupNotifications.get(i).getKey())) {
9305                                     recordsToSnooze.add(groupNotifications.get(i));
9306                                 }
9307                             }
9308                         }
9309                     }
9310                 }
9311             }
9312             // snooze the notification
9313             recordsToSnooze.add(r);
9314 
9315             if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) {
9316                 for (int i = 0; i < recordsToSnooze.size(); i++) {
9317                     snoozeNotificationLocked(recordsToSnooze.get(i));
9318                 }
9319             } else {
9320                 Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications");
9321             }
9322         }
9323 
9324         @GuardedBy("mNotificationLock")
9325         void snoozeNotificationLocked(NotificationRecord r) {
9326             MetricsLogger.action(r.getLogMaker()
9327                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
9328                     .setType(MetricsEvent.TYPE_CLOSE)
9329                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
9330                             mDuration)
9331                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
9332                             mSnoozeCriterionId == null ? 0 : 1));
9333             mNotificationRecordLogger.log(
9334                     NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, r);
9335             reportUserInteraction(r);
9336             boolean wasPosted = removeFromNotificationListsLocked(r);
9337             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null,
9338                     SystemClock.elapsedRealtime());
9339             mAttentionHelper.updateLightsLocked();
9340             if (isSnoozable(r)) {
9341                 if (mSnoozeCriterionId != null) {
9342                     mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId);
9343                     mSnoozeHelper.snooze(r, mSnoozeCriterionId);
9344                 } else {
9345                     mSnoozeHelper.snooze(r, mDuration);
9346                 }
9347                 r.recordSnoozed();
9348                 handleSavePolicyFile();
9349             }
9350         }
9351 
9352         /**
9353          * Autogroup summaries are not snoozable
9354          * They will be recreated as needed when the group children are unsnoozed
9355          */
9356         private boolean isSnoozable(NotificationRecord record) {
9357             if (notificationForceGrouping()) {
9358                 boolean isExemptedSummary =
9359                         ((record.getFlags() & FLAG_AUTOGROUP_SUMMARY) != 0
9360                         || GroupHelper.isAggregatedGroup(record));
9361                 return !(record.getNotification().isGroupSummary() && isExemptedSummary);
9362             } else {
9363                 return !(record.getNotification().isGroupSummary()
9364                         && GroupHelper.AUTOGROUP_KEY.equals(record.getNotification().getGroup()));
9365             }
9366         }
9367     }
9368 
9369     private void unsnoozeAll() {
9370         synchronized (mNotificationLock) {
9371             mSnoozeHelper.repostAll(mUserProfiles.getCurrentProfileIds());
9372             handleSavePolicyFile();
9373         }
9374     }
9375 
9376     protected class CancelNotificationRunnable implements Runnable {
9377         private final int mCallingUid;
9378         private final int mCallingPid;
9379         private final String mPkg;
9380         private final String mTag;
9381         private final int mId;
9382         private final int mMustHaveFlags;
9383         private final int mMustNotHaveFlags;
9384         private final boolean mSendDelete;
9385         private final int mUserId;
9386         private final int mReason;
9387         private final int mRank;
9388         private final int mCount;
9389         private final ManagedServiceInfo mListener;
9390         private final long mCancellationElapsedTimeMs;
9391 
9392         CancelNotificationRunnable(final int callingUid, final int callingPid,
9393                 final String pkg, final String tag, final int id,
9394                 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
9395                 final int userId, final int reason, int rank, int count,
9396                 final ManagedServiceInfo listener,
9397                 @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
9398             this.mCallingUid = callingUid;
9399             this.mCallingPid = callingPid;
9400             this.mPkg = pkg;
9401             this.mTag = tag;
9402             this.mId = id;
9403             this.mMustHaveFlags = mustHaveFlags;
9404             this.mMustNotHaveFlags = mustNotHaveFlags;
9405             this.mSendDelete = sendDelete;
9406             this.mUserId = userId;
9407             this.mReason = reason;
9408             this.mRank = rank;
9409             this.mCount = count;
9410             this.mListener = listener;
9411             this.mCancellationElapsedTimeMs = cancellationElapsedTimeMs;
9412         }
9413 
9414         @Override
9415         public void run() {
9416             String listenerName = mListener == null ? null : mListener.component.toShortString();
9417             if (DBG) {
9418                 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
9419                         mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
9420             }
9421             int packageImportance = IMPORTANCE_NONE;
9422             if (lifetimeExtensionRefactor()) {
9423                 packageImportance = getPackageImportanceWithIdentity(mPkg);
9424             }
9425             synchronized (mNotificationLock) {
9426                 // Look for the notification, searching both the posted and enqueued lists.
9427                 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
9428 
9429                 if (r != null) {
9430                     // The notification was found, check if it should be removed.
9431                     // Ideally we'd do this in the caller of this method. However, that would
9432                     // require the caller to also find the notification.
9433                     if (mReason == REASON_CLICK) {
9434                         mUsageStats.registerClickedByUser(r);
9435                     }
9436 
9437                     if ((mReason == REASON_LISTENER_CANCEL
9438                             && r.getNotification().isBubbleNotification())
9439                             || (mReason == REASON_CLICK && r.canBubble()
9440                             && r.isFlagBubbleRemoved())) {
9441                         int flags = 0;
9442                         if (r.getNotification().getBubbleMetadata() != null) {
9443                             flags = r.getNotification().getBubbleMetadata().getFlags();
9444                         }
9445                         flags |= FLAG_SUPPRESS_NOTIFICATION;
9446                         mNotificationDelegate.onBubbleMetadataFlagChanged(r.getKey(), flags);
9447                         return;
9448                     }
9449                     if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
9450                         return;
9451                     }
9452                     if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
9453                         if (lifetimeExtensionRefactor()) {
9454                             // If cancellation will be prevented due to lifetime extension,
9455                             // we need to send an update to system UI first.
9456                             maybeNotifySystemUiListenerLifetimeExtendedLocked(r, mPkg,
9457                                     packageImportance);
9458                         }
9459                         return;
9460                     }
9461 
9462                     FlagChecker childrenFlagChecker = (flags) -> {
9463                             if (mReason == REASON_CANCEL
9464                                     || mReason == REASON_CLICK
9465                                     || mReason == REASON_CANCEL_ALL) {
9466                                 // Bubbled children get to stick around if the summary was manually
9467                                 // cancelled (user removed) from systemui.
9468                                 if ((flags & FLAG_BUBBLE) != 0) {
9469                                     return false;
9470                                 }
9471                             } else if (mReason == REASON_APP_CANCEL) {
9472                                 if ((flags & FLAG_FOREGROUND_SERVICE) != 0
9473                                         || (flags & FLAG_USER_INITIATED_JOB) != 0) {
9474                                     return false;
9475                                 }
9476                             }
9477                             if ((flags & mMustNotHaveFlags) != 0) {
9478                                 return false;
9479                             }
9480                             return true;
9481                         };
9482 
9483                     // Cancel the notification.
9484                     boolean wasPosted = removeFromNotificationListsLocked(r);
9485                     cancelNotificationLocked(
9486                             r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName,
9487                             mCancellationElapsedTimeMs);
9488                     if (r.getNotification().isGroupSummary()) {
9489                         cancelGroupChildrenLocked(mUserId, mPkg, mCallingUid, mCallingPid,
9490                                 listenerName, mSendDelete, childrenFlagChecker,
9491                                 NotificationManagerService::isChildOfCurrentGroupChecker,
9492                                 r.getGroupKey(), mReason, mCancellationElapsedTimeMs);
9493                     }
9494                     mAttentionHelper.updateLightsLocked();
9495                     if (mShortcutHelper != null) {
9496                         mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
9497                                 true /* isRemoved */);
9498                     }
9499                 } else {
9500                     if (notificationForceGrouping()) {
9501                         // No notification was found => maybe it was canceled by forced grouping
9502                         if (Flags.notificationForceGroupSingletons()) {
9503                             mGroupHelper.maybeCancelGroupChildrenForCanceledSummary(mPkg, mTag,
9504                                 mId, mUserId, mReason);
9505                         }
9506                     }
9507 
9508                     // No notification was found, assume that it is snoozed and cancel it.
9509                     if (mReason != REASON_SNOOZED) {
9510                         final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
9511                         if (wasSnoozed) {
9512                             handleSavePolicyFile();
9513                         }
9514                     }
9515                 }
9516             }
9517         }
9518     }
9519 
9520     protected static class ShowNotificationPermissionPromptRunnable implements Runnable {
9521         private final String mPkgName;
9522         private final int mUserId;
9523         private final int mTaskId;
9524         private final PermissionPolicyInternal mPpi;
9525 
9526         ShowNotificationPermissionPromptRunnable(String pkg, int user, int task,
9527                 PermissionPolicyInternal pPi) {
9528             mPkgName = pkg;
9529             mUserId = user;
9530             mTaskId = task;
9531             mPpi = pPi;
9532         }
9533 
9534         @Override
9535         public boolean equals(Object o) {
9536             if (!(o instanceof ShowNotificationPermissionPromptRunnable)) {
9537                 return false;
9538             }
9539 
9540             ShowNotificationPermissionPromptRunnable other =
9541                     (ShowNotificationPermissionPromptRunnable) o;
9542 
9543             return Objects.equals(mPkgName, other.mPkgName) && mUserId == other.mUserId
9544                     && mTaskId == other.mTaskId;
9545         }
9546 
9547         @Override
9548         public int hashCode() {
9549             return Objects.hash(mPkgName, mUserId, mTaskId);
9550         }
9551 
9552         @Override
9553         public void run() {
9554             mPpi.showNotificationPromptIfNeeded(mPkgName, mUserId, mTaskId);
9555         }
9556     }
9557 
9558     protected class EnqueueNotificationRunnable implements Runnable {
9559         private final NotificationRecord r;
9560         private final int userId;
9561         private final boolean isAppForeground;
9562         private final boolean isAppProvided;
9563         private final PostNotificationTracker mTracker;
9564 
9565         EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground,
9566                 boolean isAppProvided, PostNotificationTracker tracker) {
9567             this.userId = userId;
9568             this.r = r;
9569             this.isAppForeground = foreground;
9570             this.isAppProvided = isAppProvided;
9571             this.mTracker = checkNotNull(tracker);
9572         }
9573 
9574         @Override
9575         public void run() {
9576             boolean enqueued = false;
9577             try {
9578                 enqueued = enqueueNotification();
9579             } finally {
9580                 if (!enqueued) {
9581                     mTracker.cancel();
9582                 }
9583             }
9584         }
9585 
9586         /**
9587          * @return True if we successfully enqueued the notification and handed off the task of
9588          * posting it to a background thread; false otherwise.
9589          */
9590         private boolean enqueueNotification() {
9591             synchronized (mNotificationLock) {
9592                 // allowlistToken is populated by unparceling, so it will be absent if the
9593                 // EnqueueNotificationRunnable is created directly by NMS (as we do for group
9594                 // summaries) instead of via notify(). Fix that.
9595                 r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN);
9596 
9597                 final long snoozeAt =
9598                         mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
9599                                 r.getUser().getIdentifier(),
9600                                 r.getSbn().getPackageName(), r.getSbn().getKey());
9601                 final long currentTime = System.currentTimeMillis();
9602                 if (snoozeAt > currentTime) {
9603                     (new SnoozeNotificationRunnable(r.getSbn().getKey(),
9604                             snoozeAt - currentTime, null)).snoozeLocked(r);
9605                     return false;
9606                 }
9607 
9608                 final String contextId =
9609                         mSnoozeHelper.getSnoozeContextForUnpostedNotification(
9610                                 r.getUser().getIdentifier(),
9611                                 r.getSbn().getPackageName(), r.getSbn().getKey());
9612                 if (contextId != null) {
9613                     (new SnoozeNotificationRunnable(r.getSbn().getKey(),
9614                             0, contextId)).snoozeLocked(r);
9615                     return false;
9616                 }
9617 
9618                 mEnqueuedNotifications.add(r);
9619                 if (Flags.allNotifsNeedTtl()) {
9620                     mTtlHelper.scheduleTimeoutLocked(r, SystemClock.elapsedRealtime());
9621                 } else {
9622                     scheduleTimeoutLocked(r);
9623                 }
9624 
9625                 final StatusBarNotification n = r.getSbn();
9626                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
9627                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
9628                 if (old != null) {
9629                     // Retain ranking information from previous record
9630                     r.copyRankingInformation(old);
9631                 }
9632 
9633                 final int callingUid = n.getUid();
9634                 final int callingPid = n.getInitialPid();
9635                 final Notification notification = n.getNotification();
9636                 final String pkg = n.getPackageName();
9637                 final int id = n.getId();
9638                 final String tag = n.getTag();
9639 
9640                 // We need to fix the notification up a little for bubbles
9641                 updateNotificationBubbleFlags(r, isAppForeground);
9642 
9643                 // Handle grouped notifications and bail out early if we
9644                 // can to avoid extracting signals.
9645                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
9646 
9647                 // if this is a group child, unsnooze parent summary
9648                 if (n.isGroup() && notification.isGroupChild()) {
9649                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
9650                 }
9651 
9652                 // This conditional is a dirty hack to limit the logging done on
9653                 //     behalf of the download manager without affecting other apps.
9654                 if (!pkg.equals("com.android.providers.downloads")
9655                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
9656                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
9657                     if (old != null) {
9658                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
9659                     }
9660                     int appProvided = isAppProvided ? 1 : 0;
9661                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
9662                             pkg, id, tag, userId, notification.toString(),
9663                             enqueueStatus, appProvided);
9664                 }
9665 
9666                 // tell the assistant service about the notification
9667                 if (mAssistants.isEnabled()) {
9668                     mAssistants.onNotificationEnqueuedLocked(r);
9669                     mHandler.postDelayed(
9670                             new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
9671                                     r.getUid(), mTracker),
9672                             DELAY_FOR_ASSISTANT_TIME);
9673                 } else {
9674                     mHandler.post(
9675                             new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
9676                                     r.getUid(), mTracker));
9677                 }
9678                 return true;
9679             }
9680         }
9681     }
9682 
9683     @GuardedBy("mNotificationLock")
9684     boolean isPackagePausedOrSuspended(String pkg, int uid) {
9685         boolean isPaused;
9686 
9687         final PackageManagerInternal pmi = LocalServices.getService(
9688                 PackageManagerInternal.class);
9689         int flags = pmi.getDistractingPackageRestrictions(
9690                 pkg, Binder.getCallingUserHandle().getIdentifier());
9691         isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
9692 
9693         isPaused |= isPackageSuspendedForUser(pkg, uid);
9694 
9695         return isPaused;
9696     }
9697 
9698     protected class PostNotificationRunnable implements Runnable {
9699         private final String key;
9700         private final String pkg;
9701         private final int uid;
9702         private final PostNotificationTracker mTracker;
9703 
9704         PostNotificationRunnable(String key, String pkg, int uid, PostNotificationTracker tracker) {
9705             this.key = key;
9706             this.pkg = pkg;
9707             this.uid = uid;
9708             this.mTracker = checkNotNull(tracker);
9709         }
9710 
9711         @Override
9712         public void run() {
9713             boolean posted = false;
9714             try {
9715                 posted = postNotification();
9716             }  catch (Exception e) {
9717                 Slog.e(TAG, "Error posting", e);
9718             } finally {
9719                 if (!posted) {
9720                     mTracker.cancel();
9721                 }
9722             }
9723         }
9724 
9725         /**
9726          * @return True if we successfully processed the notification and handed off the task of
9727          * notifying all listeners to a background thread; false otherwise.
9728          */
9729         private boolean postNotification() {
9730             boolean appBanned = !areNotificationsEnabledForPackageInt(uid);
9731             boolean isCallNotification = isCallNotification(pkg, uid);
9732             boolean posted = false;
9733             synchronized (NotificationManagerService.this.mNotificationLock) {
9734                 try {
9735                     NotificationRecord r = findNotificationByListLocked(mEnqueuedNotifications,
9736                             key);
9737                     if (r == null) {
9738                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
9739                         return false;
9740                     }
9741 
9742                     final StatusBarNotification n = r.getSbn();
9743                     final Notification notification = n.getNotification();
9744                     boolean isCallNotificationAndCorrectStyle = isCallNotification
9745                             && notification.isStyle(Notification.CallStyle.class);
9746 
9747                     if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle)
9748                             && (appBanned || isRecordBlockedLocked(r))) {
9749                         mUsageStats.registerBlocked(r);
9750                         if (DBG) {
9751                             Slog.e(TAG, "Suppressing notification from package " + pkg);
9752                         }
9753                         return false;
9754                     }
9755 
9756                     if (notificationForceGrouping()) {
9757                         if (Flags.notificationForceGroupSingletons()) {
9758                             // Check if this is an updated for a summary for an aggregated sparse
9759                             // group and remove it because that summary has been canceled
9760                             if (mGroupHelper.isUpdateForCanceledSummary(r)) {
9761                                 if (DBG) {
9762                                     Log.w(TAG,
9763                                         "Suppressing notification because summary was canceled: "
9764                                             + r);
9765                                 }
9766 
9767                                 String groupKey = r.getGroupKey();
9768                                 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
9769                                 if (groupSummary != null && groupSummary.getKey()
9770                                         .equals(r.getKey())) {
9771                                     mSummaryByGroupKey.remove(groupKey);
9772                                 }
9773                                 return false;
9774                             }
9775                         }
9776                     }
9777 
9778 
9779                     final boolean isPackageSuspended =
9780                             isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid());
9781                     r.setHidden(isPackageSuspended);
9782                     if (isPackageSuspended) {
9783                         mUsageStats.registerSuspendedByAdmin(r);
9784                     }
9785                     NotificationRecord old = mNotificationsByKey.get(key);
9786 
9787                     // Make sure the SBN has an instance ID for statsd logging.
9788                     if (old == null || old.getSbn().getInstanceId() == null) {
9789                         n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
9790                     } else {
9791                         n.setInstanceId(old.getSbn().getInstanceId());
9792                     }
9793 
9794                     int index = indexOfNotificationLocked(n.getKey());
9795                     if (index < 0) {
9796                         mNotificationList.add(r);
9797                         mUsageStats.registerPostedByApp(r);
9798                         mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(),
9799                                 r.getSbn().getUser(), mTracker.getStartTime());
9800                         final boolean isInterruptive = isVisuallyInterruptive(null, r);
9801                         r.setInterruptive(isInterruptive);
9802                         r.setTextChanged(isInterruptive);
9803                     } else {
9804                         old = mNotificationList.get(index);  // Potentially *changes* old
9805                         mNotificationList.set(index, r);
9806                         mUsageStats.registerUpdatedByApp(r, old);
9807                         mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(),
9808                                 r.getSbn().getUser(), mTracker.getStartTime());
9809                         // Make sure we don't lose the foreground service state.
9810                         notification.flags |=
9811                                 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
9812                         r.isUpdate = true;
9813                         final boolean isInterruptive = isVisuallyInterruptive(old, r);
9814                         r.setTextChanged(isInterruptive);
9815                         if (sortSectionByTime()) {
9816                             if (isInterruptive) {
9817                                 r.resetRankingTime();
9818                             }
9819                         }
9820                     }
9821 
9822                     mNotificationsByKey.put(n.getKey(), r);
9823 
9824                     // Ensure if this is a foreground service that the proper additional
9825                     // flags are set.
9826                     if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
9827                         notification.flags |= FLAG_NO_CLEAR;
9828                     }
9829 
9830                     // Posts the notification if it has a small icon, and potentially autogroup
9831                     // the new notification.
9832                     if (android.app.Flags.checkAutogroupBeforePost()) {
9833                         if (notification.getSmallIcon() != null && !isCritical(r)) {
9834                             StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
9835                             if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())
9836                                     || !Objects.equals(oldSbn.getNotification().getGroup(),
9837                                         n.getNotification().getGroup())
9838                                     || oldSbn.getNotification().flags
9839                                     != n.getNotification().flags
9840                                     || !old.getChannel().getId().equals(r.getChannel().getId())) {
9841                                 synchronized (mNotificationLock) {
9842                                     final String autogroupName =
9843                                             notificationForceGrouping() ?
9844                                                 GroupHelper.getFullAggregateGroupKey(r)
9845                                                 : GroupHelper.AUTOGROUP_KEY;
9846                                     boolean willBeAutogrouped =
9847                                             mGroupHelper.onNotificationPosted(r,
9848                                                 hasAutoGroupSummaryLocked(r));
9849                                     if (willBeAutogrouped) {
9850                                         // The newly posted notification will be autogrouped, but
9851                                         // was not autogrouped onPost, to avoid an unnecessary sort.
9852                                         // We add the autogroup key to the notification without a
9853                                         // sort here, and it'll be sorted below with extractSignals.
9854                                         addAutogroupKeyLocked(key,
9855                                                 autogroupName, /*requestSort=*/false);
9856                                     } else {
9857                                         if (notificationForceGrouping()) {
9858                                             // Wait 3 seconds so that the app has a chance to post
9859                                             // a group summary or children (complete a group)
9860                                             mHandler.postDelayed(() -> {
9861                                                 synchronized (mNotificationLock) {
9862                                                     NotificationRecord record =
9863                                                             mNotificationsByKey.get(key);
9864                                                     if (record != null) {
9865                                                         mGroupHelper.onNotificationPostedWithDelay(
9866                                                                 record, mNotificationList,
9867                                                                 mSummaryByGroupKey);
9868                                                     }
9869                                                 }
9870                                             }, key, DELAY_FORCE_REGROUP_TIME);
9871                                         }
9872                                     }
9873 
9874                                 }
9875                             }
9876                         }
9877                     }
9878 
9879                     mRankingHelper.extractSignals(r);
9880                     mRankingHelper.sort(mNotificationList);
9881                     final int position = mRankingHelper.indexOf(mNotificationList, r);
9882 
9883                     int buzzBeepBlinkLoggingCode = 0;
9884                     if (!r.isHidden()) {
9885                         buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
9886                                 new NotificationAttentionHelper.Signals(
9887                                         mUserProfiles.isCurrentProfile(r.getUserId()),
9888                                         mListenerHints));
9889                     }
9890 
9891                     if (notification.getSmallIcon() != null) {
9892                         NotificationRecordLogger.NotificationReported maybeReport =
9893                                 mNotificationRecordLogger.prepareToLogNotificationPosted(r, old,
9894                                         position, buzzBeepBlinkLoggingCode,
9895                                         getGroupInstanceId(r.getSbn().getGroupKey()));
9896                         notifyListenersPostedAndLogLocked(r, old, mTracker, maybeReport);
9897                         posted = true;
9898 
9899                         if (!android.app.Flags.checkAutogroupBeforePost()) {
9900                             StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
9901                             if (oldSbn == null
9902                                     || !Objects.equals(oldSbn.getGroup(), n.getGroup())
9903                                     || oldSbn.getNotification().flags
9904                                         != n.getNotification().flags) {
9905                                 if (!isCritical(r)) {
9906                                     mHandler.post(() -> {
9907                                         synchronized (mNotificationLock) {
9908                                             mGroupHelper.onNotificationPosted(
9909                                                     r, hasAutoGroupSummaryLocked(r));
9910                                         }
9911                                     });
9912 
9913                                     if (notificationForceGrouping()) {
9914                                         mHandler.postDelayed(() -> {
9915                                             synchronized (mNotificationLock) {
9916                                                 NotificationRecord record =
9917                                                         mNotificationsByKey.get(key);
9918                                                 if (record != null) {
9919                                                     mGroupHelper.onNotificationPostedWithDelay(
9920                                                             record, mNotificationList,
9921                                                             mSummaryByGroupKey);
9922                                                 }
9923                                             }
9924                                         }, key, DELAY_FORCE_REGROUP_TIME);
9925                                     }
9926                                 }
9927                             }
9928                         }
9929                     } else {
9930                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
9931                         if (old != null && !old.isCanceled) {
9932                             mListeners.notifyRemovedLocked(r,
9933                                     REASON_ERROR, r.getStats());
9934                             if (notificationForceGrouping()) {
9935                                 mHandler.post(() -> {
9936                                     synchronized (mNotificationLock) {
9937                                         mGroupHelper.onNotificationRemoved(r, mNotificationList,
9938                                                 /* sendingDelete= */ false);
9939                                     }
9940                                 });
9941                             } else {
9942                                 mHandler.post(new Runnable() {
9943                                     @Override
9944                                     public void run() {
9945                                         mGroupHelper.onNotificationRemoved(r);
9946                                     }
9947                                 });
9948                             }
9949                         }
9950 
9951                         if (callstyleCallbackApi()) {
9952                             notifyCallNotificationEventListenerOnRemoved(r);
9953                         }
9954 
9955                         // ATTENTION: in a future release we will bail out here
9956                         // so that we do not play sounds, show lights, etc. for invalid
9957                         // notifications
9958                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
9959                                 + n.getPackageName());
9960                     }
9961 
9962                     if (mShortcutHelper != null) {
9963                         mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
9964                                 false /* isRemoved */);
9965                     }
9966 
9967                     maybeRecordInterruptionLocked(r);
9968                     maybeRegisterMessageSent(r);
9969                     maybeReportForegroundServiceUpdate(r, true);
9970                 } finally {
9971                     int N = mEnqueuedNotifications.size();
9972                     for (int i = 0; i < N; i++) {
9973                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
9974                         if (Objects.equals(key, enqueued.getKey())) {
9975                             mEnqueuedNotifications.remove(i);
9976                             break;
9977                         }
9978                     }
9979                 }
9980             }
9981             return posted;
9982         }
9983     }
9984 
9985     /**
9986      *
9987      */
9988     @GuardedBy("mNotificationLock")
9989     InstanceId getGroupInstanceId(String groupKey) {
9990         if (groupKey == null) {
9991             return null;
9992         }
9993         NotificationRecord group = mSummaryByGroupKey.get(groupKey);
9994         if (group == null) {
9995             return null;
9996         }
9997         return group.getSbn().getInstanceId();
9998     }
9999 
10000     /**
10001      * If the notification differs enough visually, consider it a new interruptive notification.
10002      */
10003     @GuardedBy("mNotificationLock")
10004     @VisibleForTesting
10005     protected boolean isVisuallyInterruptive(@Nullable NotificationRecord old,
10006             @NonNull NotificationRecord r) {
10007         // Ignore summary updates because we don't display most of the information.
10008         if (r.getSbn().isGroup() && r.getSbn().getNotification().isGroupSummary()) {
10009             if (DEBUG_INTERRUPTIVENESS) {
10010                 Slog.v(TAG, "INTERRUPTIVENESS: "
10011                         +  r.getKey() + " is not interruptive: summary");
10012             }
10013             return false;
10014         }
10015 
10016         if (old == null) {
10017             if (DEBUG_INTERRUPTIVENESS) {
10018                 Slog.v(TAG, "INTERRUPTIVENESS: "
10019                         +  r.getKey() + " is interruptive: new notification");
10020             }
10021             return true;
10022         }
10023 
10024         Notification oldN = old.getSbn().getNotification();
10025         Notification newN = r.getSbn().getNotification();
10026         if (oldN.extras == null || newN.extras == null) {
10027             if (DEBUG_INTERRUPTIVENESS) {
10028                 Slog.v(TAG, "INTERRUPTIVENESS: "
10029                         +  r.getKey() + " is not interruptive: no extras");
10030             }
10031             return false;
10032         }
10033 
10034         if (sortSectionByTime()) {
10035             // Ignore visual interruptions from FGS/UIJs because users
10036             // consider them one 'session'. Count them for everything else.
10037             if (r.getSbn().getNotification().isFgsOrUij()) {
10038                 if (DEBUG_INTERRUPTIVENESS) {
10039                     Slog.v(TAG, "INTERRUPTIVENESS: "
10040                             + r.getKey() + " is not interruptive: FGS/UIJ");
10041                 }
10042                 return false;
10043             }
10044         } else {
10045             // Ignore visual interruptions from foreground services because users
10046             // consider them one 'session'. Count them for everything else.
10047             if ((r.getSbn().getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
10048                 if (DEBUG_INTERRUPTIVENESS) {
10049                     Slog.v(TAG, "INTERRUPTIVENESS: "
10050                             + r.getKey() + " is not interruptive: foreground service");
10051                 }
10052                 return false;
10053             }
10054         }
10055 
10056         final String oldTitle = String.valueOf(oldN.extras.get(EXTRA_TITLE));
10057         final String newTitle = String.valueOf(newN.extras.get(EXTRA_TITLE));
10058         if (!Objects.equals(oldTitle, newTitle)) {
10059             if (DEBUG_INTERRUPTIVENESS) {
10060                 Slog.v(TAG, "INTERRUPTIVENESS: "
10061                         +  r.getKey() + " is interruptive: changed title");
10062                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old title: %s (%s@0x%08x)",
10063                         oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
10064                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new title: %s (%s@0x%08x)",
10065                         newTitle, newTitle.getClass(), newTitle.hashCode()));
10066             }
10067             return true;
10068         }
10069 
10070         // Do not compare Spannables (will always return false); compare unstyled Strings
10071         final String oldText = String.valueOf(oldN.extras.get(EXTRA_TEXT));
10072         final String newText = String.valueOf(newN.extras.get(EXTRA_TEXT));
10073         if (!Objects.equals(oldText, newText)) {
10074             if (DEBUG_INTERRUPTIVENESS) {
10075                 Slog.v(TAG, "INTERRUPTIVENESS: "
10076                         + r.getKey() + " is interruptive: changed text");
10077                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old text: %s (%s@0x%08x)",
10078                         oldText, oldText.getClass(), oldText.hashCode()));
10079                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new text: %s (%s@0x%08x)",
10080                         newText, newText.getClass(), newText.hashCode()));
10081             }
10082             return true;
10083         }
10084 
10085         if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
10086             if (DEBUG_INTERRUPTIVENESS) {
10087                 Slog.v(TAG, "INTERRUPTIVENESS: "
10088                     +  r.getKey() + " is interruptive: completed progress");
10089             }
10090             return true;
10091         }
10092 
10093         if (Notification.areIconsDifferent(oldN, newN)) {
10094             if (DEBUG_INTERRUPTIVENESS) {
10095                 Slog.v(TAG, "INTERRUPTIVENESS: "
10096                         +  r.getKey() + " is interruptive: icons differ");
10097             }
10098             return true;
10099         }
10100 
10101         // Fields below are invisible to bubbles.
10102         if (r.canBubble()) {
10103             if (DEBUG_INTERRUPTIVENESS) {
10104                 Slog.v(TAG, "INTERRUPTIVENESS: "
10105                         +  r.getKey() + " is not interruptive: bubble");
10106             }
10107             return false;
10108         }
10109 
10110         // Actions
10111         if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
10112             if (DEBUG_INTERRUPTIVENESS) {
10113                 Slog.v(TAG, "INTERRUPTIVENESS: "
10114                         +  r.getKey() + " is interruptive: changed actions");
10115             }
10116             return true;
10117         }
10118 
10119         try {
10120             Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
10121             Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
10122 
10123             // Style based comparisons
10124             if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
10125                 if (DEBUG_INTERRUPTIVENESS) {
10126                     Slog.v(TAG, "INTERRUPTIVENESS: "
10127                             +  r.getKey() + " is interruptive: styles differ");
10128                 }
10129                 return true;
10130             }
10131 
10132             // Remote views
10133             if (Notification.areRemoteViewsChanged(oldB, newB)) {
10134                 if (DEBUG_INTERRUPTIVENESS) {
10135                     Slog.v(TAG, "INTERRUPTIVENESS: "
10136                             +  r.getKey() + " is interruptive: remoteviews differ");
10137                 }
10138                 return true;
10139             }
10140         } catch (Exception e) {
10141             Slog.w(TAG, "error recovering builder", e);
10142         }
10143         return false;
10144     }
10145 
10146     /**
10147      * Check if the notification is classified as critical.
10148      *
10149      * @param record the record to test for criticality
10150      * @return {@code true} if notification is considered critical
10151      *
10152      * @see CriticalNotificationExtractor for criteria
10153      */
10154     private boolean isCritical(NotificationRecord record) {
10155         // 0 is the most critical
10156         return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
10157     }
10158 
10159     /**
10160      *  Check if the notification was a summary that has been auto-grouped
10161      * @param r the current notification record
10162      * @param old the previous notification record
10163      * @return true if the notification record was a summary that was auto-grouped
10164      */
10165     @GuardedBy("mNotificationLock")
10166     private boolean wasSummaryAutogrouped(NotificationRecord r, NotificationRecord old) {
10167         boolean wasAutogrouped = false;
10168         if (old != null) {
10169             boolean wasSummary = (old.mOriginalFlags & FLAG_GROUP_SUMMARY) != 0;
10170             boolean wasForcedGrouped = (old.getFlags() & FLAG_GROUP_SUMMARY) == 0
10171                     && old.getSbn().getOverrideGroupKey() != null;
10172             boolean isNotAutogroupSummary = (r.getFlags() & FLAG_AUTOGROUP_SUMMARY) == 0
10173                     && (r.getFlags() & FLAG_GROUP_SUMMARY) != 0;
10174             if ((wasSummary && wasForcedGrouped) || (wasForcedGrouped && isNotAutogroupSummary)) {
10175                 wasAutogrouped = true;
10176             }
10177         }
10178         return wasAutogrouped;
10179     }
10180 
10181     /**
10182      * Ensures that grouped notification receive their special treatment.
10183      *
10184      * <p>Cancels group children if the new notification causes a group to lose
10185      * its summary.</p>
10186      *
10187      * <p>Updates mSummaryByGroupKey.</p>
10188      */
10189     @GuardedBy("mNotificationLock")
10190     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
10191             int callingUid, int callingPid) {
10192         StatusBarNotification sbn = r.getSbn();
10193         Notification n = sbn.getNotification();
10194         if (n.isGroupSummary() && !sbn.isAppGroup())  {
10195             // notifications without a group shouldn't be a summary, otherwise autobundling can
10196             // lead to bugs
10197             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
10198         }
10199 
10200         if (notificationForceGrouping()) {
10201             // If this is an update to a summary that was forced grouped => remove summary flag
10202             if (wasSummaryAutogrouped(r, old)) {
10203                 n.flags &= ~FLAG_GROUP_SUMMARY;
10204             }
10205         }
10206 
10207         String group = sbn.getGroupKey();
10208         boolean isSummary = n.isGroupSummary();
10209 
10210         Notification oldN = old != null ? old.getSbn().getNotification() : null;
10211         String oldGroup = old != null ? old.getSbn().getGroupKey() : null;
10212         boolean oldIsSummary = old != null && oldN.isGroupSummary();
10213 
10214         if (oldIsSummary) {
10215             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
10216             if (removedSummary != old) {
10217                 String removedKey =
10218                         removedSummary != null ? removedSummary.getKey() : "<null>";
10219                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
10220                         ", removed=" + removedKey);
10221             }
10222         }
10223         if (isSummary) {
10224             mSummaryByGroupKey.put(group, r);
10225 
10226             if (notificationForceGrouping()) {
10227                 // If any formerly-ungrouped notifications will be grouped by this summary, update
10228                 // accordingly.
10229                 mGroupHelper.onGroupSummaryAdded(r, mNotificationList);
10230             }
10231         }
10232 
10233         FlagChecker childrenFlagChecker = (flags) -> {
10234             if ((flags & FLAG_FOREGROUND_SERVICE) != 0 || (flags & FLAG_USER_INITIATED_JOB) != 0) {
10235                 return false;
10236             }
10237             return true;
10238         };
10239 
10240         // Clear out group children of the old notification if the update
10241         // causes the group summary to go away. This happens when the old
10242         // notification was a summary and the new one isn't, or when the old
10243         // notification was a summary and its group key changed.
10244         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
10245             cancelGroupChildrenLocked(old.getUserId(), old.getSbn().getPackageName(), callingUid,
10246                     callingPid, null, false /* sendDelete */, childrenFlagChecker,
10247                     NotificationManagerService::isChildOfCurrentGroupChecker, old.getGroupKey(),
10248                     REASON_APP_CANCEL, SystemClock.elapsedRealtime());
10249         }
10250     }
10251 
10252     private PendingIntent getNotificationTimeoutPendingIntent(NotificationRecord record,
10253             int flags) {
10254         flags |= PendingIntent.FLAG_IMMUTABLE;
10255         return PendingIntent.getBroadcast(getContext(),
10256                 REQUEST_CODE_TIMEOUT,
10257                 new Intent(ACTION_NOTIFICATION_TIMEOUT)
10258                         .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
10259                         .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
10260                                 .appendPath(record.getKey()).build())
10261                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
10262                         .putExtra(EXTRA_KEY, record.getKey()),
10263                 flags);
10264     }
10265 
10266     @VisibleForTesting
10267     @GuardedBy("mNotificationLock")
10268     void scheduleTimeoutLocked(NotificationRecord record) {
10269         if (record.getNotification().getTimeoutAfter() > 0) {
10270             final PendingIntent pi = getNotificationTimeoutPendingIntent(
10271                     record, PendingIntent.FLAG_UPDATE_CURRENT);
10272             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
10273                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
10274         }
10275     }
10276 
10277     @VisibleForTesting
10278     @GuardedBy("mNotificationLock")
10279     void cancelScheduledTimeoutLocked(NotificationRecord record) {
10280         final PendingIntent pi = getNotificationTimeoutPendingIntent(
10281                 record, PendingIntent.FLAG_CANCEL_CURRENT);
10282         if (pi != null) {
10283             mAlarmManager.cancel(pi);
10284         }
10285     }
10286 
10287     @GuardedBy("mToastQueue")
10288     void showNextToastLocked(boolean lastToastWasTextRecord) {
10289         if (mIsCurrentToastShown) {
10290             return; // Don't show the same toast twice.
10291         }
10292 
10293         ToastRecord record = mToastQueue.get(0);
10294         while (record != null) {
10295             int userId = UserHandle.getUserId(record.uid);
10296             boolean rateLimitingEnabled =
10297                     !mToastRateLimitingDisabledUids.contains(record.uid);
10298             boolean isWithinQuota =
10299                     mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG)
10300                             || isExemptFromRateLimiting(record.pkg, userId);
10301             boolean isPackageInForeground = isPackageInForegroundForToast(record.uid);
10302 
10303             if (tryShowToast(
10304                     record, rateLimitingEnabled, isWithinQuota, isPackageInForeground)) {
10305                 scheduleDurationReachedLocked(record, lastToastWasTextRecord);
10306                 mIsCurrentToastShown = true;
10307                 if (rateLimitingEnabled && !isPackageInForeground) {
10308                     mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG);
10309                 }
10310                 return;
10311             }
10312 
10313             int index = mToastQueue.indexOf(record);
10314             if (index >= 0) {
10315                 ToastRecord toast = mToastQueue.remove(index);
10316                 mWindowManagerInternal.removeWindowToken(
10317                         toast.windowToken, true /* removeWindows */, toast.displayId);
10318             }
10319             record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null;
10320         }
10321     }
10322 
10323     /** Returns true if it successfully showed the toast. */
10324     private boolean tryShowToast(ToastRecord record, boolean rateLimitingEnabled,
10325             boolean isWithinQuota, boolean isPackageInForeground) {
10326         if (rateLimitingEnabled && !isWithinQuota && !isPackageInForeground) {
10327             reportCompatRateLimitingToastsChange(record.uid);
10328             Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the "
10329                     + "following toast was blocked and discarded: " + record);
10330             return false;
10331         }
10332         if (blockToast(record.uid, record.isSystemToast, record.isAppRendered(),
10333                 isPackageInForeground)) {
10334             Slog.w(TAG, "Blocking custom toast from package " + record.pkg
10335                     + " due to package not in the foreground at the time of showing the toast");
10336             return false;
10337         }
10338         return record.show();
10339     }
10340 
10341     private boolean isExemptFromRateLimiting(String pkg, int userId) {
10342         boolean isExemptFromRateLimiting = false;
10343         try {
10344             isExemptFromRateLimiting = mPackageManager.checkPermission(
10345                     android.Manifest.permission.UNLIMITED_TOASTS, pkg, userId)
10346                     == PERMISSION_GRANTED;
10347         } catch (RemoteException e) {
10348             Slog.e(TAG, "Failed to connect with package manager");
10349         }
10350         return isExemptFromRateLimiting;
10351     }
10352 
10353     /** Reports rate limiting toasts compat change (used when the toast was blocked). */
10354     private void reportCompatRateLimitingToastsChange(int uid) {
10355         final long id = Binder.clearCallingIdentity();
10356         try {
10357             mPlatformCompat.reportChangeByUid(RATE_LIMIT_TOASTS, uid);
10358         } catch (RemoteException e) {
10359             Slog.e(TAG, "Unexpected exception while reporting toast was blocked due to rate"
10360                     + " limiting", e);
10361         } finally {
10362             Binder.restoreCallingIdentity(id);
10363         }
10364     }
10365 
10366     @GuardedBy("mToastQueue")
10367     void cancelToastLocked(int index) {
10368         ToastRecord record = mToastQueue.get(index);
10369         record.hide();
10370 
10371         if (index == 0) {
10372             mIsCurrentToastShown = false;
10373         }
10374 
10375         ToastRecord lastToast = mToastQueue.remove(index);
10376 
10377         // We need to schedule a timeout to make sure the token is eventually killed
10378         scheduleKillTokenTimeout(lastToast);
10379 
10380         keepProcessAliveForToastIfNeededLocked(record.pid);
10381         if (mToastQueue.size() > 0) {
10382             // Show the next one. If the callback fails, this will remove
10383             // it from the list, so don't assume that the list hasn't changed
10384             // after this point.
10385             showNextToastLocked(lastToast instanceof TextToastRecord);
10386         }
10387     }
10388 
10389     void finishWindowTokenLocked(IBinder t, int displayId) {
10390         mHandler.removeCallbacksAndMessages(t);
10391         // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
10392         // remaining surfaces as either the client has called finishToken indicating
10393         // it has successfully removed the views, or the client has timed out
10394         // at which point anything goes.
10395         mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
10396     }
10397 
10398     @GuardedBy("mToastQueue")
10399     private void scheduleDurationReachedLocked(ToastRecord r, boolean lastToastWasTextRecord)
10400     {
10401         mHandler.removeCallbacksAndMessages(r);
10402         Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
10403         int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
10404         // Accessibility users may need longer timeout duration. This api compares original delay
10405         // with user's preference and return longer one. It returns original delay if there's no
10406         // preference.
10407         delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
10408                 AccessibilityManager.FLAG_CONTENT_TEXT);
10409 
10410         if (lastToastWasTextRecord) {
10411             delay += 250; // delay to account for previous toast's "out" animation
10412         }
10413         if (r instanceof TextToastRecord) {
10414             delay += 333; // delay to account for this toast's "in" animation
10415         }
10416 
10417         mHandler.sendMessageDelayed(m, delay);
10418     }
10419 
10420     private void handleDurationReached(ToastRecord record)
10421     {
10422         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " token=" + record.token);
10423         synchronized (mToastQueue) {
10424             int index = indexOfToastLocked(record.pkg, record.token);
10425             if (index >= 0) {
10426                 cancelToastLocked(index);
10427             }
10428         }
10429     }
10430 
10431     @GuardedBy("mToastQueue")
10432     private void scheduleKillTokenTimeout(ToastRecord r)
10433     {
10434         mHandler.removeCallbacksAndMessages(r);
10435         Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
10436         mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
10437     }
10438 
10439     private void handleKillTokenTimeout(ToastRecord record)
10440     {
10441         if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.windowToken);
10442         synchronized (mToastQueue) {
10443             finishWindowTokenLocked(record.windowToken, record.displayId);
10444         }
10445     }
10446 
10447     @GuardedBy("mToastQueue")
10448     int indexOfToastLocked(String pkg, IBinder token) {
10449         ArrayList<ToastRecord> list = mToastQueue;
10450         int len = list.size();
10451         for (int i=0; i<len; i++) {
10452             ToastRecord r = list.get(i);
10453             if (r.pkg.equals(pkg) && r.token == token) {
10454                 return i;
10455             }
10456         }
10457         return -1;
10458     }
10459 
10460     /**
10461      * Adjust process {@code pid} importance according to whether it has toasts in the queue or not.
10462      */
10463     public void keepProcessAliveForToastIfNeeded(int pid) {
10464         synchronized (mToastQueue) {
10465             keepProcessAliveForToastIfNeededLocked(pid);
10466         }
10467     }
10468 
10469     @GuardedBy("mToastQueue")
10470     private void keepProcessAliveForToastIfNeededLocked(int pid) {
10471         int toastCount = 0; // toasts from this pid, rendered by the app
10472         ArrayList<ToastRecord> list = mToastQueue;
10473         int n = list.size();
10474         for (int i = 0; i < n; i++) {
10475             ToastRecord r = list.get(i);
10476             if (r.pid == pid && r.keepProcessAlive()) {
10477                 toastCount++;
10478             }
10479         }
10480         try {
10481             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
10482         } catch (RemoteException e) {
10483             // Shouldn't happen.
10484         }
10485     }
10486 
10487     /**
10488      * Implementation note: Our definition of foreground for toasts is an implementation matter
10489      * and should strike a balance between functionality and anti-abuse effectiveness. We
10490      * currently worry about the following cases:
10491      * <ol>
10492      *     <li>App with fullscreen activity: Allow toasts
10493      *     <li>App behind translucent activity from other app: Block toasts
10494      *     <li>App in multi-window: Allow toasts
10495      *     <li>App with expanded bubble: Allow toasts
10496      *     <li>App posting toasts on onCreate(), onStart(), onResume(): Allow toasts
10497      *     <li>App posting toasts on onPause(), onStop(), onDestroy(): Block toasts
10498      * </ol>
10499      * Checking if the UID has any resumed activities satisfy use-cases above.
10500      *
10501      * <p>Checking if {@code mActivityManager.getUidImportance(callingUid) ==
10502      * IMPORTANCE_FOREGROUND} does not work because it considers the app in foreground if it has
10503      * any visible activities, failing case 2 in list above.
10504      */
10505     private boolean isPackageInForegroundForToast(int callingUid) {
10506         return mAtm.hasResumedActivity(callingUid);
10507     }
10508 
10509     /**
10510      * True if the toast should be blocked. It will return true if all of the following conditions
10511      * apply: it's a custom toast, it's not a system toast, the package that sent the toast is in
10512      * the background and CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is enabled.
10513      *
10514      * CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so it will return false for apps
10515      * with targetSdk < R. For apps with targetSdk R+, text toasts are not app-rendered, so
10516      * isAppRenderedToast == true means it's a custom toast.
10517      */
10518     private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast,
10519             boolean isPackageInForeground) {
10520         return isAppRenderedToast
10521                 && !isSystemToast
10522                 && !isPackageInForeground
10523                 && CompatChanges.isChangeEnabled(CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, uid);
10524     }
10525 
10526     private void handleRankingReconsideration(Message message) {
10527         if (!(message.obj instanceof RankingReconsideration)) return;
10528         RankingReconsideration recon = (RankingReconsideration) message.obj;
10529         recon.run();
10530         boolean changed;
10531         synchronized (mNotificationLock) {
10532             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
10533             if (record == null) {
10534                 return;
10535             }
10536             int indexBefore = findNotificationRecordIndexLocked(record);
10537             boolean interceptBefore = record.isIntercepted();
10538             int visibilityBefore = record.getPackageVisibilityOverride();
10539             boolean interruptiveBefore = record.isInterruptive();
10540 
10541             recon.applyChangesLocked(record);
10542             applyZenModeLocked(record);
10543             mRankingHelper.sort(mNotificationList);
10544             boolean indexChanged = indexBefore != findNotificationRecordIndexLocked(record);
10545             boolean interceptChanged = interceptBefore != record.isIntercepted();
10546             boolean visibilityChanged = visibilityBefore != record.getPackageVisibilityOverride();
10547 
10548             // Broadcast isInterruptive changes for bubbles.
10549             boolean interruptiveChanged =
10550                     record.canBubble() && (interruptiveBefore != record.isInterruptive());
10551 
10552             changed = indexChanged
10553                     || interceptChanged
10554                     || visibilityChanged
10555                     || interruptiveChanged;
10556             if (interceptBefore && !record.isIntercepted()
10557                     && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
10558 
10559                 mAttentionHelper.buzzBeepBlinkLocked(record,
10560                         new NotificationAttentionHelper.Signals(mUserProfiles.isCurrentProfile(
10561                                 record.getUserId()), mListenerHints));
10562 
10563                 // Log alert after change in intercepted state to Zen Log as well
10564                 ZenLog.traceAlertOnUpdatedIntercept(record);
10565             }
10566         }
10567         if (changed) {
10568             mHandler.scheduleSendRankingUpdate();
10569         }
10570     }
10571 
10572     void handleRankingSort() {
10573         if (mRankingHelper == null) return;
10574         synchronized (mNotificationLock) {
10575             final int N = mNotificationList.size();
10576             // Any field that can change via one of the extractors needs to be added here.
10577             ArrayMap<String, NotificationRecordExtractorData> extractorDataBefore =
10578                     new ArrayMap<>(N);
10579             for (int i = 0; i < N; i++) {
10580                 final NotificationRecord r = mNotificationList.get(i);
10581                 NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData(
10582                         i,
10583                         r.getPackageVisibilityOverride(),
10584                         r.canShowBadge(),
10585                         r.canBubble(),
10586                         r.getNotification().isBubbleNotification(),
10587                         r.getChannel(),
10588                         r.getGroupKey(),
10589                         r.getPeopleOverride(),
10590                         r.getSnoozeCriteria(),
10591                         r.getUserSentiment(),
10592                         r.getSuppressedVisualEffects(),
10593                         r.getSystemGeneratedSmartActions(),
10594                         r.getSmartReplies(),
10595                         r.getImportance(),
10596                         r.getRankingScore(),
10597                         r.isConversation(),
10598                         r.getProposedImportance(),
10599                         r.hasSensitiveContent(),
10600                         r.getSummarization());
10601                 extractorDataBefore.put(r.getKey(), extractorData);
10602                 mRankingHelper.extractSignals(r);
10603             }
10604             mRankingHelper.sort(mNotificationList);
10605             for (int i = 0; i < N; i++) {
10606                 final NotificationRecord r = mNotificationList.get(i);
10607                 if (!extractorDataBefore.containsKey(r.getKey())) {
10608                     // This shouldn't happen given that we just built this with all the
10609                     // notifications, but check just to be safe.
10610                     continue;
10611                 }
10612                 if (extractorDataBefore.get(r.getKey()).hasDiffForRankingLocked(r, i)) {
10613                     mHandler.scheduleSendRankingUpdate();
10614                 }
10615 
10616                 // If this notification is one for which we wanted to log an update, and
10617                 // sufficient relevant bits are different, log update.
10618                 if (r.hasPendingLogUpdate()) {
10619                     // We need to acquire the previous data associated with this specific
10620                     // notification, as the one at the current index may be unrelated if
10621                     // notification order has changed.
10622                     NotificationRecordExtractorData prevData = extractorDataBefore.get(r.getKey());
10623                     if (prevData.hasDiffForLoggingLocked(r, i)) {
10624                         mNotificationRecordLogger.logNotificationAdjusted(r, i, 0,
10625                                 getGroupInstanceId(r.getSbn().getGroupKey()));
10626                     }
10627 
10628                     // Remove whether there was a diff or not; we've sorted the key, so if it
10629                     // turns out there was nothing to log, that's fine too.
10630                     r.setPendingLogUpdate(false);
10631                 }
10632             }
10633         }
10634     }
10635 
10636     @GuardedBy("mNotificationLock")
10637     private void recordCallerLocked(NotificationRecord record) {
10638         if (mZenModeHelper.isCall(record)) {
10639             mZenModeHelper.recordCaller(record);
10640         }
10641     }
10642 
10643     // let zen mode evaluate this record
10644     @GuardedBy("mNotificationLock")
10645     private void applyZenModeLocked(NotificationRecord record) {
10646         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
10647         if (record.isIntercepted()) {
10648             record.setSuppressedVisualEffects(
10649                     mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
10650         } else {
10651             record.setSuppressedVisualEffects(0);
10652         }
10653     }
10654 
10655     @GuardedBy("mNotificationLock")
10656     private int findNotificationRecordIndexLocked(NotificationRecord target) {
10657         return mRankingHelper.indexOf(mNotificationList, target);
10658     }
10659 
10660     private void handleSendRankingUpdate() {
10661         synchronized (mNotificationLock) {
10662             mListeners.notifyRankingUpdateLocked(null);
10663         }
10664     }
10665 
10666     private void scheduleListenerHintsChanged(int state) {
10667         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
10668         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
10669     }
10670 
10671     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
10672         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
10673         mHandler.obtainMessage(
10674                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
10675                 listenerInterruptionFilter,
10676                 0).sendToTarget();
10677     }
10678 
10679     private void handleListenerHintsChanged(int hints) {
10680         synchronized (mNotificationLock) {
10681             mListeners.notifyListenerHintsChangedLocked(hints);
10682         }
10683     }
10684 
10685     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
10686         synchronized (mNotificationLock) {
10687             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
10688         }
10689     }
10690 
10691     void handleOnPackageChanged(boolean removingPackage, int changeUserId,
10692             String[] pkgList, int[] uidList) {
10693         boolean preferencesChanged = removingPackage;
10694         mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
10695         mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
10696         mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
10697         preferencesChanged |= mPreferencesHelper.onPackagesChanged(
10698                 removingPackage, changeUserId, pkgList, uidList);
10699         if (removingPackage) {
10700             int size = Math.min(pkgList.length, uidList.length);
10701             for (int i = 0; i < size; i++) {
10702                 final String pkg = pkgList[i];
10703                 final int uid = uidList[i];
10704                 final int userHandle = UserHandle.getUserId(uid);
10705                 // Removes this package's notifications from both recent notification archive
10706                 // (recently dismissed notifications) and notification history.
10707                 mArchive.removePackageNotifications(pkg, userHandle);
10708                 mHistoryManager.onPackageRemoved(userHandle, pkg);
10709             }
10710         }
10711         if (preferencesChanged) {
10712             handleSavePolicyFile();
10713         }
10714     }
10715 
10716     protected class WorkerHandler extends Handler
10717     {
10718         public WorkerHandler(Looper looper) {
10719             super(looper);
10720         }
10721 
10722         @Override
10723         public void handleMessage(Message msg)
10724         {
10725             switch (msg.what)
10726             {
10727                 case MESSAGE_DURATION_REACHED:
10728                     handleDurationReached((ToastRecord) msg.obj);
10729                     break;
10730                 case MESSAGE_FINISH_TOKEN_TIMEOUT:
10731                     handleKillTokenTimeout((ToastRecord) msg.obj);
10732                     break;
10733                 case MESSAGE_SEND_RANKING_UPDATE:
10734                     handleSendRankingUpdate();
10735                     break;
10736                 case MESSAGE_LISTENER_HINTS_CHANGED:
10737                     handleListenerHintsChanged(msg.arg1);
10738                     break;
10739                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
10740                     handleListenerInterruptionFilterChanged(msg.arg1);
10741                     break;
10742                 case MESSAGE_ON_PACKAGE_CHANGED:
10743                     SomeArgs args = (SomeArgs) msg.obj;
10744                     handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2,
10745                             (int[]) args.arg3);
10746                     args.recycle();
10747                     break;
10748             }
10749         }
10750 
10751         protected void scheduleSendRankingUpdate() {
10752             if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
10753                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
10754                 sendMessage(m);
10755             }
10756         }
10757 
10758         protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable,
10759                                                   int delay) {
10760             if (lifetimeExtensionRefactor()) {
10761                 sendMessageDelayed(Message.obtain(this, cancelRunnable), delay);
10762             } else {
10763                 if (!hasCallbacks(cancelRunnable)) {
10764                     sendMessage(Message.obtain(this, cancelRunnable));
10765                 }
10766             }
10767         }
10768 
10769         protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId,
10770                 String[] pkgList, int[] uidList) {
10771             SomeArgs args = SomeArgs.obtain();
10772             args.arg1 = removingPackage;
10773             args.argi1 = changeUserId;
10774             args.arg2 = pkgList;
10775             args.arg3 = uidList;
10776             sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args));
10777         }
10778     }
10779 
10780     private final class RankingHandlerWorker extends Handler implements RankingHandler
10781     {
10782         public RankingHandlerWorker(Looper looper) {
10783             super(looper);
10784         }
10785 
10786         @Override
10787         public void handleMessage(Message msg) {
10788             switch (msg.what) {
10789                 case MESSAGE_RECONSIDER_RANKING:
10790                     handleRankingReconsideration(msg);
10791                     break;
10792                 case MESSAGE_RANKING_SORT:
10793                     handleRankingSort();
10794                     break;
10795             }
10796         }
10797 
10798         public void requestSort() {
10799             removeMessages(MESSAGE_RANKING_SORT);
10800             Message msg = Message.obtain();
10801             msg.what = MESSAGE_RANKING_SORT;
10802             sendMessage(msg);
10803         }
10804 
10805         public void requestReconsideration(RankingReconsideration recon) {
10806             Message m = Message.obtain(this,
10807                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
10808             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
10809             sendMessageDelayed(m, delay);
10810         }
10811     }
10812 
10813     // Notifications
10814     // ============================================================================
10815     static int clamp(int x, int low, int high) {
10816         return (x < low) ? low : ((x > high) ? high : x);
10817     }
10818 
10819     /**
10820      * Removes all NotificationsRecords with the same key as the given notification record
10821      * from both lists. Do not call this method while iterating over either list.
10822      */
10823     @GuardedBy("mNotificationLock")
10824     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
10825         // Remove from both lists, either list could have a separate Record for what is
10826         // effectively the same notification.
10827         boolean wasPosted = false;
10828         NotificationRecord recordInList = null;
10829         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
10830                 != null) {
10831             mNotificationList.remove(recordInList);
10832             mNotificationsByKey.remove(recordInList.getSbn().getKey());
10833             wasPosted = true;
10834         }
10835         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
10836                 != null) {
10837             mEnqueuedNotifications.remove(recordInList);
10838         }
10839         return wasPosted;
10840     }
10841 
10842     @GuardedBy("mNotificationLock")
10843     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete,
10844             @NotificationListenerService.NotificationCancelReason int reason,
10845             boolean wasPosted, String listenerName,
10846             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
10847         cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName,
10848                 cancellationElapsedTimeMs);
10849     }
10850 
10851     @GuardedBy("mNotificationLock")
10852     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete,
10853             @NotificationListenerService.NotificationCancelReason int reason,
10854             int rank, int count, boolean wasPosted, String listenerName,
10855             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
10856         final String canceledKey = r.getKey();
10857         if (Flags.allNotifsNeedTtl()) {
10858             mTtlHelper.cancelScheduledTimeoutLocked(r);
10859         } else {
10860             cancelScheduledTimeoutLocked(r);
10861         }
10862 
10863         // Record caller.
10864         recordCallerLocked(r);
10865 
10866         if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
10867             r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
10868         }
10869 
10870         // tell the app
10871         if (sendDelete) {
10872             sendDeleteIntent(r.getNotification().deleteIntent, r.getSbn().getPackageName());
10873         }
10874 
10875         // Only cancel these if this notification actually got to be posted.
10876         if (wasPosted) {
10877             // status bar
10878             if (r.getNotification().getSmallIcon() != null) {
10879                 if (reason != REASON_SNOOZED) {
10880                     r.isCanceled = true;
10881                 }
10882                 mListeners.notifyRemovedLocked(r, reason, r.getStats());
10883                 if (notificationForceGrouping()) {
10884                     mHandler.removeCallbacksAndEqualMessages(r.getKey());
10885                     mHandler.post(() -> {
10886                         synchronized (NotificationManagerService.this.mNotificationLock) {
10887                             mGroupHelper.onNotificationRemoved(r, mNotificationList, sendDelete);
10888                         }
10889                     });
10890 
10891                     // Wait 3 seconds so that the app has a chance to cancel/post
10892                     // a group summary or children
10893                     final NotificationRecord groupSummary = mSummaryByGroupKey.get(r.getGroupKey());
10894                     if (groupSummary != null
10895                             && !GroupHelper.isAggregatedGroup(groupSummary)
10896                             && !groupSummary.getKey().equals(canceledKey)) {
10897                         // We only care about app-provided valid group summaries
10898                         final String summaryKey = groupSummary.getKey();
10899                         mHandler.removeCallbacksAndEqualMessages(summaryKey);
10900                         mHandler.postDelayed(() -> {
10901                             synchronized (mNotificationLock) {
10902                                 NotificationRecord summaryRecord = mNotificationsByKey.get(
10903                                         summaryKey);
10904                                 if (summaryRecord != null) {
10905                                     mGroupHelper.onGroupedNotificationRemovedWithDelay(
10906                                             summaryRecord, mNotificationList, mSummaryByGroupKey);
10907                                 }
10908                             }
10909                         }, summaryKey, DELAY_FORCE_REGROUP_TIME);
10910                     }
10911                 } else {
10912                     mHandler.post(new Runnable() {
10913                         @Override
10914                         public void run() {
10915                             mGroupHelper.onNotificationRemoved(r);
10916                         }
10917                     });
10918                 }
10919                 if (callstyleCallbackApi()) {
10920                     notifyCallNotificationEventListenerOnRemoved(r);
10921                 }
10922             }
10923 
10924             mAttentionHelper.clearEffectsLocked(canceledKey);
10925         }
10926 
10927         // Record usage stats
10928         // TODO: add unbundling stats?
10929         switch (reason) {
10930             case REASON_CANCEL:
10931             case REASON_CANCEL_ALL:
10932             case REASON_LISTENER_CANCEL:
10933             case REASON_LISTENER_CANCEL_ALL:
10934                 mUsageStats.registerDismissedByUser(r);
10935                 break;
10936             case REASON_APP_CANCEL:
10937             case REASON_APP_CANCEL_ALL:
10938                 mUsageStats.registerRemovedByApp(r);
10939                 mUsageStatsManagerInternal.reportNotificationRemoved(r.getSbn().getOpPkg(),
10940                         r.getUser(), cancellationElapsedTimeMs);
10941                 break;
10942         }
10943 
10944         String groupKey = r.getGroupKey();
10945         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
10946         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
10947             mSummaryByGroupKey.remove(groupKey);
10948         }
10949         final ArrayMap<String, String> summaries =
10950                 mAutobundledSummaries.get(r.getSbn().getUserId());
10951         final String autbundledGroupKey;
10952         if (notificationForceGrouping()) {
10953             autbundledGroupKey = groupKey;
10954         } else {
10955             autbundledGroupKey = r.getSbn().getPackageName();
10956         }
10957         if (summaries != null && r.getSbn().getKey().equals(
10958                 summaries.get(autbundledGroupKey))) {
10959             summaries.remove(autbundledGroupKey);
10960         }
10961 
10962         // Save it for users of getHistoricalNotifications(), unless the whole channel was deleted
10963         if (reason != REASON_CHANNEL_REMOVED) {
10964             mArchive.record(r.getSbn(), reason);
10965         }
10966 
10967         final long now = System.currentTimeMillis();
10968         final LogMaker logMaker = r.getItemLogMaker()
10969                 .setType(MetricsEvent.TYPE_DISMISS)
10970                 .setSubtype(reason);
10971         if (rank != -1 && count != -1) {
10972             logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
10973                     .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
10974         }
10975         MetricsLogger.action(logMaker);
10976         EventLogTags.writeNotificationCanceled(canceledKey, reason,
10977                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
10978                 rank, count, listenerName);
10979         if (wasPosted) {
10980             mNotificationRecordLogger.logNotificationCancelled(r, reason,
10981                     r.getStats().getDismissalSurface());
10982         }
10983     }
10984 
10985     private static void sendDeleteIntent(@Nullable PendingIntent deleteIntent, String fromPkg) {
10986         if (deleteIntent != null) {
10987             try {
10988                 // make sure deleteIntent cannot be used to start activities from background
10989                 LocalServices.getService(ActivityManagerInternal.class)
10990                         .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(),
10991                                 ALLOWLIST_TOKEN);
10992                 deleteIntent.send();
10993             } catch (PendingIntent.CanceledException ex) {
10994                 // There's no relevant way to recover, and no reason to let this propagate
10995                 Slog.w(TAG, "canceled PendingIntent for " + fromPkg, ex);
10996             }
10997         }
10998     }
10999 
11000     @VisibleForTesting
11001     void updateUriPermissions(@Nullable NotificationRecord newRecord,
11002             @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
11003         updateUriPermissions(newRecord, oldRecord, targetPkg, targetUserId, false);
11004     }
11005 
11006     @VisibleForTesting
11007     void updateUriPermissions(@Nullable NotificationRecord newRecord,
11008             @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId,
11009             boolean onlyRevokeCurrentTarget) {
11010         final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
11011         if (DBG) Slog.d(TAG, key + ": updating permissions");
11012 
11013         final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
11014         final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
11015 
11016         // Shortcut when no Uris involved
11017         if (newUris == null && oldUris == null) {
11018             return;
11019         }
11020 
11021         // Inherit any existing owner
11022         IBinder permissionOwner = null;
11023         if (newRecord != null && permissionOwner == null) {
11024             permissionOwner = newRecord.permissionOwner;
11025         }
11026         if (oldRecord != null && permissionOwner == null) {
11027             permissionOwner = oldRecord.permissionOwner;
11028         }
11029 
11030         // If we have Uris to grant, but no owner yet, go create one
11031         if (newUris != null && permissionOwner == null) {
11032             if (DBG) Slog.d(TAG, key + ": creating owner");
11033             permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
11034         }
11035 
11036         // If we have no Uris to grant, but an existing owner, go destroy it
11037         // When revoking permissions of a single listener, destroying the owner will revoke
11038         // permissions of other listeners who need to keep access.
11039         if (newUris == null && permissionOwner != null && !onlyRevokeCurrentTarget) {
11040             destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key);
11041             permissionOwner = null;
11042         }
11043 
11044         // Grant access to new Uris
11045         if (newUris != null && permissionOwner != null) {
11046             for (int i = 0; i < newUris.size(); i++) {
11047                 final Uri uri = newUris.valueAt(i);
11048                 if (oldUris == null || !oldUris.contains(uri)) {
11049                     if (DBG) {
11050                         Slog.d(TAG, key + ": granting " + uri);
11051                     }
11052                     grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
11053                             targetUserId);
11054                 }
11055             }
11056         }
11057 
11058         // Revoke access to old Uris
11059         if (oldUris != null && permissionOwner != null) {
11060             for (int i = 0; i < oldUris.size(); i++) {
11061                 final Uri uri = oldUris.valueAt(i);
11062                 if (newUris == null || !newUris.contains(uri)) {
11063                     if (DBG) Slog.d(TAG, key + ": revoking " + uri);
11064                     if (onlyRevokeCurrentTarget) {
11065                         // We're revoking permission from one listener only; other listeners may
11066                         // still need access because the notification may still exist
11067                         revokeUriPermission(permissionOwner, uri,
11068                                 UserHandle.getUserId(oldRecord.getUid()), targetPkg, targetUserId);
11069                     } else {
11070                         // This is broad to unilaterally revoke permissions to this Uri as granted
11071                         // by this notification.  But this code-path can only be used when the
11072                         // reason for revoking is that the notification posted again without this
11073                         // Uri, not when removing an individual listener.
11074                         revokeUriPermission(permissionOwner, uri,
11075                                 UserHandle.getUserId(oldRecord.getUid()),
11076                                 null, USER_ALL);
11077                     }
11078                 }
11079             }
11080         }
11081 
11082         if (newRecord != null) {
11083             newRecord.permissionOwner = permissionOwner;
11084         }
11085     }
11086 
11087     private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
11088             int targetUserId) {
11089         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
11090         final long ident = Binder.clearCallingIdentity();
11091         try {
11092             mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
11093                     ContentProvider.getUriWithoutUserId(uri),
11094                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
11095                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
11096                     targetUserId);
11097         } catch (RemoteException ignored) {
11098             // Ignored because we're in same process
11099         } catch (SecurityException e) {
11100             Slog.e(TAG, "Cannot grant uri access; " + sourceUid + " does not own " + uri);
11101         } finally {
11102             Binder.restoreCallingIdentity(ident);
11103         }
11104     }
11105 
11106     private void revokeUriPermission(IBinder owner, Uri uri, int sourceUserId, String targetPkg,
11107             int targetUserId) {
11108         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
11109         int userId = ContentProvider.getUserIdFromUri(uri, sourceUserId);
11110 
11111         final long ident = Binder.clearCallingIdentity();
11112         try {
11113             mUgmInternal.revokeUriPermissionFromOwner(
11114                     owner,
11115                     ContentProvider.getUriWithoutUserId(uri),
11116                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
11117                     userId, targetPkg, targetUserId);
11118         } finally {
11119             Binder.restoreCallingIdentity(ident);
11120         }
11121     }
11122 
11123     private void destroyPermissionOwner(IBinder owner, int userId, String logKey) {
11124         final long ident = Binder.clearCallingIdentity();
11125         try {
11126             if (DBG) Slog.d(TAG, logKey + ": destroying owner");
11127             mUgmInternal.revokeUriPermissionFromOwner(owner, null, ~0, userId);
11128         } finally {
11129             Binder.restoreCallingIdentity(ident);
11130         }
11131     }
11132 
11133     /**
11134      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
11135      * and none of the {@code mustNotHaveFlags}.
11136      */
11137     void cancelNotification(final int callingUid, final int callingPid,
11138             final String pkg, final String tag, int id,
11139             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
11140             final int userId, final int reason, final ManagedServiceInfo listener) {
11141         cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
11142                 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
11143     }
11144 
11145     /**
11146      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
11147      * and none of the {@code mustNotHaveFlags}.
11148      */
11149     void cancelNotification(final int callingUid, final int callingPid,
11150             final String pkg, final String tag, final int id,
11151             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
11152             final int userId, final int reason, int rank, int count,
11153             final ManagedServiceInfo listener) {
11154         // In enqueueNotificationInternal notifications are added by scheduling the
11155         // work on the worker handler. Hence, we also schedule the cancel on this
11156         // handler to avoid a scenario where an add notification call followed by a
11157         // remove notification call ends up in not removing the notification.
11158         mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
11159                 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
11160                 count, listener, SystemClock.elapsedRealtime()), 0);
11161     }
11162 
11163     /**
11164      * Determine whether the userId applies to the notification in question, either because
11165      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
11166      */
11167     private static boolean notificationMatchesUserId(NotificationRecord r, int userId,
11168             boolean isAutogroupSummary) {
11169         if (isAutogroupSummary) {
11170             return r.getUserId() == userId;
11171         } else {
11172             return
11173                 // looking for USER_ALL notifications? match everything
11174                 userId == USER_ALL
11175                         // a notification sent to USER_ALL matches any query
11176                         || r.getUserId() == USER_ALL
11177                         // an exact user match
11178                         || r.getUserId() == userId;
11179         }
11180     }
11181 
11182     /**
11183      * Determine whether the userId applies to the notification in question, either because
11184      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
11185      * because it matches one of the users profiles.
11186      */
11187     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
11188         return notificationMatchesUserId(r, userId, false)
11189                 || mUserProfiles.isCurrentProfile(r.getUserId());
11190     }
11191 
11192     /**
11193      * Cancels all notifications from a given package that have all of the
11194      * {@code mustHaveFlags} and none of the {@code mustNotHaveFlags}.
11195      */
11196     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg,
11197             @Nullable String channelId, int mustHaveFlags, int mustNotHaveFlags, int userId,
11198             int reason) {
11199         final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime();
11200         mHandler.post(new Runnable() {
11201             @Override
11202             public void run() {
11203                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
11204                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
11205                         /* listener= */ null);
11206 
11207                 synchronized (mNotificationLock) {
11208                     FlagChecker flagChecker = (int flags) -> {
11209                         if ((flags & mustHaveFlags) != mustHaveFlags) {
11210                             return false;
11211                         }
11212                         if ((flags & mustNotHaveFlags) != 0) {
11213                             return false;
11214                         }
11215                         return true;
11216                     };
11217                     cancelAllNotificationsByListLocked(mNotificationList, pkg,
11218                             true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
11219                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
11220                             null /* listenerName */, true /* wasPosted */,
11221                             cancellationElapsedTimeMs);
11222                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, pkg,
11223                             true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
11224                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
11225                             null /* listenerName */, false /* wasPosted */,
11226                             cancellationElapsedTimeMs);
11227                     mSnoozeHelper.cancel(userId, pkg);
11228                 }
11229             }
11230         });
11231     }
11232 
11233     private interface FlagChecker {
11234         // Returns false if these flags do not pass the defined flag test.
11235         public boolean apply(int flags);
11236     }
11237 
11238     @FunctionalInterface
11239     private interface GroupChildChecker {
11240         // Returns true if the childRecord is a child of the group defined
11241         // by the rest of the parameters
11242         boolean apply(NotificationRecord childRecord, int userId, String pkg, String groupKey);
11243     }
11244 
11245     /**
11246      * Checks that the notification is currently a child of the group
11247      * @param childRecord the notification to check
11248      * @param userId userId of the group
11249      * @param pkg package name of the group
11250      * @param groupKey group key for a current group
11251      * @return true if the childRecord is currently a child of the group
11252      */
11253     private static boolean isChildOfCurrentGroupChecker(NotificationRecord childRecord, int userId,
11254             String pkg, String groupKey) {
11255         return (childRecord.getUser().getIdentifier() == userId
11256             && childRecord.getSbn().getPackageName().equals(pkg)
11257             && childRecord.getSbn().isGroup()
11258             && !childRecord.getNotification().isGroupSummary()
11259             && TextUtils.equals(groupKey, childRecord.getGroupKey()));
11260     }
11261 
11262     /**
11263      * Checks that the notification was originally a child of the group
11264      * @param childRecord the notification to check
11265      * @param userId userId of the group
11266      * @param pkg package name of the group
11267      * @param groupKey original/initial group key for a group that was force grouped
11268      * @return true if the childRecord was originally a child of the group
11269      */
11270     private static boolean wasChildOfForceRegroupedGroupChecker(NotificationRecord childRecord,
11271             int userId, String pkg, String groupKey) {
11272         return (childRecord.getUser().getIdentifier() == userId
11273             && childRecord.getSbn().getPackageName().equals(pkg)
11274             && childRecord.getSbn().isGroup()
11275             && !childRecord.getNotification().isGroupSummary()
11276             && TextUtils.equals(groupKey, childRecord.getOriginalGroupKey()));
11277     }
11278 
11279     @GuardedBy("mNotificationLock")
11280     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
11281             @Nullable String pkg, boolean nullPkgIndicatesUserSwitch, @Nullable String channelId,
11282             FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, boolean sendDelete,
11283             int reason, String listenerName, boolean wasPosted,
11284             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
11285         Set<String> childNotifications = null;
11286         for (int i = notificationList.size() - 1; i >= 0; --i) {
11287             NotificationRecord r = notificationList.get(i);
11288             if (includeCurrentProfiles) {
11289                 if (!notificationMatchesCurrentProfiles(r, userId)) {
11290                     continue;
11291                 }
11292             } else if (!notificationMatchesUserId(r, userId, false)) {
11293                 continue;
11294             }
11295             // Don't remove notifications to all, if there's no package name specified
11296             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == USER_ALL) {
11297                 continue;
11298             }
11299             if (!flagChecker.apply(r.getFlags())) {
11300                 continue;
11301             }
11302             if (pkg != null && !r.getSbn().getPackageName().equals(pkg)) {
11303                 continue;
11304             }
11305             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
11306                 continue;
11307             }
11308             if (r.getSbn().isGroup() && r.getNotification().isGroupChild()) {
11309                 if (childNotifications == null) {
11310                     childNotifications = new HashSet<>();
11311                 }
11312                 childNotifications.add(r.getKey());
11313                 continue;
11314             }
11315             notificationList.remove(i);
11316             mNotificationsByKey.remove(r.getKey());
11317             r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
11318             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName,
11319                     cancellationElapsedTimeMs);
11320         }
11321         if (childNotifications != null) {
11322             final int M = notificationList.size();
11323             for (int i = M - 1; i >= 0; i--) {
11324                 NotificationRecord r = notificationList.get(i);
11325                 if (childNotifications.contains(r.getKey())) {
11326                     // dismiss conditions were checked in the first loop and so don't need to be
11327                     // checked again
11328                     notificationList.remove(i);
11329                     mNotificationsByKey.remove(r.getKey());
11330                     r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
11331                     cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName,
11332                             cancellationElapsedTimeMs);
11333                 }
11334             }
11335             mAttentionHelper.updateLightsLocked();
11336         }
11337     }
11338 
11339     void snoozeNotificationInt(int callingUid, INotificationListener token, String key,
11340             long duration, String snoozeCriterionId) {
11341         final String packageName;
11342         final long notificationUpdateTimeMs;
11343 
11344         synchronized (mNotificationLock) {
11345             final ManagedServiceInfo listener = mListeners.checkServiceTokenLocked(token);
11346             if (listener == null) {
11347                 return;
11348             }
11349             packageName = listener.component.getPackageName();
11350             String listenerName = listener.component.toShortString();
11351             if ((duration <= 0 && snoozeCriterionId == null) || key == null) {
11352                 return;
11353             }
11354 
11355             final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key);
11356             if (r == null) {
11357                 return;
11358             }
11359             if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){
11360                 return;
11361             }
11362             notificationUpdateTimeMs = r.getUpdateTimeMs();
11363 
11364             if (DBG) {
11365                 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
11366                         snoozeCriterionId, listenerName));
11367             }
11368             // Needs to post so that it can cancel notifications not yet enqueued.
11369             mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
11370         }
11371 
11372         if (isNotificationRecent(notificationUpdateTimeMs)) {
11373             mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
11374                     callingUid, packageName, /* attributionTag= */ null, /* message= */ null);
11375         }
11376     }
11377 
11378     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) {
11379         String listenerName = listener == null ? null : listener.component.toShortString();
11380         if (DBG) {
11381             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
11382         }
11383         mSnoozeHelper.repost(key, muteOnReturn);
11384         handleSavePolicyFile();
11385     }
11386 
11387     private boolean isNotificationRecent(long notificationUpdateTimeMs) {
11388         if (!rapidClearNotificationsByListenerAppOpEnabled()) {
11389             return false;
11390         }
11391         return System.currentTimeMillis() - notificationUpdateTimeMs
11392                 < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS;
11393     }
11394 
11395     @GuardedBy("mNotificationLock")
11396     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
11397             ManagedServiceInfo listener, boolean includeCurrentProfiles, int mustNotHaveFlags) {
11398         final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime();
11399         mHandler.post(new Runnable() {
11400             @Override
11401             public void run() {
11402                 synchronized (mNotificationLock) {
11403                     String listenerName =
11404                             listener == null ? null : listener.component.toShortString();
11405                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
11406                             null, userId, 0, 0, reason, listenerName);
11407 
11408                     FlagChecker flagChecker = (int flags) -> {
11409                         int flagsToCheck = mustNotHaveFlags;
11410                         if (REASON_LISTENER_CANCEL_ALL == reason
11411                                 || REASON_CANCEL_ALL == reason) {
11412                             flagsToCheck |= FLAG_BUBBLE;
11413                         }
11414                         if ((flags & flagsToCheck) != 0) {
11415                             return false;
11416                         }
11417                         return true;
11418                     };
11419 
11420                     cancelAllNotificationsByListLocked(mNotificationList,
11421                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
11422                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
11423                             listenerName, true, cancellationElapsedTimeMs);
11424                     cancelAllNotificationsByListLocked(mEnqueuedNotifications,
11425                             null, false /*nullPkgIndicatesUserSwitch*/, null,
11426                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
11427                             reason, listenerName, false, cancellationElapsedTimeMs);
11428                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
11429                 }
11430             }
11431         });
11432     }
11433 
11434     // Warning: The caller is responsible for invoking updateLightsLocked().
11435     @GuardedBy("mNotificationLock")
11436     private void cancelGroupChildrenLocked(int userId, String pkg, int callingUid, int callingPid,
11437             String listenerName, boolean sendDelete, FlagChecker flagChecker,
11438             GroupChildChecker groupChildChecker, String groupKey, int reason,
11439             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
11440         if (pkg == null) {
11441             if (DBG) Slog.e(TAG, "No package for group summary");
11442             return;
11443         }
11444 
11445         cancelGroupChildrenByListLocked(mNotificationList, userId, pkg, callingUid, callingPid,
11446                 listenerName, sendDelete, true, flagChecker, groupChildChecker, groupKey,
11447                 reason, cancellationElapsedTimeMs);
11448         cancelGroupChildrenByListLocked(mEnqueuedNotifications, userId, pkg, callingUid, callingPid,
11449                 listenerName, sendDelete, false, flagChecker, groupChildChecker, groupKey,
11450                 reason, cancellationElapsedTimeMs);
11451     }
11452 
11453     @GuardedBy("mNotificationLock")
11454     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
11455             int userId, String pkg, int callingUid, int callingPid,
11456             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker,
11457             GroupChildChecker grouChildChecker, String groupKey, int reason,
11458             @ElapsedRealtimeLong long cancellationElapsedTimeMs) {
11459         final int childReason = REASON_GROUP_SUMMARY_CANCELED;
11460         for (int i = notificationList.size() - 1; i >= 0; i--) {
11461             final NotificationRecord childR = notificationList.get(i);
11462             final StatusBarNotification childSbn = childR.getSbn();
11463             if (grouChildChecker.apply(childR, userId, pkg, groupKey)
11464                 && (flagChecker == null || flagChecker.apply(childR.getFlags()))
11465                 && (!childR.getChannel().isImportantConversation() || reason != REASON_CANCEL)) {
11466                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
11467                         childSbn.getTag(), userId, 0, 0, childReason, listenerName);
11468                 notificationList.remove(i);
11469                 mNotificationsByKey.remove(childR.getKey());
11470                 cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName,
11471                         cancellationElapsedTimeMs);
11472             }
11473         }
11474     }
11475 
11476     @GuardedBy("mNotificationLock")
11477     @NonNull
11478     List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg,
11479             String groupKey, int userId) {
11480         List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId);
11481         records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId));
11482         return records;
11483     }
11484 
11485     @GuardedBy("mNotificationLock")
11486     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
11487             String groupKey, int userId) {
11488         List<NotificationRecord> records = new ArrayList<>();
11489         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
11490         records.addAll(
11491                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
11492         return records;
11493     }
11494 
11495     @GuardedBy("mNotificationLock")
11496     private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) {
11497         NotificationRecord r = findNotificationByKeyLocked(key);
11498         if (r == null) {
11499             r = mSnoozeHelper.getNotification(key);
11500         }
11501         return r;
11502 
11503     }
11504 
11505     @GuardedBy("mNotificationLock")
11506     @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
11507     private @NonNull List<NotificationRecord> findAppNotificationByListLocked(
11508             ArrayList<NotificationRecord> list, String pkg, int userId) {
11509         List<NotificationRecord> records = new ArrayList<>();
11510         final int len = list.size();
11511         for (int i = 0; i < len; i++) {
11512             NotificationRecord r = list.get(i);
11513             if (notificationMatchesUserId(r, userId, false)
11514                     && r.getSbn().getPackageName().equals(pkg)) {
11515                 records.add(r);
11516             }
11517         }
11518         return records;
11519     }
11520 
11521     @GuardedBy("mNotificationLock")
11522     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
11523             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
11524         List<NotificationRecord> records = new ArrayList<>();
11525         final int len = list.size();
11526         for (int i = 0; i < len; i++) {
11527             NotificationRecord r = list.get(i);
11528             if (notificationMatchesUserId(r, userId, false) && r.getGroupKey().equals(groupKey)
11529                     && r.getSbn().getPackageName().equals(pkg)) {
11530                 records.add(r);
11531             }
11532         }
11533         return records;
11534     }
11535 
11536     // Searches both enqueued and posted notifications by key.
11537     // TODO: need to combine a bunch of these getters with slightly different behavior.
11538     // TODO: Should enqueuing just add to mNotificationsByKey instead?
11539     @GuardedBy("mNotificationLock")
11540     private NotificationRecord findNotificationByKeyLocked(String key) {
11541         NotificationRecord r;
11542         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
11543             return r;
11544         }
11545         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
11546             return r;
11547         }
11548         return null;
11549     }
11550 
11551     @GuardedBy("mNotificationLock")
11552     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
11553         NotificationRecord r;
11554         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
11555             return r;
11556         }
11557         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
11558                 != null) {
11559             return r;
11560         }
11561 
11562         return null;
11563     }
11564 
11565     @Nullable
11566     private static NotificationRecord findNotificationByListLocked(
11567             ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
11568         final int len = list.size();
11569         for (int i = 0; i < len; i++) {
11570             NotificationRecord r = list.get(i);
11571             if (notificationMatchesUserId(r, userId, (r.getFlags() & GroupHelper.BASE_FLAGS) != 0)
11572                     && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag)
11573                     && r.getSbn().getPackageName().equals(pkg)) {
11574                 return r;
11575             }
11576         }
11577         return null;
11578     }
11579 
11580     private static List<NotificationRecord> findNotificationsByListLocked(
11581             ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
11582         List<NotificationRecord> matching = new ArrayList<>();
11583         final int len = list.size();
11584         for (int i = 0; i < len; i++) {
11585             NotificationRecord r = list.get(i);
11586             if (notificationMatchesUserId(r, userId, false) && r.getSbn().getId() == id
11587                     && TextUtils.equals(r.getSbn().getTag(), tag)
11588                     && r.getSbn().getPackageName().equals(pkg)) {
11589                 matching.add(r);
11590             }
11591         }
11592         return matching;
11593     }
11594 
11595     @Nullable
11596     private static NotificationRecord findNotificationByListLocked(
11597             ArrayList<NotificationRecord> list, String key) {
11598         final int N = list.size();
11599         for (int i = 0; i < N; i++) {
11600             if (key.equals(list.get(i).getKey())) {
11601                 return list.get(i);
11602             }
11603         }
11604         return null;
11605     }
11606 
11607     @GuardedBy("mNotificationLock")
11608     int indexOfNotificationLocked(String key) {
11609         final int N = mNotificationList.size();
11610         for (int i = 0; i < N; i++) {
11611             if (key.equals(mNotificationList.get(i).getKey())) {
11612                 return i;
11613             }
11614         }
11615         return -1;
11616     }
11617 
11618     private void hideNotificationsForPackages(@NonNull String[] pkgs, @NonNull int[] uidList) {
11619         synchronized (mNotificationLock) {
11620             Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet());
11621             List<String> pkgList = Arrays.asList(pkgs);
11622             List<NotificationRecord> changedNotifications = new ArrayList<>();
11623             int numNotifications = mNotificationList.size();
11624             for (int i = 0; i < numNotifications; i++) {
11625                 NotificationRecord rec = mNotificationList.get(i);
11626                 if (pkgList.contains(rec.getSbn().getPackageName())
11627                         && uidSet.contains(rec.getUid())) {
11628                     rec.setHidden(true);
11629                     changedNotifications.add(rec);
11630                 }
11631             }
11632 
11633             mListeners.notifyHiddenLocked(changedNotifications);
11634         }
11635     }
11636 
11637     private void unhideNotificationsForPackages(@NonNull String[] pkgs,
11638             @NonNull int[] uidList) {
11639         synchronized (mNotificationLock) {
11640             Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet());
11641             List<String> pkgList = Arrays.asList(pkgs);
11642             List<NotificationRecord> changedNotifications = new ArrayList<>();
11643             int numNotifications = mNotificationList.size();
11644             for (int i = 0; i < numNotifications; i++) {
11645                 NotificationRecord rec = mNotificationList.get(i);
11646                 if (pkgList.contains(rec.getSbn().getPackageName())
11647                         && uidSet.contains(rec.getUid())) {
11648                     rec.setHidden(false);
11649                     changedNotifications.add(rec);
11650                 }
11651             }
11652 
11653             mListeners.notifyUnhiddenLocked(changedNotifications);
11654         }
11655     }
11656 
11657     private void cancelNotificationsWhenEnterLockDownMode(int userId) {
11658         synchronized (mNotificationLock) {
11659             int numNotifications = mNotificationList.size();
11660             for (int i = 0; i < numNotifications; i++) {
11661                 NotificationRecord rec = mNotificationList.get(i);
11662                 if (rec.getUser().getIdentifier() != userId) {
11663                     continue;
11664                 }
11665                 mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN,
11666                         rec.getStats());
11667             }
11668 
11669         }
11670     }
11671 
11672     private void postNotificationsWhenExitLockDownMode(int userId) {
11673         synchronized (mNotificationLock) {
11674             int numNotifications = mNotificationList.size();
11675             // Set the delay to spread out the burst of notifications.
11676             long delay = 0;
11677             for (int i = 0; i < numNotifications; i++) {
11678                 NotificationRecord rec = mNotificationList.get(i);
11679                 if (rec.getUser().getIdentifier() != userId) {
11680                     continue;
11681                 }
11682                 mHandler.postDelayed(() -> {
11683                     synchronized (mNotificationLock) {
11684                         mListeners.notifyPostedLocked(rec, rec);
11685                     }
11686                 }, delay);
11687                 delay += 20;
11688             }
11689         }
11690     }
11691 
11692     protected boolean isCallingUidSystem() {
11693         final int uid = Binder.getCallingUid();
11694         return uid == Process.SYSTEM_UID;
11695     }
11696 
11697     protected boolean isCallingAppIdSystem() {
11698         final int uid = Binder.getCallingUid();
11699         final int appid = UserHandle.getAppId(uid);
11700         return appid == Process.SYSTEM_UID;
11701     }
11702 
11703     protected boolean isUidSystemOrPhone(int uid) {
11704         final int appid = UserHandle.getAppId(uid);
11705         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID
11706                 || uid == Process.ROOT_UID);
11707     }
11708 
11709     // TODO: Most calls should probably move to isCallerSystem.
11710     protected boolean isCallerSystemOrPhone() {
11711         return isUidSystemOrPhone(Binder.getCallingUid());
11712     }
11713 
11714     @VisibleForTesting
11715     protected boolean isCallerSystemOrSystemUi() {
11716         if (isCallerSystemOrPhone()) {
11717             return true;
11718         }
11719         return getContext().checkCallingPermission(STATUS_BAR_SERVICE)
11720                 == PERMISSION_GRANTED;
11721     }
11722 
11723     private boolean isCallerSystemOrSystemUiOrShell() {
11724         int callingUid = Binder.getCallingUid();
11725         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
11726             return true;
11727         }
11728         return isCallerSystemOrSystemUi();
11729     }
11730 
11731     private void checkCallerIsSystemOrShell() {
11732         int callingUid = Binder.getCallingUid();
11733         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
11734             return;
11735         }
11736         checkCallerIsSystem();
11737     }
11738 
11739     private void checkCallerIsSystem() {
11740         if (isCallerSystemOrPhone()) {
11741             return;
11742         }
11743         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
11744     }
11745 
11746     private void checkCallerIsSystemOrSystemUiOrShell() {
11747         checkCallerIsSystemOrSystemUiOrShell(null);
11748     }
11749 
11750     private void checkCallerIsSystemOrSystemUiOrShell(String message) {
11751         int callingUid = Binder.getCallingUid();
11752         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
11753             return;
11754         }
11755         if (isCallerSystemOrPhone()) {
11756             return;
11757         }
11758         getContext().enforceCallingPermission(STATUS_BAR_SERVICE,
11759                 message);
11760     }
11761 
11762     private void checkCallerIsSystemOrSameApp(String pkg) {
11763         if (isCallerSystemOrPhone()) {
11764             return;
11765         }
11766         checkCallerIsSameApp(pkg);
11767     }
11768 
11769     private boolean isCallerAndroid(String callingPkg, int uid) {
11770         return isUidSystemOrPhone(uid) && callingPkg != null
11771                 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
11772     }
11773 
11774     /**
11775      * Check if the notification is of a category type that is restricted to system use only,
11776      * if so throw SecurityException
11777      */
11778     private void checkRestrictedCategories(final Notification notification) {
11779         try {
11780             if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
11781                 return;
11782             }
11783         } catch (RemoteException re) {
11784             if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
11785                     + "restrictions check thus the check will be done anyway");
11786         }
11787         if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
11788                 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
11789                 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
11790             getContext().enforceCallingPermission(
11791                     android.Manifest.permission.SEND_CATEGORY_CAR_NOTIFICATIONS,
11792                     String.format("Notification category %s restricted",
11793                             notification.category));
11794         }
11795     }
11796 
11797     @VisibleForTesting
11798     boolean isCallerInstantApp(int callingUid, int userId) {
11799         // System is always allowed to act for ephemeral apps.
11800         if (isUidSystemOrPhone(callingUid)) {
11801             return false;
11802         }
11803 
11804         if (userId == USER_ALL) {
11805             userId = USER_SYSTEM;
11806         }
11807 
11808         try {
11809             final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
11810             if (pkgs == null) {
11811                 throw new SecurityException("Unknown uid " + callingUid);
11812             }
11813             final String pkg = pkgs[0];
11814             mAppOps.checkPackage(callingUid, pkg);
11815 
11816             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
11817             if (ai == null) {
11818                 throw new SecurityException("Unknown package " + pkg);
11819             }
11820             return ai.isInstantApp();
11821         } catch (RemoteException re) {
11822             throw new SecurityException("Unknown uid " + callingUid, re);
11823         }
11824     }
11825 
11826     private void checkCallerIsSameApp(String pkg) {
11827         checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
11828     }
11829 
11830     private void checkCallerIsSameApp(String pkg, int uid, int userId) {
11831         if (uid == Process.ROOT_UID && ROOT_PKG.equals(pkg)) {
11832             return;
11833         }
11834         if (!mPackageManagerInternal.isSameApp(pkg, uid, userId)) {
11835             throw new SecurityException("Package " + pkg + " is not owned by uid " + uid);
11836         }
11837     }
11838 
11839     private boolean isCallerSameApp(String pkg, int uid, int userId) {
11840         try {
11841             checkCallerIsSameApp(pkg, uid, userId);
11842             return true;
11843         } catch (SecurityException e) {
11844             return false;
11845         }
11846     }
11847 
11848     private static String callStateToString(int state) {
11849         switch (state) {
11850             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
11851             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
11852             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
11853             default: return "CALL_STATE_UNKNOWN_" + state;
11854         }
11855     }
11856 
11857     /**
11858      * Generates a NotificationRankingUpdate from 'sbns', considering only
11859      * notifications visible to the given listener.
11860      */
11861     @GuardedBy("mNotificationLock")
11862     NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
11863         final int N = mNotificationList.size();
11864         final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>();
11865 
11866         for (int i = 0; i < N; i++) {
11867             NotificationRecord record = mNotificationList.get(i);
11868             if (isInLockDownMode(record.getUser().getIdentifier())) {
11869                 continue;
11870             }
11871             if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) {
11872                 continue;
11873             }
11874             final String key = record.getSbn().getKey();
11875             final NotificationListenerService.Ranking ranking =
11876                     new NotificationListenerService.Ranking();
11877             ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
11878             ArrayList<CharSequence> smartReplies = record.getSmartReplies();
11879             boolean hasSensitiveContent = record.hasSensitiveContent();
11880             if (redactSensitiveNotificationsFromUntrustedListeners()) {
11881                 if (!mListeners.isUidTrusted(info.uid) && mListeners.hasSensitiveContent(record)) {
11882                     smartActions = null;
11883                     smartReplies = null;
11884                 }
11885             }
11886             ranking.populate(
11887                     key,
11888                     rankings.size(),
11889                     !record.isIntercepted(),
11890                     record.getPackageVisibilityOverride(),
11891                     record.getSuppressedVisualEffects(),
11892                     record.getImportance(),
11893                     record.getImportanceExplanation(),
11894                     record.getSbn().getOverrideGroupKey(),
11895                     record.getChannel(),
11896                     record.getPeopleOverride(),
11897                     record.getSnoozeCriteria(),
11898                     record.canShowBadge(),
11899                     record.getUserSentiment(),
11900                     record.isHidden(),
11901                     record.getLastAudiblyAlertedMs(),
11902                     record.getSound() != null || record.getVibration() != null,
11903                     smartActions,
11904                     smartReplies,
11905                     record.canBubble(),
11906                     record.isTextChanged(),
11907                     record.isConversation(),
11908                     record.getShortcutInfo(),
11909                     record.getRankingScore() == 0
11910                             ? RANKING_UNCHANGED
11911                             : (record.getRankingScore() > 0 ?  RANKING_PROMOTED : RANKING_DEMOTED),
11912                     record.getNotification().isBubbleNotification(),
11913                     record.getProposedImportance(),
11914                     hasSensitiveContent,
11915                     record.getSummarization()
11916             );
11917             rankings.add(ranking);
11918         }
11919 
11920         return new NotificationRankingUpdate(
11921                 rankings.toArray(new NotificationListenerService.Ranking[0]));
11922     }
11923 
11924     boolean isInLockDownMode(int userId) {
11925         return mStrongAuthTracker.isInLockDownMode(userId);
11926     }
11927 
11928     boolean hasCompanionDevice(ManagedServiceInfo info) {
11929         return hasCompanionDevice(info.component.getPackageName(),
11930                 info.userid, /* withDeviceProfile= */ null);
11931     }
11932 
11933     private boolean hasCompanionDevice(String pkg, @UserIdInt int userId,
11934             @Nullable Set</* @AssociationRequest.DeviceProfile */ String> withDeviceProfiles) {
11935         if (mCompanionManager == null) {
11936             mCompanionManager = getCompanionManager();
11937         }
11938         // Companion mgr doesn't exist on all device types
11939         if (mCompanionManager == null) {
11940             return false;
11941         }
11942         final long identity = Binder.clearCallingIdentity();
11943         try {
11944             List<AssociationInfo> associations = mCompanionManager.getAssociations(pkg, userId);
11945             for (AssociationInfo association : associations) {
11946                 if (withDeviceProfiles == null || withDeviceProfiles.contains(
11947                         association.getDeviceProfile())) {
11948                     return true;
11949                 }
11950             }
11951         } catch (SecurityException se) {
11952             // Not a privileged listener
11953         } catch (RemoteException re) {
11954             Slog.e(TAG, "Cannot reach companion device service", re);
11955         } catch (Exception e) {
11956             Slog.e(TAG, "Cannot verify caller pkg=" + pkg + ", userId=" + userId, e);
11957         } finally {
11958             Binder.restoreCallingIdentity(identity);
11959         }
11960         return false;
11961     }
11962 
11963     protected ICompanionDeviceManager getCompanionManager() {
11964         return ICompanionDeviceManager.Stub.asInterface(
11965                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
11966     }
11967 
11968     @VisibleForTesting
11969     boolean isVisibleToListener(StatusBarNotification sbn, int notificationType,
11970             ManagedServiceInfo listener) {
11971         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
11972             return false;
11973         }
11974         if (!isInteractionVisibleToListener(listener, sbn.getUserId())) {
11975             return false;
11976         }
11977         NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey);
11978         if (nls != null
11979                 && (!nls.isTypeAllowed(notificationType)
11980                 || !nls.isPackageAllowed(
11981                         new VersionedPackage(sbn.getPackageName(), sbn.getUid())))) {
11982             return false;
11983         }
11984         return true;
11985     }
11986 
11987     /**
11988      * Returns whether the given assistant should be informed about interactions on the given user.
11989      *
11990      * Normally an assistant would be able to see all interactions on the current user and any
11991      * associated profiles because they are notification listeners, but since NASes have one
11992      * instance per user, we want to filter out interactions that are not for the user that the
11993      * given NAS is bound in.
11994      */
11995     @VisibleForTesting
11996     boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) {
11997         boolean isAssistantService = isServiceTokenValid(info.getService());
11998         return !isAssistantService || info.isSameUser(userId);
11999     }
12000 
12001     private boolean isServiceTokenValid(IInterface service) {
12002         synchronized (mNotificationLock) {
12003             return mAssistants.isServiceTokenValidLocked(service);
12004         }
12005     }
12006 
12007     private boolean isPackageSuspendedForUser(String pkg, int uid) {
12008         final long identity = Binder.clearCallingIdentity();
12009         int userId = UserHandle.getUserId(uid);
12010         try {
12011             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
12012         } catch (RemoteException re) {
12013             throw new SecurityException("Could not talk to package manager service");
12014         } catch (IllegalArgumentException ex) {
12015             // Package not found.
12016             return false;
12017         } finally {
12018             Binder.restoreCallingIdentity(identity);
12019         }
12020     }
12021 
12022     @VisibleForTesting
12023     boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
12024         boolean canUseManagedServices = true;
12025         if (requiredPermission != null) {
12026             try {
12027                 if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
12028                         != PERMISSION_GRANTED) {
12029                     canUseManagedServices = false;
12030                 }
12031             } catch (RemoteException e) {
12032                 Slog.e(TAG, "can't talk to pm", e);
12033             }
12034         }
12035 
12036         return canUseManagedServices;
12037     }
12038 
12039     private class TrimCache {
12040         StatusBarNotification heavy;
12041         StatusBarNotification sbnClone;
12042         StatusBarNotification sbnCloneLight;
12043 
12044         TrimCache(StatusBarNotification sbn) {
12045             heavy = sbn;
12046         }
12047 
12048         StatusBarNotification ForListener(ManagedServiceInfo info) {
12049             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
12050                 if (sbnCloneLight == null) {
12051                     sbnCloneLight = heavy.cloneLight();
12052                 }
12053                 return sbnCloneLight;
12054             } else {
12055                 if (sbnClone == null) {
12056                     sbnClone = heavy.clone();
12057                 }
12058                 return sbnClone;
12059             }
12060         }
12061     }
12062 
12063     public class NotificationAssistants extends ManagedServices {
12064         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
12065 
12066         private static final String ATT_TYPES = "types";
12067         private static final String TAG_DENIED = "user_denied_adjustments";
12068         private static final String TAG_DENIED_KEY = "adjustment";
12069         private static final String ATT_DENIED_KEY = "key";
12070         private static final String ATT_DENIED_KEY_APPS = "denied_apps";
12071         private static final String TAG_ENABLED_TYPES = "enabled_classification_types";
12072         private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
12073 
12074         private final Object mLock = new Object();
12075 
12076         @GuardedBy("mLock")
12077         private Set<Integer> mAllowedClassificationTypes = new ArraySet<>();
12078 
12079         @GuardedBy("mLock")
12080         private Set<String> mAllowedAdjustments = new ArraySet<>();
12081 
12082         @GuardedBy("mLock")
12083         private Set<String> mDeniedAdjustments = new ArraySet<>();
12084 
12085         @GuardedBy("mLock")
12086         private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
12087 
12088         // key: Adjustment key. value - list of pkgs that we shouldn't apply adjustments with that
12089         // key to
12090         @GuardedBy("mLock")
12091         private Map<String, Set<String>> mAdjustmentKeyDeniedPackages = new ArrayMap<>();
12092 
12093         protected ComponentName mDefaultFromConfig = null;
12094 
12095         @Override
12096         protected void loadDefaultsFromConfig() {
12097             loadDefaultsFromConfig(true);
12098         }
12099 
12100         protected void loadDefaultsFromConfig(boolean addToDefault) {
12101             ArraySet<String> assistants = new ArraySet<>();
12102             assistants.addAll(Arrays.asList(mContext.getResources().getString(
12103                     com.android.internal.R.string.config_defaultAssistantAccessComponent)
12104                     .split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
12105             for (int i = 0; i < assistants.size(); i++) {
12106                 ComponentName assistantCn = ComponentName
12107                         .unflattenFromString(assistants.valueAt(i));
12108                 String packageName = assistants.valueAt(i);
12109                 if (assistantCn != null) {
12110                     packageName = assistantCn.getPackageName();
12111                 }
12112                 if (TextUtils.isEmpty(packageName)) {
12113                     continue;
12114                 }
12115                 ArraySet<ComponentName> approved = queryPackageForServices(packageName,
12116                         MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
12117                 if (approved.contains(assistantCn)) {
12118                     if (addToDefault) {
12119                         // add the default loaded from config file to mDefaultComponents and
12120                         // mDefaultPackages
12121                         addDefaultComponentOrPackage(assistantCn.flattenToString());
12122                     } else {
12123                         // otherwise, store in the mDefaultFromConfig for NAS settings migration
12124                         mDefaultFromConfig = assistantCn;
12125                     }
12126                 }
12127             }
12128         }
12129 
12130         ComponentName getDefaultFromConfig() {
12131             if (mDefaultFromConfig == null) {
12132                 loadDefaultsFromConfig(false);
12133             }
12134             return mDefaultFromConfig;
12135         }
12136 
12137         @Override
12138         protected void upgradeUserSet() {
12139             for (int userId: mApproved.keySet()) {
12140                 ArraySet<String> userSetServices = mUserSetServices.get(userId);
12141                 mIsUserChanged.put(userId, (userSetServices != null && userSetServices.size() > 0));
12142             }
12143         }
12144 
12145         @Override
12146         protected void addApprovedList(String approved, int userId, boolean isPrimary,
12147                 String userSet) {
12148             if (!TextUtils.isEmpty(approved)) {
12149                 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
12150                 if (approvedArray.length > 1) {
12151                     Slog.d(TAG, "More than one approved assistants");
12152                     approved = approvedArray[0];
12153                 }
12154             }
12155             super.addApprovedList(approved, userId, isPrimary, userSet);
12156         }
12157 
12158         public NotificationAssistants(Context context, Object lock, UserProfiles up,
12159                 IPackageManager pm) {
12160             super(context, lock, up, pm);
12161 
12162             if (!notificationClassification()) {
12163                 // Add all default allowed adjustment types.
12164                 for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
12165                     mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
12166                 }
12167             } else {
12168                 mAllowedClassificationTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES));
12169             }
12170         }
12171 
12172         @Override
12173         protected Config getConfig() {
12174             Config c = new Config();
12175             c.caption = "notification assistant";
12176             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
12177             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
12178             c.secureSettingName = Secure.ENABLED_NOTIFICATION_ASSISTANT;
12179             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
12180             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
12181             c.clientLabel = R.string.notification_ranker_binding_label;
12182             return c;
12183         }
12184 
12185         @Override
12186         protected IInterface asInterface(IBinder binder) {
12187             return INotificationListener.Stub.asInterface(binder);
12188         }
12189 
12190         @Override
12191         protected boolean checkType(IInterface service) {
12192             return service instanceof INotificationListener;
12193         }
12194 
12195         @Override
12196         protected void onServiceAdded(ManagedServiceInfo info) {
12197             mListeners.registerGuestService(info);
12198         }
12199 
12200         @Override
12201         protected void ensureFilters(ServiceInfo si, int userId) {
12202             // nothing to filter; no user visible settings for types/packages like other
12203             // listeners
12204         }
12205 
12206         @Override
12207         @GuardedBy("mNotificationLock")
12208         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
12209             mListeners.unregisterService(removed.service, removed.userid);
12210         }
12211 
12212         @Override
12213         public void onUserUnlocked(int user) {
12214             if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
12215             // force rebind the assistant, as it might be keeping its own state in user locked
12216             // storage
12217             rebindServices(true, user);
12218         }
12219 
12220         @Override
12221         protected boolean allowRebindForParentUser() {
12222             return false;
12223         }
12224 
12225         @Override
12226         protected String getRequiredPermission() {
12227             // only signature/privileged apps can be bound.
12228             return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
12229         }
12230 
12231         protected Set<String> getAllowedAssistantAdjustments() {
12232             synchronized (mLock) {
12233                 if (notificationClassification()) {
12234                     Set<String> types = new HashSet<>(Set.of(DEFAULT_ALLOWED_ADJUSTMENTS));
12235                     types.removeAll(mDeniedAdjustments);
12236                     return types;
12237                 } else {
12238                     Set<String> types = new HashSet<>();
12239                     types.addAll(mAllowedAdjustments);
12240                     return types;
12241                 }
12242             }
12243         }
12244 
12245         protected boolean isAdjustmentAllowed(String type) {
12246             synchronized (mLock) {
12247                 if (notificationClassification()) {
12248                     return List.of(DEFAULT_ALLOWED_ADJUSTMENTS).contains(type)
12249                             && !mDeniedAdjustments.contains(type);
12250                 } else {
12251                     return mAllowedAdjustments.contains(type);
12252                 }
12253             }
12254         }
12255 
12256         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
12257         protected @NonNull boolean isAdjustmentKeyTypeAllowed(@Adjustment.Types int type) {
12258             synchronized (mLock) {
12259                 if (notificationClassification()) {
12260                     return mAllowedClassificationTypes.contains(type);
12261                 }
12262             }
12263             return false;
12264         }
12265 
12266         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
12267         protected @NonNull int[] getAllowedClassificationTypes() {
12268             synchronized (mLock) {
12269                 if (notificationClassification()) {
12270                     return mAllowedClassificationTypes.stream()
12271                             .mapToInt(Integer::intValue).toArray();
12272                 }
12273             }
12274             return new int[]{};
12275         }
12276 
12277         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
12278         public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type,
12279                 boolean enabled) {
12280             if (!android.service.notification.Flags.notificationClassification()) {
12281                 return;
12282             }
12283             synchronized (mLock) {
12284                 if (enabled) {
12285                     mAllowedClassificationTypes.add(type);
12286                 } else {
12287                     mAllowedClassificationTypes.remove(type);
12288                 }
12289             }
12290         }
12291 
12292         protected @NonNull String[] getAdjustmentDeniedPackages(@Adjustment.Keys String key) {
12293             synchronized (mLock) {
12294                 if (notificationClassificationUi() || nmSummarization() | nmSummarizationUi()) {
12295                     return mAdjustmentKeyDeniedPackages.getOrDefault(
12296                             key, new ArraySet<>()).toArray(new String[0]);
12297                 }
12298             }
12299             return new String[]{};
12300         }
12301 
12302         protected @NonNull boolean isAdjustmentAllowedForPackage(@Adjustment.Keys String key,
12303                 String pkg) {
12304             synchronized (mLock) {
12305                 if (notificationClassificationUi() || nmSummarization() | nmSummarizationUi()) {
12306                     return !mAdjustmentKeyDeniedPackages.getOrDefault(
12307                             key, new ArraySet<>()).contains(pkg);
12308                 }
12309             }
12310             return true;
12311         }
12312 
12313         public void setAdjustmentSupportedForPackage(@Adjustment.Keys String key, String pkg,
12314                 boolean enabled) {
12315             if (!(notificationClassificationUi() || nmSummarization() | nmSummarizationUi())) {
12316                 return;
12317             }
12318             synchronized (mLock) {
12319                 mAdjustmentKeyDeniedPackages.putIfAbsent(key, new ArraySet<>());
12320                 if (enabled) {
12321                     mAdjustmentKeyDeniedPackages.get(key).remove(pkg);
12322                 } else {
12323                     mAdjustmentKeyDeniedPackages.get(key).add(pkg);
12324                 }
12325             }
12326         }
12327 
12328         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
12329             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12330                 ArrayList<String> keys = new ArrayList<>(records.size());
12331                 for (NotificationRecord r : records) {
12332                     boolean sbnVisible = isVisibleToListener(
12333                             r.getSbn(), r.getNotificationType(), info)
12334                             && info.isSameUser(r.getUserId());
12335                     if (sbnVisible) {
12336                         keys.add(r.getKey());
12337                     }
12338                 }
12339 
12340                 if (!keys.isEmpty()) {
12341                     mHandler.post(() -> notifySeen(info, keys));
12342                 }
12343             }
12344         }
12345 
12346         protected void onPanelRevealed(int items) {
12347             // send to all currently bounds NASes since notifications from both users will appear in
12348             // the panel
12349             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12350                 mHandler.post(() -> {
12351                     final INotificationListener assistant = (INotificationListener) info.service;
12352                     try {
12353                         assistant.onPanelRevealed(items);
12354                     } catch (RemoteException ex) {
12355                         Slog.e(TAG, "unable to notify assistant (panel revealed): " + info, ex);
12356                     }
12357                 });
12358             }
12359         }
12360 
12361         protected void onPanelHidden() {
12362             // send to all currently bounds NASes since notifications from both users will appear in
12363             // the panel
12364             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12365                 mHandler.post(() -> {
12366                     final INotificationListener assistant = (INotificationListener) info.service;
12367                     try {
12368                         assistant.onPanelHidden();
12369                     } catch (RemoteException ex) {
12370                         Slog.e(TAG, "unable to notify assistant (panel hidden): " + info, ex);
12371                     }
12372                 });
12373             }
12374         }
12375 
12376         boolean hasUserSet(int userId) {
12377             Boolean userSet = mIsUserChanged.get(userId);
12378             return (userSet != null && userSet);
12379         }
12380 
12381         void setUserSet(int userId, boolean set) {
12382             mIsUserChanged.put(userId, set);
12383         }
12384 
12385         private void notifySeen(final ManagedServiceInfo info,
12386                 final ArrayList<String> keys) {
12387             final INotificationListener assistant = (INotificationListener) info.service;
12388             try {
12389                 assistant.onNotificationsSeen(keys);
12390             } catch (RemoteException ex) {
12391                 Slog.e(TAG, "unable to notify assistant (seen): " + info, ex);
12392             }
12393         }
12394 
12395         @GuardedBy("mNotificationLock")
12396         private void onNotificationEnqueuedLocked(final NotificationRecord r) {
12397             final boolean debug = isVerboseLogEnabled();
12398             if (debug) {
12399                 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
12400             }
12401             final StatusBarNotification sbn = r.getSbn();
12402 
12403             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12404                 boolean sbnVisible = isVisibleToListener(
12405                         sbn, r.getNotificationType(), info)
12406                         && info.isSameUser(r.getUserId());
12407                 if (sbnVisible) {
12408                     TrimCache trimCache = new TrimCache(sbn);
12409                     final INotificationListener assistant = (INotificationListener) info.service;
12410                     final StatusBarNotification sbnToPost = trimCache.ForListener(info);
12411                     final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
12412 
12413                     try {
12414                         if (android.app.Flags.noSbnholder()) {
12415                             assistant.onNotificationEnqueuedWithChannelFull(sbnToPost,
12416                                     r.getChannel(), update);
12417                         } else {
12418                             final StatusBarNotificationHolder sbnHolder =
12419                                     new StatusBarNotificationHolder(sbnToPost);
12420 
12421                             assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
12422                                     update);
12423                         }
12424                     } catch (DeadObjectException ex) {
12425                         Slog.wtf(TAG, "unable to notify assistant (enqueued): " + info, ex);
12426                     } catch (RemoteException ex) {
12427                         Slog.e(TAG, "unable to notify assistant (enqueued): " + info, ex);
12428                     }
12429                 }
12430             }
12431         }
12432 
12433         @GuardedBy("mNotificationLock")
12434         void notifyAssistantVisibilityChangedLocked(
12435                 final NotificationRecord r,
12436                 final boolean isVisible) {
12437             final String key = r.getSbn().getKey();
12438             if (DBG) {
12439                 Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key);
12440             }
12441             notifyAssistantLocked(
12442                     r.getSbn(),
12443                     r.getNotificationType(),
12444                     true /* sameUserOnly */,
12445                     (assistant, unused) -> {
12446                         try {
12447                             assistant.onNotificationVisibilityChanged(key, isVisible);
12448                         } catch (RemoteException ex) {
12449                             Slog.e(TAG, "unable to notify assistant (visible): " + assistant, ex);
12450                         }
12451                     });
12452         }
12453 
12454         @GuardedBy("mNotificationLock")
12455         void notifyAssistantExpansionChangedLocked(
12456                 final StatusBarNotification sbn,
12457                 final int notificationType,
12458                 final boolean isUserAction,
12459                 final boolean isExpanded) {
12460             final String key = sbn.getKey();
12461             notifyAssistantLocked(
12462                     sbn,
12463                     notificationType,
12464                     true /* sameUserOnly */,
12465                     (assistant, unused) -> {
12466                         try {
12467                             assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
12468                         } catch (RemoteException ex) {
12469                             Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
12470                         }
12471                     });
12472         }
12473 
12474         @GuardedBy("mNotificationLock")
12475         void notifyAssistantNotificationDirectReplyLocked(
12476                 final NotificationRecord r) {
12477             final String key = r.getKey();
12478             notifyAssistantLocked(
12479                     r.getSbn(),
12480                     r.getNotificationType(),
12481                     true /* sameUserOnly */,
12482                     (assistant, unused) -> {
12483                         try {
12484                             assistant.onNotificationDirectReply(key);
12485                         } catch (RemoteException ex) {
12486                             Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
12487                         }
12488                     });
12489         }
12490 
12491         @GuardedBy("mNotificationLock")
12492         void notifyAssistantSuggestedReplySent(
12493                 final StatusBarNotification sbn, int notificationType,
12494                 CharSequence reply, boolean generatedByAssistant) {
12495             final String key = sbn.getKey();
12496             notifyAssistantLocked(
12497                     sbn,
12498                     notificationType,
12499                     true /* sameUserOnly */,
12500                     (assistant, unused) -> {
12501                         try {
12502                             assistant.onSuggestedReplySent(
12503                                     key,
12504                                     reply,
12505                                     generatedByAssistant
12506                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
12507                                             : NotificationAssistantService.SOURCE_FROM_APP);
12508                         } catch (RemoteException ex) {
12509                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
12510                         }
12511                     });
12512         }
12513 
12514         @GuardedBy("mNotificationLock")
12515         void notifyAssistantActionClicked(
12516                 final NotificationRecord r, Notification.Action action,
12517                 boolean generatedByAssistant) {
12518             final String key = r.getSbn().getKey();
12519             notifyAssistantLocked(
12520                     r.getSbn(),
12521                     r.getNotificationType(),
12522                     true /* sameUserOnly */,
12523                     (assistant, unused) -> {
12524                         try {
12525                             assistant.onActionClicked(
12526                                     key,
12527                                     action,
12528                                     generatedByAssistant
12529                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
12530                                             : NotificationAssistantService.SOURCE_FROM_APP);
12531                         } catch (RemoteException ex) {
12532                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
12533                         }
12534                     });
12535         }
12536 
12537         /**
12538          * asynchronously notify the assistant that a notification has been snoozed until a
12539          * context
12540          */
12541         @GuardedBy("mNotificationLock")
12542         private void notifyAssistantSnoozedLocked(
12543                 final NotificationRecord r, final String snoozeCriterionId) {
12544             notifyAssistantLocked(
12545                     r.getSbn(),
12546                     r.getNotificationType(),
12547                     true /* sameUserOnly */,
12548                     (info, sbnToPost) -> {
12549                         try {
12550                             if (android.app.Flags.noSbnholder()) {
12551                                 info.onNotificationSnoozedUntilContextFull(
12552                                         sbnToPost, snoozeCriterionId);
12553                             } else {
12554                                 final StatusBarNotificationHolder sbnHolder =
12555                                         new StatusBarNotificationHolder(sbnToPost);
12556                                 info.onNotificationSnoozedUntilContext(
12557                                         sbnHolder, snoozeCriterionId);
12558                             }
12559                         } catch (DeadObjectException ex) {
12560                             Slog.wtf(TAG, "unable to notify assistant (snoozed): " + info, ex);
12561                         } catch (RemoteException ex) {
12562                             Slog.e(TAG, "unable to notify assistant (snoozed): " + info, ex);
12563                         }
12564                     });
12565         }
12566 
12567         @GuardedBy("mNotificationLock")
12568         void notifyAssistantNotificationClicked(final NotificationRecord r) {
12569             final String key = r.getSbn().getKey();
12570             notifyAssistantLocked(
12571                     r.getSbn(),
12572                     r.getNotificationType(),
12573                     true /* sameUserOnly */,
12574                     (assistant, unused) -> {
12575                         try {
12576                             assistant.onNotificationClicked(key);
12577                         } catch (RemoteException ex) {
12578                             Slog.e(TAG, "unable to notify assistant (clicked): " + assistant, ex);
12579                         }
12580                     });
12581         }
12582 
12583         @GuardedBy("mNotificationLock")
12584         void notifyAssistantFeedbackReceived(final NotificationRecord r, Bundle feedback) {
12585             final StatusBarNotification sbn = r.getSbn();
12586 
12587             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12588                 boolean sbnVisible = isVisibleToListener(
12589                         sbn, r.getNotificationType(), info)
12590                         && info.isSameUser(r.getUserId());
12591                 if (sbnVisible) {
12592                     final INotificationListener assistant = (INotificationListener) info.service;
12593                     try {
12594                         final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
12595                         assistant.onNotificationFeedbackReceived(sbn.getKey(), update, feedback);
12596                     } catch (RemoteException ex) {
12597                         Slog.e(TAG, "unable to notify assistant (feedback): " + assistant, ex);
12598                     }
12599                 }
12600             }
12601         }
12602 
12603         /**
12604          * Notifies the assistant something about the specified notification, only assistant
12605          * that is visible to the notification will be notified.
12606          *
12607          * @param sbn          the notification object that the update is about.
12608          * @param sameUserOnly should the update  be sent to the assistant in the same user only.
12609          * @param callback     the callback that provides the assistant to be notified, executed
12610          *                     in WorkerHandler.
12611          */
12612         @GuardedBy("mNotificationLock")
12613         private void notifyAssistantLocked(
12614                 final StatusBarNotification sbn,
12615                 int notificationType,
12616                 boolean sameUserOnly,
12617                 BiConsumer<INotificationListener, StatusBarNotification> callback) {
12618             TrimCache trimCache = new TrimCache(sbn);
12619             // There should be only one, but it's a list, so while we enforce
12620             // singularity elsewhere, we keep it general here, to avoid surprises.
12621 
12622             final boolean debug = isVerboseLogEnabled();
12623             if (debug) {
12624                 Slog.v(TAG,
12625                         "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
12626                                 + sameUserOnly + "], callback = [" + callback + "]");
12627             }
12628             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12629                 boolean sbnVisible = isVisibleToListener(sbn, notificationType, info)
12630                         && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
12631                 if (debug) {
12632                     Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
12633                 }
12634                 if (!sbnVisible) {
12635                     continue;
12636                 }
12637                 final INotificationListener assistant = (INotificationListener) info.service;
12638                 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
12639                 mHandler.post(() -> callback.accept(assistant, sbnToPost));
12640             }
12641         }
12642 
12643         public boolean isEnabled() {
12644             return !getServices().isEmpty();
12645         }
12646 
12647         protected void resetDefaultAssistantsIfNecessary() {
12648             final List<UserInfo> activeUsers = mUm.getAliveUsers();
12649             for (UserInfo userInfo : activeUsers) {
12650                 int userId = userInfo.getUserHandle().getIdentifier();
12651                 if (!hasUserSet(userId)) {
12652                     if (!isNASMigrationDone(userId)) {
12653                         resetDefaultFromConfig();
12654                         setNASMigrationDone(userId);
12655                     }
12656                     Slog.d(TAG, "Approving default notification assistant for user " + userId);
12657                     setDefaultAssistantForUser(userId);
12658                 }
12659             }
12660         }
12661 
12662         protected void resetDefaultFromConfig() {
12663             clearDefaults();
12664             loadDefaultsFromConfig();
12665         }
12666 
12667         protected void clearDefaults() {
12668             mDefaultComponents.clear();
12669             mDefaultPackages.clear();
12670         }
12671 
12672         @Override
12673         protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
12674                 boolean isPrimary, boolean enabled, boolean userSet) {
12675             // Ensures that only one component is enabled at a time
12676             if (enabled) {
12677                 List<ComponentName> allowedComponents = getAllowedComponents(userId);
12678                 if (!allowedComponents.isEmpty()) {
12679                     ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
12680                     if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
12681                     setNotificationAssistantAccessGrantedForUserInternal(
12682                             currentComponent, userId, false, userSet);
12683                 }
12684             }
12685             super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
12686         }
12687 
12688         private boolean isVerboseLogEnabled() {
12689             return Log.isLoggable("notification_assistant", Log.VERBOSE);
12690         }
12691 
12692         private void addDefaultClassificationTypes() {
12693             // Add the default classification types if the list is empty
12694             synchronized (mLock) {
12695                 if (mAllowedClassificationTypes.isEmpty()) {
12696                     mAllowedClassificationTypes.addAll(
12697                             List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES));
12698                 }
12699             }
12700         }
12701 
12702         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
12703         @GuardedBy("mNotificationLock")
12704         public void allowAdjustmentType(@Adjustment.Keys String key) {
12705             if (!android.service.notification.Flags.notificationClassification()) {
12706                 return;
12707             }
12708             mDeniedAdjustments.remove(key);
12709             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12710                 mHandler.post(() -> notifyCapabilitiesChanged(info));
12711             }
12712             if (KEY_TYPE.equals(key)) {
12713                 addDefaultClassificationTypes();
12714             }
12715         }
12716 
12717         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
12718         @GuardedBy("mNotificationLock")
12719         public void disallowAdjustmentType(@Adjustment.Keys String key) {
12720             if (!android.service.notification.Flags.notificationClassification()) {
12721                 return;
12722             }
12723             mDeniedAdjustments.add(key);
12724             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
12725                 mHandler.post(() -> notifyCapabilitiesChanged(info));
12726             }
12727         }
12728 
12729         @GuardedBy("mNotificationLock")
12730         public void setAdjustmentTypeSupportedState(@UserIdInt int userId,
12731                 @Adjustment.Keys String key, boolean supported) {
12732             if (!(android.service.notification.Flags.notificationClassification()
12733                     || android.app.Flags.nmSummarizationUi()
12734                     || android.app.Flags.nmSummarization())) {
12735                 return;
12736             }
12737             HashSet<String> disabledAdjustments =
12738                     mNasUnsupported.getOrDefault(userId, new HashSet<>());
12739             if (supported) {
12740                 disabledAdjustments.remove(key);
12741             } else {
12742                 disabledAdjustments.add(key);
12743             }
12744             mNasUnsupported.put(userId, disabledAdjustments);
12745             handleSavePolicyFile();
12746         }
12747 
12748         @GuardedBy("mNotificationLock")
12749         public @NonNull Set<String> getUnsupportedAdjustments(@UserIdInt int userId) {
12750             if (!(android.service.notification.Flags.notificationClassification()
12751                     || android.app.Flags.nmSummarizationUi()
12752                     || android.app.Flags.nmSummarization())) {
12753                 return new HashSet<>();
12754             }
12755             return mNasUnsupported.getOrDefault(userId, new HashSet<>());
12756         }
12757 
12758         private void setNasUnsupportedDefaults(@UserIdInt int userId) {
12759             if (mNasUnsupported != null) {
12760                 mNasUnsupported.put(userId, new HashSet(List.of(mDefaultUnsupportedAdjustments)));
12761                 handleSavePolicyFile();
12762             }
12763         }
12764 
12765         @Override
12766         protected void writeExtraAttributes(TypedXmlSerializer out, @UserIdInt int approvedUserId)
12767                 throws IOException {
12768             if (!android.service.notification.Flags.notificationClassification()) {
12769                 return;
12770             }
12771             synchronized (mLock) {
12772                 out.attribute(null, ATT_NAS_UNSUPPORTED, TextUtils.join(",",
12773                         mNasUnsupported.getOrDefault(approvedUserId, new HashSet<>())));
12774             }
12775         }
12776 
12777         @Override
12778         protected void readExtraAttributes(String tag, TypedXmlPullParser parser,
12779                 @UserIdInt int approvedUserId) throws IOException {
12780             if (!android.service.notification.Flags.notificationClassification()) {
12781                 return;
12782             }
12783             if (ManagedServices.TAG_MANAGED_SERVICES.equals(tag)) {
12784                 final String types = XmlUtils.readStringAttribute(parser, ATT_NAS_UNSUPPORTED);
12785                 synchronized (mLock) {
12786                     if (types == null) {
12787                         setNasUnsupportedDefaults(approvedUserId);
12788                     } else {
12789                         if (!TextUtils.isEmpty(types)) {
12790                             mNasUnsupported.put(approvedUserId,
12791                                     new HashSet(List.of(types.split(","))));
12792                         } else {
12793                             mNasUnsupported.put(approvedUserId, new HashSet());
12794                         }
12795                     }
12796                 }
12797             }
12798         }
12799 
12800         @Override
12801         protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
12802             if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())) {
12803                 return;
12804             }
12805             synchronized (mLock) {
12806                 out.startTag(null, TAG_DENIED);
12807                 out.attribute(null, ATT_TYPES, TextUtils.join(",", mDeniedAdjustments));
12808                 for (String key : mAdjustmentKeyDeniedPackages.keySet()) {
12809                     Set<String> pkgs = mAdjustmentKeyDeniedPackages.get(key);
12810                     if (pkgs != null && !pkgs.isEmpty()) {
12811                         out.startTag(null, TAG_DENIED_KEY);
12812                         out.attribute(null, ATT_DENIED_KEY, key);
12813                         out.attribute(null, ATT_DENIED_KEY_APPS, TextUtils.join(",", pkgs));
12814                         out.endTag(null, TAG_DENIED_KEY);
12815                     }
12816                 }
12817                 out.endTag(null, TAG_DENIED);
12818                 out.startTag(null, TAG_ENABLED_TYPES);
12819                 out.attribute(null, ATT_TYPES,
12820                         TextUtils.join(",", mAllowedClassificationTypes));
12821                 out.endTag(null, TAG_ENABLED_TYPES);
12822             }
12823         }
12824 
12825         @Override
12826         protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
12827             if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())) {
12828                 return;
12829             }
12830             if (TAG_DENIED.equals(tag)) {
12831                 final String keys = XmlUtils.readStringAttribute(parser, ATT_TYPES);
12832                 synchronized (mLock) {
12833                     mDeniedAdjustments.clear();
12834                     if (!TextUtils.isEmpty(keys)) {
12835                         mDeniedAdjustments.addAll(Arrays.asList(keys.split(",")));
12836                     }
12837                 }
12838             } else if (TAG_ENABLED_TYPES.equals(tag)) {
12839                 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
12840                 synchronized (mLock) {
12841                     mAllowedClassificationTypes.clear();
12842                     if (!TextUtils.isEmpty(types)) {
12843                         List<String> typeList = Arrays.asList(types.split(","));
12844                         for (String type : typeList) {
12845                             try {
12846                                 mAllowedClassificationTypes.add(Integer.parseInt(type));
12847                             } catch (NumberFormatException e) {
12848                                 Slog.wtf(TAG, "Bad type specified", e);
12849                             }
12850                         }
12851                     }
12852                 }
12853             } else if (TAG_DENIED_KEY.equals(tag)) {
12854                 final String key = XmlUtils.readStringAttribute(parser, ATT_DENIED_KEY);
12855                 final String pkgs = XmlUtils.readStringAttribute(parser, ATT_DENIED_KEY_APPS);
12856                 if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(pkgs)) {
12857                     List<String> pkgList = Arrays.asList(pkgs.split(","));
12858                     mAdjustmentKeyDeniedPackages.put(key, new ArraySet<>(pkgList));
12859                 }
12860             }
12861         }
12862 
12863         private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
12864             final INotificationListener assistant = (INotificationListener) info.service;
12865             try {
12866                 assistant.onAllowedAdjustmentsChanged();
12867             } catch (RemoteException ex) {
12868                 Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
12869             }
12870         }
12871 
12872         /**
12873          * Fills out {@link BundlePreferences} proto and wraps it in a {@link StatsEvent}.
12874          */
12875         @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
12876         protected void pullBundlePreferencesStats(List<StatsEvent> events) {
12877             boolean bundlesAllowed = true;
12878             synchronized (mLock) {
12879                 List<String> unsupportedAdjustments = new ArrayList(
12880                         mNasUnsupported.getOrDefault(
12881                                 UserHandle.getUserId(Binder.getCallingUid()),
12882                                 new HashSet(List.of(mDefaultUnsupportedAdjustments)))
12883                 );
12884                 bundlesAllowed = !unsupportedAdjustments.contains(Adjustment.KEY_TYPE);
12885             }
12886 
12887             int[] allowedBundleTypes = getAllowedClassificationTypes();
12888 
12889             events.add(FrameworkStatsLog.buildStatsEvent(
12890                     NOTIFICATION_BUNDLE_PREFERENCES,
12891                     /* optional int32 event_id = 1 */
12892                     NotificationPullStatsEvent.NOTIFICATION_BUNDLE_PREFERENCES_PULLED.getId(),
12893                     /* optional bool bundles_allowed = 2 */ bundlesAllowed,
12894                     /* repeated android.stats.notification.BundleTypes allowed_bundle_types = 3 */
12895                     allowedBundleTypes));
12896         }
12897     }
12898 
12899     /**
12900      * Asynchronously notify all listeners about a posted (new or updated) notification. This
12901      * should be called from {@link PostNotificationRunnable} to "complete" the post (since SysUI is
12902      * one of the NLSes, and will display it to the user).
12903      *
12904      * <p>This method will call {@link PostNotificationTracker#finish} on the supplied tracker
12905      * when every {@link NotificationListenerService} has received the news.
12906      *
12907      * <p>Also takes care of removing a notification that has been visible to a listener before,
12908      * but isn't anymore.
12909      */
12910     @GuardedBy("mNotificationLock")
12911     private void notifyListenersPostedAndLogLocked(NotificationRecord r, NotificationRecord old,
12912             @NonNull PostNotificationTracker tracker,
12913             @Nullable NotificationRecordLogger.NotificationReported report) {
12914         List<Runnable> listenerCalls = mListeners.prepareNotifyPostedLocked(r, old, true);
12915         mHandler.post(() -> {
12916             for (Runnable listenerCall : listenerCalls) {
12917                 listenerCall.run();
12918             }
12919 
12920             long postDurationMillis = tracker.finish();
12921             if (report != null) {
12922                 report.post_duration_millis = postDurationMillis;
12923                 mNotificationRecordLogger.logNotificationPosted(report);
12924             }
12925         });
12926 
12927         if (callstyleCallbackApi()) {
12928             notifyCallNotificationEventListenerOnPosted(r);
12929         }
12930     }
12931 
12932     @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR)
12933     @GuardedBy("mNotificationLock")
12934     private void maybeNotifySystemUiListenerLifetimeExtendedListLocked(
12935             List<NotificationRecord> notificationList, int packageImportance) {
12936         for (int i = notificationList.size() - 1; i >= 0; --i) {
12937             NotificationRecord record = notificationList.get(i);
12938             maybeNotifySystemUiListenerLifetimeExtendedLocked(record,
12939                     record.getSbn().getPackageName(), packageImportance);
12940         }
12941     }
12942 
12943     @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR)
12944     @GuardedBy("mNotificationLock")
12945     private void maybeNotifySystemUiListenerLifetimeExtendedLocked(NotificationRecord record,
12946             String pkg, int packageImportance) {
12947         if (record != null && (record.getSbn().getNotification().flags
12948                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0
12949                 && !record.isCanceledAfterLifetimeExtension()) {
12950             // Mark that the notification is being updated due to cancelation, so it won't
12951             // be updated again if the app cancels multiple times.
12952             record.setCanceledAfterLifetimeExtension(true);
12953 
12954             boolean isAppForeground = pkg != null && packageImportance == IMPORTANCE_FOREGROUND;
12955 
12956             // Save the original Record's post silently value, so we can restore it after we send
12957             // the SystemUI specific silent update.
12958             boolean savedPostSilentlyState = record.shouldPostSilently();
12959             boolean savedOnlyAlertOnceState = (record.getNotification().flags
12960                     & FLAG_ONLY_ALERT_ONCE) > 0;
12961             // Lifetime extended notifications don't need to alert on new state change.
12962             record.setPostSilently(true);
12963             // We also set FLAG_ONLY_ALERT_ONCE to avoid the notification from HUN-ing again.
12964             record.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
12965 
12966             PostNotificationTracker tracker = mPostNotificationTrackerFactory.newTracker(null);
12967             tracker.addCleanupRunnable(() -> {
12968                 synchronized (mNotificationLock) {
12969                     // Set the post silently status to the record's previous value.
12970                     record.setPostSilently(savedPostSilentlyState);
12971                     // Remove FLAG_ONLY_ALERT_ONCE if the notification did not previously have it.
12972                     if (!savedOnlyAlertOnceState) {
12973                         record.getNotification().flags &= ~FLAG_ONLY_ALERT_ONCE;
12974                     }
12975                 }
12976             });
12977 
12978             mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(),
12979                     record, isAppForeground, /* isAppProvided= */ false, tracker));
12980 
12981             EventLogTags.writeNotificationCancelPrevented(record.getKey());
12982         }
12983     }
12984 
12985     @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR)
12986     private int getPackageImportanceWithIdentity(String pkg) {
12987         final long token = Binder.clearCallingIdentity();
12988         final int packageImportance;
12989         try {
12990             packageImportance = mActivityManager.getPackageImportance(pkg);
12991         } finally {
12992             Binder.restoreCallingIdentity(token);
12993         }
12994         return packageImportance;
12995     }
12996 
12997     public class NotificationListeners extends ManagedServices {
12998         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
12999         static final String TAG_REQUESTED_LISTENERS = "request_listeners";
13000         static final String TAG_REQUESTED_LISTENER = "listener";
13001         static final String ATT_COMPONENT = "component";
13002         static final String ATT_TYPES = "types";
13003         static final String ATT_PKG = "pkg";
13004         static final String ATT_UID = "uid";
13005         static final String TAG_APPROVED = "allowed";
13006         static final String TAG_DISALLOWED= "disallowed";
13007         static final String XML_SEPARATOR = ",";
13008         static final String FLAG_SEPARATOR = "\\|";
13009 
13010         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
13011 
13012         @GuardedBy("mTrustedListenerUids")
13013         private final ArraySet<Integer> mTrustedListenerUids = new ArraySet<>();
13014         @GuardedBy("mRequestedNotificationListeners")
13015         private final ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter>
13016                 mRequestedNotificationListeners = new ArrayMap<>();
13017         private final boolean mIsHeadlessSystemUserMode;
13018 
13019         public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
13020                 IPackageManager pm) {
13021             this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode());
13022         }
13023 
13024         @VisibleForTesting
13025         public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
13026                 IPackageManager pm, boolean isHeadlessSystemUserMode) {
13027             super(context, lock, userProfiles, pm);
13028             this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode;
13029         }
13030 
13031         @Override
13032         protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
13033                 boolean isPrimary, boolean enabled, boolean userSet) {
13034             super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
13035             String pkgName = getPackageName(pkgOrComponent);
13036             if (redactSensitiveNotificationsFromUntrustedListeners()) {
13037                 int uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId);
13038                 if (!enabled && uid >= 0) {
13039                     synchronized (mTrustedListenerUids) {
13040                         mTrustedListenerUids.remove(uid);
13041                     }
13042                 }
13043                 if (enabled && uid >= 0 && isAppTrustedNotificationListenerService(uid, pkgName)) {
13044                     synchronized (mTrustedListenerUids) {
13045                         mTrustedListenerUids.add(uid);
13046                     }
13047                 }
13048             }
13049 
13050             mContext.sendBroadcastAsUser(
13051                     new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED)
13052                             .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
13053                     UserHandle.of(userId), null);
13054         }
13055 
13056         @Override
13057         protected void loadDefaultsFromConfig() {
13058             String defaultListenerAccess = mContext.getResources().getString(
13059                     R.string.config_defaultListenerAccessPackages);
13060             if (defaultListenerAccess != null) {
13061                 String[] listeners =
13062                         defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
13063                 for (int i = 0; i < listeners.length; i++) {
13064                     if (TextUtils.isEmpty(listeners[i])) {
13065                         continue;
13066                     }
13067                     int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
13068                     // In the headless system user mode, packages might not be installed for the
13069                     // system user. Match packages for any user since apps can be installed only for
13070                     // non-system users and would be considering uninstalled for the system user.
13071                     if (mIsHeadlessSystemUserMode) {
13072                         packageQueryFlags += MATCH_ANY_USER;
13073                     }
13074                     ArraySet<ComponentName> approvedListeners =
13075                             this.queryPackageForServices(listeners[i], packageQueryFlags,
13076                                     USER_SYSTEM);
13077                     for (int k = 0; k < approvedListeners.size(); k++) {
13078                         ComponentName cn = approvedListeners.valueAt(k);
13079                         addDefaultComponentOrPackage(cn.flattenToString());
13080                     }
13081                 }
13082             }
13083         }
13084 
13085         @Override
13086         protected int getBindFlags() {
13087             // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE
13088             // because too many 3P apps could be kept in memory as notification listeners and
13089             // cause extreme memory pressure.
13090             // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
13091             return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
13092                     | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
13093         }
13094 
13095         @Override
13096         protected Config getConfig() {
13097             Config c = new Config();
13098             c.caption = "notification listener";
13099             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
13100             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
13101             c.secureSettingName = Secure.ENABLED_NOTIFICATION_LISTENERS;
13102             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
13103             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
13104             c.clientLabel = R.string.notification_listener_binding_label;
13105             return c;
13106         }
13107 
13108         @Override
13109         protected IInterface asInterface(IBinder binder) {
13110             return INotificationListener.Stub.asInterface(binder);
13111         }
13112 
13113         @Override
13114         protected boolean checkType(IInterface service) {
13115             return service instanceof INotificationListener;
13116         }
13117 
13118         @Override
13119         public void onServiceAdded(ManagedServiceInfo info) {
13120             if (lifetimeExtensionRefactor()) {
13121                 // Generally, only System or System UI should have the permissions to call
13122                 // registerSystemService.
13123                 // isCallerSystemOrPhone tells us whether the caller is System. We negate this,
13124                 // to eliminate cases where the service was added by the system. This leaves
13125                 // services registered by system server.
13126                 // To identify system UI, we explicitly check the status bar permission for the
13127                 // uid in the info object.
13128                 // We can't use the calling uid here because it belongs to system server.
13129                 // Note that this will also return true for the shell, but we deem this
13130                 // acceptable, for the purposes of testing.
13131                 info.isSystemUi = !isCallerSystemOrPhone() && getContext().checkPermission(
13132                         android.Manifest.permission.STATUS_BAR_SERVICE, -1, info.uid)
13133                         == PERMISSION_GRANTED;
13134             }
13135             final INotificationListener listener = (INotificationListener) info.service;
13136             final NotificationRankingUpdate update;
13137             synchronized (mNotificationLock) {
13138                 update = makeRankingUpdateLocked(info);
13139                 updateUriPermissionsForActiveNotificationsLocked(info, true);
13140             }
13141             if (redactSensitiveNotificationsFromUntrustedListeners()
13142                     && isAppTrustedNotificationListenerService(
13143                     info.uid, info.component.getPackageName())) {
13144                 synchronized (mTrustedListenerUids) {
13145                     mTrustedListenerUids.add(info.uid);
13146                 }
13147             }
13148             try {
13149                 listener.onListenerConnected(update);
13150             } catch (RemoteException e) {
13151                 // we tried
13152             }
13153         }
13154 
13155         @Override
13156         @GuardedBy("mNotificationLock")
13157         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
13158             updateUriPermissionsForActiveNotificationsLocked(removed, false);
13159             if (removeDisabledHints(removed)) {
13160                 updateListenerHintsLocked();
13161                 updateEffectsSuppressorLocked();
13162             }
13163             if (redactSensitiveNotificationsFromUntrustedListeners()) {
13164                 synchronized (mTrustedListenerUids) {
13165                     mTrustedListenerUids.remove(removed.uid);
13166                 }
13167             }
13168             mLightTrimListeners.remove(removed);
13169         }
13170 
13171         @Override
13172         public void onUserRemoved(int user) {
13173             super.onUserRemoved(user);
13174             synchronized (mRequestedNotificationListeners) {
13175                 for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) {
13176                     if (mRequestedNotificationListeners.keyAt(i).second == user) {
13177                         mRequestedNotificationListeners.removeAt(i);
13178                     }
13179                 }
13180             }
13181         }
13182 
13183         @Override
13184         public void onUserUnlocked(int user) {
13185             if (!managedServicesConcurrentMultiuser()
13186                     && mUmInternal.isVisibleBackgroundFullUser(user)) {
13187                 // The main use case for visible background users is the Automotive
13188                 // multi-display configuration where a passenger can use a secondary
13189                 // display while the driver is using the main display.
13190                 // NotificationListeners is designed only for the current user and work
13191                 // profile. We added a condition to prevent visible background users from
13192                 // updating the data managed within the NotificationListeners object.
13193                 return;
13194             }
13195             super.onUserUnlocked(user);
13196         }
13197 
13198         @Override
13199         protected boolean allowRebindForParentUser() {
13200             return true;
13201         }
13202 
13203         @Override
13204         public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
13205             super.onPackagesChanged(removingPackage, pkgList, uidList);
13206 
13207             synchronized (mRequestedNotificationListeners) {
13208                 // Since the default behavior is to allow everything, we don't need to explicitly
13209                 // handle package add or update. they will be added to the xml file on next boot or
13210                 // when the user tries to change the settings.
13211                 if (removingPackage) {
13212                     for (int i = 0; i < pkgList.length; i++) {
13213                         String pkg = pkgList[i];
13214                         int userId = UserHandle.getUserId(uidList[i]);
13215                         for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
13216                             Pair<ComponentName, Integer> key =
13217                                     mRequestedNotificationListeners.keyAt(j);
13218                             if (key.second == userId && key.first.getPackageName().equals(pkg)) {
13219                                 mRequestedNotificationListeners.removeAt(j);
13220                             }
13221                         }
13222                     }
13223 
13224                     // Clean up removed package from the disallowed packages list
13225                     for (int i = 0; i < pkgList.length; i++) {
13226                         String pkg = pkgList[i];
13227                         for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
13228                             NotificationListenerFilter nlf =
13229                                     mRequestedNotificationListeners.valueAt(j);
13230                             VersionedPackage ai = new VersionedPackage(pkg, uidList[i]);
13231                             nlf.removePackage(ai);
13232                         }
13233                     }
13234                 }
13235             }
13236         }
13237 
13238         @Override
13239         protected String getRequiredPermission() {
13240             return null;
13241         }
13242 
13243         @Override
13244         protected boolean shouldReflectToSettings() {
13245             // androidx has a public method that reads the approved set of listeners from
13246             // Settings so we have to continue writing this list for this type of service
13247             return true;
13248         }
13249 
13250         @Override
13251         protected void readExtraTag(String tag, TypedXmlPullParser parser)
13252                 throws IOException, XmlPullParserException {
13253             if (TAG_REQUESTED_LISTENERS.equals(tag)) {
13254                 final int listenersOuterDepth = parser.getDepth();
13255                 while (XmlUtils.nextElementWithin(parser, listenersOuterDepth)) {
13256                     if (!TAG_REQUESTED_LISTENER.equals(parser.getName())) {
13257                         continue;
13258                     }
13259                     final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID);
13260                     final ComponentName cn = ComponentName.unflattenFromString(
13261                             XmlUtils.readStringAttribute(parser, ATT_COMPONENT));
13262                     int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING
13263                             | FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING;
13264 
13265                     ArraySet<VersionedPackage> disallowedPkgs = new ArraySet<>();
13266                     final int listenerOuterDepth = parser.getDepth();
13267                     while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) {
13268                         if (TAG_APPROVED.equals(parser.getName())) {
13269                             approved = XmlUtils.readIntAttribute(parser, ATT_TYPES);
13270                         } else if (TAG_DISALLOWED.equals(parser.getName())) {
13271                             String pkg = XmlUtils.readStringAttribute(parser, ATT_PKG);
13272                             int uid = XmlUtils.readIntAttribute(parser, ATT_UID);
13273                             if (!TextUtils.isEmpty(pkg)) {
13274                                 VersionedPackage ai = new VersionedPackage(pkg, uid);
13275                                 disallowedPkgs.add(ai);
13276                             }
13277                         }
13278                     }
13279                     NotificationListenerFilter nlf =
13280                             new NotificationListenerFilter(approved, disallowedPkgs);
13281                     synchronized (mRequestedNotificationListeners) {
13282                         mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf);
13283                     }
13284                 }
13285             }
13286         }
13287 
13288         @Override
13289         protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
13290             out.startTag(null, TAG_REQUESTED_LISTENERS);
13291             synchronized (mRequestedNotificationListeners) {
13292                 for (Pair<ComponentName, Integer> listener :
13293                         mRequestedNotificationListeners.keySet()) {
13294                     NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener);
13295                     out.startTag(null, TAG_REQUESTED_LISTENER);
13296                     XmlUtils.writeStringAttribute(
13297                             out, ATT_COMPONENT, listener.first.flattenToString());
13298                     XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second);
13299 
13300                     out.startTag(null, TAG_APPROVED);
13301                     XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes());
13302                     out.endTag(null, TAG_APPROVED);
13303 
13304                     for (VersionedPackage ai : nlf.getDisallowedPackages()) {
13305                         if (!TextUtils.isEmpty(ai.getPackageName())) {
13306                             out.startTag(null, TAG_DISALLOWED);
13307                             XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName());
13308                             XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode());
13309                             out.endTag(null, TAG_DISALLOWED);
13310                         }
13311                     }
13312 
13313                     out.endTag(null, TAG_REQUESTED_LISTENER);
13314                 }
13315             }
13316 
13317             out.endTag(null, TAG_REQUESTED_LISTENERS);
13318         }
13319 
13320         @Nullable protected NotificationListenerFilter getNotificationListenerFilter(
13321                 Pair<ComponentName, Integer> pair) {
13322             synchronized (mRequestedNotificationListeners) {
13323                 return mRequestedNotificationListeners.get(pair);
13324             }
13325         }
13326 
13327         protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair,
13328                 NotificationListenerFilter nlf) {
13329             synchronized (mRequestedNotificationListeners) {
13330                 mRequestedNotificationListeners.put(pair, nlf);
13331             }
13332         }
13333 
13334         @Override
13335         protected void ensureFilters(ServiceInfo si, int userId) {
13336             Pair<ComponentName, Integer> listener = Pair.create(si.getComponentName(), userId);
13337             synchronized (mRequestedNotificationListeners) {
13338                 NotificationListenerFilter existingNlf =
13339                         mRequestedNotificationListeners.get(listener);
13340                 if (si.metaData != null) {
13341                     if (existingNlf == null) {
13342                         // no stored filters for this listener; see if they provided a default
13343                         if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
13344                             String typeList =
13345                                     si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
13346                             if (typeList != null) {
13347                                 int types = getTypesFromStringList(typeList);
13348                                 NotificationListenerFilter nlf =
13349                                         new NotificationListenerFilter(types, new ArraySet<>());
13350                                 mRequestedNotificationListeners.put(listener, nlf);
13351                             }
13352                         }
13353                     }
13354 
13355                     // also check the types they never want bridged
13356                     if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
13357                         int neverBridge = getTypesFromStringList(si.metaData.get(
13358                                 META_DATA_DISABLED_FILTER_TYPES).toString());
13359                         if (neverBridge != 0) {
13360                             NotificationListenerFilter nlf =
13361                                     mRequestedNotificationListeners.getOrDefault(
13362                                             listener, new NotificationListenerFilter());
13363                             nlf.setTypes(nlf.getTypes() & ~neverBridge);
13364                             mRequestedNotificationListeners.put(listener, nlf);
13365                         }
13366                     }
13367                 }
13368             }
13369         }
13370 
13371         private int getTypesFromStringList(String typeList) {
13372             int types = 0;
13373             if (typeList != null) {
13374                 String[] typeStrings = typeList.split(FLAG_SEPARATOR);
13375                 for (int i = 0; i < typeStrings.length; i++) {
13376                     final String typeString = typeStrings[i];
13377                     if (TextUtils.isEmpty(typeString)) {
13378                         continue;
13379                     }
13380                     if (typeString.equalsIgnoreCase("ONGOING")) {
13381                         types |= FLAG_FILTER_TYPE_ONGOING;
13382                     } else if (typeString.equalsIgnoreCase("CONVERSATIONS")) {
13383                         types |= FLAG_FILTER_TYPE_CONVERSATIONS;
13384                     } else if (typeString.equalsIgnoreCase("SILENT")) {
13385                         types |= FLAG_FILTER_TYPE_SILENT;
13386                     } else if (typeString.equalsIgnoreCase("ALERTING")) {
13387                         types |= FLAG_FILTER_TYPE_ALERTING;
13388                     } else {
13389                         try {
13390                             types |= Integer.parseInt(typeString);
13391                         } catch (NumberFormatException e) {
13392                             // skip
13393                         }
13394                     }
13395                 }
13396             }
13397             return types;
13398         }
13399 
13400         @GuardedBy("mNotificationLock")
13401         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
13402             if (trim == TRIM_LIGHT) {
13403                 mLightTrimListeners.add(info);
13404             } else {
13405                 mLightTrimListeners.remove(info);
13406             }
13407         }
13408 
13409         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
13410             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
13411         }
13412 
13413         public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
13414             // send to all currently bounds NASes since notifications from both users will appear in
13415             // the status bar
13416             for (final ManagedServiceInfo info : getServices()) {
13417                 mHandler.post(() -> {
13418                     final INotificationListener listener = (INotificationListener) info.service;
13419                     try {
13420                         listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
13421                     } catch (RemoteException ex) {
13422                         Slog.e(TAG, "unable to notify listener "
13423                                 + "(hideSilentStatusIcons): " + info, ex);
13424                     }
13425                 });
13426             }
13427         }
13428 
13429         /**
13430          * Asynchronously notify all listeners about a new or updated notification. Note that the
13431          * notification is new or updated from the point of view of the NLS, but might not be
13432          * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method
13433          * is also invoked after exiting lockdown mode.
13434          *
13435          * <p>
13436          * Also takes care of removing a notification that has been visible to a listener before,
13437          * but isn't anymore.
13438          */
13439         @VisibleForTesting
13440         @GuardedBy("mNotificationLock")
13441         void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
13442             notifyPostedLocked(r, old, true);
13443         }
13444 
13445         /**
13446          * Asynchronously notify all listeners about a new or updated notification. Note that the
13447          * notification is new or updated from the point of view of the NLS, but might not be
13448          * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method
13449          * is invoked after exiting lockdown mode.
13450          *
13451          * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
13452          *                           targeting <= O_MR1
13453          */
13454         @VisibleForTesting
13455         @GuardedBy("mNotificationLock")
13456         void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
13457                 boolean notifyAllListeners) {
13458             for (Runnable listenerCall : prepareNotifyPostedLocked(r, old, notifyAllListeners)) {
13459                 mHandler.post(listenerCall);
13460             }
13461         }
13462 
13463         /**
13464          * "Prepares" to notify all listeners about the posted notification.
13465          *
13466          * <p>This method <em>does not invoke</em> the listeners; the caller should post each
13467          * returned {@link Runnable} on a suitable thread to do so.
13468          *
13469          * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
13470          *                           targeting <= O_MR1
13471          * @return A list of {@link Runnable} operations to notify all listeners about the posted
13472          * notification.
13473          */
13474         @VisibleForTesting
13475         @GuardedBy("mNotificationLock")
13476         List<Runnable> prepareNotifyPostedLocked(NotificationRecord r,
13477                 NotificationRecord old, boolean notifyAllListeners) {
13478             if (isInLockDownMode(r.getUser().getIdentifier())) {
13479                 return new ArrayList<>();
13480             }
13481 
13482             ArrayList<Runnable> listenerCalls = new ArrayList<>();
13483             try {
13484                 // Lazily initialized snapshots of the notification.
13485                 StatusBarNotification sbn = r.getSbn();
13486                 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
13487                 TrimCache trimCache = new TrimCache(sbn);
13488                 TrimCache redactedCache = null;
13489                 StatusBarNotification redactedSbn = null;
13490                 StatusBarNotification oldRedactedSbn = null;
13491                 boolean isNewSensitive = hasSensitiveContent(r);
13492                 boolean isOldSensitive = hasSensitiveContent(old);
13493                 boolean redactionEnabled = redactSensitiveNotificationsFromUntrustedListeners()
13494                         && mRedactOtpNotifications;
13495 
13496                 for (final ManagedServiceInfo info : getServices()) {
13497                     boolean isTrusted = isUidTrusted(info.uid);
13498                     boolean sendRedacted = redactionEnabled && isNewSensitive && !isTrusted;
13499                     boolean sendOldRedacted = redactionEnabled && isOldSensitive && !isTrusted;
13500                     boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info);
13501                     boolean oldSbnVisible = (oldSbn != null)
13502                             && isVisibleToListener(oldSbn, old.getNotificationType(), info);
13503                     // This notification hasn't been and still isn't visible -> ignore.
13504                     if (!oldSbnVisible && !sbnVisible) {
13505                         continue;
13506                     }
13507                     // If the notification is hidden, don't notifyPosted listeners targeting < P.
13508                     // Instead, those listeners will receive notifyPosted when the notification is
13509                     // unhidden.
13510                     if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
13511                         continue;
13512                     }
13513 
13514                     if (lifetimeExtensionRefactor()) {
13515                         if (sendRedacted && redactedSbn == null) {
13516                             redactedSbn = redactStatusBarNotification(sbn);
13517                             redactedCache = new TrimCache(redactedSbn);
13518                         }
13519                         final StatusBarNotification sbnToPost = sendRedacted
13520                                 ? redactedCache.ForListener(info) : trimCache.ForListener(info);
13521 
13522                         // Checks if this is a request to notify system UI about a notification that
13523                         // has been lifetime extended.
13524                         // We check both old and new for the flag, to avoid catching updates
13525                         // (where new will not have the flag).
13526                         // If it is such a request, and this is the system UI listener, we send
13527                         // the post request. If it's any other listener, we skip it.
13528                         if (old != null && old.getNotification() != null
13529                                 && (old.getNotification().flags
13530                                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0
13531                                 && sbn != null && sbn.getNotification() != null
13532                                 && (sbn.getNotification().flags
13533                                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) {
13534                             if (info.isSystemUi()) {
13535                                 final NotificationRankingUpdate update =
13536                                         makeRankingUpdateLocked(info);
13537                                 listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
13538                                 break;
13539                             } else {
13540                                 // Skipping because this is the direct-reply "update" and we only
13541                                 // need to send it to sysui, so we immediately continue, before it
13542                                 // can get sent to other listeners below.
13543                                 if (DBG) {
13544                                     Slog.d(TAG, "prepareNotifyPostedLocked: direct reply update, "
13545                                             + "skipping post to " + info.toString());
13546                                 }
13547                                 continue;
13548                             }
13549                         }
13550                     }
13551 
13552                     // If we shouldn't notify all listeners, this means the hidden state of
13553                     // a notification was changed.  Don't notifyPosted listeners targeting >= P.
13554                     // Instead, those listeners will receive notifyRankingUpdate.
13555                     if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
13556                         continue;
13557                     }
13558 
13559                     final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
13560 
13561                     // This notification became invisible -> remove the old one.
13562                     if (oldSbnVisible && !sbnVisible) {
13563                         if (sendOldRedacted && oldRedactedSbn == null) {
13564                             oldRedactedSbn = redactStatusBarNotification(oldSbn);
13565                         }
13566                         final StatusBarNotification oldSbnLightClone =
13567                                 sendOldRedacted ? oldRedactedSbn.cloneLight() : oldSbn.cloneLight();
13568                         listenerCalls.add(() -> notifyRemoved(
13569                                 info, oldSbnLightClone, update, null, REASON_USER_STOPPED));
13570 
13571                         continue;
13572                     }
13573                     // Grant access before listener is notified
13574                     final int targetUserId = (info.userid == USER_ALL)
13575                             ? USER_SYSTEM : info.userid;
13576                     updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
13577 
13578                     mPackageManagerInternal.grantImplicitAccess(
13579                             targetUserId, null /* intent */,
13580                             UserHandle.getAppId(info.uid),
13581                             sbn.getUid(),
13582                             false /* direct */, false /* retainOnUpdate */);
13583 
13584                     if (sendRedacted && redactedSbn == null) {
13585                         redactedSbn = redactStatusBarNotification(sbn);
13586                         redactedCache = new TrimCache(redactedSbn);
13587                     }
13588 
13589                     final StatusBarNotification sbnToPost = sendRedacted
13590                             ? redactedCache.ForListener(info) : trimCache.ForListener(info);
13591                     listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
13592                 }
13593             } catch (Exception e) {
13594                 Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e);
13595             }
13596             return listenerCalls;
13597         }
13598 
13599         boolean isAppTrustedNotificationListenerService(int uid, String pkg) {
13600             if (!redactSensitiveNotificationsFromUntrustedListeners()) {
13601                 return true;
13602             }
13603 
13604             long token = Binder.clearCallingIdentity();
13605             try {
13606                 if (mPackageManager.checkUidPermission(RECEIVE_SENSITIVE_NOTIFICATIONS, uid)
13607                         == PERMISSION_GRANTED || mPackageManagerInternal.isPlatformSigned(pkg)
13608                         || mAppOps
13609                         .noteOpNoThrow(OP_RECEIVE_SENSITIVE_NOTIFICATIONS, uid, pkg, null, null)
13610                         == MODE_ALLOWED) {
13611                     return true;
13612                 }
13613 
13614                 // check if there is a CDM association with the listener
13615                 // We don't listen for changes because if an association is lost, the app loses
13616                 // NLS access
13617                 List<AssociationInfo> cdmAssocs = new ArrayList<>();
13618                 if (mCompanionManager == null) {
13619                     mCompanionManager = getCompanionManager();
13620                 }
13621                 if (mCompanionManager != null) {
13622                     cdmAssocs =
13623                             mCompanionManager.getAllAssociationsForUser(UserHandle.getUserId(uid));
13624                 }
13625                 for (int i = 0; i < cdmAssocs.size(); i++) {
13626                     AssociationInfo assocInfo = cdmAssocs.get(i);
13627                     if (!assocInfo.isRevoked() && pkg.equals(assocInfo.getPackageName())
13628                             && assocInfo.getUserId() == UserHandle.getUserId(uid)) {
13629                         return true;
13630                     }
13631                 }
13632             } catch (RemoteException e) {
13633                 Slog.e(TAG, "Failed to check trusted status of listener", e);
13634             } finally {
13635                 Binder.restoreCallingIdentity(token);
13636             }
13637             return false;
13638         }
13639 
13640         StatusBarNotification redactStatusBarNotification(StatusBarNotification sbn) {
13641             if (!redactSensitiveNotificationsFromUntrustedListeners()) {
13642                 throw new RuntimeException("redactStatusBarNotification called while flag is off");
13643             }
13644 
13645             ApplicationInfo appInfo = sbn.getNotification().extras.getParcelable(
13646                     EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
13647             String pkgLabel;
13648             if (appInfo != null) {
13649                 pkgLabel = appInfo.loadLabel(mPackageManagerClient).toString();
13650             } else {
13651                 Slog.w(TAG, "StatusBarNotification " + sbn + " does not have ApplicationInfo."
13652                         + " Did you pass in a 'cloneLight' notification?");
13653                 pkgLabel = sbn.getPackageName();
13654             }
13655             String redactedText = mContext.getString(R.string.redacted_notification_message);
13656             Notification oldNotif = sbn.getNotification();
13657             Notification oldClone = new Notification();
13658             oldNotif.cloneInto(oldClone, false);
13659             Notification.Builder redactedNotifBuilder =
13660                     new Notification.Builder(getContext(), oldClone);
13661             redactedNotifBuilder.setContentTitle(pkgLabel);
13662             redactedNotifBuilder.setContentText(redactedText);
13663             redactedNotifBuilder.setSubText(null);
13664             redactedNotifBuilder.setActions();
13665             if (oldNotif.actions != null) {
13666                 for (int i = 0; i < oldNotif.actions.length; i++) {
13667                     Notification.Action act =
13668                             new Notification.Action.Builder(oldNotif.actions[i]).build();
13669                     act.title = mContext.getString(R.string.redacted_notification_action_title);
13670                     redactedNotifBuilder.addAction(act);
13671                 }
13672             }
13673 
13674             if (oldNotif.isStyle(MessagingStyle.class)) {
13675                 Person empty = new Person.Builder().setName("").build();
13676                 MessagingStyle messageStyle = new MessagingStyle(empty);
13677                 messageStyle.addMessage(new MessagingStyle.Message(
13678                         redactedText, System.currentTimeMillis(), empty));
13679                 redactedNotifBuilder.setStyle(messageStyle);
13680             }
13681             if (redactSensitiveNotificationsBigTextStyle()
13682                     && oldNotif.isStyle(Notification.BigTextStyle.class)) {
13683                 Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle();
13684                 bigTextStyle.bigText(mContext.getString(R.string.redacted_notification_message));
13685                 bigTextStyle.setBigContentTitle("");
13686                 bigTextStyle.setSummaryText("");
13687                 redactedNotifBuilder.setStyle(bigTextStyle);
13688             }
13689 
13690             Notification redacted = redactedNotifBuilder.build();
13691             // Notification extras can't always be overridden by a builder (configured by a system
13692             // property), so set them after building
13693             if (redacted.extras.containsKey(EXTRA_TITLE_BIG)) {
13694                 redacted.extras.putString(EXTRA_TITLE_BIG, pkgLabel);
13695             }
13696             redacted.extras.remove(EXTRA_SUB_TEXT);
13697             redacted.extras.remove(EXTRA_TEXT_LINES);
13698             redacted.extras.remove(EXTRA_LARGE_ICON_BIG);
13699             return sbn.cloneShallow(redacted);
13700         }
13701 
13702         boolean hasSensitiveContent(NotificationRecord r) {
13703             if (r == null || !redactSensitiveNotificationsFromUntrustedListeners()) {
13704                 return false;
13705             }
13706             return r.hasSensitiveContent();
13707         }
13708 
13709         boolean isUidTrusted(int uid) {
13710             synchronized (mTrustedListenerUids) {
13711                 return !redactSensitiveNotificationsFromUntrustedListeners()
13712                         || mTrustedListenerUids.contains(uid);
13713             }
13714         }
13715 
13716         /**
13717          * Synchronously grant or revoke permissions to Uris for all active and visible
13718          * notifications to just the NotificationListenerService provided.
13719          */
13720         @GuardedBy("mNotificationLock")
13721         private void updateUriPermissionsForActiveNotificationsLocked(
13722                 ManagedServiceInfo info, boolean grant) {
13723             try {
13724                 for (final NotificationRecord r : mNotificationList) {
13725                     // When granting permissions, ignore notifications which are invisible.
13726                     // When revoking permissions, all notifications are invisible, so process all.
13727                     if (grant && !isVisibleToListener(r.getSbn(), r.getNotificationType(), info)) {
13728                         continue;
13729                     }
13730                     // If the notification is hidden, permissions are not required by the listener.
13731                     if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
13732                         continue;
13733                     }
13734                     // Grant or revoke access synchronously
13735                     final int targetUserId = (info.userid == USER_ALL)
13736                             ? USER_SYSTEM : info.userid;
13737                     if (grant) {
13738                         // Grant permissions by passing arguments as if the notification is new.
13739                         updateUriPermissions(/* newRecord */ r, /* oldRecord */ null,
13740                                 info.component.getPackageName(), targetUserId);
13741                     } else {
13742                         // Revoke permissions by passing arguments as if the notification was
13743                         // removed, but set `onlyRevokeCurrentTarget` to avoid revoking permissions
13744                         // granted to *other* targets by this notification's URIs.
13745                         updateUriPermissions(/* newRecord */ null, /* oldRecord */ r,
13746                                 info.component.getPackageName(), targetUserId,
13747                                 /* onlyRevokeCurrentTarget */ true);
13748                     }
13749                 }
13750             } catch (Exception e) {
13751                 Slog.e(TAG, "Could not " + (grant ? "grant" : "revoke") + " Uri permissions to "
13752                         + info.component, e);
13753             }
13754         }
13755 
13756         /**
13757          * asynchronously notify all listeners about a removed notification
13758          */
13759         @GuardedBy("mNotificationLock")
13760         public void notifyRemovedLocked(NotificationRecord r, int reason,
13761                 NotificationStats notificationStats) {
13762             if (isInLockDownMode(r.getUser().getIdentifier())) {
13763                 return;
13764             }
13765 
13766             final StatusBarNotification sbn = r.getSbn();
13767 
13768             // make a copy in case changes are made to the underlying Notification object
13769             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
13770             // notification
13771             final StatusBarNotification sbnLight = sbn.cloneLight();
13772             StatusBarNotification redactedSbn = null;
13773             boolean hasSensitiveContent = hasSensitiveContent(r);
13774             for (final ManagedServiceInfo info : getServices()) {
13775                 if (!isVisibleToListener(sbn, r.getNotificationType(), info)) {
13776                     continue;
13777                 }
13778 
13779                 // don't notifyRemoved for listeners targeting < P
13780                 // if not for reason package suspended
13781                 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
13782                         && info.targetSdkVersion < Build.VERSION_CODES.P) {
13783                     continue;
13784                 }
13785 
13786                 // don't notifyRemoved for listeners targeting >= P
13787                 // if the reason is package suspended
13788                 if (reason == REASON_PACKAGE_SUSPENDED
13789                         && info.targetSdkVersion >= Build.VERSION_CODES.P) {
13790                     continue;
13791                 }
13792 
13793                 boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners()
13794                         && hasSensitiveContent && !isUidTrusted(info.uid);
13795                 if (sendRedacted && redactedSbn == null) {
13796                     redactedSbn = redactStatusBarNotification(sbn);
13797                 }
13798 
13799                 // Only assistants can get stats
13800                 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
13801                         ? notificationStats : null;
13802                 final StatusBarNotification sbnToSend = sendRedacted ? redactedSbn : sbnLight;
13803                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
13804                 mHandler.post(() -> notifyRemoved(info, sbnToSend, update, stats, reason));
13805             }
13806 
13807             // Revoke access after all listeners have been updated
13808             mHandler.post(() -> updateUriPermissions(null, r, null, USER_SYSTEM));
13809         }
13810 
13811         /**
13812          * Asynchronously notify all listeners about a reordering of notifications
13813          * unless changedHiddenNotifications is populated.
13814          * If changedHiddenNotifications is populated, there was a change in the hidden state
13815          * of the notifications.  In this case, we only send updates to listeners that
13816          * target >= P.
13817          */
13818         @GuardedBy("mNotificationLock")
13819         public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
13820             boolean isHiddenRankingUpdate = changedHiddenNotifications != null
13821                     && changedHiddenNotifications.size() > 0;
13822 
13823             // TODO (b/73052211): if the ranking update changed the notification type,
13824             // cancel notifications for NLSes that can't see them anymore
13825             for (final ManagedServiceInfo serviceInfo : getServices()) {
13826                 if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener(
13827                         serviceInfo, ActivityManager.getCurrentUser())) {
13828                     continue;
13829                 }
13830 
13831                 boolean notifyThisListener = false;
13832                 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
13833                         Build.VERSION_CODES.P) {
13834                     for (NotificationRecord rec : changedHiddenNotifications) {
13835                         if (isVisibleToListener(
13836                                 rec.getSbn(), rec.getNotificationType(), serviceInfo)) {
13837                             notifyThisListener = true;
13838                             break;
13839                         }
13840                     }
13841                 }
13842 
13843                 if (notifyThisListener || !isHiddenRankingUpdate) {
13844                     final NotificationRankingUpdate update = makeRankingUpdateLocked(
13845                             serviceInfo);
13846                     mHandler.post(() -> notifyRankingUpdate(serviceInfo, update));
13847                 }
13848             }
13849         }
13850 
13851         @GuardedBy("mNotificationLock")
13852         public void notifyListenerHintsChangedLocked(final int hints) {
13853             for (final ManagedServiceInfo serviceInfo : getServices()) {
13854                 if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener(
13855                         serviceInfo, ActivityManager.getCurrentUser())) {
13856                     continue;
13857                 }
13858                 mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints));
13859             }
13860         }
13861 
13862         /**
13863          * asynchronously notify relevant listeners their notification is hidden
13864          * NotificationListenerServices that target P+:
13865          *      NotificationListenerService#notifyRankingUpdateLocked()
13866          * NotificationListenerServices that target <= P:
13867          *      NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
13868          */
13869         @GuardedBy("mNotificationLock")
13870         public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
13871             if (changedNotifications == null || changedNotifications.size() == 0) {
13872                 return;
13873             }
13874 
13875             notifyRankingUpdateLocked(changedNotifications);
13876 
13877             // for listeners that target < P, notifyRemoveLocked
13878             int numChangedNotifications = changedNotifications.size();
13879             for (int i = 0; i < numChangedNotifications; i++) {
13880                 NotificationRecord rec = changedNotifications.get(i);
13881                 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
13882             }
13883         }
13884 
13885         /**
13886          * asynchronously notify relevant listeners their notification is unhidden
13887          * NotificationListenerServices that target P+:
13888          *      NotificationListenerService#notifyRankingUpdateLocked()
13889          * NotificationListenerServices that target <= P:
13890          *      NotificationListeners#notifyPostedLocked()
13891          */
13892         @GuardedBy("mNotificationLock")
13893         public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
13894             if (changedNotifications == null || changedNotifications.size() == 0) {
13895                 return;
13896             }
13897 
13898             notifyRankingUpdateLocked(changedNotifications);
13899 
13900             // for listeners that target < P, notifyPostedLocked
13901             int numChangedNotifications = changedNotifications.size();
13902             for (int i = 0; i < numChangedNotifications; i++) {
13903                 NotificationRecord rec = changedNotifications.get(i);
13904                 notifyPostedLocked(rec, rec, false);
13905             }
13906         }
13907 
13908         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
13909             for (final ManagedServiceInfo serviceInfo : getServices()) {
13910                 if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener(
13911                         serviceInfo, ActivityManager.getCurrentUser())) {
13912                     continue;
13913                 }
13914                 mHandler.post(
13915                         () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter));
13916             }
13917         }
13918 
13919         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
13920                 final NotificationChannel channel, final int modificationType) {
13921             if (channel == null) {
13922                 return;
13923             }
13924             for (final ManagedServiceInfo info : getServices()) {
13925                 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
13926                         || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
13927                     continue;
13928                 }
13929 
13930                 BackgroundThread.getHandler().post(() -> {
13931                     if (info.isSystem
13932                             || hasCompanionDevice(info)
13933                             || isServiceTokenValid(info.service)) {
13934                         notifyNotificationChannelChanged(
13935                                 info, pkg, user, channel, modificationType);
13936                     }
13937                 });
13938             }
13939         }
13940 
13941         protected void notifyNotificationChannelGroupChanged(
13942                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
13943                 final int modificationType) {
13944             if (group == null) {
13945                 return;
13946             }
13947             for (final ManagedServiceInfo info : getServices()) {
13948                 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
13949                         || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
13950                     continue;
13951                 }
13952 
13953                 BackgroundThread.getHandler().post(() -> {
13954                     if (info.isSystem() || hasCompanionDevice(info)) {
13955                         notifyNotificationChannelGroupChanged(
13956                                 info, pkg, user, group, modificationType);
13957                     }
13958                 });
13959             }
13960         }
13961 
13962         private void notifyPosted(final ManagedServiceInfo info,
13963                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
13964             final INotificationListener listener = (INotificationListener) info.service;
13965             try {
13966                 if (android.app.Flags.noSbnholder()) {
13967                     listener.onNotificationPostedFull(sbn, rankingUpdate);
13968                 } else {
13969                     StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
13970                     listener.onNotificationPosted(sbnHolder, rankingUpdate);
13971                 }
13972             } catch (DeadObjectException ex) {
13973                 Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex);
13974             } catch (RemoteException ex) {
13975                 Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
13976             }
13977         }
13978 
13979         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
13980                 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
13981             final INotificationListener listener = (INotificationListener) info.service;
13982             try {
13983                 if (!CompatChanges.isChangeEnabled(NOTIFICATION_CANCELLATION_REASONS, info.uid)
13984                         && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
13985                     reason = REASON_CHANNEL_BANNED;
13986                 }
13987                 // apps before T don't know about REASON_ASSISTANT, so replace it with the
13988                 // previously-used case, REASON_LISTENER_CANCEL
13989                 if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid)
13990                         && reason == REASON_ASSISTANT_CANCEL) {
13991                     reason = REASON_LISTENER_CANCEL;
13992                 }
13993                 if (android.app.Flags.noSbnholder()) {
13994                     listener.onNotificationRemovedFull(sbn, rankingUpdate, stats, reason);
13995                 } else {
13996                     StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
13997                     listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
13998                 }
13999             } catch (DeadObjectException ex) {
14000                 Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex);
14001             } catch (RemoteException ex) {
14002                 Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
14003             }
14004         }
14005 
14006         private void notifyRankingUpdate(ManagedServiceInfo info,
14007                                          NotificationRankingUpdate rankingUpdate) {
14008             final INotificationListener listener = (INotificationListener) info.service;
14009             try {
14010                 listener.onNotificationRankingUpdate(rankingUpdate);
14011             } catch (DeadObjectException ex) {
14012                 Slog.wtf(TAG, "unable to notify listener (ranking update): " + info, ex);
14013             } catch (RemoteException ex) {
14014                 Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
14015             }
14016         }
14017 
14018         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
14019             final INotificationListener listener = (INotificationListener) info.service;
14020             try {
14021                 listener.onListenerHintsChanged(hints);
14022             } catch (RemoteException ex) {
14023                 Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex);
14024             }
14025         }
14026 
14027         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
14028                 int interruptionFilter) {
14029             final INotificationListener listener = (INotificationListener) info.service;
14030             try {
14031                 listener.onInterruptionFilterChanged(interruptionFilter);
14032             } catch (RemoteException ex) {
14033                 Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex);
14034             }
14035         }
14036 
14037         void notifyNotificationChannelChanged(ManagedServiceInfo info,
14038                 final String pkg, final UserHandle user, final NotificationChannel channel,
14039                 final int modificationType) {
14040             final INotificationListener listener = (INotificationListener) info.service;
14041             try {
14042                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
14043             } catch (RemoteException ex) {
14044                 Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex);
14045             }
14046         }
14047 
14048         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
14049                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
14050                 final int modificationType) {
14051             final INotificationListener listener = (INotificationListener) info.getService();
14052             try {
14053                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
14054             } catch (RemoteException ex) {
14055                 Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex);
14056             }
14057         }
14058 
14059         public boolean isListenerPackage(String packageName) {
14060             if (packageName == null) {
14061                 return false;
14062             }
14063             // TODO: clean up locking object later
14064             synchronized (mNotificationLock) {
14065                 for (final ManagedServiceInfo serviceInfo : getServices()) {
14066                     if (packageName.equals(serviceInfo.component.getPackageName())) {
14067                         return true;
14068                     }
14069                 }
14070             }
14071             return false;
14072         }
14073 
14074         // Returns whether there is a component with listener access granted that is associated
14075         // with the given package name / user ID.
14076         boolean hasAllowedListener(String packageName, int userId) {
14077             if (packageName == null) {
14078                 return false;
14079             }
14080 
14081             // Loop through allowed components to compare package names
14082             List<ComponentName> allowedComponents = getAllowedComponents(userId);
14083             for (int i = 0; i < allowedComponents.size(); i++) {
14084                 if (allowedComponents.get(i).getPackageName().equals(packageName)) {
14085                     return true;
14086                 }
14087             }
14088             return false;
14089         }
14090     }
14091 
14092     @GuardedBy("mNotificationLock")
14093     private void broadcastToCallNotificationEventCallbacks(
14094             final RemoteCallbackList<ICallNotificationEventCallback> callbackList,
14095             final NotificationRecord r,
14096             boolean isPosted) {
14097         if (callbackList != null) {
14098             int numCallbacks = callbackList.beginBroadcast();
14099             try {
14100                 for (int i = 0; i < numCallbacks; i++) {
14101                     if (isPosted) {
14102                         callbackList.getBroadcastItem(i)
14103                                 .onCallNotificationPosted(r.getSbn().getPackageName(), r.getUser());
14104                     } else {
14105                         callbackList.getBroadcastItem(i)
14106                                 .onCallNotificationRemoved(r.getSbn().getPackageName(),
14107                                     r.getUser());
14108                     }
14109                 }
14110             } catch (RemoteException e) {
14111                 throw new RuntimeException(e);
14112             }
14113             callbackList.finishBroadcast();
14114         }
14115     }
14116 
14117     @GuardedBy("mNotificationLock")
14118     void notifyCallNotificationEventListenerOnPosted(final NotificationRecord r) {
14119         if (!r.getNotification().isStyle(Notification.CallStyle.class)) {
14120             return;
14121         }
14122 
14123         synchronized (mCallNotificationEventCallbacks) {
14124             ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
14125                     callbacksForPackage =
14126                     mCallNotificationEventCallbacks.get(r.getSbn().getPackageName());
14127             if (callbacksForPackage == null) {
14128                 return;
14129             }
14130 
14131             if (!r.getUser().equals(UserHandle.ALL)) {
14132                 broadcastToCallNotificationEventCallbacks(
14133                         callbacksForPackage.get(r.getUser().getIdentifier()), r, true);
14134                 // Also notify the listeners registered for USER_ALL
14135                 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r,
14136                         true);
14137             } else {
14138                 // Notify listeners registered for any userId
14139                 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList
14140                         : callbacksForPackage.values()) {
14141                     broadcastToCallNotificationEventCallbacks(callbackList, r, true);
14142                 }
14143             }
14144         }
14145     }
14146 
14147     @GuardedBy("mNotificationLock")
14148     void notifyCallNotificationEventListenerOnRemoved(final NotificationRecord r) {
14149         if (!r.getNotification().isStyle(Notification.CallStyle.class)) {
14150             return;
14151         }
14152 
14153         synchronized (mCallNotificationEventCallbacks) {
14154             ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>>
14155                     callbacksForPackage =
14156                     mCallNotificationEventCallbacks.get(r.getSbn().getPackageName());
14157             if (callbacksForPackage == null) {
14158                 return;
14159             }
14160 
14161             if (!r.getUser().equals(UserHandle.ALL)) {
14162                 broadcastToCallNotificationEventCallbacks(
14163                         callbacksForPackage.get(r.getUser().getIdentifier()), r, false);
14164                 // Also notify the listeners registered for USER_ALL
14165                 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r,
14166                         false);
14167             } else {
14168                 // Notify listeners registered for any userId
14169                 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList
14170                         : callbacksForPackage.values()) {
14171                     broadcastToCallNotificationEventCallbacks(callbackList, r, false);
14172                 }
14173             }
14174         }
14175     }
14176 
14177     // TODO (b/194833441): remove when we've fully migrated to a permission
14178     class RoleObserver implements OnRoleHoldersChangedListener {
14179         // Role name : user id : list of approved packages
14180         private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
14181 
14182         /**
14183          * Writes should be pretty rare (only when default browser changes) and reads are done
14184          * during activity start code-path, so we're optimizing for reads. This means this set is
14185          * immutable once written and we'll recreate the set every time there is a role change and
14186          * then assign that new set to the volatile below, so reads can be done without needing to
14187          * hold a lock. Every write is done on the main-thread, so write atomicity is guaranteed.
14188          *
14189          * Didn't use unmodifiable set to enforce immutability to avoid iterating via iterators.
14190          */
14191         private volatile ArraySet<Integer> mTrampolineExemptUids = new ArraySet<>();
14192 
14193         private final RoleManager mRm;
14194         private final IPackageManager mPm;
14195         private final Executor mExecutor;
14196         private final Looper mMainLooper;
14197 
14198         RoleObserver(Context context, @NonNull RoleManager roleManager,
14199                 @NonNull IPackageManager pkgMgr, @NonNull Looper mainLooper) {
14200             mRm = roleManager;
14201             mPm = pkgMgr;
14202             mExecutor = context.getMainExecutor();
14203             mMainLooper = mainLooper;
14204         }
14205 
14206         /** Should be called from the main-thread. */
14207         @MainThread
14208         public void init() {
14209             List<UserHandle> users = mUm.getUserHandles(/* excludeDying */ true);
14210             mNonBlockableDefaultApps = new ArrayMap<>();
14211             for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
14212                 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
14213                 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
14214                 for (int j = 0; j < users.size(); j++) {
14215                     Integer userId = users.get(j).getIdentifier();
14216                     ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
14217                             NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
14218                     ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
14219                     for (String pkg : approvedForUserId) {
14220                         approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
14221                     }
14222                     userToApprovedList.put(userId, approvedForUserId);
14223                     mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
14224                 }
14225             }
14226             updateTrampolineExemptUidsForUsers(users.toArray(new UserHandle[0]));
14227             mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
14228         }
14229 
14230         void destroy() {
14231             mRm.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.ALL);
14232         }
14233 
14234         @VisibleForTesting
14235         public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
14236             return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
14237         }
14238 
14239         @VisibleForTesting
14240         public boolean isUidExemptFromTrampolineRestrictions(int uid) {
14241             return mTrampolineExemptUids.contains(uid);
14242         }
14243 
14244         /**
14245          * Convert the assistant-role holder into settings. The rest of the system uses the
14246          * settings.
14247          *
14248          * @param roleName the name of the role whose holders are changed
14249          * @param user the user for this role holder change
14250          */
14251         @Override
14252         public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
14253             onRoleHoldersChangedForNonBlockableDefaultApps(roleName, user);
14254             onRoleHoldersChangedForTrampolines(roleName, user);
14255         }
14256 
14257         private void onRoleHoldersChangedForNonBlockableDefaultApps(@NonNull String roleName,
14258                 @NonNull UserHandle user) {
14259             // we only care about a couple of the roles they'll tell us about
14260             boolean relevantChange = false;
14261             for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
14262                 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
14263                     relevantChange = true;
14264                     break;
14265                 }
14266             }
14267 
14268             if (!relevantChange) {
14269                 return;
14270             }
14271 
14272             ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
14273 
14274             // find the diff
14275             ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
14276                     mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
14277             ArraySet<String> previouslyApproved =
14278                     prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
14279 
14280             ArraySet<String> toRemove = new ArraySet<>();
14281             ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
14282 
14283             for (String previous : previouslyApproved) {
14284                 if (!roleHolders.contains(previous)) {
14285                     toRemove.add(previous);
14286                 }
14287             }
14288             for (String nowApproved : roleHolders) {
14289                 if (!previouslyApproved.contains(nowApproved)) {
14290                     toAdd.add(new Pair(nowApproved,
14291                             getUidForPackage(nowApproved, user.getIdentifier())));
14292                 }
14293             }
14294 
14295             // store newly approved apps
14296             prevApprovedForRole.put(user.getIdentifier(), roleHolders);
14297             mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
14298 
14299             // update what apps can be blocked
14300             mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
14301 
14302             // RoleManager is the source of truth for this data so we don't need to trigger a
14303             // write of the notification policy xml for this change
14304         }
14305 
14306         private void onRoleHoldersChangedForTrampolines(@NonNull String roleName,
14307                 @NonNull UserHandle user) {
14308             if (!RoleManager.ROLE_BROWSER.equals(roleName)) {
14309                 return;
14310             }
14311             updateTrampolineExemptUidsForUsers(user);
14312         }
14313 
14314         private void updateTrampolineExemptUidsForUsers(UserHandle... users) {
14315             Preconditions.checkState(mMainLooper.isCurrentThread());
14316             ArraySet<Integer> oldUids = mTrampolineExemptUids;
14317             ArraySet<Integer> newUids = new ArraySet<>();
14318             // Add the uids from previous set for the users that we won't update.
14319             for (int i = 0, n = oldUids.size(); i < n; i++) {
14320                 int uid = oldUids.valueAt(i);
14321                 UserHandle user = UserHandle.of(UserHandle.getUserId(uid));
14322                 if (!ArrayUtils.contains(users, user)) {
14323                     newUids.add(uid);
14324                 }
14325             }
14326             // Now lookup the new uids for the users that we want to update.
14327             for (int i = 0, n = users.length; i < n; i++) {
14328                 UserHandle user = users[i];
14329                 for (String pkg : mRm.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, user)) {
14330                     int uid = getUidForPackage(pkg, user.getIdentifier());
14331                     if (uid != -1) {
14332                         newUids.add(uid);
14333                     } else {
14334                         Slog.e(TAG, "Bad uid (-1) for browser package " + pkg);
14335                     }
14336                 }
14337             }
14338             mTrampolineExemptUids = newUids;
14339         }
14340 
14341         private int getUidForPackage(String pkg, int userId) {
14342             try {
14343                 return mPm.getPackageUid(pkg, MATCH_ALL, userId);
14344             } catch (RemoteException e) {
14345                 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
14346             }
14347             return -1;
14348         }
14349     }
14350 
14351     public static final class DumpFilter {
14352         public boolean filtered = false;
14353         public String pkgFilter;
14354         public boolean zen;
14355         public long since;
14356         public boolean stats;
14357         public boolean rvStats;
14358         public boolean redact = true;
14359         public boolean proto = false;
14360         public boolean criticalPriority = false;
14361         public boolean normalPriority = false;
14362 
14363         @NonNull
14364         public static DumpFilter parseFromArguments(String[] args) {
14365             final DumpFilter filter = new DumpFilter();
14366             for (int ai = 0; ai < args.length; ai++) {
14367                 final String a = args[ai];
14368                 if ("--proto".equals(a)) {
14369                     filter.proto = true;
14370                 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
14371                     filter.redact = false;
14372                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
14373                     if (ai < args.length-1) {
14374                         ai++;
14375                         filter.pkgFilter = args[ai].trim().toLowerCase();
14376                         if (filter.pkgFilter.isEmpty()) {
14377                             filter.pkgFilter = null;
14378                         } else {
14379                             filter.filtered = true;
14380                         }
14381                     }
14382                 } else if ("--zen".equals(a) || "zen".equals(a)) {
14383                     filter.filtered = true;
14384                     filter.zen = true;
14385                 } else if ("--stats".equals(a)) {
14386                     filter.stats = true;
14387                     if (ai < args.length-1) {
14388                         ai++;
14389                         filter.since = Long.parseLong(args[ai]);
14390                     } else {
14391                         filter.since = 0;
14392                     }
14393                 } else if ("--remote-view-stats".equals(a)) {
14394                     filter.rvStats = true;
14395                     if (ai < args.length-1) {
14396                         ai++;
14397                         filter.since = Long.parseLong(args[ai]);
14398                     } else {
14399                         filter.since = 0;
14400                     }
14401                 } else if (PRIORITY_ARG.equals(a)) {
14402                     // Bugreport will call the service twice with priority arguments, first to dump
14403                     // critical sections and then non critical ones. Set appropriate filters
14404                     // to generate the desired data.
14405                     if (ai < args.length - 1) {
14406                         ai++;
14407                         switch (args[ai]) {
14408                             case PRIORITY_ARG_CRITICAL:
14409                                 filter.criticalPriority = true;
14410                                 break;
14411                             case PRIORITY_ARG_NORMAL:
14412                                 filter.normalPriority = true;
14413                                 break;
14414                         }
14415                     }
14416                 }
14417             }
14418             return filter;
14419         }
14420 
14421         public boolean matches(StatusBarNotification sbn) {
14422             if (!filtered) return true;
14423             return zen ? true : sbn != null
14424                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
14425         }
14426 
14427         public boolean matches(ComponentName component) {
14428             if (!filtered) return true;
14429             return zen ? true : component != null && matches(component.getPackageName());
14430         }
14431 
14432         public boolean matches(String pkg) {
14433             if (!filtered) return true;
14434             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
14435         }
14436 
14437         @Override
14438         public String toString() {
14439             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
14440         }
14441     }
14442 
14443     @VisibleForTesting
14444     void resetAssistantUserSet(int userId) {
14445         checkCallerIsSystemOrShell();
14446         mAssistants.setUserSet(userId, false);
14447         handleSavePolicyFile();
14448     }
14449 
14450     @VisibleForTesting
14451     @Nullable
14452     ComponentName getApprovedAssistant(int userId) {
14453         checkCallerIsSystemOrShell();
14454         List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
14455         return CollectionUtils.firstOrNull(allowedComponents);
14456     }
14457 
14458     /**
14459      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
14460      * binder without sending large amounts of data over a oneway transaction.
14461      */
14462     private static final class StatusBarNotificationHolder
14463             extends IStatusBarNotificationHolder.Stub {
14464         private StatusBarNotification mValue;
14465 
14466         public StatusBarNotificationHolder(StatusBarNotification value) {
14467             mValue = value;
14468         }
14469 
14470         /** Get the held value and clear it. This function should only be called once per holder */
14471         @Override
14472         public StatusBarNotification get() {
14473             StatusBarNotification value = mValue;
14474             mValue = null;
14475             return value;
14476         }
14477     }
14478 
14479     private void writeSecureNotificationsPolicy(TypedXmlSerializer out) throws IOException {
14480         out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
14481         out.attributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
14482                 mLockScreenAllowSecureNotifications);
14483         out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
14484     }
14485 
14486     // Creates a notification that informs the user about changes due to the migration to
14487     // use permissions for notifications.
14488     protected Notification createReviewPermissionsNotification() {
14489         int title = R.string.review_notification_settings_title;
14490         int content = R.string.review_notification_settings_text;
14491 
14492         // Tapping on the notification leads to the settings screen for managing app notifications,
14493         // using the intent reserved for system services to indicate it comes from this notification
14494         Intent tapIntent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS_FOR_REVIEW);
14495         Intent remindIntent = new Intent(REVIEW_NOTIF_ACTION_REMIND);
14496         Intent dismissIntent = new Intent(REVIEW_NOTIF_ACTION_DISMISS);
14497         Intent swipeIntent = new Intent(REVIEW_NOTIF_ACTION_CANCELED);
14498 
14499         // Both "remind me" and "dismiss" actions will be actions received by the BroadcastReceiver
14500         final Notification.Action remindMe = new Notification.Action.Builder(null,
14501                 getContext().getResources().getString(
14502                         R.string.review_notification_settings_remind_me_action),
14503                 PendingIntent.getBroadcast(
14504                         getContext(), 0, remindIntent,
14505                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
14506                 .build();
14507         final Notification.Action dismiss = new Notification.Action.Builder(null,
14508                 getContext().getResources().getString(
14509                         R.string.review_notification_settings_dismiss),
14510                 PendingIntent.getBroadcast(
14511                         getContext(), 0, dismissIntent,
14512                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
14513                 .build();
14514 
14515         return new Notification.Builder(getContext(), SystemNotificationChannels.SYSTEM_CHANGES)
14516                 .setSmallIcon(R.drawable.stat_sys_adb)
14517                 .setContentTitle(getContext().getResources().getString(title))
14518                 .setContentText(getContext().getResources().getString(content))
14519                 .setContentIntent(PendingIntent.getActivity(getContext(), 0, tapIntent,
14520                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
14521                 .setStyle(new Notification.BigTextStyle())
14522                 .setFlag(FLAG_NO_CLEAR, true)
14523                 .setAutoCancel(true)
14524                 .addAction(remindMe)
14525                 .addAction(dismiss)
14526                 .setDeleteIntent(PendingIntent.getBroadcast(getContext(), 0, swipeIntent,
14527                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
14528                 .build();
14529     }
14530 
14531     protected void maybeShowInitialReviewPermissionsNotification() {
14532         if (!mShowReviewPermissionsNotification) {
14533             // if this notification is disabled by settings do not ever show it
14534             return;
14535         }
14536 
14537         int currentState = Settings.Global.getInt(getContext().getContentResolver(),
14538                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14539                 REVIEW_NOTIF_STATE_UNKNOWN);
14540 
14541         // now check the last known state of the notification -- this determination of whether the
14542         // user is in the correct target audience occurs elsewhere, and will have written the
14543         // REVIEW_NOTIF_STATE_SHOULD_SHOW to indicate it should be shown in the future.
14544         //
14545         // alternatively, if the user has rescheduled the notification (so it has been shown
14546         // again) but not yet interacted with the new notification, then show it again on boot,
14547         // as this state indicates that the user had the notification open before rebooting.
14548         //
14549         // sending the notification here does not record a new state for the notification;
14550         // that will be written by parts of the system further down the line if at any point
14551         // the user interacts with the notification.
14552         if (currentState == REVIEW_NOTIF_STATE_SHOULD_SHOW
14553                 || currentState == REVIEW_NOTIF_STATE_RESHOWN) {
14554             NotificationManager nm = getContext().getSystemService(NotificationManager.class);
14555             nm.notify(TAG,
14556                     SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS,
14557                     createReviewPermissionsNotification());
14558         }
14559     }
14560 
14561     /**
14562      * Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too
14563      * aggressive and annoying the user.
14564      *
14565      * TODO(b/161957908): Remove dogfooder toast.
14566      */
14567     private class NotificationTrampolineCallback implements BackgroundActivityStartCallback {
14568         @Override
14569         public BackgroundActivityStartCallbackResult isActivityStartAllowed(
14570                 Collection<IBinder> tokens, int uid, String packageName) {
14571             checkArgument(!tokens.isEmpty());
14572             for (IBinder token : tokens) {
14573                 if (token != ALLOWLIST_TOKEN) {
14574                     // We only block or warn if the start is exclusively due to notification
14575                     return RESULT_TRUE;
14576                 }
14577             }
14578             String logcatMessage =
14579                     "Indirect notification activity start (trampoline) from " + packageName;
14580             if (blockTrampoline(uid)) {
14581                 Slog.e(TAG, logcatMessage + " blocked");
14582                 return RESULT_FALSE;
14583             } else {
14584                 Slog.w(TAG, logcatMessage + ", this should be avoided for performance reasons");
14585                 return new BackgroundActivityStartCallbackResult(true, ALLOWLIST_TOKEN);
14586             }
14587         }
14588 
14589         private boolean blockTrampoline(int uid) {
14590             if (mRoleObserver != null && mRoleObserver.isUidExemptFromTrampolineRestrictions(uid)) {
14591                 return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES,
14592                         uid);
14593             }
14594             return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid);
14595         }
14596 
14597         @Override
14598         public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) {
14599             // If the start is allowed via notification, we allow the app to close system dialogs
14600             // only if their targetSdk < S, otherwise they have no valid reason to do this since
14601             // trampolines are blocked.
14602             return tokens.contains(ALLOWLIST_TOKEN)
14603                     && !CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid);
14604         }
14605     }
14606 
14607     interface PostNotificationTrackerFactory {
14608         default PostNotificationTracker newTracker(@Nullable WakeLock optionalWakelock) {
14609             return new PostNotificationTracker(optionalWakelock);
14610         }
14611     }
14612 
14613     static class PostNotificationTracker {
14614         @ElapsedRealtimeLong private final long mStartTime;
14615         @Nullable private final WakeLock mWakeLock;
14616         private boolean mOngoing;
14617         private final List<Runnable> mCleanupRunnables;
14618 
14619         @VisibleForTesting
14620         PostNotificationTracker(@Nullable WakeLock wakeLock) {
14621             mStartTime = SystemClock.elapsedRealtime();
14622             mWakeLock = wakeLock;
14623             mOngoing = true;
14624             mCleanupRunnables = new ArrayList<Runnable>();
14625             if (DBG) {
14626                 Slog.d(TAG, "PostNotification: Started");
14627             }
14628         }
14629 
14630         void addCleanupRunnable(Runnable runnable) {
14631             mCleanupRunnables.add(runnable);
14632         }
14633 
14634         @ElapsedRealtimeLong
14635         long getStartTime() {
14636             return mStartTime;
14637         }
14638 
14639         @VisibleForTesting
14640         boolean isOngoing() {
14641             return mOngoing;
14642         }
14643 
14644         /**
14645          * Cancels the tracker (releasing the acquired WakeLock) and runs any set cleanup runnables.
14646          * Either {@link #finish} or {@link #cancel} (exclusively) should be called on this object
14647          * before it's discarded.
14648          */
14649         void cancel() {
14650             if (!isOngoing()) {
14651                 Log.wtfStack(TAG, "cancel() called on already-finished tracker");
14652                 return;
14653             }
14654             mOngoing = false;
14655             if (mWakeLock != null) {
14656                 Binder.withCleanCallingIdentity(() -> mWakeLock.release());
14657             }
14658             for (Runnable r : mCleanupRunnables) {
14659                 r.run();
14660             }
14661             if (DBG) {
14662                 long elapsedTime = SystemClock.elapsedRealtime() - mStartTime;
14663                 Slog.d(TAG, TextUtils.formatSimple("PostNotification: Abandoned after %d ms",
14664                         elapsedTime));
14665             }
14666         }
14667 
14668         /**
14669          * Finishes the tracker (releasing the acquired WakeLock), runs any set cleanup runnables,
14670          * and returns the time elapsed since the operation started, in milliseconds.
14671          * Either {@link #finish} or {@link #cancel} (exclusively) should be called on this object
14672          * before it's discarded.
14673          */
14674         @DurationMillisLong
14675         long finish() {
14676             long elapsedTime = SystemClock.elapsedRealtime() - mStartTime;
14677             if (!isOngoing()) {
14678                 Log.wtfStack(TAG, "finish() called on already-finished tracker");
14679                 return elapsedTime;
14680             }
14681             mOngoing = false;
14682             if (mWakeLock != null) {
14683                 Binder.withCleanCallingIdentity(() -> mWakeLock.release());
14684             }
14685             for (Runnable r : mCleanupRunnables) {
14686                 r.run();
14687             }
14688             if (DBG) {
14689                 Slog.d(TAG,
14690                         TextUtils.formatSimple("PostNotification: Finished in %d ms", elapsedTime));
14691             }
14692             return elapsedTime;
14693         }
14694     }
14695 }
14696