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