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