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