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