• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.notification;
18 
19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
20 import static android.app.Notification.CATEGORY_CALL;
21 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
22 import static android.app.Notification.FLAG_BUBBLE;
23 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
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.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
28 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
29 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
30 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
31 import static android.app.NotificationManager.IMPORTANCE_LOW;
32 import static android.app.NotificationManager.IMPORTANCE_MIN;
33 import static android.app.NotificationManager.IMPORTANCE_NONE;
34 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
35 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
36 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
37 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
38 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
39 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
40 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
41 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
42 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
43 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
44 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
45 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
46 import static android.content.Context.BIND_AUTO_CREATE;
47 import static android.content.Context.BIND_FOREGROUND_SERVICE;
48 import static android.content.Context.BIND_NOT_PERCEPTIBLE;
49 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
50 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
51 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
52 import static android.content.pm.PackageManager.MATCH_ALL;
53 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
54 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
55 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
56 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
57 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
58 import static android.os.UserHandle.USER_NULL;
59 import static android.os.UserHandle.USER_SYSTEM;
60 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
61 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
62 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
63 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
64 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
65 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
66 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
67 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
68 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
69 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
70 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
71 import static android.service.notification.NotificationListenerService.REASON_CLICK;
72 import static android.service.notification.NotificationListenerService.REASON_ERROR;
73 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
74 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
75 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
76 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
77 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
78 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
79 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
80 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
81 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
82 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
83 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
84 import static android.service.notification.NotificationListenerService.TRIM_FULL;
85 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
86 import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
87 import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
88 import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
89 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
90 
91 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
92 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
93 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
94 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
95 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
96 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
97 
98 import android.Manifest;
99 import android.Manifest.permission;
100 import android.annotation.CallbackExecutor;
101 import android.annotation.NonNull;
102 import android.annotation.Nullable;
103 import android.app.ActivityManager;
104 import android.app.ActivityManagerInternal;
105 import android.app.AlarmManager;
106 import android.app.AppGlobals;
107 import android.app.AppOpsManager;
108 import android.app.AutomaticZenRule;
109 import android.app.IActivityManager;
110 import android.app.INotificationManager;
111 import android.app.ITransientNotification;
112 import android.app.IUriGrantsManager;
113 import android.app.Notification;
114 import android.app.NotificationChannel;
115 import android.app.NotificationChannelGroup;
116 import android.app.NotificationManager;
117 import android.app.NotificationManager.Policy;
118 import android.app.PendingIntent;
119 import android.app.Person;
120 import android.app.RemoteInput;
121 import android.app.StatusBarManager;
122 import android.app.UriGrantsManager;
123 import android.app.admin.DeviceAdminInfo;
124 import android.app.admin.DevicePolicyManagerInternal;
125 import android.app.backup.BackupManager;
126 import android.app.role.OnRoleHoldersChangedListener;
127 import android.app.role.RoleManager;
128 import android.app.usage.UsageEvents;
129 import android.app.usage.UsageStatsManagerInternal;
130 import android.companion.ICompanionDeviceManager;
131 import android.content.BroadcastReceiver;
132 import android.content.ComponentName;
133 import android.content.ContentProvider;
134 import android.content.ContentResolver;
135 import android.content.Context;
136 import android.content.Intent;
137 import android.content.IntentFilter;
138 import android.content.pm.ActivityInfo;
139 import android.content.pm.ApplicationInfo;
140 import android.content.pm.IPackageManager;
141 import android.content.pm.PackageManager;
142 import android.content.pm.PackageManager.NameNotFoundException;
143 import android.content.pm.PackageManagerInternal;
144 import android.content.pm.ParceledListSlice;
145 import android.content.pm.UserInfo;
146 import android.content.res.Resources;
147 import android.database.ContentObserver;
148 import android.media.AudioAttributes;
149 import android.media.AudioManager;
150 import android.media.AudioManagerInternal;
151 import android.media.IRingtonePlayer;
152 import android.metrics.LogMaker;
153 import android.net.Uri;
154 import android.os.Binder;
155 import android.os.Build;
156 import android.os.Bundle;
157 import android.os.Environment;
158 import android.os.Handler;
159 import android.os.HandlerThread;
160 import android.os.IBinder;
161 import android.os.IDeviceIdleController;
162 import android.os.IInterface;
163 import android.os.Looper;
164 import android.os.Message;
165 import android.os.Process;
166 import android.os.RemoteException;
167 import android.os.ResultReceiver;
168 import android.os.ServiceManager;
169 import android.os.ShellCallback;
170 import android.os.SystemClock;
171 import android.os.SystemProperties;
172 import android.os.UserHandle;
173 import android.os.UserManager;
174 import android.os.VibrationEffect;
175 import android.os.Vibrator;
176 import android.provider.DeviceConfig;
177 import android.provider.Settings;
178 import android.service.notification.Adjustment;
179 import android.service.notification.Condition;
180 import android.service.notification.IConditionProvider;
181 import android.service.notification.INotificationListener;
182 import android.service.notification.IStatusBarNotificationHolder;
183 import android.service.notification.ListenersDisablingEffectsProto;
184 import android.service.notification.NotificationAssistantService;
185 import android.service.notification.NotificationListenerService;
186 import android.service.notification.NotificationRankingUpdate;
187 import android.service.notification.NotificationRecordProto;
188 import android.service.notification.NotificationServiceDumpProto;
189 import android.service.notification.NotificationStats;
190 import android.service.notification.SnoozeCriterion;
191 import android.service.notification.StatusBarNotification;
192 import android.service.notification.ZenModeConfig;
193 import android.service.notification.ZenModeProto;
194 import android.telephony.PhoneStateListener;
195 import android.telephony.TelephonyManager;
196 import android.text.TextUtils;
197 import android.util.ArrayMap;
198 import android.util.ArraySet;
199 import android.util.AtomicFile;
200 import android.util.IntArray;
201 import android.util.Log;
202 import android.util.Pair;
203 import android.util.Slog;
204 import android.util.SparseArray;
205 import android.util.StatsLog;
206 import android.util.Xml;
207 import android.util.proto.ProtoOutputStream;
208 import android.view.accessibility.AccessibilityEvent;
209 import android.view.accessibility.AccessibilityManager;
210 import android.widget.Toast;
211 
212 import com.android.internal.R;
213 import com.android.internal.annotations.GuardedBy;
214 import com.android.internal.annotations.VisibleForTesting;
215 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
216 import com.android.internal.logging.MetricsLogger;
217 import com.android.internal.logging.nano.MetricsProto;
218 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
219 import com.android.internal.notification.SystemNotificationChannels;
220 import com.android.internal.os.BackgroundThread;
221 import com.android.internal.os.SomeArgs;
222 import com.android.internal.statusbar.NotificationVisibility;
223 import com.android.internal.util.ArrayUtils;
224 import com.android.internal.util.CollectionUtils;
225 import com.android.internal.util.DumpUtils;
226 import com.android.internal.util.FastXmlSerializer;
227 import com.android.internal.util.Preconditions;
228 import com.android.internal.util.XmlUtils;
229 import com.android.internal.util.function.TriPredicate;
230 import com.android.server.DeviceIdleController;
231 import com.android.server.EventLogTags;
232 import com.android.server.IoThread;
233 import com.android.server.LocalServices;
234 import com.android.server.SystemService;
235 import com.android.server.lights.Light;
236 import com.android.server.lights.LightsManager;
237 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
238 import com.android.server.notification.ManagedServices.UserProfiles;
239 import com.android.server.pm.PackageManagerService;
240 import com.android.server.policy.PhoneWindowManager;
241 import com.android.server.statusbar.StatusBarManagerInternal;
242 import com.android.server.uri.UriGrantsManagerInternal;
243 import com.android.server.wm.WindowManagerInternal;
244 
245 import libcore.io.IoUtils;
246 
247 import org.json.JSONException;
248 import org.json.JSONObject;
249 import org.xmlpull.v1.XmlPullParser;
250 import org.xmlpull.v1.XmlPullParserException;
251 import org.xmlpull.v1.XmlSerializer;
252 
253 import java.io.ByteArrayInputStream;
254 import java.io.ByteArrayOutputStream;
255 import java.io.File;
256 import java.io.FileDescriptor;
257 import java.io.FileNotFoundException;
258 import java.io.FileOutputStream;
259 import java.io.IOException;
260 import java.io.InputStream;
261 import java.io.OutputStream;
262 import java.io.PrintWriter;
263 import java.nio.charset.StandardCharsets;
264 import java.util.ArrayDeque;
265 import java.util.ArrayList;
266 import java.util.Arrays;
267 import java.util.Iterator;
268 import java.util.List;
269 import java.util.Map.Entry;
270 import java.util.Objects;
271 import java.util.Set;
272 import java.util.concurrent.Executor;
273 import java.util.concurrent.TimeUnit;
274 import java.util.function.BiConsumer;
275 
276 /** {@hide} */
277 public class NotificationManagerService extends SystemService {
278     static final String TAG = "NotificationService";
279     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
280     public static final boolean ENABLE_CHILD_NOTIFICATIONS
281             = SystemProperties.getBoolean("debug.child_notifs", true);
282 
283     static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
284             "debug.notification.interruptiveness", false);
285 
286     static final int MAX_PACKAGE_NOTIFICATIONS = 25;
287     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
288 
289     // message codes
290     static final int MESSAGE_DURATION_REACHED = 2;
291     // 3: removed to a different handler
292     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
293     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
294     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
295     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
296     static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
297 
298     // ranking thread messages
299     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
300     private static final int MESSAGE_RANKING_SORT = 1001;
301 
302     static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
303     static final int SHORT_DELAY = 2000; // 2 seconds
304 
305     // 1 second past the ANR timeout.
306     static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
307 
308     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
309 
310     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
311 
312     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
313 
314     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
315 
316     static final boolean ENABLE_BLOCKED_TOASTS = true;
317 
318     static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
319             Adjustment.KEY_CONTEXTUAL_ACTIONS,
320             Adjustment.KEY_TEXT_REPLIES};
321 
322     static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
323             RoleManager.ROLE_DIALER,
324             RoleManager.ROLE_EMERGENCY
325     };
326 
327     // When #matchesCallFilter is called from the ringer, wait at most
328     // 3s to resolve the contacts. This timeout is required since
329     // ContactsProvider might take a long time to start up.
330     //
331     // Return STARRED_CONTACT when the timeout is hit in order to avoid
332     // missed calls in ZEN mode "Important".
333     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
334     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
335             ValidateNotificationPeople.STARRED_CONTACT;
336 
337     /** notification_enqueue status value for a newly enqueued notification. */
338     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
339 
340     /** notification_enqueue status value for an existing notification. */
341     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
342 
343     /** notification_enqueue status value for an ignored notification. */
344     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
345     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
346 
347     private static final long DELAY_FOR_ASSISTANT_TIME = 100;
348 
349     private static final String ACTION_NOTIFICATION_TIMEOUT =
350             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
351     private static final int REQUEST_CODE_TIMEOUT = 1;
352     private static final String SCHEME_TIMEOUT = "timeout";
353     private static final String EXTRA_KEY = "key";
354 
355     private IActivityManager mAm;
356     private ActivityManager mActivityManager;
357     private IPackageManager mPackageManager;
358     private PackageManager mPackageManagerClient;
359     AudioManager mAudioManager;
360     AudioManagerInternal mAudioManagerInternal;
361     @Nullable StatusBarManagerInternal mStatusBar;
362     Vibrator mVibrator;
363     private WindowManagerInternal mWindowManagerInternal;
364     private AlarmManager mAlarmManager;
365     private ICompanionDeviceManager mCompanionManager;
366     private AccessibilityManager mAccessibilityManager;
367     private IDeviceIdleController mDeviceIdleController;
368     private IUriGrantsManager mUgm;
369     private UriGrantsManagerInternal mUgmInternal;
370     private RoleObserver mRoleObserver;
371     private UserManager mUm;
372 
373     final IBinder mForegroundToken = new Binder();
374     private WorkerHandler mHandler;
375     private final HandlerThread mRankingThread = new HandlerThread("ranker",
376             Process.THREAD_PRIORITY_BACKGROUND);
377 
378     private Light mNotificationLight;
379     Light mAttentionLight;
380 
381     private long[] mFallbackVibrationPattern;
382     private boolean mUseAttentionLight;
383     boolean mHasLight = true;
384     boolean mLightEnabled;
385     boolean mSystemReady;
386 
387     private boolean mDisableNotificationEffects;
388     private int mCallState;
389     private String mSoundNotificationKey;
390     private String mVibrateNotificationKey;
391 
392     private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
393             new SparseArray<>();
394     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
395     private int mListenerHints;  // right now, all hints are global
396     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
397 
398     // for enabling and disabling notification pulse behavior
399     boolean mScreenOn = true;
400     protected boolean mInCall = false;
401     boolean mNotificationPulseEnabled;
402 
403     private Uri mInCallNotificationUri;
404     private AudioAttributes mInCallNotificationAudioAttributes;
405     private float mInCallNotificationVolume;
406     private Binder mCallNotificationToken = null;
407 
408     // used as a mutex for access to all active notifications & listeners
409     final Object mNotificationLock = new Object();
410     @GuardedBy("mNotificationLock")
411     final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
412     @GuardedBy("mNotificationLock")
413     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
414     @GuardedBy("mNotificationLock")
415     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
416     @GuardedBy("mNotificationLock")
417     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
418     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
419     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
420 
421     // The last key in this list owns the hardware.
422     ArrayList<String> mLights = new ArrayList<>();
423 
424     private AppOpsManager mAppOps;
425     private UsageStatsManagerInternal mAppUsageStats;
426     private DevicePolicyManagerInternal mDpm;
427 
428     private Archive mArchive;
429 
430     // Persistent storage for notification policy
431     private AtomicFile mPolicyFile;
432 
433     private static final int DB_VERSION = 1;
434 
435     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
436     private static final String ATTR_VERSION = "version";
437 
438     private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
439             "allow-secure-notifications-on-lockscreen";
440     private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
441 
442     private RankingHelper mRankingHelper;
443     private PreferencesHelper mPreferencesHelper;
444 
445     private final UserProfiles mUserProfiles = new UserProfiles();
446     private NotificationListeners mListeners;
447     private NotificationAssistants mAssistants;
448     private ConditionProviders mConditionProviders;
449     private NotificationUsageStats mUsageStats;
450     private boolean mLockScreenAllowSecureNotifications = true;
451 
452     private static final int MY_UID = Process.myUid();
453     private static final int MY_PID = Process.myPid();
454     private static final IBinder WHITELIST_TOKEN = new Binder();
455     private RankingHandler mRankingHandler;
456     private long mLastOverRateLogTime;
457     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
458 
459     private SnoozeHelper mSnoozeHelper;
460     private GroupHelper mGroupHelper;
461     private int mAutoGroupAtCount;
462     private boolean mIsTelevision;
463     private boolean mIsAutomotive;
464     private boolean mNotificationEffectsEnabledForAutomotive;
465 
466     private MetricsLogger mMetricsLogger;
467     private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
468 
469     private static class Archive {
470         final int mBufferSize;
471         final ArrayDeque<StatusBarNotification> mBuffer;
472 
Archive(int size)473         public Archive(int size) {
474             mBufferSize = size;
475             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
476         }
477 
toString()478         public String toString() {
479             final StringBuilder sb = new StringBuilder();
480             final int N = mBuffer.size();
481             sb.append("Archive (");
482             sb.append(N);
483             sb.append(" notification");
484             sb.append((N==1)?")":"s)");
485             return sb.toString();
486         }
487 
record(StatusBarNotification nr)488         public void record(StatusBarNotification nr) {
489             if (mBuffer.size() == mBufferSize) {
490                 mBuffer.removeFirst();
491             }
492 
493             // We don't want to store the heavy bits of the notification in the archive,
494             // but other clients in the system process might be using the object, so we
495             // store a (lightened) copy.
496             mBuffer.addLast(nr.cloneLight());
497         }
498 
descendingIterator()499         public Iterator<StatusBarNotification> descendingIterator() {
500             return mBuffer.descendingIterator();
501         }
502 
getArray(int count)503         public StatusBarNotification[] getArray(int count) {
504             if (count == 0) count = mBufferSize;
505             final StatusBarNotification[] a
506                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
507             Iterator<StatusBarNotification> iter = descendingIterator();
508             int i=0;
509             while (iter.hasNext() && i < count) {
510                 a[i++] = iter.next();
511             }
512             return a;
513         }
514 
515     }
516 
readDefaultApprovedServices(int userId)517     protected void readDefaultApprovedServices(int userId) {
518         String defaultListenerAccess = getContext().getResources().getString(
519                 com.android.internal.R.string.config_defaultListenerAccessPackages);
520         if (defaultListenerAccess != null) {
521             for (String whitelisted :
522                     defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
523                 // Gather all notification listener components for candidate pkgs.
524                 Set<ComponentName> approvedListeners =
525                         mListeners.queryPackageForServices(whitelisted,
526                                 MATCH_DIRECT_BOOT_AWARE
527                                         | MATCH_DIRECT_BOOT_UNAWARE, userId);
528                 for (ComponentName cn : approvedListeners) {
529                     try {
530                         getBinderService().setNotificationListenerAccessGrantedForUser(cn,
531                                     userId, true);
532                     } catch (RemoteException e) {
533                         e.printStackTrace();
534                     }
535                 }
536             }
537         }
538 
539         String defaultDndAccess = getContext().getResources().getString(
540                 com.android.internal.R.string.config_defaultDndAccessPackages);
541         if (defaultDndAccess != null) {
542             for (String whitelisted :
543                     defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
544                 try {
545                     getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
546                 } catch (RemoteException e) {
547                     e.printStackTrace();
548                 }
549             }
550         }
551 
552         setDefaultAssistantForUser(userId);
553     }
554 
setDefaultAssistantForUser(int userId)555     protected void setDefaultAssistantForUser(int userId) {
556         List<ComponentName> validAssistants = new ArrayList<>(
557                 mAssistants.queryPackageForServices(
558                         null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId));
559 
560         List<String> candidateStrs = new ArrayList<>();
561         candidateStrs.add(DeviceConfig.getProperty(
562                 DeviceConfig.NAMESPACE_SYSTEMUI,
563                 SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE));
564         candidateStrs.add(getContext().getResources().getString(
565                 com.android.internal.R.string.config_defaultAssistantAccessComponent));
566 
567         for (String candidateStr : candidateStrs) {
568             if (TextUtils.isEmpty(candidateStr)) {
569                 continue;
570             }
571             ComponentName candidate = ComponentName.unflattenFromString(candidateStr);
572             if (candidate != null && validAssistants.contains(candidate)) {
573                 setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true);
574                 Slog.d(TAG, String.format("Set default NAS to be %s in %d", candidateStr, userId));
575                 return;
576             } else {
577                 Slog.w(TAG, "Invalid default NAS config is found: " + candidateStr);
578             }
579         }
580     }
581 
readPolicyXml(InputStream stream, boolean forRestore, int userId)582     void readPolicyXml(InputStream stream, boolean forRestore, int userId)
583             throws XmlPullParserException, NumberFormatException, IOException {
584         final XmlPullParser parser = Xml.newPullParser();
585         parser.setInput(stream, StandardCharsets.UTF_8.name());
586         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
587         boolean migratedManagedServices = false;
588         boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
589         int outerDepth = parser.getDepth();
590         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
591             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
592                 mZenModeHelper.readXml(parser, forRestore, userId);
593             } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
594                 mPreferencesHelper.readXml(parser, forRestore, userId);
595             }
596             if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
597                 if (ineligibleForManagedServices) {
598                     continue;
599                 }
600                 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
601                 migratedManagedServices = true;
602             } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
603                 if (ineligibleForManagedServices) {
604                     continue;
605                 }
606                 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
607                 migratedManagedServices = true;
608             } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
609                 if (ineligibleForManagedServices) {
610                     continue;
611                 }
612                 mConditionProviders.readXml(
613                         parser, mAllowedManagedServicePackages, forRestore, userId);
614                 migratedManagedServices = true;
615             }
616             if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
617                 if (forRestore && userId != UserHandle.USER_SYSTEM) {
618                     continue;
619                 }
620                 mLockScreenAllowSecureNotifications =
621                         safeBoolean(parser.getAttributeValue(null,
622                                         LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
623             }
624         }
625 
626         if (!migratedManagedServices) {
627             mListeners.migrateToXml();
628             mAssistants.migrateToXml();
629             mConditionProviders.migrateToXml();
630             handleSavePolicyFile();
631         }
632 
633         mAssistants.resetDefaultAssistantsIfNecessary();
634     }
635 
636     @VisibleForTesting
loadPolicyFile()637     protected void loadPolicyFile() {
638         if (DBG) Slog.d(TAG, "loadPolicyFile");
639         synchronized (mPolicyFile) {
640             InputStream infile = null;
641             try {
642                 infile = mPolicyFile.openRead();
643                 readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
644             } catch (FileNotFoundException e) {
645                 // No data yet
646                 // Load default managed services approvals
647                 readDefaultApprovedServices(USER_SYSTEM);
648             } catch (IOException e) {
649                 Log.wtf(TAG, "Unable to read notification policy", e);
650             } catch (NumberFormatException e) {
651                 Log.wtf(TAG, "Unable to parse notification policy", e);
652             } catch (XmlPullParserException e) {
653                 Log.wtf(TAG, "Unable to parse notification policy", e);
654             } finally {
655                 IoUtils.closeQuietly(infile);
656             }
657         }
658     }
659 
660     @VisibleForTesting
handleSavePolicyFile()661     protected void handleSavePolicyFile() {
662         IoThread.getHandler().post(() -> {
663             if (DBG) Slog.d(TAG, "handleSavePolicyFile");
664             synchronized (mPolicyFile) {
665                 final FileOutputStream stream;
666                 try {
667                     stream = mPolicyFile.startWrite();
668                 } catch (IOException e) {
669                     Slog.w(TAG, "Failed to save policy file", e);
670                     return;
671                 }
672 
673                 try {
674                     writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL);
675                     mPolicyFile.finishWrite(stream);
676                 } catch (IOException e) {
677                     Slog.w(TAG, "Failed to save policy file, restoring backup", e);
678                     mPolicyFile.failWrite(stream);
679                 }
680             }
681             BackupManager.dataChanged(getContext().getPackageName());
682         });
683     }
684 
writePolicyXml(OutputStream stream, boolean forBackup, int userId)685     private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
686             throws IOException {
687         final XmlSerializer out = new FastXmlSerializer();
688         out.setOutput(stream, StandardCharsets.UTF_8.name());
689         out.startDocument(null, true);
690         out.startTag(null, TAG_NOTIFICATION_POLICY);
691         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
692         mZenModeHelper.writeXml(out, forBackup, null, userId);
693         mPreferencesHelper.writeXml(out, forBackup, userId);
694         mListeners.writeXml(out, forBackup, userId);
695         mAssistants.writeXml(out, forBackup, userId);
696         mConditionProviders.writeXml(out, forBackup, userId);
697         if (!forBackup || userId == UserHandle.USER_SYSTEM) {
698             writeSecureNotificationsPolicy(out);
699         }
700         out.endTag(null, TAG_NOTIFICATION_POLICY);
701         out.endDocument();
702     }
703 
704     private static final class ToastRecord
705     {
706         final int pid;
707         final String pkg;
708         final ITransientNotification callback;
709         int duration;
710         int displayId;
711         Binder token;
712 
ToastRecord(int pid, String pkg, ITransientNotification callback, int duration, Binder token, int displayId)713         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
714                 Binder token, int displayId) {
715             this.pid = pid;
716             this.pkg = pkg;
717             this.callback = callback;
718             this.duration = duration;
719             this.token = token;
720             this.displayId = displayId;
721         }
722 
update(int duration)723         void update(int duration) {
724             this.duration = duration;
725         }
726 
dump(PrintWriter pw, String prefix, DumpFilter filter)727         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
728             if (filter != null && !filter.matches(pkg)) return;
729             pw.println(prefix + this);
730         }
731 
732         @Override
toString()733         public final String toString()
734         {
735             return "ToastRecord{"
736                 + Integer.toHexString(System.identityHashCode(this))
737                 + " pkg=" + pkg
738                 + " callback=" + callback
739                 + " duration=" + duration;
740         }
741     }
742 
743     @VisibleForTesting
744     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
745 
746         @Override
747         public void onSetDisabled(int status) {
748             synchronized (mNotificationLock) {
749                 mDisableNotificationEffects =
750                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
751                 if (disableNotificationEffects(null) != null) {
752                     // cancel whatever's going on
753                     long identity = Binder.clearCallingIdentity();
754                     try {
755                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
756                         if (player != null) {
757                             player.stopAsync();
758                         }
759                     } catch (RemoteException e) {
760                     } finally {
761                         Binder.restoreCallingIdentity(identity);
762                     }
763 
764                     identity = Binder.clearCallingIdentity();
765                     try {
766                         mVibrator.cancel();
767                     } finally {
768                         Binder.restoreCallingIdentity(identity);
769                     }
770                 }
771             }
772         }
773 
774         @Override
775         public void onClearAll(int callingUid, int callingPid, int userId) {
776             synchronized (mNotificationLock) {
777                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
778                         /*includeCurrentProfiles*/ true);
779             }
780         }
781 
782         @Override
783         public void onNotificationClick(int callingUid, int callingPid, String key,
784                 NotificationVisibility nv) {
785             exitIdle();
786             synchronized (mNotificationLock) {
787                 NotificationRecord r = mNotificationsByKey.get(key);
788                 if (r == null) {
789                     Slog.w(TAG, "No notification with key: " + key);
790                     return;
791                 }
792                 final long now = System.currentTimeMillis();
793                 MetricsLogger.action(r.getItemLogMaker()
794                         .setType(MetricsEvent.TYPE_ACTION)
795                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
796                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
797                 EventLogTags.writeNotificationClicked(key,
798                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
799                         nv.rank, nv.count);
800 
801                 StatusBarNotification sbn = r.sbn;
802                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
803                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
804                         FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
805                         REASON_CLICK, nv.rank, nv.count, null);
806                 nv.recycle();
807                 reportUserInteraction(r);
808             }
809         }
810 
811         @Override
812         public void onNotificationActionClick(int callingUid, int callingPid, String key,
813                 int actionIndex, Notification.Action action, NotificationVisibility nv,
814                 boolean generatedByAssistant) {
815             exitIdle();
816             synchronized (mNotificationLock) {
817                 NotificationRecord r = mNotificationsByKey.get(key);
818                 if (r == null) {
819                     Slog.w(TAG, "No notification with key: " + key);
820                     return;
821                 }
822                 final long now = System.currentTimeMillis();
823                 MetricsLogger.action(r.getLogMaker(now)
824                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
825                         .setType(MetricsEvent.TYPE_ACTION)
826                         .setSubtype(actionIndex)
827                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
828                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)
829                         .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART,
830                                 action.isContextual() ? 1 : 0)
831                         .addTaggedData(
832                                 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
833                                 generatedByAssistant ? 1 : 0)
834                         .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
835                                 nv.location.toMetricsEventEnum()));
836 
837                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
838                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
839                         nv.rank, nv.count);
840                 nv.recycle();
841                 reportUserInteraction(r);
842                 mAssistants.notifyAssistantActionClicked(
843                         r.sbn, actionIndex, action, generatedByAssistant);
844             }
845         }
846 
847         @Override
848         public void onNotificationClear(int callingUid, int callingPid,
849                 String pkg, String tag, int id, int userId, String key,
850                 @NotificationStats.DismissalSurface int dismissalSurface,
851                 @NotificationStats.DismissalSentiment int dismissalSentiment,
852                 NotificationVisibility nv) {
853             synchronized (mNotificationLock) {
854                 NotificationRecord r = mNotificationsByKey.get(key);
855                 if (r != null) {
856                     r.recordDismissalSurface(dismissalSurface);
857                     r.recordDismissalSentiment(dismissalSentiment);
858                 }
859             }
860             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
861                     FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
862                     true, userId, REASON_CANCEL, nv.rank, nv.count,null);
863             nv.recycle();
864         }
865 
866         @Override
867         public void onPanelRevealed(boolean clearEffects, int items) {
868             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
869             MetricsLogger.histogram(getContext(), "note_load", items);
870             EventLogTags.writeNotificationPanelRevealed(items);
871             if (clearEffects) {
872                 clearEffects();
873             }
874         }
875 
876         @Override
877         public void onPanelHidden() {
878             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
879             EventLogTags.writeNotificationPanelHidden();
880         }
881 
882         @Override
883         public void clearEffects() {
884             synchronized (mNotificationLock) {
885                 if (DBG) Slog.d(TAG, "clearEffects");
886                 clearSoundLocked();
887                 clearVibrateLocked();
888                 clearLightsLocked();
889             }
890         }
891 
892         @Override
893         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
894                 int id, int uid, int initialPid, String message, int userId) {
895             final boolean fgService;
896             synchronized (mNotificationLock) {
897                 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
898                 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
899             }
900             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
901                     REASON_ERROR, null);
902             if (fgService) {
903                 // Still crash for foreground services, preventing the not-crash behaviour abused
904                 // by apps to give us a garbage notification and silently start a fg service.
905                 Binder.withCleanCallingIdentity(
906                         () -> mAm.crashApplication(uid, initialPid, pkg, -1,
907                             "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
908                                 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
909                                 + message, true /* force */));
910             }
911         }
912 
913         @Override
914         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
915                 NotificationVisibility[] noLongerVisibleKeys) {
916             synchronized (mNotificationLock) {
917                 for (NotificationVisibility nv : newlyVisibleKeys) {
918                     NotificationRecord r = mNotificationsByKey.get(nv.key);
919                     if (r == null) continue;
920                     if (!r.isSeen()) {
921                         // Report to usage stats that notification was made visible
922                         if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
923                         reportSeen(r);
924                     }
925                     r.setVisibility(true, nv.rank, nv.count);
926                     boolean isHun = (nv.location
927                             == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
928                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
929                     // the NotificationRecord to ensure the expansion state is up-to-date.
930                     if (isHun || r.hasBeenVisiblyExpanded()) {
931                         logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
932                     }
933                     maybeRecordInterruptionLocked(r);
934                     nv.recycle();
935                 }
936                 // Note that we might receive this event after notifications
937                 // have already left the system, e.g. after dismissing from the
938                 // shade. Hence not finding notifications in
939                 // mNotificationsByKey is not an exceptional condition.
940                 for (NotificationVisibility nv : noLongerVisibleKeys) {
941                     NotificationRecord r = mNotificationsByKey.get(nv.key);
942                     if (r == null) continue;
943                     r.setVisibility(false, nv.rank, nv.count);
944                     nv.recycle();
945                 }
946             }
947         }
948 
949         @Override
950         public void onNotificationExpansionChanged(String key,
951                 boolean userAction, boolean expanded, int notificationLocation) {
952             synchronized (mNotificationLock) {
953                 NotificationRecord r = mNotificationsByKey.get(key);
954                 if (r != null) {
955                     r.stats.onExpansionChanged(userAction, expanded);
956                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
957                     // the NotificationRecord to ensure the expansion state is up-to-date.
958                     if (r.hasBeenVisiblyExpanded()) {
959                         logSmartSuggestionsVisible(r, notificationLocation);
960                     }
961                     if (userAction) {
962                         MetricsLogger.action(r.getItemLogMaker()
963                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
964                                         : MetricsEvent.TYPE_COLLAPSE));
965                     }
966                     if (expanded && userAction) {
967                         r.recordExpanded();
968                         reportUserInteraction(r);
969                     }
970                     mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
971                 }
972             }
973         }
974 
975         @Override
976         public void onNotificationDirectReplied(String key) {
977             exitIdle();
978             synchronized (mNotificationLock) {
979                 NotificationRecord r = mNotificationsByKey.get(key);
980                 if (r != null) {
981                     r.recordDirectReplied();
982                     mMetricsLogger.write(r.getLogMaker()
983                             .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
984                             .setType(MetricsEvent.TYPE_ACTION));
985                     reportUserInteraction(r);
986                     mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn);
987                 }
988             }
989         }
990 
991         @Override
992         public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
993                 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
994             synchronized (mNotificationLock) {
995                 NotificationRecord r = mNotificationsByKey.get(key);
996                 if (r != null) {
997                     r.setNumSmartRepliesAdded(smartReplyCount);
998                     r.setNumSmartActionsAdded(smartActionCount);
999                     r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
1000                     r.setEditChoicesBeforeSending(editBeforeSending);
1001                 }
1002             }
1003         }
1004 
1005         @Override
1006         public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
1007                 int notificationLocation, boolean modifiedBeforeSending) {
1008 
1009             synchronized (mNotificationLock) {
1010                 NotificationRecord r = mNotificationsByKey.get(key);
1011                 if (r != null) {
1012                     LogMaker logMaker = r.getLogMaker()
1013                             .setCategory(MetricsEvent.SMART_REPLY_ACTION)
1014                             .setSubtype(replyIndex)
1015                             .addTaggedData(
1016                                     MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1017                                     r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1018                             .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
1019                                     notificationLocation)
1020                             .addTaggedData(
1021                                     MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1022                                     r.getEditChoicesBeforeSending() ? 1 : 0)
1023                             .addTaggedData(
1024                                     MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
1025                                     modifiedBeforeSending ? 1 : 0);
1026                     mMetricsLogger.write(logMaker);
1027                     // Treat clicking on a smart reply as a user interaction.
1028                     reportUserInteraction(r);
1029                     mAssistants.notifyAssistantSuggestedReplySent(
1030                             r.sbn, reply, r.getSuggestionsGeneratedByAssistant());
1031                 }
1032             }
1033         }
1034 
1035         @Override
1036         public void onNotificationSettingsViewed(String key) {
1037             synchronized (mNotificationLock) {
1038                 NotificationRecord r = mNotificationsByKey.get(key);
1039                 if (r != null) {
1040                     r.recordViewedSettings();
1041                 }
1042             }
1043         }
1044 
1045         @Override
1046         public void onNotificationBubbleChanged(String key, boolean isBubble) {
1047             synchronized (mNotificationLock) {
1048                 NotificationRecord r = mNotificationsByKey.get(key);
1049                 if (r != null) {
1050                     final StatusBarNotification n = r.sbn;
1051                     final int callingUid = n.getUid();
1052                     final String pkg = n.getPackageName();
1053                     if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid,
1054                             null /* oldEntry */)) {
1055                         r.getNotification().flags |= FLAG_BUBBLE;
1056                     } else {
1057                         r.getNotification().flags &= ~FLAG_BUBBLE;
1058                     }
1059                 }
1060             }
1061         }
1062     };
1063 
1064     @VisibleForTesting
logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)1065     void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
1066         // If the newly visible notification has smart suggestions
1067         // then log that the user has seen them.
1068         if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
1069                 && !r.hasSeenSmartReplies()) {
1070             r.setSeenSmartReplies(true);
1071             LogMaker logMaker = r.getLogMaker()
1072                     .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
1073                     .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
1074                             r.getNumSmartRepliesAdded())
1075                     .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
1076                             r.getNumSmartActionsAdded())
1077                     .addTaggedData(
1078                             MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
1079                             r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1080                     // The fields in the NotificationVisibility.NotificationLocation enum map
1081                     // directly to the fields in the MetricsEvent.NotificationLocation enum.
1082                     .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
1083                     .addTaggedData(
1084                             MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1085                             r.getEditChoicesBeforeSending() ? 1 : 0);
1086             mMetricsLogger.write(logMaker);
1087         }
1088     }
1089 
1090     @GuardedBy("mNotificationLock")
clearSoundLocked()1091     private void clearSoundLocked() {
1092         mSoundNotificationKey = null;
1093         long identity = Binder.clearCallingIdentity();
1094         try {
1095             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
1096             if (player != null) {
1097                 player.stopAsync();
1098             }
1099         } catch (RemoteException e) {
1100         } finally {
1101             Binder.restoreCallingIdentity(identity);
1102         }
1103     }
1104 
1105     @GuardedBy("mNotificationLock")
clearVibrateLocked()1106     private void clearVibrateLocked() {
1107         mVibrateNotificationKey = null;
1108         long identity = Binder.clearCallingIdentity();
1109         try {
1110             mVibrator.cancel();
1111         } finally {
1112             Binder.restoreCallingIdentity(identity);
1113         }
1114     }
1115 
1116     @GuardedBy("mNotificationLock")
clearLightsLocked()1117     private void clearLightsLocked() {
1118         // light
1119         mLights.clear();
1120         updateLightsLocked();
1121     }
1122 
1123     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
1124         @Override
1125         public void onReceive(Context context, Intent intent) {
1126             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
1127                 // update system notification channels
1128                 SystemNotificationChannels.createAll(context);
1129                 mZenModeHelper.updateDefaultZenRules();
1130                 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
1131             }
1132         }
1133     };
1134 
1135     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
1136         @Override
1137         public void onReceive(Context context, Intent intent) {
1138             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
1139                 try {
1140                     String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
1141                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
1142                     int restoredFromSdkInt = intent.getIntExtra(
1143                             Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
1144                     mListeners.onSettingRestored(
1145                             element, newValue, restoredFromSdkInt, getSendingUserId());
1146                     mConditionProviders.onSettingRestored(
1147                             element, newValue, restoredFromSdkInt, getSendingUserId());
1148                 } catch (Exception e) {
1149                     Slog.wtf(TAG, "Cannot restore managed services from settings", e);
1150                 }
1151             }
1152         }
1153     };
1154 
1155     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
1156         @Override
1157         public void onReceive(Context context, Intent intent) {
1158             String action = intent.getAction();
1159             if (action == null) {
1160                 return;
1161             }
1162             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
1163                 final NotificationRecord record;
1164                 synchronized (mNotificationLock) {
1165                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
1166                 }
1167                 if (record != null) {
1168                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
1169                             record.sbn.getPackageName(), record.sbn.getTag(),
1170                             record.sbn.getId(), 0,
1171                             FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
1172                             REASON_TIMEOUT, null);
1173                 }
1174             }
1175         }
1176     };
1177 
1178     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
1179         @Override
1180         public void onReceive(Context context, Intent intent) {
1181             String action = intent.getAction();
1182             if (action == null) {
1183                 return;
1184             }
1185 
1186             boolean queryRestart = false;
1187             boolean queryRemove = false;
1188             boolean packageChanged = false;
1189             boolean cancelNotifications = true;
1190             boolean hideNotifications = false;
1191             boolean unhideNotifications = false;
1192             int reason = REASON_PACKAGE_CHANGED;
1193 
1194             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
1195                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
1196                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
1197                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
1198                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
1199                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
1200                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1201                     || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
1202                     || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1203                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1204                         UserHandle.USER_ALL);
1205                 String pkgList[] = null;
1206                 int uidList[] = null;
1207                 boolean removingPackage = queryRemove &&
1208                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1209                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
1210                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1211                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1212                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1213                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1214                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1215                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1216                     cancelNotifications = false;
1217                     hideNotifications = true;
1218                 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1219                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1220                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1221                     cancelNotifications = false;
1222                     unhideNotifications = true;
1223                 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1224                     final int distractionRestrictions =
1225                             intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
1226                                     PackageManager.RESTRICTION_NONE);
1227                     if ((distractionRestrictions
1228                             & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
1229                         pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1230                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1231                         cancelNotifications = false;
1232                         hideNotifications = true;
1233                     } else {
1234                         pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1235                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1236                         cancelNotifications = false;
1237                         unhideNotifications = true;
1238                     }
1239 
1240                 } else if (queryRestart) {
1241                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1242                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
1243                 } else {
1244                     Uri uri = intent.getData();
1245                     if (uri == null) {
1246                         return;
1247                     }
1248                     String pkgName = uri.getSchemeSpecificPart();
1249                     if (pkgName == null) {
1250                         return;
1251                     }
1252                     if (packageChanged) {
1253                         // We cancel notifications for packages which have just been disabled
1254                         try {
1255                             final int enabled = mPackageManager.getApplicationEnabledSetting(
1256                                     pkgName,
1257                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
1258                                             USER_SYSTEM);
1259                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1260                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1261                                 cancelNotifications = false;
1262                             }
1263                         } catch (IllegalArgumentException e) {
1264                             // Package doesn't exist; probably racing with uninstall.
1265                             // cancelNotifications is already true, so nothing to do here.
1266                             if (DBG) {
1267                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1268                             }
1269                         } catch (RemoteException e) {
1270                             // Failed to talk to PackageManagerService Should never happen!
1271                         }
1272                     }
1273                     pkgList = new String[]{pkgName};
1274                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
1275                 }
1276                 if (pkgList != null && (pkgList.length > 0)) {
1277                     for (String pkgName : pkgList) {
1278                         if (cancelNotifications) {
1279                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1280                                     !queryRestart, changeUserId, reason, null);
1281                         } else if (hideNotifications) {
1282                             hideNotificationsForPackages(pkgList);
1283                         } else if (unhideNotifications) {
1284                             unhideNotificationsForPackages(pkgList);
1285                         }
1286 
1287                     }
1288                 }
1289 
1290                 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
1291             }
1292         }
1293     };
1294 
1295     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1296         @Override
1297         public void onReceive(Context context, Intent intent) {
1298             String action = intent.getAction();
1299 
1300             if (action.equals(Intent.ACTION_SCREEN_ON)) {
1301                 // Keep track of screen on/off state, but do not turn off the notification light
1302                 // until user passes through the lock screen or views the notification.
1303                 mScreenOn = true;
1304                 updateNotificationPulse();
1305             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1306                 mScreenOn = false;
1307                 updateNotificationPulse();
1308             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
1309                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1310                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
1311                 updateNotificationPulse();
1312             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1313                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1314                 if (userHandle >= 0) {
1315                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
1316                             REASON_USER_STOPPED, null);
1317                 }
1318             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
1319                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1320                 if (userHandle >= 0) {
1321                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
1322                             REASON_PROFILE_TURNED_OFF, null);
1323                 }
1324             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1325                 // turn off LED when user passes through lock screen
1326                 mNotificationLight.turnOff();
1327             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
1328                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1329                 mUserProfiles.updateCache(context);
1330                 if (!mUserProfiles.isManagedProfile(userId)) {
1331                     // reload per-user settings
1332                     mSettingsObserver.update(null);
1333                     // Refresh managed services
1334                     mConditionProviders.onUserSwitched(userId);
1335                     mListeners.onUserSwitched(userId);
1336                     mZenModeHelper.onUserSwitched(userId);
1337                     mPreferencesHelper.onUserSwitched(userId);
1338                 }
1339                 // assistant is the only thing that cares about managed profiles specifically
1340                 mAssistants.onUserSwitched(userId);
1341             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
1342                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1343                 if (userId != USER_NULL) {
1344                     mUserProfiles.updateCache(context);
1345                     if (!mUserProfiles.isManagedProfile(userId)) {
1346                         readDefaultApprovedServices(userId);
1347                     }
1348                 }
1349             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
1350                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1351                 mUserProfiles.updateCache(context);
1352                 mZenModeHelper.onUserRemoved(userId);
1353                 mPreferencesHelper.onUserRemoved(userId);
1354                 mListeners.onUserRemoved(userId);
1355                 mConditionProviders.onUserRemoved(userId);
1356                 mAssistants.onUserRemoved(userId);
1357                 handleSavePolicyFile();
1358             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1359                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1360                 mUserProfiles.updateCache(context);
1361                 mAssistants.onUserUnlocked(userId);
1362                 if (!mUserProfiles.isManagedProfile(userId)) {
1363                     mConditionProviders.onUserUnlocked(userId);
1364                     mListeners.onUserUnlocked(userId);
1365                     mZenModeHelper.onUserUnlocked(userId);
1366                     mPreferencesHelper.onUserUnlocked(userId);
1367                 }
1368             }
1369         }
1370     };
1371 
1372     private final class SettingsObserver extends ContentObserver {
1373         private final Uri NOTIFICATION_BADGING_URI
1374                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
1375         private final Uri NOTIFICATION_BUBBLES_URI
1376                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
1377         private final Uri NOTIFICATION_LIGHT_PULSE_URI
1378                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
1379         private final Uri NOTIFICATION_RATE_LIMIT_URI
1380                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
1381 
SettingsObserver(Handler handler)1382         SettingsObserver(Handler handler) {
1383             super(handler);
1384         }
1385 
observe()1386         void observe() {
1387             ContentResolver resolver = getContext().getContentResolver();
1388             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1389                     false, this, UserHandle.USER_ALL);
1390             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
1391                     false, this, UserHandle.USER_ALL);
1392             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1393                     false, this, UserHandle.USER_ALL);
1394             resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
1395                     false, this, UserHandle.USER_ALL);
1396             update(null);
1397         }
1398 
onChange(boolean selfChange, Uri uri)1399         @Override public void onChange(boolean selfChange, Uri uri) {
1400             update(uri);
1401         }
1402 
update(Uri uri)1403         public void update(Uri uri) {
1404             ContentResolver resolver = getContext().getContentResolver();
1405             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
1406                 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1407                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1408                         != 0;
1409                 if (mNotificationPulseEnabled != pulseEnabled) {
1410                     mNotificationPulseEnabled = pulseEnabled;
1411                     updateNotificationPulse();
1412                 }
1413             }
1414             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1415                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1416                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1417             }
1418             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1419                 mPreferencesHelper.updateBadgingEnabled();
1420             }
1421             if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
1422                 mPreferencesHelper.updateBubblesEnabled();
1423             }
1424         }
1425     }
1426 
1427     private SettingsObserver mSettingsObserver;
1428     protected ZenModeHelper mZenModeHelper;
1429 
getLongArray(Resources r, int resid, int maxlen, long[] def)1430     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1431         int[] ar = r.getIntArray(resid);
1432         if (ar == null) {
1433             return def;
1434         }
1435         final int len = ar.length > maxlen ? maxlen : ar.length;
1436         long[] out = new long[len];
1437         for (int i=0; i<len; i++) {
1438             out[i] = ar[i];
1439         }
1440         return out;
1441     }
1442 
NotificationManagerService(Context context)1443     public NotificationManagerService(Context context) {
1444         super(context);
1445         Notification.processWhitelistToken = WHITELIST_TOKEN;
1446     }
1447 
1448     // TODO - replace these methods with a single VisibleForTesting constructor
1449     @VisibleForTesting
setAudioManager(AudioManager audioMananger)1450     void setAudioManager(AudioManager audioMananger) {
1451         mAudioManager = audioMananger;
1452     }
1453 
1454     @VisibleForTesting
setHints(int hints)1455     void setHints(int hints) {
1456         mListenerHints = hints;
1457     }
1458 
1459     @VisibleForTesting
setVibrator(Vibrator vibrator)1460     void setVibrator(Vibrator vibrator) {
1461         mVibrator = vibrator;
1462     }
1463 
1464     @VisibleForTesting
setLights(Light light)1465     void setLights(Light light) {
1466         mNotificationLight = light;
1467         mAttentionLight = light;
1468         mNotificationPulseEnabled = true;
1469     }
1470 
1471     @VisibleForTesting
setScreenOn(boolean on)1472     void setScreenOn(boolean on) {
1473         mScreenOn = on;
1474     }
1475 
1476     @VisibleForTesting
getNotificationRecordCount()1477     int getNotificationRecordCount() {
1478         synchronized (mNotificationLock) {
1479             int count = mNotificationList.size() + mNotificationsByKey.size()
1480                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1481             // subtract duplicates
1482             for (NotificationRecord posted : mNotificationList) {
1483                 if (mNotificationsByKey.containsKey(posted.getKey())) {
1484                     count--;
1485                 }
1486                 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1487                     count--;
1488                 }
1489             }
1490 
1491             return count;
1492         }
1493     }
1494 
1495     @VisibleForTesting
clearNotifications()1496     void clearNotifications() {
1497         mEnqueuedNotifications.clear();
1498         mNotificationList.clear();
1499         mNotificationsByKey.clear();
1500         mSummaryByGroupKey.clear();
1501     }
1502 
1503     @VisibleForTesting
addNotification(NotificationRecord r)1504     void addNotification(NotificationRecord r) {
1505         mNotificationList.add(r);
1506         mNotificationsByKey.put(r.sbn.getKey(), r);
1507         if (r.sbn.isGroup()) {
1508             mSummaryByGroupKey.put(r.getGroupKey(), r);
1509         }
1510     }
1511 
1512     @VisibleForTesting
addEnqueuedNotification(NotificationRecord r)1513     void addEnqueuedNotification(NotificationRecord r) {
1514         mEnqueuedNotifications.add(r);
1515     }
1516 
1517     @VisibleForTesting
getNotificationRecord(String key)1518     NotificationRecord getNotificationRecord(String key) {
1519         return mNotificationsByKey.get(key);
1520     }
1521 
1522 
1523     @VisibleForTesting
setSystemReady(boolean systemReady)1524     void setSystemReady(boolean systemReady) {
1525         mSystemReady = systemReady;
1526     }
1527 
1528     @VisibleForTesting
setHandler(WorkerHandler handler)1529     void setHandler(WorkerHandler handler) {
1530         mHandler = handler;
1531     }
1532 
1533     @VisibleForTesting
setFallbackVibrationPattern(long[] vibrationPattern)1534     void setFallbackVibrationPattern(long[] vibrationPattern) {
1535         mFallbackVibrationPattern = vibrationPattern;
1536     }
1537 
1538     @VisibleForTesting
setPackageManager(IPackageManager packageManager)1539     void setPackageManager(IPackageManager packageManager) {
1540         mPackageManager = packageManager;
1541     }
1542 
1543     @VisibleForTesting
setRankingHelper(RankingHelper rankingHelper)1544     void setRankingHelper(RankingHelper rankingHelper) {
1545         mRankingHelper = rankingHelper;
1546     }
1547 
1548     @VisibleForTesting
setPreferencesHelper(PreferencesHelper prefHelper)1549     void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
1550 
1551     @VisibleForTesting
setRankingHandler(RankingHandler rankingHandler)1552     void setRankingHandler(RankingHandler rankingHandler) {
1553         mRankingHandler = rankingHandler;
1554     }
1555 
1556     @VisibleForTesting
setZenHelper(ZenModeHelper zenHelper)1557     void setZenHelper(ZenModeHelper zenHelper) {
1558         mZenModeHelper = zenHelper;
1559     }
1560 
1561     @VisibleForTesting
setIsAutomotive(boolean isAutomotive)1562     void setIsAutomotive(boolean isAutomotive) {
1563         mIsAutomotive = isAutomotive;
1564     }
1565 
1566     @VisibleForTesting
setNotificationEffectsEnabledForAutomotive(boolean isEnabled)1567     void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) {
1568         mNotificationEffectsEnabledForAutomotive = isEnabled;
1569     }
1570 
1571     @VisibleForTesting
setIsTelevision(boolean isTelevision)1572     void setIsTelevision(boolean isTelevision) {
1573         mIsTelevision = isTelevision;
1574     }
1575 
1576     @VisibleForTesting
setUsageStats(NotificationUsageStats us)1577     void setUsageStats(NotificationUsageStats us) {
1578         mUsageStats = us;
1579     }
1580 
1581     @VisibleForTesting
setAccessibilityManager(AccessibilityManager am)1582     void setAccessibilityManager(AccessibilityManager am) {
1583         mAccessibilityManager = am;
1584     }
1585 
1586     // TODO: All tests should use this init instead of the one-off setters above.
1587     @VisibleForTesting
init(Looper looper, 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, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager)1588     void init(Looper looper, IPackageManager packageManager,
1589             PackageManager packageManagerClient,
1590             LightsManager lightsManager, NotificationListeners notificationListeners,
1591             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
1592             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1593             NotificationUsageStats usageStats, AtomicFile policyFile,
1594             ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
1595             UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
1596             IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
1597             UserManager userManager) {
1598         Resources resources = getContext().getResources();
1599         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1600                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1601                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1602 
1603         mAccessibilityManager =
1604                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
1605         mAm = am;
1606         mUgm = ugm;
1607         mUgmInternal = ugmInternal;
1608         mPackageManager = packageManager;
1609         mPackageManagerClient = packageManagerClient;
1610         mAppOps = appOps;
1611         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1612         mAppUsageStats = appUsageStats;
1613         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1614         mCompanionManager = companionManager;
1615         mActivityManager = activityManager;
1616         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1617                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
1618         mDpm = dpm;
1619         mUm = userManager;
1620 
1621         mHandler = new WorkerHandler(looper);
1622         mRankingThread.start();
1623         String[] extractorNames;
1624         try {
1625             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1626         } catch (Resources.NotFoundException e) {
1627             extractorNames = new String[0];
1628         }
1629         mUsageStats = usageStats;
1630         mMetricsLogger = new MetricsLogger();
1631         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1632         mConditionProviders = conditionProviders;
1633         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1634         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1635             @Override
1636             public void onConfigChanged() {
1637                 handleSavePolicyFile();
1638             }
1639 
1640             @Override
1641             void onZenModeChanged() {
1642                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1643                 getContext().sendBroadcastAsUser(
1644                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1645                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1646                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1647                 synchronized (mNotificationLock) {
1648                     updateInterruptionFilterLocked();
1649                 }
1650                 mRankingHandler.requestSort();
1651             }
1652 
1653             @Override
1654             void onPolicyChanged() {
1655                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1656                 mRankingHandler.requestSort();
1657             }
1658         });
1659         mPreferencesHelper = new PreferencesHelper(getContext(),
1660                 mPackageManagerClient,
1661                 mRankingHandler,
1662                 mZenModeHelper);
1663         mRankingHelper = new RankingHelper(getContext(),
1664                 mRankingHandler,
1665                 mPreferencesHelper,
1666                 mZenModeHelper,
1667                 mUsageStats,
1668                 extractorNames);
1669         mSnoozeHelper = snoozeHelper;
1670         mGroupHelper = groupHelper;
1671 
1672         // This is a ManagedServices object that keeps track of the listeners.
1673         mListeners = notificationListeners;
1674 
1675         // This is a MangedServices object that keeps track of the assistant.
1676         mAssistants = notificationAssistants;
1677 
1678         // Needs to be set before loadPolicyFile
1679         mAllowedManagedServicePackages = this::canUseManagedServices;
1680 
1681         mPolicyFile = policyFile;
1682         loadPolicyFile();
1683 
1684         mStatusBar = getLocalService(StatusBarManagerInternal.class);
1685         if (mStatusBar != null) {
1686             mStatusBar.setNotificationDelegate(mNotificationDelegate);
1687         }
1688 
1689         mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1690         mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1691 
1692         mFallbackVibrationPattern = getLongArray(resources,
1693                 R.array.config_notificationFallbackVibePattern,
1694                 VIBRATE_PATTERN_MAXLEN,
1695                 DEFAULT_VIBRATE_PATTERN);
1696         mInCallNotificationUri = Uri.parse("file://" +
1697                 resources.getString(R.string.config_inCallNotificationSound));
1698         mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1699                 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1700                 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1701                 .build();
1702         mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1703 
1704         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1705         mHasLight =
1706                 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
1707 
1708         // Don't start allowing notifications until the setup wizard has run once.
1709         // After that, including subsequent boots, init with notifications turned on.
1710         // This works on the first boot because the setup wizard will toggle this
1711         // flag at least once and we'll go back to 0 after that.
1712         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1713                     Settings.Global.DEVICE_PROVISIONED, 0)) {
1714             mDisableNotificationEffects = true;
1715         }
1716         mZenModeHelper.initZenMode();
1717         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1718 
1719         mUserProfiles.updateCache(getContext());
1720         listenForCallState();
1721 
1722         mSettingsObserver = new SettingsObserver(mHandler);
1723 
1724         mArchive = new Archive(resources.getInteger(
1725                 R.integer.config_notificationServiceArchiveSize));
1726 
1727         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1728                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1729 
1730         mIsAutomotive =
1731                 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
1732         mNotificationEffectsEnabledForAutomotive =
1733                 resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
1734 
1735         mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
1736                 com.android.internal.R.array.config_nonBlockableNotificationPackages));
1737 
1738         mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
1739                 com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
1740     }
1741 
1742     @Override
onStart()1743     public void onStart() {
1744         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1745             @Override
1746             public void repost(int userId, NotificationRecord r) {
1747                 try {
1748                     if (DBG) {
1749                         Slog.d(TAG, "Reposting " + r.getKey());
1750                     }
1751                     enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1752                             r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1753                             r.sbn.getNotification(), userId);
1754                 } catch (Exception e) {
1755                     Slog.e(TAG, "Cannot un-snooze notification", e);
1756                 }
1757             }
1758         }, mUserProfiles);
1759 
1760         final File systemDir = new File(Environment.getDataDirectory(), "system");
1761 
1762         init(Looper.myLooper(),
1763                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1764                 getLocalService(LightsManager.class),
1765                 new NotificationListeners(AppGlobals.getPackageManager()),
1766                 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1767                         AppGlobals.getPackageManager()),
1768                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1769                 null, snoozeHelper, new NotificationUsageStats(getContext()),
1770                 new AtomicFile(new File(
1771                         systemDir, "notification_policy.xml"), "notification-policy"),
1772                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1773                 getGroupHelper(), ActivityManager.getService(),
1774                 LocalServices.getService(UsageStatsManagerInternal.class),
1775                 LocalServices.getService(DevicePolicyManagerInternal.class),
1776                 UriGrantsManager.getService(),
1777                 LocalServices.getService(UriGrantsManagerInternal.class),
1778                 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
1779                 getContext().getSystemService(UserManager.class));
1780 
1781         // register for various Intents
1782         IntentFilter filter = new IntentFilter();
1783         filter.addAction(Intent.ACTION_SCREEN_ON);
1784         filter.addAction(Intent.ACTION_SCREEN_OFF);
1785         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1786         filter.addAction(Intent.ACTION_USER_PRESENT);
1787         filter.addAction(Intent.ACTION_USER_STOPPED);
1788         filter.addAction(Intent.ACTION_USER_SWITCHED);
1789         filter.addAction(Intent.ACTION_USER_ADDED);
1790         filter.addAction(Intent.ACTION_USER_REMOVED);
1791         filter.addAction(Intent.ACTION_USER_UNLOCKED);
1792         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1793         getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
1794 
1795         IntentFilter pkgFilter = new IntentFilter();
1796         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1797         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1798         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1799         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1800         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1801         pkgFilter.addDataScheme("package");
1802         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1803                 null);
1804 
1805         IntentFilter suspendedPkgFilter = new IntentFilter();
1806         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1807         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
1808         suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
1809         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1810                 suspendedPkgFilter, null, null);
1811 
1812         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1813         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1814                 null);
1815 
1816         IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1817         timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1818         getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1819 
1820         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1821         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1822 
1823         IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1824         getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1825 
1826         publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1827                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
1828         publishLocalService(NotificationManagerInternal.class, mInternalService);
1829     }
1830 
registerDeviceConfigChange()1831     private void registerDeviceConfigChange() {
1832         DeviceConfig.addOnPropertiesChangedListener(
1833                 DeviceConfig.NAMESPACE_SYSTEMUI,
1834                 getContext().getMainExecutor(),
1835                 (properties) -> {
1836                     if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
1837                         return;
1838                     }
1839                     if (properties.getKeyset()
1840                             .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
1841                         mAssistants.resetDefaultAssistantsIfNecessary();
1842                     }
1843                 });
1844     }
1845 
1846 
getGroupHelper()1847     private GroupHelper getGroupHelper() {
1848         mAutoGroupAtCount =
1849                 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
1850         return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
1851             @Override
1852             public void addAutoGroup(String key) {
1853                 synchronized (mNotificationLock) {
1854                     addAutogroupKeyLocked(key);
1855                 }
1856             }
1857 
1858             @Override
1859             public void removeAutoGroup(String key) {
1860                 synchronized (mNotificationLock) {
1861                     removeAutogroupKeyLocked(key);
1862                 }
1863             }
1864 
1865             @Override
1866             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1867                 createAutoGroupSummary(userId, pkg, triggeringKey);
1868             }
1869 
1870             @Override
1871             public void removeAutoGroupSummary(int userId, String pkg) {
1872                 synchronized (mNotificationLock) {
1873                     clearAutogroupSummaryLocked(userId, pkg);
1874                 }
1875             }
1876         });
1877     }
1878 
1879     private void sendRegisteredOnlyBroadcast(String action) {
1880         Intent intent = new Intent(action);
1881         getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
1882                 UserHandle.ALL, null);
1883         // explicitly send the broadcast to all DND packages, even if they aren't currently running
1884         intent.setFlags(0);
1885         final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
1886         for (String pkg : dndApprovedPackages) {
1887             intent.setPackage(pkg);
1888             getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1889         }
1890     }
1891 
1892     @Override
1893     public void onBootPhase(int phase) {
1894         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1895             // no beeping until we're basically done booting
1896             mSystemReady = true;
1897 
1898             // Grab our optional AudioService
1899             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1900             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1901             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1902             mZenModeHelper.onSystemReady();
1903             mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
1904                     mPackageManager, getContext().getMainExecutor());
1905             mRoleObserver.init();
1906         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1907             // This observer will force an update when observe is called, causing us to
1908             // bind to listener services.
1909             mSettingsObserver.observe();
1910             mListeners.onBootPhaseAppsCanStart();
1911             mAssistants.onBootPhaseAppsCanStart();
1912             mConditionProviders.onBootPhaseAppsCanStart();
1913             registerDeviceConfigChange();
1914         }
1915     }
1916 
1917     @GuardedBy("mNotificationLock")
1918     private void updateListenerHintsLocked() {
1919         final int hints = calculateHints();
1920         if (hints == mListenerHints) return;
1921         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1922         mListenerHints = hints;
1923         scheduleListenerHintsChanged(hints);
1924     }
1925 
1926     @GuardedBy("mNotificationLock")
1927     private void updateEffectsSuppressorLocked() {
1928         final long updatedSuppressedEffects = calculateSuppressedEffects();
1929         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1930         final List<ComponentName> suppressors = getSuppressors();
1931         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1932         mEffectsSuppressors = suppressors;
1933         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1934         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1935     }
1936 
1937     private void exitIdle() {
1938         try {
1939             if (mDeviceIdleController != null) {
1940                 mDeviceIdleController.exitIdle("notification interaction");
1941             }
1942         } catch (RemoteException e) {
1943         }
1944     }
1945 
1946     private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1947             boolean fromListener) {
1948         if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1949             // cancel
1950             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1951                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
1952                     null);
1953             if (isUidSystemOrPhone(uid)) {
1954                 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
1955                 int N = profileIds.size();
1956                 for (int i = 0; i < N; i++) {
1957                     int profileId = profileIds.get(i);
1958                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1959                             profileId, REASON_CHANNEL_BANNED,
1960                             null);
1961                 }
1962             }
1963         }
1964         final NotificationChannel preUpdate =
1965                 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1966 
1967         mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
1968         maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
1969 
1970         if (!fromListener) {
1971             final NotificationChannel modifiedChannel =
1972                     mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1973             mListeners.notifyNotificationChannelChanged(
1974                     pkg, UserHandle.getUserHandleForUid(uid),
1975                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1976         }
1977 
1978         handleSavePolicyFile();
1979     }
1980 
1981     private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1982             NotificationChannel update) {
1983         try {
1984             if ((preUpdate.getImportance() == IMPORTANCE_NONE
1985                     && update.getImportance() != IMPORTANCE_NONE)
1986                     || (preUpdate.getImportance() != IMPORTANCE_NONE
1987                     && update.getImportance() == IMPORTANCE_NONE)) {
1988                 getContext().sendBroadcastAsUser(
1989                         new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
1990                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
1991                                         update.getId())
1992                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1993                                         update.getImportance() == IMPORTANCE_NONE)
1994                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1995                                 .setPackage(pkg),
1996                         UserHandle.of(UserHandle.getUserId(uid)), null);
1997             }
1998         } catch (SecurityException e) {
1999             Slog.w(TAG, "Can't notify app about channel change", e);
2000         }
2001     }
2002 
2003     private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
2004             boolean fromApp, boolean fromListener) {
2005         Preconditions.checkNotNull(group);
2006         Preconditions.checkNotNull(pkg);
2007 
2008         final NotificationChannelGroup preUpdate =
2009                 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
2010         mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
2011                 fromApp);
2012         if (!fromApp) {
2013             maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
2014         }
2015         if (!fromListener) {
2016             mListeners.notifyNotificationChannelGroupChanged(pkg,
2017                     UserHandle.of(UserHandle.getCallingUserId()), group,
2018                     NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2019         }
2020     }
2021 
2022     private void maybeNotifyChannelGroupOwner(String pkg, int uid,
2023             NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
2024         try {
2025             if (preUpdate.isBlocked() != update.isBlocked()) {
2026                 getContext().sendBroadcastAsUser(
2027                         new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
2028                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
2029                                         update.getId())
2030                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
2031                                         update.isBlocked())
2032                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2033                                 .setPackage(pkg),
2034                         UserHandle.of(UserHandle.getUserId(uid)), null);
2035             }
2036         } catch (SecurityException e) {
2037             Slog.w(TAG, "Can't notify app about group change", e);
2038         }
2039     }
2040 
2041     private ArrayList<ComponentName> getSuppressors() {
2042         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
2043         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2044             ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
2045 
2046             for (ComponentName info : serviceInfoList) {
2047                 names.add(info);
2048             }
2049         }
2050 
2051         return names;
2052     }
2053 
2054     private boolean removeDisabledHints(ManagedServiceInfo info) {
2055         return removeDisabledHints(info, 0);
2056     }
2057 
2058     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
2059         boolean removed = false;
2060 
2061         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2062             final int hint = mListenersDisablingEffects.keyAt(i);
2063             final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
2064 
2065             if (hints == 0 || (hint & hints) == hint) {
2066                 removed |= listeners.remove(info.component);
2067             }
2068         }
2069 
2070         return removed;
2071     }
2072 
2073     private void addDisabledHints(ManagedServiceInfo info, int hints) {
2074         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2075             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
2076         }
2077 
2078         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2079             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
2080         }
2081 
2082         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2083             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
2084         }
2085     }
2086 
2087     private void addDisabledHint(ManagedServiceInfo info, int hint) {
2088         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
2089             mListenersDisablingEffects.put(hint, new ArraySet<>());
2090         }
2091 
2092         ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
2093         hintListeners.add(info.component);
2094     }
2095 
2096     private int calculateHints() {
2097         int hints = 0;
2098         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2099             int hint = mListenersDisablingEffects.keyAt(i);
2100             ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
2101 
2102             if (!serviceInfoList.isEmpty()) {
2103                 hints |= hint;
2104             }
2105         }
2106 
2107         return hints;
2108     }
2109 
2110     private long calculateSuppressedEffects() {
2111         int hints = calculateHints();
2112         long suppressedEffects = 0;
2113 
2114         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2115             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
2116         }
2117 
2118         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2119             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
2120         }
2121 
2122         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2123             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
2124         }
2125 
2126         return suppressedEffects;
2127     }
2128 
2129     @GuardedBy("mNotificationLock")
2130     private void updateInterruptionFilterLocked() {
2131         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
2132         if (interruptionFilter == mInterruptionFilter) return;
2133         mInterruptionFilter = interruptionFilter;
2134         scheduleInterruptionFilterChanged(interruptionFilter);
2135     }
2136 
2137     @VisibleForTesting
2138     INotificationManager getBinderService() {
2139         return INotificationManager.Stub.asInterface(mService);
2140     }
2141 
2142     /**
2143      * Report to usage stats that the notification was seen.
2144      * @param r notification record
2145      */
2146     @GuardedBy("mNotificationLock")
2147     protected void reportSeen(NotificationRecord r) {
2148         if (!r.isProxied()) {
2149             mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2150                     getRealUserId(r.sbn.getUserId()),
2151                     UsageEvents.Event.NOTIFICATION_SEEN);
2152         }
2153     }
2154 
2155     protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
2156             int targetSdkVersion) {
2157         if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
2158             return incomingPolicy.suppressedVisualEffects;
2159         }
2160         final int[] effectsIntroducedInP = {
2161                 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
2162                 SUPPRESSED_EFFECT_LIGHTS,
2163                 SUPPRESSED_EFFECT_PEEK,
2164                 SUPPRESSED_EFFECT_STATUS_BAR,
2165                 SUPPRESSED_EFFECT_BADGE,
2166                 SUPPRESSED_EFFECT_AMBIENT,
2167                 SUPPRESSED_EFFECT_NOTIFICATION_LIST
2168         };
2169 
2170         int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
2171         if (targetSdkVersion < Build.VERSION_CODES.P) {
2172             // unset higher order bits introduced in P, maintain the user's higher order bits
2173             for (int i = 0; i < effectsIntroducedInP.length ; i++) {
2174                 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
2175                 newSuppressedVisualEffects |=
2176                         (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
2177             }
2178             // set higher order bits according to lower order bits
2179             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2180                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2181                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
2182             }
2183             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2184                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2185             }
2186         } else {
2187             boolean hasNewEffects = (newSuppressedVisualEffects
2188                     - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
2189             // if any of the new effects introduced in P are set
2190             if (hasNewEffects) {
2191                 // clear out the deprecated effects
2192                 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
2193                         | SUPPRESSED_EFFECT_SCREEN_OFF);
2194 
2195                 // set the deprecated effects according to the new more specific effects
2196                 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
2197                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
2198                 }
2199                 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
2200                         && (newSuppressedVisualEffects
2201                         & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
2202                         && (newSuppressedVisualEffects
2203                         & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
2204                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
2205                 }
2206             } else {
2207                 // set higher order bits according to lower order bits
2208                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2209                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2210                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
2211                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
2212                 }
2213                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2214                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2215                 }
2216             }
2217         }
2218 
2219         return newSuppressedVisualEffects;
2220     }
2221 
2222     @GuardedBy("mNotificationLock")
2223     protected void maybeRecordInterruptionLocked(NotificationRecord r) {
2224         if (r.isInterruptive() && !r.hasRecordedInterruption()) {
2225             mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
2226                     r.getChannel().getId(),
2227                     getRealUserId(r.sbn.getUserId()));
2228             r.setRecordedInterruption(true);
2229         }
2230     }
2231 
2232     /**
2233      * Report to usage stats that the user interacted with the notification.
2234      * @param r notification record
2235      */
2236     protected void reportUserInteraction(NotificationRecord r) {
2237         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2238                 getRealUserId(r.sbn.getUserId()),
2239                 UsageEvents.Event.USER_INTERACTION);
2240     }
2241 
2242     private int getRealUserId(int userId) {
2243         return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
2244     }
2245 
2246     @VisibleForTesting
2247     NotificationManagerInternal getInternalService() {
2248         return mInternalService;
2249     }
2250 
2251     @VisibleForTesting
2252     final IBinder mService = new INotificationManager.Stub() {
2253         // Toasts
2254         // ============================================================================
2255 
2256         @Override
2257         public void enqueueToast(String pkg, ITransientNotification callback, int duration,
2258                 int displayId)
2259         {
2260             if (DBG) {
2261                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
2262                         + " duration=" + duration + " displayId=" + displayId);
2263             }
2264 
2265             if (pkg == null || callback == null) {
2266                 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback);
2267                 return ;
2268             }
2269 
2270             final int callingUid = Binder.getCallingUid();
2271             final boolean isSystemToast = isCallerSystemOrPhone()
2272                     || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
2273             final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2274             final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
2275                     callingUid);
2276 
2277             long callingIdentity = Binder.clearCallingIdentity();
2278             try {
2279                 final boolean appIsForeground = mActivityManager.getUidImportance(callingUid)
2280                         == IMPORTANCE_FOREGROUND;
2281                 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage
2282                         && !appIsForeground) || isPackageSuspended)) {
2283                     Slog.e(TAG, "Suppressing toast from package " + pkg
2284                             + (isPackageSuspended ? " due to package suspended."
2285                             : " by user request."));
2286                     return;
2287                 }
2288             } finally {
2289                 Binder.restoreCallingIdentity(callingIdentity);
2290             }
2291 
2292             synchronized (mToastQueue) {
2293                 int callingPid = Binder.getCallingPid();
2294                 long callingId = Binder.clearCallingIdentity();
2295                 try {
2296                     ToastRecord record;
2297                     int index = indexOfToastLocked(pkg, callback);
2298                     // If it's already in the queue, we update it in place, we don't
2299                     // move it to the end of the queue.
2300                     if (index >= 0) {
2301                         record = mToastQueue.get(index);
2302                         record.update(duration);
2303                     } else {
2304                         // Limit the number of toasts that any given package except the android
2305                         // package can enqueue.  Prevents DOS attacks and deals with leaks.
2306                         if (!isSystemToast) {
2307                             int count = 0;
2308                             final int N = mToastQueue.size();
2309                             for (int i=0; i<N; i++) {
2310                                  final ToastRecord r = mToastQueue.get(i);
2311                                  if (r.pkg.equals(pkg)) {
2312                                      count++;
2313                                      if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2314                                          Slog.e(TAG, "Package has already posted " + count
2315                                                 + " toasts. Not showing more. Package=" + pkg);
2316                                          return;
2317                                      }
2318                                  }
2319                             }
2320                         }
2321 
2322                         Binder token = new Binder();
2323                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
2324                         record = new ToastRecord(callingPid, pkg, callback, duration, token,
2325                                 displayId);
2326                         mToastQueue.add(record);
2327                         index = mToastQueue.size() - 1;
2328                         keepProcessAliveIfNeededLocked(callingPid);
2329                     }
2330                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
2331                     // new or just been updated.  Call back and tell it to show itself.
2332                     // If the callback fails, this will remove it from the list, so don't
2333                     // assume that it's valid after this.
2334                     if (index == 0) {
2335                         showNextToastLocked();
2336                     }
2337                 } finally {
2338                     Binder.restoreCallingIdentity(callingId);
2339                 }
2340             }
2341         }
2342 
2343         @Override
2344         public void cancelToast(String pkg, ITransientNotification callback) {
2345             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2346 
2347             if (pkg == null || callback == null) {
2348                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2349                 return ;
2350             }
2351 
2352             synchronized (mToastQueue) {
2353                 long callingId = Binder.clearCallingIdentity();
2354                 try {
2355                     int index = indexOfToastLocked(pkg, callback);
2356                     if (index >= 0) {
2357                         cancelToastLocked(index);
2358                     } else {
2359                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2360                                 + " callback=" + callback);
2361                     }
2362                 } finally {
2363                     Binder.restoreCallingIdentity(callingId);
2364                 }
2365             }
2366         }
2367 
2368         @Override
2369         public void finishToken(String pkg, ITransientNotification callback) {
2370             synchronized (mToastQueue) {
2371                 long callingId = Binder.clearCallingIdentity();
2372                 try {
2373                     int index = indexOfToastLocked(pkg, callback);
2374                     if (index >= 0) {
2375                         ToastRecord record = mToastQueue.get(index);
2376                         finishTokenLocked(record.token, record.displayId);
2377                     } else {
2378                         Slog.w(TAG, "Toast already killed. pkg=" + pkg
2379                                 + " callback=" + callback);
2380                     }
2381                 } finally {
2382                     Binder.restoreCallingIdentity(callingId);
2383                 }
2384             }
2385         }
2386 
2387         @Override
2388         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
2389                 Notification notification, int userId) throws RemoteException {
2390             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
2391                     Binder.getCallingPid(), tag, id, notification, userId);
2392         }
2393 
2394         @Override
2395         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
2396             checkCallerIsSystemOrSameApp(pkg);
2397             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2398                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
2399             // Don't allow client applications to cancel foreground service notis or autobundled
2400             // summaries.
2401             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
2402                     (FLAG_FOREGROUND_SERVICE | FLAG_AUTOGROUP_SUMMARY);
2403             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
2404                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
2405         }
2406 
2407         @Override
2408         public void cancelAllNotifications(String pkg, int userId) {
2409             checkCallerIsSystemOrSameApp(pkg);
2410 
2411             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2412                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2413 
2414             // Calling from user space, don't allow the canceling of actively
2415             // running foreground services.
2416             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
2417                     pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
2418                     REASON_APP_CANCEL_ALL, null);
2419         }
2420 
2421         @Override
2422         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
2423             enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
2424 
2425             mPreferencesHelper.setEnabled(pkg, uid, enabled);
2426             mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2427                     .setType(MetricsEvent.TYPE_ACTION)
2428                     .setPackageName(pkg)
2429                     .setSubtype(enabled ? 1 : 0));
2430             // Now, cancel any outstanding notifications that are part of a just-disabled app
2431             if (!enabled) {
2432                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2433                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2434             }
2435 
2436             try {
2437                 getContext().sendBroadcastAsUser(
2438                         new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2439                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2440                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2441                                 .setPackage(pkg),
2442                         UserHandle.of(UserHandle.getUserId(uid)), null);
2443             } catch (SecurityException e) {
2444                 Slog.w(TAG, "Can't notify app about app block change", e);
2445             }
2446 
2447             handleSavePolicyFile();
2448         }
2449 
2450         /**
2451          * Updates the enabled state for notifications for the given package (and uid).
2452          * Additionally, this method marks the app importance as locked by the user, which means
2453          * that notifications from the app will <b>not</b> be considered for showing a
2454          * blocking helper.
2455          *
2456          * @param pkg package that owns the notifications to update
2457          * @param uid uid of the app providing notifications
2458          * @param enabled whether notifications should be enabled for the app
2459          *
2460          * @see #setNotificationsEnabledForPackage(String, int, boolean)
2461          */
2462         @Override
2463         public void setNotificationsEnabledWithImportanceLockForPackage(
2464                 String pkg, int uid, boolean enabled) {
2465             setNotificationsEnabledForPackage(pkg, uid, enabled);
2466 
2467             mPreferencesHelper.setAppImportanceLocked(pkg, uid);
2468         }
2469 
2470         /**
2471          * Use this when you just want to know if notifications are OK for this package.
2472          */
2473         @Override
2474         public boolean areNotificationsEnabled(String pkg) {
2475             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2476         }
2477 
2478         /**
2479          * Use this when you just want to know if notifications are OK for this package.
2480          */
2481         @Override
2482         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
2483             enforceSystemOrSystemUIOrSamePackage(pkg,
2484                     "Caller not system or systemui or same package");
2485             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
2486                 getContext().enforceCallingPermission(
2487                         android.Manifest.permission.INTERACT_ACROSS_USERS,
2488                         "canNotifyAsPackage for uid " + uid);
2489             }
2490 
2491             return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
2492         }
2493 
2494         @Override
2495         public boolean areBubblesAllowed(String pkg) {
2496             return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
2497         }
2498 
2499         @Override
2500         public boolean areBubblesAllowedForPackage(String pkg, int uid) {
2501             enforceSystemOrSystemUIOrSamePackage(pkg,
2502                     "Caller not system or systemui or same package");
2503 
2504             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
2505                 getContext().enforceCallingPermission(
2506                         android.Manifest.permission.INTERACT_ACROSS_USERS,
2507                         "canNotifyAsPackage for uid " + uid);
2508             }
2509 
2510             return mPreferencesHelper.areBubblesAllowed(pkg, uid);
2511         }
2512 
2513         @Override
2514         public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
2515             enforceSystemOrSystemUI("Caller not system or systemui");
2516             mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
2517             handleSavePolicyFile();
2518         }
2519 
2520         @Override
2521         public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) {
2522             enforceSystemOrSystemUI("Caller not system or systemui");
2523             int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid);
2524             return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0;
2525         }
2526 
2527         @Override
2528         public boolean shouldHideSilentStatusIcons(String callingPkg) {
2529             checkCallerIsSameApp(callingPkg);
2530 
2531             if (isCallerSystemOrPhone()
2532                     || mListeners.isListenerPackage(callingPkg)) {
2533                 return mPreferencesHelper.shouldHideSilentStatusIcons();
2534             } else {
2535                 throw new SecurityException("Only available for notification listeners");
2536             }
2537         }
2538 
2539         @Override
2540         public void setHideSilentStatusIcons(boolean hide) {
2541             checkCallerIsSystem();
2542 
2543             mPreferencesHelper.setHideSilentStatusIcons(hide);
2544             handleSavePolicyFile();
2545 
2546             mListeners.onStatusBarIconsBehaviorChanged(hide);
2547         }
2548 
2549         @Override
2550         public int getPackageImportance(String pkg) {
2551             checkCallerIsSystemOrSameApp(pkg);
2552             return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
2553         }
2554 
2555         @Override
2556         public boolean canShowBadge(String pkg, int uid) {
2557             checkCallerIsSystem();
2558             return mPreferencesHelper.canShowBadge(pkg, uid);
2559         }
2560 
2561         @Override
2562         public void setShowBadge(String pkg, int uid, boolean showBadge) {
2563             checkCallerIsSystem();
2564             mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
2565             handleSavePolicyFile();
2566         }
2567 
2568         @Override
2569         public void setNotificationDelegate(String callingPkg, String delegate) {
2570             checkCallerIsSameApp(callingPkg);
2571             final int callingUid = Binder.getCallingUid();
2572             UserHandle user = UserHandle.getUserHandleForUid(callingUid);
2573             if (delegate == null) {
2574                 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
2575                 handleSavePolicyFile();
2576             } else {
2577                 try {
2578                     ApplicationInfo info =
2579                             mPackageManager.getApplicationInfo(delegate,
2580                                     MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2581                                     user.getIdentifier());
2582                     if (info != null) {
2583                         mPreferencesHelper.setNotificationDelegate(
2584                                 callingPkg, callingUid, delegate, info.uid);
2585                         handleSavePolicyFile();
2586                     }
2587                 } catch (RemoteException e) {
2588                     e.rethrowFromSystemServer();
2589                 }
2590             }
2591         }
2592 
2593         @Override
2594         public String getNotificationDelegate(String callingPkg) {
2595             // callable by Settings also
2596             checkCallerIsSystemOrSameApp(callingPkg);
2597             return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
2598         }
2599 
2600         @Override
2601         public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) {
2602             checkCallerIsSameApp(callingPkg);
2603             final int callingUid = Binder.getCallingUid();
2604             UserHandle user = UserHandle.getUserHandleForUid(callingUid);
2605             if (user.getIdentifier() != userId) {
2606                 getContext().enforceCallingPermission(
2607                         android.Manifest.permission.INTERACT_ACROSS_USERS,
2608                         "canNotifyAsPackage for user " + userId);
2609             }
2610             if (callingPkg.equals(targetPkg)) {
2611                 return true;
2612             }
2613             try {
2614                 ApplicationInfo info =
2615                         mPackageManager.getApplicationInfo(targetPkg,
2616                                 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2617                                 userId);
2618                 if (info != null) {
2619                     return mPreferencesHelper.isDelegateAllowed(
2620                             targetPkg, info.uid, callingPkg, callingUid);
2621                 }
2622             } catch (RemoteException e) {
2623                 // :(
2624             }
2625             return false;
2626         }
2627 
2628         @Override
2629         public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2630                 NotificationChannelGroup group) throws RemoteException {
2631             enforceSystemOrSystemUI("Caller not system or systemui");
2632             createNotificationChannelGroup(pkg, uid, group, false, false);
2633             handleSavePolicyFile();
2634         }
2635 
2636         @Override
2637         public void createNotificationChannelGroups(String pkg,
2638                 ParceledListSlice channelGroupList) throws RemoteException {
2639             checkCallerIsSystemOrSameApp(pkg);
2640             List<NotificationChannelGroup> groups = channelGroupList.getList();
2641             final int groupSize = groups.size();
2642             for (int i = 0; i < groupSize; i++) {
2643                 final NotificationChannelGroup group = groups.get(i);
2644                 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
2645             }
2646             handleSavePolicyFile();
2647         }
2648 
2649         private void createNotificationChannelsImpl(String pkg, int uid,
2650                 ParceledListSlice channelsList) {
2651             List<NotificationChannel> channels = channelsList.getList();
2652             final int channelsSize = channels.size();
2653             boolean needsPolicyFileChange = false;
2654             for (int i = 0; i < channelsSize; i++) {
2655                 final NotificationChannel channel = channels.get(i);
2656                 Preconditions.checkNotNull(channel, "channel in list is null");
2657                 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid,
2658                         channel, true /* fromTargetApp */,
2659                         mConditionProviders.isPackageOrComponentAllowed(
2660                                 pkg, UserHandle.getUserId(uid)));
2661                 if (needsPolicyFileChange) {
2662                     mListeners.notifyNotificationChannelChanged(pkg,
2663                             UserHandle.getUserHandleForUid(uid),
2664                             mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
2665                                     false),
2666                             NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2667                 }
2668             }
2669             if (needsPolicyFileChange) {
2670                 handleSavePolicyFile();
2671             }
2672         }
2673 
2674         @Override
2675         public void createNotificationChannels(String pkg,
2676                 ParceledListSlice channelsList) throws RemoteException {
2677             checkCallerIsSystemOrSameApp(pkg);
2678             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2679         }
2680 
2681         @Override
2682         public void createNotificationChannelsForPackage(String pkg, int uid,
2683                 ParceledListSlice channelsList) throws RemoteException {
2684             checkCallerIsSystem();
2685             createNotificationChannelsImpl(pkg, uid, channelsList);
2686         }
2687 
2688         @Override
2689         public NotificationChannel getNotificationChannel(String callingPkg, int userId,
2690                 String targetPkg, String channelId) {
2691             if (canNotifyAsPackage(callingPkg, targetPkg, userId)
2692                     || isCallingUidSystem()) {
2693                 int targetUid = -1;
2694                 try {
2695                     targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
2696                 } catch (NameNotFoundException e) {
2697                     /* ignore */
2698                 }
2699                 return mPreferencesHelper.getNotificationChannel(
2700                         targetPkg, targetUid, channelId, false /* includeDeleted */);
2701             }
2702             throw new SecurityException("Pkg " + callingPkg
2703                     + " cannot read channels for " + targetPkg + " in " + userId);
2704         }
2705 
2706         @Override
2707         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
2708                 String channelId, boolean includeDeleted) {
2709             checkCallerIsSystem();
2710             return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
2711         }
2712 
2713         @Override
2714         public void deleteNotificationChannel(String pkg, String channelId) {
2715             checkCallerIsSystemOrSameApp(pkg);
2716             final int callingUid = Binder.getCallingUid();
2717             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2718                 throw new IllegalArgumentException("Cannot delete default channel");
2719             }
2720             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
2721                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2722             mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2723             mListeners.notifyNotificationChannelChanged(pkg,
2724                     UserHandle.getUserHandleForUid(callingUid),
2725                     mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2726                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2727             handleSavePolicyFile();
2728         }
2729 
2730         @Override
2731         public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2732             checkCallerIsSystemOrSameApp(pkg);
2733             return mPreferencesHelper.getNotificationChannelGroupWithChannels(
2734                     pkg, Binder.getCallingUid(), groupId, false);
2735         }
2736 
2737         @Override
2738         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2739                 String pkg) {
2740             checkCallerIsSystemOrSameApp(pkg);
2741             return mPreferencesHelper.getNotificationChannelGroups(
2742                     pkg, Binder.getCallingUid(), false, false, true);
2743         }
2744 
2745         @Override
2746         public void deleteNotificationChannelGroup(String pkg, String groupId) {
2747             checkCallerIsSystemOrSameApp(pkg);
2748 
2749             final int callingUid = Binder.getCallingUid();
2750             NotificationChannelGroup groupToDelete =
2751                     mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2752             if (groupToDelete != null) {
2753                 List<NotificationChannel> deletedChannels =
2754                         mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2755                 for (int i = 0; i < deletedChannels.size(); i++) {
2756                     final NotificationChannel deletedChannel = deletedChannels.get(i);
2757                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2758                             true,
2759                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2760                             null);
2761                     mListeners.notifyNotificationChannelChanged(pkg,
2762                             UserHandle.getUserHandleForUid(callingUid),
2763                             deletedChannel,
2764                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2765                 }
2766                 mListeners.notifyNotificationChannelGroupChanged(
2767                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2768                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2769                 handleSavePolicyFile();
2770             }
2771         }
2772 
2773         @Override
2774         public void updateNotificationChannelForPackage(String pkg, int uid,
2775                 NotificationChannel channel) {
2776             enforceSystemOrSystemUI("Caller not system or systemui");
2777             Preconditions.checkNotNull(channel);
2778             updateNotificationChannelInt(pkg, uid, channel, false);
2779         }
2780 
2781         @Override
2782         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
2783                 int uid, boolean includeDeleted) {
2784             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
2785             return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
2786         }
2787 
2788         @Override
2789         public int getNumNotificationChannelsForPackage(String pkg, int uid,
2790                 boolean includeDeleted) {
2791             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2792             return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted)
2793                     .getList().size();
2794         }
2795 
2796         @Override
2797         public boolean onlyHasDefaultChannel(String pkg, int uid) {
2798             enforceSystemOrSystemUI("onlyHasDefaultChannel");
2799             return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
2800         }
2801 
2802         @Override
2803         public int getDeletedChannelCount(String pkg, int uid) {
2804             enforceSystemOrSystemUI("getDeletedChannelCount");
2805             return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
2806         }
2807 
2808         @Override
2809         public int getBlockedChannelCount(String pkg, int uid) {
2810             enforceSystemOrSystemUI("getBlockedChannelCount");
2811             return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
2812         }
2813 
2814         @Override
2815         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2816                 String pkg, int uid, boolean includeDeleted) {
2817             enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
2818             return mPreferencesHelper.getNotificationChannelGroups(
2819                     pkg, uid, includeDeleted, true, false);
2820         }
2821 
2822         @Override
2823         public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2824                 String pkg, int uid, String groupId, boolean includeDeleted) {
2825             enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2826             return mPreferencesHelper.getNotificationChannelGroupWithChannels(
2827                     pkg, uid, groupId, includeDeleted);
2828         }
2829 
2830         @Override
2831         public NotificationChannelGroup getNotificationChannelGroupForPackage(
2832                 String groupId, String pkg, int uid) {
2833             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2834             return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
2835         }
2836 
2837         @Override
2838         public ParceledListSlice<NotificationChannel> getNotificationChannels(
2839                 String callingPkg, String targetPkg, int userId) {
2840             if (canNotifyAsPackage(callingPkg, targetPkg, userId)
2841                 || isCallingUidSystem()) {
2842                 int targetUid = -1;
2843                 try {
2844                     targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
2845                 } catch (NameNotFoundException e) {
2846                     /* ignore */
2847                 }
2848                 return mPreferencesHelper.getNotificationChannels(
2849                         targetPkg, targetUid, false /* includeDeleted */);
2850             }
2851             throw new SecurityException("Pkg " + callingPkg
2852                     + " cannot read channels for " + targetPkg + " in " + userId);
2853         }
2854 
2855         @Override
2856         public int getBlockedAppCount(int userId) {
2857             checkCallerIsSystem();
2858             return mPreferencesHelper.getBlockedAppCount(userId);
2859         }
2860 
2861         @Override
2862         public int getAppsBypassingDndCount(int userId) {
2863             checkCallerIsSystem();
2864             return mPreferencesHelper.getAppsBypassingDndCount(userId);
2865         }
2866 
2867         @Override
2868         public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
2869                 String pkg, int userId) {
2870             checkCallerIsSystem();
2871             return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId);
2872         }
2873 
2874         @Override
2875         public boolean areChannelsBypassingDnd() {
2876             return mPreferencesHelper.areChannelsBypassingDnd();
2877         }
2878 
2879         @Override
2880         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
2881             checkCallerIsSystem();
2882 
2883             // Cancel posted notifications
2884             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2885                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2886 
2887             final String[] packages = new String[] {packageName};
2888             final int[] uids = new int[] {uid};
2889 
2890             // Listener & assistant
2891             mListeners.onPackagesChanged(true, packages, uids);
2892             mAssistants.onPackagesChanged(true, packages, uids);
2893 
2894             // Zen
2895             mConditionProviders.onPackagesChanged(true, packages, uids);
2896 
2897             // Snoozing
2898             mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
2899 
2900             // Reset notification preferences
2901             if (!fromApp) {
2902                 mPreferencesHelper.clearData(packageName, uid);
2903             }
2904 
2905             handleSavePolicyFile();
2906         }
2907 
2908         @Override
2909         public List<String> getAllowedAssistantAdjustments(String pkg) {
2910             checkCallerIsSystemOrSameApp(pkg);
2911 
2912             if (!isCallerSystemOrPhone()
2913                     && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
2914                     throw new SecurityException("Not currently an assistant");
2915             }
2916 
2917             return mAssistants.getAllowedAssistantAdjustments();
2918         }
2919 
2920         @Override
2921         public void allowAssistantAdjustment(String adjustmentType) {
2922             checkCallerIsSystemOrSystemUiOrShell();
2923             mAssistants.allowAdjustmentType(adjustmentType);
2924 
2925             handleSavePolicyFile();
2926         }
2927 
2928         @Override
2929         public void disallowAssistantAdjustment(String adjustmentType) {
2930             checkCallerIsSystemOrSystemUiOrShell();
2931             mAssistants.disallowAdjustmentType(adjustmentType);
2932 
2933             handleSavePolicyFile();
2934         }
2935 
2936         /**
2937          * System-only API for getting a list of current (i.e. not cleared) notifications.
2938          *
2939          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2940          * @returns A list of all the notifications, in natural order.
2941          */
2942         @Override
2943         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2944             // enforce() will ensure the calling uid has the correct permission
2945             getContext().enforceCallingOrSelfPermission(
2946                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2947                     "NotificationManagerService.getActiveNotifications");
2948 
2949             StatusBarNotification[] tmp = null;
2950             int uid = Binder.getCallingUid();
2951 
2952             // noteOp will check to make sure the callingPkg matches the uid
2953             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2954                     == AppOpsManager.MODE_ALLOWED) {
2955                 synchronized (mNotificationLock) {
2956                     tmp = new StatusBarNotification[mNotificationList.size()];
2957                     final int N = mNotificationList.size();
2958                     for (int i=0; i<N; i++) {
2959                         tmp[i] = mNotificationList.get(i).sbn;
2960                     }
2961                 }
2962             }
2963             return tmp;
2964         }
2965 
2966         /**
2967          * Public API for getting a list of current notifications for the calling package/uid.
2968          *
2969          * Note that since notification posting is done asynchronously, this will not return
2970          * notifications that are in the process of being posted.
2971          *
2972          * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as
2973          * an app's notification delegate via
2974          * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}.
2975          *
2976          * @returns A list of all the package's notifications, in natural order.
2977          */
2978         @Override
2979         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2980                 int incomingUserId) {
2981             checkCallerIsSystemOrSameApp(pkg);
2982             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2983                     Binder.getCallingUid(), incomingUserId, true, false,
2984                     "getAppActiveNotifications", pkg);
2985             synchronized (mNotificationLock) {
2986                 final ArrayMap<String, StatusBarNotification> map
2987                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2988                 final int N = mNotificationList.size();
2989                 for (int i = 0; i < N; i++) {
2990                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2991                             mNotificationList.get(i).sbn);
2992                     if (sbn != null) {
2993                         map.put(sbn.getKey(), sbn);
2994                     }
2995                 }
2996                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2997                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2998                     if (sbn != null) {
2999                         map.put(sbn.getKey(), sbn);
3000                     }
3001                 }
3002                 final int M = mEnqueuedNotifications.size();
3003                 for (int i = 0; i < M; i++) {
3004                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
3005                             mEnqueuedNotifications.get(i).sbn);
3006                     if (sbn != null) {
3007                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
3008                     }
3009                 }
3010                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
3011                 list.addAll(map.values());
3012                 return new ParceledListSlice<StatusBarNotification>(list);
3013             }
3014         }
3015 
3016         private StatusBarNotification sanitizeSbn(String pkg, int userId,
3017                 StatusBarNotification sbn) {
3018             if (sbn.getUserId() == userId) {
3019                 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) {
3020                     // We could pass back a cloneLight() but clients might get confused and
3021                     // try to send this thing back to notify() again, which would not work
3022                     // very well.
3023                     return new StatusBarNotification(
3024                             sbn.getPackageName(),
3025                             sbn.getOpPkg(),
3026                             sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
3027                             sbn.getNotification().clone(),
3028                             sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
3029                 }
3030             }
3031             return null;
3032         }
3033 
3034         /**
3035          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
3036          *
3037          * Requires ACCESS_NOTIFICATIONS which is signature|system.
3038          */
3039         @Override
3040         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
3041             // enforce() will ensure the calling uid has the correct permission
3042             getContext().enforceCallingOrSelfPermission(
3043                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
3044                     "NotificationManagerService.getHistoricalNotifications");
3045 
3046             StatusBarNotification[] tmp = null;
3047             int uid = Binder.getCallingUid();
3048 
3049             // noteOp will check to make sure the callingPkg matches the uid
3050             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
3051                     == AppOpsManager.MODE_ALLOWED) {
3052                 synchronized (mArchive) {
3053                     tmp = mArchive.getArray(count);
3054                 }
3055             }
3056             return tmp;
3057         }
3058 
3059         /**
3060          * Register a listener binder directly with the notification manager.
3061          *
3062          * Only works with system callers. Apps should extend
3063          * {@link android.service.notification.NotificationListenerService}.
3064          */
3065         @Override
3066         public void registerListener(final INotificationListener listener,
3067                 final ComponentName component, final int userid) {
3068             enforceSystemOrSystemUI("INotificationManager.registerListener");
3069             mListeners.registerService(listener, component, userid);
3070         }
3071 
3072         /**
3073          * Remove a listener binder directly
3074          */
3075         @Override
3076         public void unregisterListener(INotificationListener token, int userid) {
3077             mListeners.unregisterService(token, userid);
3078         }
3079 
3080         /**
3081          * Allow an INotificationListener to simulate a "clear all" operation.
3082          *
3083          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
3084          *
3085          * @param token The binder for the listener, to check that the caller is allowed
3086          */
3087         @Override
3088         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
3089             final int callingUid = Binder.getCallingUid();
3090             final int callingPid = Binder.getCallingPid();
3091             long identity = Binder.clearCallingIdentity();
3092             try {
3093                 synchronized (mNotificationLock) {
3094                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3095 
3096                     if (keys != null) {
3097                         final int N = keys.length;
3098                         for (int i = 0; i < N; i++) {
3099                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
3100                             if (r == null) continue;
3101                             final int userId = r.sbn.getUserId();
3102                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
3103                                     !mUserProfiles.isCurrentProfile(userId)) {
3104                                 throw new SecurityException("Disallowed call from listener: "
3105                                         + info.service);
3106                             }
3107                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3108                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
3109                                     userId);
3110                         }
3111                     } else {
3112                         cancelAllLocked(callingUid, callingPid, info.userid,
3113                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
3114                     }
3115                 }
3116             } finally {
3117                 Binder.restoreCallingIdentity(identity);
3118             }
3119         }
3120 
3121         /**
3122          * Handle request from an approved listener to re-enable itself.
3123          *
3124          * @param component The componenet to be re-enabled, caller must match package.
3125          */
3126         @Override
3127         public void requestBindListener(ComponentName component) {
3128             checkCallerIsSystemOrSameApp(component.getPackageName());
3129             long identity = Binder.clearCallingIdentity();
3130             try {
3131                 ManagedServices manager =
3132                         mAssistants.isComponentEnabledForCurrentProfiles(component)
3133                         ? mAssistants
3134                         : mListeners;
3135                 manager.setComponentState(component, true);
3136             } finally {
3137                 Binder.restoreCallingIdentity(identity);
3138             }
3139         }
3140 
3141         @Override
3142         public void requestUnbindListener(INotificationListener token) {
3143             long identity = Binder.clearCallingIdentity();
3144             try {
3145                 // allow bound services to disable themselves
3146                 synchronized (mNotificationLock) {
3147                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3148                     info.getOwner().setComponentState(info.component, false);
3149                 }
3150             } finally {
3151                 Binder.restoreCallingIdentity(identity);
3152             }
3153         }
3154 
3155         @Override
3156         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
3157             long identity = Binder.clearCallingIdentity();
3158             try {
3159                 synchronized (mNotificationLock) {
3160                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3161                     if (keys == null) {
3162                         return;
3163                     }
3164                     ArrayList<NotificationRecord> seen = new ArrayList<>();
3165                     final int n = keys.length;
3166                     for (int i = 0; i < n; i++) {
3167                         NotificationRecord r = mNotificationsByKey.get(keys[i]);
3168                         if (r == null) continue;
3169                         final int userId = r.sbn.getUserId();
3170                         if (userId != info.userid && userId != UserHandle.USER_ALL
3171                                 && !mUserProfiles.isCurrentProfile(userId)) {
3172                             throw new SecurityException("Disallowed call from listener: "
3173                                     + info.service);
3174                         }
3175                         seen.add(r);
3176                         if (!r.isSeen()) {
3177                             if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
3178                             reportSeen(r);
3179                             r.setSeen();
3180                             maybeRecordInterruptionLocked(r);
3181                         }
3182                     }
3183                     if (!seen.isEmpty()) {
3184                         mAssistants.onNotificationsSeenLocked(seen);
3185                     }
3186                 }
3187             } finally {
3188                 Binder.restoreCallingIdentity(identity);
3189             }
3190         }
3191 
3192         /**
3193          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3194          *
3195          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3196          *
3197          * @param info The binder for the listener, to check that the caller is allowed
3198          */
3199         @GuardedBy("mNotificationLock")
3200         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
3201                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
3202             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
3203                     FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE,
3204                     true,
3205                     userId, REASON_LISTENER_CANCEL, info);
3206         }
3207 
3208         /**
3209          * Allow an INotificationListener to snooze a single notification until a context.
3210          *
3211          * @param token The binder for the listener, to check that the caller is allowed
3212          */
3213         @Override
3214         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
3215                 String key, String snoozeCriterionId) {
3216             long identity = Binder.clearCallingIdentity();
3217             try {
3218                 synchronized (mNotificationLock) {
3219                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3220                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
3221                 }
3222             } finally {
3223                 Binder.restoreCallingIdentity(identity);
3224             }
3225         }
3226 
3227         /**
3228          * Allow an INotificationListener to snooze a single notification until a time.
3229          *
3230          * @param token The binder for the listener, to check that the caller is allowed
3231          */
3232         @Override
3233         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
3234                 long duration) {
3235             long identity = Binder.clearCallingIdentity();
3236             try {
3237                 synchronized (mNotificationLock) {
3238                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3239                     snoozeNotificationInt(key, duration, null, info);
3240                 }
3241             } finally {
3242                 Binder.restoreCallingIdentity(identity);
3243             }
3244         }
3245 
3246         /**
3247          * Allows the notification assistant to un-snooze a single notification.
3248          *
3249          * @param token The binder for the assistant, to check that the caller is allowed
3250          */
3251         @Override
3252         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
3253             long identity = Binder.clearCallingIdentity();
3254             try {
3255                 synchronized (mNotificationLock) {
3256                     final ManagedServiceInfo info =
3257                             mAssistants.checkServiceTokenLocked(token);
3258                     unsnoozeNotificationInt(key, info);
3259                 }
3260             } finally {
3261                 Binder.restoreCallingIdentity(identity);
3262             }
3263         }
3264 
3265         /**
3266          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3267          *
3268          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3269          *
3270          * @param token The binder for the listener, to check that the caller is allowed
3271          */
3272         @Override
3273         public void cancelNotificationFromListener(INotificationListener token, String pkg,
3274                 String tag, int id) {
3275             final int callingUid = Binder.getCallingUid();
3276             final int callingPid = Binder.getCallingPid();
3277             long identity = Binder.clearCallingIdentity();
3278             try {
3279                 synchronized (mNotificationLock) {
3280                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3281                     if (info.supportsProfiles()) {
3282                         Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
3283                                 + "from " + info.component
3284                                 + " use cancelNotification(key) instead.");
3285                     } else {
3286                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3287                                 pkg, tag, id, info.userid);
3288                     }
3289                 }
3290             } finally {
3291                 Binder.restoreCallingIdentity(identity);
3292             }
3293         }
3294 
3295         /**
3296          * Allow an INotificationListener to request the list of outstanding notifications seen by
3297          * the current user. Useful when starting up, after which point the listener callbacks
3298          * should be used.
3299          *
3300          * @param token The binder for the listener, to check that the caller is allowed
3301          * @param keys An array of notification keys to fetch, or null to fetch everything
3302          * @returns The return value will contain the notifications specified in keys, in that
3303          *      order, or if keys is null, all the notifications, in natural order.
3304          */
3305         @Override
3306         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
3307                 INotificationListener token, String[] keys, int trim) {
3308             synchronized (mNotificationLock) {
3309                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3310                 final boolean getKeys = keys != null;
3311                 final int N = getKeys ? keys.length : mNotificationList.size();
3312                 final ArrayList<StatusBarNotification> list
3313                         = new ArrayList<StatusBarNotification>(N);
3314                 for (int i=0; i<N; i++) {
3315                     final NotificationRecord r = getKeys
3316                             ? mNotificationsByKey.get(keys[i])
3317                             : mNotificationList.get(i);
3318                     if (r == null) continue;
3319                     StatusBarNotification sbn = r.sbn;
3320                     if (!isVisibleToListener(sbn, info)) continue;
3321                     StatusBarNotification sbnToSend =
3322                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3323                     list.add(sbnToSend);
3324                 }
3325                 return new ParceledListSlice<StatusBarNotification>(list);
3326             }
3327         }
3328 
3329         /**
3330          * Allow an INotificationListener to request the list of outstanding snoozed notifications
3331          * seen by the current user. Useful when starting up, after which point the listener
3332          * callbacks should be used.
3333          *
3334          * @param token The binder for the listener, to check that the caller is allowed
3335          * @returns The return value will contain the notifications specified in keys, in that
3336          *      order, or if keys is null, all the notifications, in natural order.
3337          */
3338         @Override
3339         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
3340                 INotificationListener token, int trim) {
3341             synchronized (mNotificationLock) {
3342                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3343                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
3344                 final int N = snoozedRecords.size();
3345                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
3346                 for (int i=0; i < N; i++) {
3347                     final NotificationRecord r = snoozedRecords.get(i);
3348                     if (r == null) continue;
3349                     StatusBarNotification sbn = r.sbn;
3350                     if (!isVisibleToListener(sbn, info)) continue;
3351                     StatusBarNotification sbnToSend =
3352                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3353                     list.add(sbnToSend);
3354                 }
3355                 return new ParceledListSlice<>(list);
3356             }
3357         }
3358 
3359         @Override
3360         public void clearRequestedListenerHints(INotificationListener token) {
3361             final long identity = Binder.clearCallingIdentity();
3362             try {
3363                 synchronized (mNotificationLock) {
3364                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3365                     removeDisabledHints(info);
3366                     updateListenerHintsLocked();
3367                     updateEffectsSuppressorLocked();
3368                 }
3369             } finally {
3370                 Binder.restoreCallingIdentity(identity);
3371             }
3372         }
3373 
3374         @Override
3375         public void requestHintsFromListener(INotificationListener token, int hints) {
3376             final long identity = Binder.clearCallingIdentity();
3377             try {
3378                 synchronized (mNotificationLock) {
3379                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3380                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
3381                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
3382                             | HINT_HOST_DISABLE_CALL_EFFECTS;
3383                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
3384                     if (disableEffects) {
3385                         addDisabledHints(info, hints);
3386                     } else {
3387                         removeDisabledHints(info, hints);
3388                     }
3389                     updateListenerHintsLocked();
3390                     updateEffectsSuppressorLocked();
3391                 }
3392             } finally {
3393                 Binder.restoreCallingIdentity(identity);
3394             }
3395         }
3396 
3397         @Override
3398         public int getHintsFromListener(INotificationListener token) {
3399             synchronized (mNotificationLock) {
3400                 return mListenerHints;
3401             }
3402         }
3403 
3404         @Override
3405         public void requestInterruptionFilterFromListener(INotificationListener token,
3406                 int interruptionFilter) throws RemoteException {
3407             final long identity = Binder.clearCallingIdentity();
3408             try {
3409                 synchronized (mNotificationLock) {
3410                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3411                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
3412                     updateInterruptionFilterLocked();
3413                 }
3414             } finally {
3415                 Binder.restoreCallingIdentity(identity);
3416             }
3417         }
3418 
3419         @Override
3420         public int getInterruptionFilterFromListener(INotificationListener token)
3421                 throws RemoteException {
3422             synchronized (mNotificationLight) {
3423                 return mInterruptionFilter;
3424             }
3425         }
3426 
3427         @Override
3428         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
3429                 throws RemoteException {
3430             synchronized (mNotificationLock) {
3431                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3432                 if (info == null) return;
3433                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
3434             }
3435         }
3436 
3437         @Override
3438         public int getZenMode() {
3439             return mZenModeHelper.getZenMode();
3440         }
3441 
3442         @Override
3443         public ZenModeConfig getZenModeConfig() {
3444             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
3445             return mZenModeHelper.getConfig();
3446         }
3447 
3448         @Override
3449         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
3450             enforceSystemOrSystemUI("INotificationManager.setZenMode");
3451             final long identity = Binder.clearCallingIdentity();
3452             try {
3453                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
3454             } finally {
3455                 Binder.restoreCallingIdentity(identity);
3456             }
3457         }
3458 
3459         @Override
3460         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
3461             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
3462             return mZenModeHelper.getZenRules();
3463         }
3464 
3465         @Override
3466         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
3467             Preconditions.checkNotNull(id, "Id is null");
3468             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
3469             return mZenModeHelper.getAutomaticZenRule(id);
3470         }
3471 
3472         @Override
3473         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
3474             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3475             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
3476             if (automaticZenRule.getOwner() == null
3477                     && automaticZenRule.getConfigurationActivity() == null) {
3478                 throw new NullPointerException(
3479                         "Rule must have a conditionproviderservice and/or configuration activity");
3480             }
3481             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3482             if (automaticZenRule.getZenPolicy() != null
3483                     && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
3484                 throw new IllegalArgumentException("ZenPolicy is only applicable to "
3485                         + "INTERRUPTION_FILTER_PRIORITY filters");
3486             }
3487             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
3488 
3489             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
3490                     "addAutomaticZenRule");
3491         }
3492 
3493         @Override
3494         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
3495                 throws RemoteException {
3496             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3497             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
3498             if (automaticZenRule.getOwner() == null
3499                     && automaticZenRule.getConfigurationActivity() == null) {
3500                 throw new NullPointerException(
3501                         "Rule must have a conditionproviderservice and/or configuration activity");
3502             }
3503             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3504             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
3505 
3506             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
3507                     "updateAutomaticZenRule");
3508         }
3509 
3510         @Override
3511         public boolean removeAutomaticZenRule(String id) throws RemoteException {
3512             Preconditions.checkNotNull(id, "Id is null");
3513             // Verify that they can modify zen rules.
3514             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3515 
3516             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
3517         }
3518 
3519         @Override
3520         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3521             Preconditions.checkNotNull(packageName, "Package name is null");
3522             enforceSystemOrSystemUI("removeAutomaticZenRules");
3523 
3524             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3525         }
3526 
3527         @Override
3528         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3529             Preconditions.checkNotNull(owner, "Owner is null");
3530             enforceSystemOrSystemUI("getRuleInstanceCount");
3531 
3532             return mZenModeHelper.getCurrentInstanceCount(owner);
3533         }
3534 
3535         @Override
3536         public void setAutomaticZenRuleState(String id, Condition condition) {
3537             Preconditions.checkNotNull(id, "id is null");
3538             Preconditions.checkNotNull(condition, "Condition is null");
3539 
3540             enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
3541 
3542             mZenModeHelper.setAutomaticZenRuleState(id, condition);
3543         }
3544 
3545         @Override
3546         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3547             enforcePolicyAccess(pkg, "setInterruptionFilter");
3548             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3549             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3550             final long identity = Binder.clearCallingIdentity();
3551             try {
3552                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
3553             } finally {
3554                 Binder.restoreCallingIdentity(identity);
3555             }
3556         }
3557 
3558         @Override
3559         public void notifyConditions(final String pkg, IConditionProvider provider,
3560                 final Condition[] conditions) {
3561             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3562             checkCallerIsSystemOrSameApp(pkg);
3563             mHandler.post(new Runnable() {
3564                 @Override
3565                 public void run() {
3566                     mConditionProviders.notifyConditions(pkg, info, conditions);
3567                 }
3568             });
3569         }
3570 
3571         @Override
3572         public void requestUnbindProvider(IConditionProvider provider) {
3573             long identity = Binder.clearCallingIdentity();
3574             try {
3575                 // allow bound services to disable themselves
3576                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3577                 info.getOwner().setComponentState(info.component, false);
3578             } finally {
3579                 Binder.restoreCallingIdentity(identity);
3580             }
3581         }
3582 
3583         @Override
3584         public void requestBindProvider(ComponentName component) {
3585             checkCallerIsSystemOrSameApp(component.getPackageName());
3586             long identity = Binder.clearCallingIdentity();
3587             try {
3588                 mConditionProviders.setComponentState(component, true);
3589             } finally {
3590                 Binder.restoreCallingIdentity(identity);
3591             }
3592         }
3593 
3594         private void enforceSystemOrSystemUI(String message) {
3595             if (isCallerSystemOrPhone()) return;
3596             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3597                     message);
3598         }
3599 
3600         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3601             try {
3602                 checkCallerIsSystemOrSameApp(pkg);
3603             } catch (SecurityException e) {
3604                 getContext().enforceCallingPermission(
3605                         android.Manifest.permission.STATUS_BAR_SERVICE,
3606                         message);
3607             }
3608         }
3609 
3610         private void enforcePolicyAccess(int uid, String method) {
3611             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3612                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3613                 return;
3614             }
3615             boolean accessAllowed = false;
3616             String[] packages = mPackageManagerClient.getPackagesForUid(uid);
3617             final int packageCount = packages.length;
3618             for (int i = 0; i < packageCount; i++) {
3619                 if (mConditionProviders.isPackageOrComponentAllowed(
3620                         packages[i], UserHandle.getUserId(uid))) {
3621                     accessAllowed = true;
3622                 }
3623             }
3624             if (!accessAllowed) {
3625                 Slog.w(TAG, "Notification policy access denied calling " + method);
3626                 throw new SecurityException("Notification policy access denied");
3627             }
3628         }
3629 
3630         private void enforcePolicyAccess(String pkg, String method) {
3631             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3632                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3633                 return;
3634             }
3635             checkCallerIsSameApp(pkg);
3636             if (!checkPolicyAccess(pkg)) {
3637                 Slog.w(TAG, "Notification policy access denied calling " + method);
3638                 throw new SecurityException("Notification policy access denied");
3639             }
3640         }
3641 
3642         private boolean checkPackagePolicyAccess(String pkg) {
3643             return mConditionProviders.isPackageOrComponentAllowed(
3644                     pkg, getCallingUserHandle().getIdentifier());
3645         }
3646 
3647         private boolean checkPolicyAccess(String pkg) {
3648             try {
3649                 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3650                         UserHandle.getCallingUserId());
3651                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3652                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3653                         -1, true)) {
3654                     return true;
3655                 }
3656             } catch (NameNotFoundException e) {
3657                 return false;
3658             }
3659             return checkPackagePolicyAccess(pkg)
3660                     || mListeners.isComponentEnabledForPackage(pkg)
3661                     || (mDpm != null &&
3662                             mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3663                                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
3664         }
3665 
3666         @Override
3667         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3668             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
3669             final DumpFilter filter = DumpFilter.parseFromArguments(args);
3670             final long token = Binder.clearCallingIdentity();
3671             try {
3672                 if (filter.stats) {
3673                     dumpJson(pw, filter);
3674                 } else if (filter.proto) {
3675                     dumpProto(fd, filter);
3676                 } else if (filter.criticalPriority) {
3677                     dumpNotificationRecords(pw, filter);
3678                 } else {
3679                     dumpImpl(pw, filter);
3680                 }
3681             } finally {
3682                 Binder.restoreCallingIdentity(token);
3683             }
3684         }
3685 
3686         @Override
3687         public ComponentName getEffectsSuppressor() {
3688             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
3689         }
3690 
3691         @Override
3692         public boolean matchesCallFilter(Bundle extras) {
3693             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
3694             return mZenModeHelper.matchesCallFilter(
3695                     Binder.getCallingUserHandle(),
3696                     extras,
3697                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3698                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3699                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
3700         }
3701 
3702         @Override
3703         public boolean isSystemConditionProviderEnabled(String path) {
3704             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
3705             return mConditionProviders.isSystemProviderEnabled(path);
3706         }
3707 
3708         // Backup/restore interface
3709         @Override
3710         public byte[] getBackupPayload(int user) {
3711             checkCallerIsSystem();
3712             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
3713             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3714             try {
3715                 writePolicyXml(baos, true /*forBackup*/, user);
3716                 return baos.toByteArray();
3717             } catch (IOException e) {
3718                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3719             }
3720             return null;
3721         }
3722 
3723         @Override
3724         public void applyRestore(byte[] payload, int user) {
3725             checkCallerIsSystem();
3726             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3727                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3728             if (payload == null) {
3729                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3730                 return;
3731             }
3732             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3733             try {
3734                 readPolicyXml(bais, true /*forRestore*/, user);
3735                 handleSavePolicyFile();
3736             } catch (NumberFormatException | XmlPullParserException | IOException e) {
3737                 Slog.w(TAG, "applyRestore: error reading payload", e);
3738             }
3739         }
3740 
3741         @Override
3742         public boolean isNotificationPolicyAccessGranted(String pkg) {
3743             return checkPolicyAccess(pkg);
3744         }
3745 
3746         @Override
3747         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3748             enforceSystemOrSystemUIOrSamePackage(pkg,
3749                     "request policy access status for another package");
3750             return checkPolicyAccess(pkg);
3751         }
3752 
3753         @Override
3754         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3755                 throws RemoteException {
3756             setNotificationPolicyAccessGrantedForUser(
3757                     pkg, getCallingUserHandle().getIdentifier(), granted);
3758         }
3759 
3760         @Override
3761         public void setNotificationPolicyAccessGrantedForUser(
3762                 String pkg, int userId, boolean granted) {
3763             checkCallerIsSystemOrShell();
3764             final long identity = Binder.clearCallingIdentity();
3765             try {
3766                 if (mAllowedManagedServicePackages.test(
3767                         pkg, userId, mConditionProviders.getRequiredPermission())) {
3768                     mConditionProviders.setPackageOrComponentEnabled(
3769                             pkg, userId, true, granted);
3770 
3771                     getContext().sendBroadcastAsUser(new Intent(
3772                             ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3773                                     .setPackage(pkg)
3774                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
3775                             UserHandle.of(userId), null);
3776                     handleSavePolicyFile();
3777                 }
3778             } finally {
3779                 Binder.restoreCallingIdentity(identity);
3780             }
3781         }
3782 
3783         @Override
3784         public Policy getNotificationPolicy(String pkg) {
3785             final long identity = Binder.clearCallingIdentity();
3786             try {
3787                 return mZenModeHelper.getNotificationPolicy();
3788             } finally {
3789                 Binder.restoreCallingIdentity(identity);
3790             }
3791         }
3792 
3793         @Override
3794         public Policy getConsolidatedNotificationPolicy() {
3795             final long identity = Binder.clearCallingIdentity();
3796             try {
3797                 return mZenModeHelper.getConsolidatedNotificationPolicy();
3798             } finally {
3799                 Binder.restoreCallingIdentity(identity);
3800             }
3801         }
3802 
3803         /**
3804          * Sets the notification policy.  Apps that target API levels below
3805          * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
3806          * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3807          * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3808          * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
3809          */
3810         @Override
3811         public void setNotificationPolicy(String pkg, Policy policy) {
3812             enforcePolicyAccess(pkg, "setNotificationPolicy");
3813             final long identity = Binder.clearCallingIdentity();
3814             try {
3815                 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3816                         0, UserHandle.getUserId(MY_UID));
3817                 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
3818 
3819                 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
3820                     int priorityCategories = policy.priorityCategories;
3821                     // ignore alarm and media values from new policy
3822                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
3823                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3824                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
3825                     // use user-designated values
3826                     priorityCategories |= currPolicy.priorityCategories
3827                             & Policy.PRIORITY_CATEGORY_ALARMS;
3828                     priorityCategories |= currPolicy.priorityCategories
3829                             & Policy.PRIORITY_CATEGORY_MEDIA;
3830                     priorityCategories |= currPolicy.priorityCategories
3831                             & Policy.PRIORITY_CATEGORY_SYSTEM;
3832 
3833                     policy = new Policy(priorityCategories,
3834                             policy.priorityCallSenders, policy.priorityMessageSenders,
3835                             policy.suppressedVisualEffects);
3836                 }
3837                 int newVisualEffects = calculateSuppressedVisualEffects(
3838                             policy, currPolicy, applicationInfo.targetSdkVersion);
3839                 policy = new Policy(policy.priorityCategories,
3840                         policy.priorityCallSenders, policy.priorityMessageSenders,
3841                         newVisualEffects);
3842                 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
3843                 mZenModeHelper.setNotificationPolicy(policy);
3844             } catch (RemoteException e) {
3845             } finally {
3846                 Binder.restoreCallingIdentity(identity);
3847             }
3848         }
3849 
3850         @Override
3851         public List<String> getEnabledNotificationListenerPackages() {
3852             checkCallerIsSystem();
3853             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3854         }
3855 
3856         @Override
3857         public List<ComponentName> getEnabledNotificationListeners(int userId) {
3858             checkCallerIsSystem();
3859             return mListeners.getAllowedComponents(userId);
3860         }
3861 
3862         @Override
3863         public ComponentName getAllowedNotificationAssistantForUser(int userId) {
3864             checkCallerIsSystemOrSystemUiOrShell();
3865             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
3866             if (allowedComponents.size() > 1) {
3867                 throw new IllegalStateException(
3868                         "At most one NotificationAssistant: " + allowedComponents.size());
3869             }
3870             return CollectionUtils.firstOrNull(allowedComponents);
3871         }
3872 
3873         @Override
3874         public ComponentName getAllowedNotificationAssistant() {
3875             return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier());
3876         }
3877 
3878         @Override
3879         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3880             Preconditions.checkNotNull(listener);
3881             checkCallerIsSystemOrSameApp(listener.getPackageName());
3882             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3883                     getCallingUserHandle().getIdentifier());
3884         }
3885 
3886         @Override
3887         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3888                 int userId) {
3889             Preconditions.checkNotNull(listener);
3890             checkCallerIsSystem();
3891             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3892                     userId);
3893         }
3894 
3895         @Override
3896         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3897             Preconditions.checkNotNull(assistant);
3898             checkCallerIsSystemOrSameApp(assistant.getPackageName());
3899             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
3900                     getCallingUserHandle().getIdentifier());
3901         }
3902 
3903         @Override
3904         public void setNotificationListenerAccessGranted(ComponentName listener,
3905                 boolean granted) throws RemoteException {
3906             setNotificationListenerAccessGrantedForUser(
3907                     listener, getCallingUserHandle().getIdentifier(), granted);
3908         }
3909 
3910         @Override
3911         public void setNotificationAssistantAccessGranted(ComponentName assistant,
3912                 boolean granted) {
3913             setNotificationAssistantAccessGrantedForUser(
3914                     assistant, getCallingUserHandle().getIdentifier(), granted);
3915         }
3916 
3917         @Override
3918         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3919                 boolean granted) {
3920             Preconditions.checkNotNull(listener);
3921             checkCallerIsSystemOrShell();
3922             final long identity = Binder.clearCallingIdentity();
3923             try {
3924                 if (mAllowedManagedServicePackages.test(
3925                         listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
3926                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3927                             userId, false, granted);
3928                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3929                             userId, true, granted);
3930 
3931                     getContext().sendBroadcastAsUser(new Intent(
3932                             ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3933                                     .setPackage(listener.getPackageName())
3934                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3935                             UserHandle.of(userId), null);
3936 
3937                     handleSavePolicyFile();
3938                 }
3939             } finally {
3940                 Binder.restoreCallingIdentity(identity);
3941             }
3942         }
3943 
3944         @Override
3945         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3946                 int userId, boolean granted) {
3947             checkCallerIsSystemOrSystemUiOrShell();
3948             for (UserInfo ui : mUm.getEnabledProfiles(userId)) {
3949                 mAssistants.setUserSet(ui.id, true);
3950             }
3951             final long identity = Binder.clearCallingIdentity();
3952             try {
3953                 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
3954             } finally {
3955                 Binder.restoreCallingIdentity(identity);
3956             }
3957         }
3958 
3959         @Override
3960         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3961                 Adjustment adjustment) {
3962             boolean foundEnqueued = false;
3963             final long identity = Binder.clearCallingIdentity();
3964             try {
3965                 synchronized (mNotificationLock) {
3966                     mAssistants.checkServiceTokenLocked(token);
3967                     int N = mEnqueuedNotifications.size();
3968                     for (int i = 0; i < N; i++) {
3969                         final NotificationRecord r = mEnqueuedNotifications.get(i);
3970                         if (Objects.equals(adjustment.getKey(), r.getKey())
3971                                 && Objects.equals(adjustment.getUser(), r.getUserId())
3972                                 && mAssistants.isSameUser(token, r.getUserId())) {
3973                             applyAdjustment(r, adjustment);
3974                             r.applyAdjustments();
3975                             // importance is checked at the beginning of the
3976                             // PostNotificationRunnable, before the signal extractors are run, so
3977                             // calculate the final importance here
3978                             r.calculateImportance();
3979                             foundEnqueued = true;
3980                             break;
3981                         }
3982                     }
3983                     if (!foundEnqueued) {
3984                         applyAdjustmentFromAssistant(token, adjustment);
3985                     }
3986                 }
3987             } finally {
3988                 Binder.restoreCallingIdentity(identity);
3989             }
3990         }
3991 
3992         @Override
3993         public void applyAdjustmentFromAssistant(INotificationListener token,
3994                 Adjustment adjustment) {
3995             List<Adjustment> adjustments = new ArrayList<>();
3996             adjustments.add(adjustment);
3997             applyAdjustmentsFromAssistant(token, adjustments);
3998         }
3999 
4000         @Override
4001         public void applyAdjustmentsFromAssistant(INotificationListener token,
4002                 List<Adjustment> adjustments) {
4003 
4004             boolean needsSort = false;
4005             final long identity = Binder.clearCallingIdentity();
4006             try {
4007                 synchronized (mNotificationLock) {
4008                     mAssistants.checkServiceTokenLocked(token);
4009                     for (Adjustment adjustment : adjustments) {
4010                         NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
4011                         if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
4012                             applyAdjustment(r, adjustment);
4013                             // If the assistant has blocked the notification, cancel it
4014                             // This will trigger a sort, so we don't have to explicitly ask for
4015                             // one here.
4016                             if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
4017                                     && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
4018                                     == IMPORTANCE_NONE) {
4019                                 cancelNotificationsFromListener(token, new String[]{r.getKey()});
4020                             } else {
4021                                 needsSort = true;
4022                             }
4023                         }
4024                     }
4025                 }
4026                 if (needsSort) {
4027                     mRankingHandler.requestSort();
4028                 }
4029             } finally {
4030                 Binder.restoreCallingIdentity(identity);
4031             }
4032         }
4033 
4034         @Override
4035         public void updateNotificationChannelGroupFromPrivilegedListener(
4036                 INotificationListener token, String pkg, UserHandle user,
4037                 NotificationChannelGroup group) throws RemoteException {
4038             Preconditions.checkNotNull(user);
4039             verifyPrivilegedListener(token, user, false);
4040             createNotificationChannelGroup(
4041                     pkg, getUidForPackageAndUser(pkg, user), group, false, true);
4042             handleSavePolicyFile();
4043         }
4044 
4045         @Override
4046         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
4047                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
4048             Preconditions.checkNotNull(channel);
4049             Preconditions.checkNotNull(pkg);
4050             Preconditions.checkNotNull(user);
4051 
4052             verifyPrivilegedListener(token, user, false);
4053             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
4054         }
4055 
4056         @Override
4057         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
4058                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
4059             Preconditions.checkNotNull(pkg);
4060             Preconditions.checkNotNull(user);
4061             verifyPrivilegedListener(token, user, true);
4062 
4063             return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
4064                     false /* includeDeleted */);
4065         }
4066 
4067         @Override
4068         public ParceledListSlice<NotificationChannelGroup>
4069                 getNotificationChannelGroupsFromPrivilegedListener(
4070                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
4071             Preconditions.checkNotNull(pkg);
4072             Preconditions.checkNotNull(user);
4073             verifyPrivilegedListener(token, user, true);
4074 
4075             List<NotificationChannelGroup> groups = new ArrayList<>();
4076             groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
4077                     pkg, getUidForPackageAndUser(pkg, user)));
4078             return new ParceledListSlice<>(groups);
4079         }
4080 
4081         @Override
4082         public void setPrivateNotificationsAllowed(boolean allow) {
4083             if (PackageManager.PERMISSION_GRANTED
4084                     != getContext().checkCallingPermission(
4085                             permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
4086                 throw new SecurityException(
4087                         "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
4088             }
4089             if (allow != mLockScreenAllowSecureNotifications) {
4090                 mLockScreenAllowSecureNotifications = allow;
4091                 handleSavePolicyFile();
4092             }
4093         }
4094 
4095         @Override
4096         public boolean getPrivateNotificationsAllowed() {
4097             if (PackageManager.PERMISSION_GRANTED
4098                     != getContext().checkCallingPermission(
4099                             permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
4100                 throw new SecurityException(
4101                         "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
4102             }
4103             return mLockScreenAllowSecureNotifications;
4104         }
4105 
4106         @Override
4107         public boolean isPackagePaused(String pkg) {
4108             Preconditions.checkNotNull(pkg);
4109             checkCallerIsSameApp(pkg);
4110 
4111             boolean isPaused;
4112 
4113             final PackageManagerInternal pmi = LocalServices.getService(
4114                     PackageManagerInternal.class);
4115             int flags = pmi.getDistractingPackageRestrictions(
4116                     pkg, Binder.getCallingUserHandle().getIdentifier());
4117             isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
4118 
4119             isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
4120 
4121             return isPaused;
4122         }
4123 
4124         private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
4125                 boolean assistantAllowed) {
4126             ManagedServiceInfo info;
4127             synchronized (mNotificationLock) {
4128                 info = mListeners.checkServiceTokenLocked(token);
4129             }
4130             if (!hasCompanionDevice(info)) {
4131                 synchronized (mNotificationLock) {
4132                     if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
4133                         throw new SecurityException(info + " does not have access");
4134                     }
4135                 }
4136             }
4137             if (!info.enabledAndUserMatches(user.getIdentifier())) {
4138                 throw new SecurityException(info + " does not have access");
4139             }
4140         }
4141 
4142         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
4143             int uid = 0;
4144             long identity = Binder.clearCallingIdentity();
4145             try {
4146                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
4147             } finally {
4148                 Binder.restoreCallingIdentity(identity);
4149             }
4150             return uid;
4151         }
4152 
4153         @Override
4154         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
4155                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
4156                 throws RemoteException {
4157             new NotificationShellCmd(NotificationManagerService.this)
4158                     .exec(this, in, out, err, args, callback, resultReceiver);
4159         }
4160     };
4161 
4162     @VisibleForTesting
4163     protected void setNotificationAssistantAccessGrantedForUserInternal(
4164             ComponentName assistant, int baseUserId, boolean granted) {
4165         List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
4166         if (users != null) {
4167             for (UserInfo user : users) {
4168                 int userId = user.id;
4169                 if (assistant == null) {
4170                     ComponentName allowedAssistant = CollectionUtils.firstOrNull(
4171                             mAssistants.getAllowedComponents(userId));
4172                     if (allowedAssistant != null) {
4173                         setNotificationAssistantAccessGrantedForUserInternal(
4174                                 allowedAssistant, userId, false);
4175                     }
4176                     continue;
4177                 }
4178                 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
4179                         userId, mAssistants.getRequiredPermission())) {
4180                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
4181                             userId, false, granted);
4182                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
4183                             userId, true, granted);
4184 
4185                     getContext().sendBroadcastAsUser(
4186                             new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4187                                     .setPackage(assistant.getPackageName())
4188                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
4189                             UserHandle.of(userId), null);
4190 
4191                     handleSavePolicyFile();
4192                 }
4193             }
4194         }
4195     }
4196 
4197     private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
4198         if (r == null) {
4199             return;
4200         }
4201         if (adjustment.getSignals() != null) {
4202             final Bundle adjustments = adjustment.getSignals();
4203             Bundle.setDefusable(adjustments, true);
4204             List<String> toRemove = new ArrayList<>();
4205             for (String potentialKey : adjustments.keySet()) {
4206                 if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
4207                     toRemove.add(potentialKey);
4208                 }
4209             }
4210             for (String removeKey : toRemove) {
4211                 adjustments.remove(removeKey);
4212             }
4213             r.addAdjustment(adjustment);
4214         }
4215     }
4216 
4217     @GuardedBy("mNotificationLock")
4218     void addAutogroupKeyLocked(String key) {
4219         NotificationRecord r = mNotificationsByKey.get(key);
4220         if (r == null) {
4221             return;
4222         }
4223         if (r.sbn.getOverrideGroupKey() == null) {
4224             addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
4225             EventLogTags.writeNotificationAutogrouped(key);
4226             mRankingHandler.requestSort();
4227         }
4228     }
4229 
4230     @GuardedBy("mNotificationLock")
4231     void removeAutogroupKeyLocked(String key) {
4232         NotificationRecord r = mNotificationsByKey.get(key);
4233         if (r == null) {
4234             return;
4235         }
4236         if (r.sbn.getOverrideGroupKey() != null) {
4237             addAutoGroupAdjustment(r, null);
4238             EventLogTags.writeNotificationUnautogrouped(key);
4239             mRankingHandler.requestSort();
4240         }
4241     }
4242 
4243     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
4244         Bundle signals = new Bundle();
4245         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
4246         Adjustment adjustment =
4247                 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
4248         r.addAdjustment(adjustment);
4249     }
4250 
4251     // Clears the 'fake' auto-group summary.
4252     @GuardedBy("mNotificationLock")
4253     private void clearAutogroupSummaryLocked(int userId, String pkg) {
4254         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4255         if (summaries != null && summaries.containsKey(pkg)) {
4256             // Clear summary.
4257             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
4258             if (removed != null) {
4259                 boolean wasPosted = removeFromNotificationListsLocked(removed);
4260                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
4261             }
4262         }
4263     }
4264 
4265     @GuardedBy("mNotificationLock")
4266     private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
4267         ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
4268         return summaries != null && summaries.containsKey(sbn.getPackageName());
4269     }
4270 
4271     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
4272     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
4273         NotificationRecord summaryRecord = null;
4274         synchronized (mNotificationLock) {
4275             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
4276             if (notificationRecord == null) {
4277                 // The notification could have been cancelled again already. A successive
4278                 // adjustment will post a summary if needed.
4279                 return;
4280             }
4281             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
4282             userId = adjustedSbn.getUser().getIdentifier();
4283             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4284             if (summaries == null) {
4285                 summaries = new ArrayMap<>();
4286             }
4287             mAutobundledSummaries.put(userId, summaries);
4288             if (!summaries.containsKey(pkg)) {
4289                 // Add summary
4290                 final ApplicationInfo appInfo =
4291                        adjustedSbn.getNotification().extras.getParcelable(
4292                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
4293                 final Bundle extras = new Bundle();
4294                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
4295                 final String channelId = notificationRecord.getChannel().getId();
4296                 final Notification summaryNotification =
4297                         new Notification.Builder(getContext(), channelId)
4298                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
4299                                 .setGroupSummary(true)
4300                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
4301                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
4302                                 .setFlag(FLAG_AUTOGROUP_SUMMARY, true)
4303                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
4304                                 .setColor(adjustedSbn.getNotification().color)
4305                                 .setLocalOnly(true)
4306                                 .build();
4307                 summaryNotification.extras.putAll(extras);
4308                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
4309                 if (appIntent != null) {
4310                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
4311                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
4312                 }
4313                 final StatusBarNotification summarySbn =
4314                         new StatusBarNotification(adjustedSbn.getPackageName(),
4315                                 adjustedSbn.getOpPkg(),
4316                                 Integer.MAX_VALUE,
4317                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
4318                                 adjustedSbn.getInitialPid(), summaryNotification,
4319                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
4320                                 System.currentTimeMillis());
4321                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
4322                         notificationRecord.getChannel());
4323                 summaryRecord.setIsAppImportanceLocked(
4324                         notificationRecord.getIsAppImportanceLocked());
4325                 summaries.put(pkg, summarySbn.getKey());
4326             }
4327         }
4328         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
4329                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
4330             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
4331         }
4332     }
4333 
4334     private String disableNotificationEffects(NotificationRecord record) {
4335         if (mDisableNotificationEffects) {
4336             return "booleanState";
4337         }
4338         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
4339             return "listenerHints";
4340         }
4341         if (record != null && record.getAudioAttributes() != null) {
4342             if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
4343                 if (record.getAudioAttributes().getUsage()
4344                         != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4345                     return "listenerNoti";
4346                 }
4347             }
4348             if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
4349                 if (record.getAudioAttributes().getUsage()
4350                         == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4351                     return "listenerCall";
4352                 }
4353             }
4354         }
4355         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
4356             return "callState";
4357         }
4358         return null;
4359     };
4360 
4361     private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
4362         JSONObject dump = new JSONObject();
4363         try {
4364             dump.put("service", "Notification Manager");
4365             dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
4366             dump.put("ranking", mPreferencesHelper.dumpJson(filter));
4367             dump.put("stats", mUsageStats.dumpJson(filter));
4368             dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
4369         } catch (JSONException e) {
4370             e.printStackTrace();
4371         }
4372         pw.println(dump);
4373     }
4374 
4375     private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
4376         final ProtoOutputStream proto = new ProtoOutputStream(fd);
4377         synchronized (mNotificationLock) {
4378             int N = mNotificationList.size();
4379             for (int i = 0; i < N; i++) {
4380                 final NotificationRecord nr = mNotificationList.get(i);
4381                 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4382                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4383                         NotificationRecordProto.POSTED);
4384             }
4385             N = mEnqueuedNotifications.size();
4386             for (int i = 0; i < N; i++) {
4387                 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4388                 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4389                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4390                         NotificationRecordProto.ENQUEUED);
4391             }
4392             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
4393             N = snoozed.size();
4394             for (int i = 0; i < N; i++) {
4395                 final NotificationRecord nr = snoozed.get(i);
4396                 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4397                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4398                         NotificationRecordProto.SNOOZED);
4399             }
4400 
4401             long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
4402             mZenModeHelper.dump(proto);
4403             for (ComponentName suppressor : mEffectsSuppressors) {
4404                 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
4405             }
4406             proto.end(zenLog);
4407 
4408             long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
4409             mListeners.dump(proto, filter);
4410             proto.end(listenersToken);
4411 
4412             proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
4413 
4414             for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
4415                 long effectsToken = proto.start(
4416                     NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
4417 
4418                 proto.write(
4419                     ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
4420                 final ArraySet<ComponentName> listeners =
4421                     mListenersDisablingEffects.valueAt(i);
4422                 for (int j = 0; j < listeners.size(); j++) {
4423                     final ComponentName componentName = listeners.valueAt(j);
4424                     componentName.writeToProto(proto,
4425                             ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
4426                 }
4427 
4428                 proto.end(effectsToken);
4429             }
4430 
4431             long assistantsToken = proto.start(
4432                 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
4433             mAssistants.dump(proto, filter);
4434             proto.end(assistantsToken);
4435 
4436             long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
4437             mConditionProviders.dump(proto, filter);
4438             proto.end(conditionsToken);
4439 
4440             long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
4441             mRankingHelper.dump(proto, filter);
4442             mPreferencesHelper.dump(proto, filter);
4443             proto.end(rankingToken);
4444         }
4445 
4446         proto.flush();
4447     }
4448 
4449     private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
4450         synchronized (mNotificationLock) {
4451             int N;
4452             N = mNotificationList.size();
4453             if (N > 0) {
4454                 pw.println("  Notification List:");
4455                 for (int i = 0; i < N; i++) {
4456                     final NotificationRecord nr = mNotificationList.get(i);
4457                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
4458                     nr.dump(pw, "    ", getContext(), filter.redact);
4459                 }
4460                 pw.println("  ");
4461             }
4462         }
4463     }
4464 
4465     void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
4466         pw.print("Current Notification Manager state");
4467         if (filter.filtered) {
4468             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
4469         }
4470         pw.println(':');
4471         int N;
4472         final boolean zenOnly = filter.filtered && filter.zen;
4473 
4474         if (!zenOnly) {
4475             synchronized (mToastQueue) {
4476                 N = mToastQueue.size();
4477                 if (N > 0) {
4478                     pw.println("  Toast Queue:");
4479                     for (int i=0; i<N; i++) {
4480                         mToastQueue.get(i).dump(pw, "    ", filter);
4481                     }
4482                     pw.println("  ");
4483                 }
4484             }
4485         }
4486 
4487         synchronized (mNotificationLock) {
4488             if (!zenOnly) {
4489                 // Priority filters are only set when called via bugreport. If set
4490                 // skip sections that are part of the critical section.
4491                 if (!filter.normalPriority) {
4492                     dumpNotificationRecords(pw, filter);
4493                 }
4494                 if (!filter.filtered) {
4495                     N = mLights.size();
4496                     if (N > 0) {
4497                         pw.println("  Lights List:");
4498                         for (int i=0; i<N; i++) {
4499                             if (i == N - 1) {
4500                                 pw.print("  > ");
4501                             } else {
4502                                 pw.print("    ");
4503                             }
4504                             pw.println(mLights.get(i));
4505                         }
4506                         pw.println("  ");
4507                     }
4508                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
4509                     pw.println("  mHasLight=" + mHasLight);
4510                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
4511                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
4512                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
4513                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
4514                     pw.println("  mCallState=" + callStateToString(mCallState));
4515                     pw.println("  mSystemReady=" + mSystemReady);
4516                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
4517                 }
4518                 pw.println("  mArchive=" + mArchive.toString());
4519                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
4520                 int j=0;
4521                 while (iter.hasNext()) {
4522                     final StatusBarNotification sbn = iter.next();
4523                     if (filter != null && !filter.matches(sbn)) continue;
4524                     pw.println("    " + sbn);
4525                     if (++j >= 5) {
4526                         if (iter.hasNext()) pw.println("    ...");
4527                         break;
4528                     }
4529                 }
4530 
4531                 if (!zenOnly) {
4532                     N = mEnqueuedNotifications.size();
4533                     if (N > 0) {
4534                         pw.println("  Enqueued Notification List:");
4535                         for (int i = 0; i < N; i++) {
4536                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
4537                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
4538                             nr.dump(pw, "    ", getContext(), filter.redact);
4539                         }
4540                         pw.println("  ");
4541                     }
4542 
4543                     mSnoozeHelper.dump(pw, filter);
4544                 }
4545             }
4546 
4547             if (!zenOnly) {
4548                 pw.println("\n  Ranking Config:");
4549                 mRankingHelper.dump(pw, "    ", filter);
4550 
4551                 pw.println("\n Notification Preferences:");
4552                 mPreferencesHelper.dump(pw, "    ", filter);
4553 
4554                 pw.println("\n  Notification listeners:");
4555                 mListeners.dump(pw, filter);
4556                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
4557                 pw.print("    mListenersDisablingEffects: (");
4558                 N = mListenersDisablingEffects.size();
4559                 for (int i = 0; i < N; i++) {
4560                     final int hint = mListenersDisablingEffects.keyAt(i);
4561                     if (i > 0) pw.print(';');
4562                     pw.print("hint[" + hint + "]:");
4563 
4564                     final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
4565                     final int listenerSize = listeners.size();
4566 
4567                     for (int j = 0; j < listenerSize; j++) {
4568                         if (j > 0) pw.print(',');
4569                         final ComponentName listener = listeners.valueAt(j);
4570                         if (listener != null) {
4571                             pw.print(listener);
4572                         }
4573                     }
4574                 }
4575                 pw.println(')');
4576                 pw.println("\n  Notification assistant services:");
4577                 mAssistants.dump(pw, filter);
4578             }
4579 
4580             if (!filter.filtered || zenOnly) {
4581                 pw.println("\n  Zen Mode:");
4582                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
4583                 mZenModeHelper.dump(pw, "    ");
4584 
4585                 pw.println("\n  Zen Log:");
4586                 ZenLog.dump(pw, "    ");
4587             }
4588 
4589             pw.println("\n  Condition providers:");
4590             mConditionProviders.dump(pw, filter);
4591 
4592             pw.println("\n  Group summaries:");
4593             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
4594                 NotificationRecord r = entry.getValue();
4595                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
4596                 if (mNotificationsByKey.get(r.getKey()) != r) {
4597                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
4598                     r.dump(pw, "      ", getContext(), filter.redact);
4599                 }
4600             }
4601 
4602             if (!zenOnly) {
4603                 pw.println("\n  Usage Stats:");
4604                 mUsageStats.dump(pw, "    ", filter);
4605             }
4606         }
4607     }
4608 
4609     /**
4610      * The private API only accessible to the system process.
4611      */
4612     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
4613         @Override
4614         public NotificationChannel getNotificationChannel(String pkg, int uid, String
4615                 channelId) {
4616             return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
4617         }
4618 
4619         @Override
4620         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
4621                 String tag, int id, Notification notification, int userId) {
4622             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
4623                     userId);
4624         }
4625 
4626         @Override
4627         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
4628                 int userId) {
4629             checkCallerIsSystem();
4630             mHandler.post(() -> {
4631                 synchronized (mNotificationLock) {
4632                     // strip flag from all enqueued notifications. listeners will be informed
4633                     // in post runnable.
4634                     List<NotificationRecord> enqueued = findNotificationsByListLocked(
4635                             mEnqueuedNotifications, pkg, null, notificationId, userId);
4636                     for (int i = 0; i < enqueued.size(); i++) {
4637                         removeForegroundServiceFlagLocked(enqueued.get(i));
4638                     }
4639 
4640                     // if posted notification exists, strip its flag and tell listeners
4641                     NotificationRecord r = findNotificationByListLocked(
4642                             mNotificationList, pkg, null, notificationId, userId);
4643                     if (r != null) {
4644                         removeForegroundServiceFlagLocked(r);
4645                         mRankingHelper.sort(mNotificationList);
4646                         mListeners.notifyPostedLocked(r, r);
4647                     }
4648                 }
4649             });
4650         }
4651 
4652         @GuardedBy("mNotificationLock")
4653         private void removeForegroundServiceFlagLocked(NotificationRecord r) {
4654             if (r == null) {
4655                 return;
4656             }
4657             StatusBarNotification sbn = r.sbn;
4658             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4659             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4660             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4661             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4662             sbn.getNotification().flags =
4663                     (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
4664         }
4665     };
4666 
4667     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
4668             final int callingPid, final String tag, final int id, final Notification notification,
4669             int incomingUserId) {
4670         if (DBG) {
4671             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4672                     + " notification=" + notification);
4673         }
4674 
4675         if (pkg == null || notification == null) {
4676             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4677                     + " id=" + id + " notification=" + notification);
4678         }
4679 
4680         final int userId = ActivityManager.handleIncomingUser(callingPid,
4681                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
4682         final UserHandle user = UserHandle.of(userId);
4683 
4684         // Can throw a SecurityException if the calling uid doesn't have permission to post
4685         // as "pkg"
4686         final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
4687 
4688         checkRestrictedCategories(notification);
4689 
4690         // Fix the notification as best we can.
4691         try {
4692             fixNotification(notification, pkg, userId);
4693 
4694         } catch (NameNotFoundException e) {
4695             Slog.e(TAG, "Cannot create a context for sending app", e);
4696             return;
4697         }
4698 
4699         mUsageStats.registerEnqueuedByApp(pkg);
4700 
4701         // setup local book-keeping
4702         String channelId = notification.getChannelId();
4703         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4704             channelId = (new Notification.TvExtender(notification)).getChannelId();
4705         }
4706         final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
4707                 notificationUid, channelId, false /* includeDeleted */);
4708         if (channel == null) {
4709             final String noChannelStr = "No Channel found for "
4710                     + "pkg=" + pkg
4711                     + ", channelId=" + channelId
4712                     + ", id=" + id
4713                     + ", tag=" + tag
4714                     + ", opPkg=" + opPkg
4715                     + ", callingUid=" + callingUid
4716                     + ", userId=" + userId
4717                     + ", incomingUserId=" + incomingUserId
4718                     + ", notificationUid=" + notificationUid
4719                     + ", notification=" + notification;
4720             Slog.e(TAG, noChannelStr);
4721             boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
4722                     == NotificationManager.IMPORTANCE_NONE;
4723 
4724             if (!appNotificationsOff) {
4725                 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4726                         "Failed to post notification on channel \"" + channelId + "\"\n" +
4727                         "See log for more details");
4728             }
4729             return;
4730         }
4731 
4732         final StatusBarNotification n = new StatusBarNotification(
4733                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
4734                 user, null, System.currentTimeMillis());
4735         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
4736         r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
4737 
4738         if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4739             final boolean fgServiceShown = channel.isFgServiceShown();
4740             if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4741                         || !fgServiceShown)
4742                     && (r.getImportance() == IMPORTANCE_MIN
4743                             || r.getImportance() == IMPORTANCE_NONE)) {
4744                 // Increase the importance of foreground service notifications unless the user had
4745                 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4746                 if (TextUtils.isEmpty(channelId)
4747                         || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4748                     r.setSystemImportance(IMPORTANCE_LOW);
4749                 } else {
4750                     channel.setImportance(IMPORTANCE_LOW);
4751                     r.setSystemImportance(IMPORTANCE_LOW);
4752                     if (!fgServiceShown) {
4753                         channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4754                         channel.setFgServiceShown(true);
4755                     }
4756                     mPreferencesHelper.updateNotificationChannel(
4757                             pkg, notificationUid, channel, false);
4758                     r.updateNotificationChannel(channel);
4759                 }
4760             } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4761                     && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4762                 channel.setFgServiceShown(true);
4763                 r.updateNotificationChannel(channel);
4764             }
4765         }
4766 
4767         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4768                 r.sbn.getOverrideGroupKey() != null)) {
4769             return;
4770         }
4771 
4772         // Whitelist pending intents.
4773         if (notification.allPendingIntents != null) {
4774             final int intentCount = notification.allPendingIntents.size();
4775             if (intentCount > 0) {
4776                 final ActivityManagerInternal am = LocalServices
4777                         .getService(ActivityManagerInternal.class);
4778                 final long duration = LocalServices.getService(
4779                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4780                 for (int i = 0; i < intentCount; i++) {
4781                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4782                     if (pendingIntent != null) {
4783                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4784                                 WHITELIST_TOKEN, duration);
4785                         am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
4786                                 WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
4787                                         | FLAG_SERVICE_SENDER));
4788                     }
4789                 }
4790             }
4791         }
4792 
4793         mHandler.post(new EnqueueNotificationRunnable(userId, r));
4794     }
4795 
4796     @VisibleForTesting
4797     protected void fixNotification(Notification notification, String pkg, int userId)
4798             throws NameNotFoundException {
4799         final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
4800                 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
4801                 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
4802         Notification.addFieldsFromContext(ai, notification);
4803 
4804         int canColorize = mPackageManagerClient.checkPermission(
4805                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4806         if (canColorize == PERMISSION_GRANTED) {
4807             notification.flags |= Notification.FLAG_CAN_COLORIZE;
4808         } else {
4809             notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4810         }
4811 
4812         if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
4813             int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
4814                     android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
4815             if (fullscreenIntentPermission != PERMISSION_GRANTED) {
4816                 notification.fullScreenIntent = null;
4817                 Slog.w(TAG, "Package " + pkg +
4818                         ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
4819             }
4820         }
4821     }
4822 
4823     /**
4824      * Updates the flags for this notification to reflect whether it is a bubble or not.
4825      */
4826     private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId,
4827             NotificationRecord oldRecord) {
4828         Notification notification = r.getNotification();
4829         if (isNotificationAppropriateToBubble(r, pkg, userId, oldRecord)) {
4830             notification.flags |= FLAG_BUBBLE;
4831         } else {
4832             notification.flags &= ~FLAG_BUBBLE;
4833         }
4834     }
4835 
4836     /**
4837      * @return whether the provided notification record is allowed to be represented as a bubble.
4838      */
4839     private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
4840             NotificationRecord oldRecord) {
4841         Notification notification = r.getNotification();
4842         Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
4843         boolean intentCanBubble = metadata != null
4844                 && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg);
4845 
4846         // Does the app want to bubble & is able to bubble
4847         boolean canBubble = intentCanBubble
4848                 && mPreferencesHelper.areBubblesAllowed(pkg, userId)
4849                 && mPreferencesHelper.bubblesEnabled(r.sbn.getUser())
4850                 && r.getChannel().canBubble()
4851                 && !mActivityManager.isLowRamDevice();
4852 
4853         // Is the app in the foreground?
4854         final boolean appIsForeground =
4855                 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
4856 
4857         // Is the notification something we'd allow to bubble?
4858         // A call with a foreground service + person
4859         ArrayList<Person> peopleList = notification.extras != null
4860                 ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
4861                 : null;
4862         boolean isForegroundCall = CATEGORY_CALL.equals(notification.category)
4863                 && (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
4864         // OR message style (which always has a person) with any remote input
4865         Class<? extends Notification.Style> style = notification.getNotificationStyle();
4866         boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
4867         boolean notificationAppropriateToBubble =
4868                 (isMessageStyle && hasValidRemoteInput(notification))
4869                 || (peopleList != null && !peopleList.isEmpty() && isForegroundCall);
4870 
4871         // OR something that was previously a bubble & still exists
4872         boolean bubbleUpdate = oldRecord != null
4873                 && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0;
4874         return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate);
4875     }
4876 
4877     private boolean hasValidRemoteInput(Notification n) {
4878         // Also check for inline reply
4879         Notification.Action[] actions = n.actions;
4880         if (actions != null) {
4881             // Get the remote inputs
4882             for (int i = 0; i < actions.length; i++) {
4883                 Notification.Action action = actions[i];
4884                 RemoteInput[] inputs = action.getRemoteInputs();
4885                 if (inputs != null && inputs.length > 0) {
4886                     return true;
4887                 }
4888             }
4889         }
4890         return false;
4891     }
4892 
4893     /**
4894      * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
4895      *
4896      * @param context       the context to use.
4897      * @param pendingIntent the pending intent of the bubble.
4898      * @param packageName   the notification package name for this bubble.
4899      */
4900     // Keep checks in sync with BubbleController#canLaunchInActivityView.
4901     @VisibleForTesting
4902     protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
4903             String packageName) {
4904         if (pendingIntent == null) {
4905             Log.w(TAG, "Unable to create bubble -- no intent");
4906             return false;
4907         }
4908 
4909         // Need escalated privileges to get the intent.
4910         final long token = Binder.clearCallingIdentity();
4911         Intent intent;
4912         try {
4913             intent = pendingIntent.getIntent();
4914         } finally {
4915             Binder.restoreCallingIdentity(token);
4916         }
4917 
4918         ActivityInfo info = intent != null
4919                 ? intent.resolveActivityInfo(context.getPackageManager(), 0)
4920                 : null;
4921         if (info == null) {
4922             StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4923                     BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
4924             Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
4925                     + intent);
4926             return false;
4927         }
4928         if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
4929             StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4930                     BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
4931             Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
4932                     + intent);
4933             return false;
4934         }
4935         if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
4936             StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4937                     BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
4938             Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
4939                     + "for intent: " + intent);
4940             return false;
4941         }
4942         if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
4943             Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
4944                     + intent);
4945             return false;
4946         }
4947         return true;
4948     }
4949 
4950     private void doChannelWarningToast(CharSequence toastText) {
4951         Binder.withCleanCallingIdentity(() -> {
4952             final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4953             final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4954                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4955             if (warningEnabled) {
4956                 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4957                         Toast.LENGTH_SHORT);
4958                 toast.show();
4959             }
4960         });
4961     }
4962 
4963     @VisibleForTesting
4964     int resolveNotificationUid(String callingPkg, String targetPkg,
4965             int callingUid, int userId) {
4966         if (userId == UserHandle.USER_ALL) {
4967             userId = USER_SYSTEM;
4968         }
4969         // posted from app A on behalf of app A
4970         if (isCallerSameApp(targetPkg, callingUid, userId)
4971                 && (TextUtils.equals(callingPkg, targetPkg)
4972                 || isCallerSameApp(callingPkg, callingUid, userId))) {
4973             return callingUid;
4974         }
4975 
4976         int targetUid = -1;
4977         try {
4978             targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4979         } catch (NameNotFoundException e) {
4980             /* ignore */
4981         }
4982         // posted from app A on behalf of app B
4983         if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
4984                 || mPreferencesHelper.isDelegateAllowed(
4985                         targetPkg, targetUid, callingPkg, callingUid))) {
4986             return targetUid;
4987         }
4988 
4989         throw new SecurityException("Caller " + callingPkg + ":" + callingUid
4990                 + " cannot post for pkg " + targetPkg + " in user " + userId);
4991     }
4992 
4993     /**
4994      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4995      *
4996      * Has side effects.
4997      */
4998     private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
4999             NotificationRecord r, boolean isAutogroup) {
5000         final String pkg = r.sbn.getPackageName();
5001         final boolean isSystemNotification =
5002                 isUidSystemOrPhone(uid) || ("android".equals(pkg));
5003         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
5004 
5005         // Limit the number of notifications that any given package except the android
5006         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
5007         if (!isSystemNotification && !isNotificationFromListener) {
5008             synchronized (mNotificationLock) {
5009                 final int callingUid = Binder.getCallingUid();
5010                 if (mNotificationsByKey.get(r.sbn.getKey()) == null
5011                         && isCallerInstantApp(callingUid, userId)) {
5012                     // Ephemeral apps have some special constraints for notifications.
5013                     // They are not allowed to create new notifications however they are allowed to
5014                     // update notifications created by the system (e.g. a foreground service
5015                     // notification).
5016                     throw new SecurityException("Instant app " + pkg
5017                             + " cannot create notifications");
5018                 }
5019 
5020                 // rate limit updates that aren't completed progress notifications
5021                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
5022                         && !r.getNotification().hasCompletedProgress()
5023                         && !isAutogroup) {
5024 
5025                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
5026                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
5027                         mUsageStats.registerOverRateQuota(pkg);
5028                         final long now = SystemClock.elapsedRealtime();
5029                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
5030                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
5031                                     + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
5032                             mLastOverRateLogTime = now;
5033                         }
5034                         return false;
5035                     }
5036                 }
5037 
5038                 // limit the number of outstanding notificationrecords an app can have
5039                 int count = getNotificationCountLocked(pkg, userId, id, tag);
5040                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
5041                     mUsageStats.registerOverCountQuota(pkg);
5042                     Slog.e(TAG, "Package has already posted or enqueued " + count
5043                             + " notifications.  Not showing more.  package=" + pkg);
5044                     return false;
5045                 }
5046             }
5047         }
5048 
5049         // snoozed apps
5050         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
5051             MetricsLogger.action(r.getLogMaker()
5052                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
5053                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
5054             if (DBG) {
5055                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
5056             }
5057             mSnoozeHelper.update(userId, r);
5058             handleSavePolicyFile();
5059             return false;
5060         }
5061 
5062 
5063         // blocked apps
5064         if (isBlocked(r, mUsageStats)) {
5065             return false;
5066         }
5067 
5068         return true;
5069     }
5070 
5071     @GuardedBy("mNotificationLock")
5072     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
5073             String excludedTag) {
5074         int count = 0;
5075         final int N = mNotificationList.size();
5076         for (int i = 0; i < N; i++) {
5077             final NotificationRecord existing = mNotificationList.get(i);
5078             if (existing.sbn.getPackageName().equals(pkg)
5079                     && existing.sbn.getUserId() == userId) {
5080                 if (existing.sbn.getId() == excludedId
5081                         && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
5082                     continue;
5083                 }
5084                 count++;
5085             }
5086         }
5087         final int M = mEnqueuedNotifications.size();
5088         for (int i = 0; i < M; i++) {
5089             final NotificationRecord existing = mEnqueuedNotifications.get(i);
5090             if (existing.sbn.getPackageName().equals(pkg)
5091                     && existing.sbn.getUserId() == userId) {
5092                 count++;
5093             }
5094         }
5095         return count;
5096     }
5097 
5098     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
5099         if (isBlocked(r)) {
5100             Slog.e(TAG, "Suppressing notification from package by user request.");
5101             usageStats.registerBlocked(r);
5102             return true;
5103         }
5104         return false;
5105     }
5106 
5107     private boolean isBlocked(NotificationRecord r) {
5108         final String pkg = r.sbn.getPackageName();
5109         final int callingUid = r.sbn.getUid();
5110         return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
5111                 || mPreferencesHelper.getImportance(pkg, callingUid)
5112                 == NotificationManager.IMPORTANCE_NONE
5113                 || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
5114     }
5115 
5116     protected class SnoozeNotificationRunnable implements Runnable {
5117         private final String mKey;
5118         private final long mDuration;
5119         private final String mSnoozeCriterionId;
5120 
5121         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
5122             mKey = key;
5123             mDuration = duration;
5124             mSnoozeCriterionId = snoozeCriterionId;
5125         }
5126 
5127         @Override
5128         public void run() {
5129             synchronized (mNotificationLock) {
5130                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
5131                 if (r != null) {
5132                     snoozeLocked(r);
5133                 }
5134             }
5135         }
5136 
5137         @GuardedBy("mNotificationLock")
5138         void snoozeLocked(NotificationRecord r) {
5139             if (r.sbn.isGroup()) {
5140                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
5141                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
5142                 if (r.getNotification().isGroupSummary()) {
5143                     // snooze summary and all children
5144                     for (int i = 0; i < groupNotifications.size(); i++) {
5145                         snoozeNotificationLocked(groupNotifications.get(i));
5146                     }
5147                 } else {
5148                     // if there is a valid summary for this group, and we are snoozing the only
5149                     // child, also snooze the summary
5150                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
5151                         if (groupNotifications.size() != 2) {
5152                             snoozeNotificationLocked(r);
5153                         } else {
5154                             // snooze summary and the one child
5155                             for (int i = 0; i < groupNotifications.size(); i++) {
5156                                 snoozeNotificationLocked(groupNotifications.get(i));
5157                             }
5158                         }
5159                     } else {
5160                         snoozeNotificationLocked(r);
5161                     }
5162                 }
5163             } else {
5164                 // just snooze the one notification
5165                 snoozeNotificationLocked(r);
5166             }
5167         }
5168 
5169         @GuardedBy("mNotificationLock")
5170         void snoozeNotificationLocked(NotificationRecord r) {
5171             MetricsLogger.action(r.getLogMaker()
5172                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
5173                     .setType(MetricsEvent.TYPE_CLOSE)
5174                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
5175                             mDuration)
5176                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
5177                             mSnoozeCriterionId == null ? 0 : 1));
5178             reportUserInteraction(r);
5179             boolean wasPosted = removeFromNotificationListsLocked(r);
5180             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
5181             updateLightsLocked();
5182             if (mSnoozeCriterionId != null) {
5183                 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
5184                 mSnoozeHelper.snooze(r);
5185             } else {
5186                 mSnoozeHelper.snooze(r, mDuration);
5187             }
5188             r.recordSnoozed();
5189             handleSavePolicyFile();
5190         }
5191     }
5192 
5193     protected class CancelNotificationRunnable implements Runnable {
5194         private final int mCallingUid;
5195         private final int mCallingPid;
5196         private final String mPkg;
5197         private final String mTag;
5198         private final int mId;
5199         private final int mMustHaveFlags;
5200         private final int mMustNotHaveFlags;
5201         private final boolean mSendDelete;
5202         private final int mUserId;
5203         private final int mReason;
5204         private final int mRank;
5205         private final int mCount;
5206         private final ManagedServiceInfo mListener;
5207 
5208         CancelNotificationRunnable(final int callingUid, final int callingPid,
5209                 final String pkg, final String tag, final int id,
5210                 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5211                 final int userId, final int reason, int rank, int count,
5212                 final ManagedServiceInfo listener) {
5213             this.mCallingUid = callingUid;
5214             this.mCallingPid = callingPid;
5215             this.mPkg = pkg;
5216             this.mTag = tag;
5217             this.mId = id;
5218             this.mMustHaveFlags = mustHaveFlags;
5219             this.mMustNotHaveFlags = mustNotHaveFlags;
5220             this.mSendDelete = sendDelete;
5221             this.mUserId = userId;
5222             this.mReason = reason;
5223             this.mRank = rank;
5224             this.mCount = count;
5225             this.mListener = listener;
5226         }
5227 
5228         @Override
5229         public void run() {
5230             String listenerName = mListener == null ? null : mListener.component.toShortString();
5231             if (DBG) {
5232                 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
5233                         mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
5234             }
5235 
5236             synchronized (mNotificationLock) {
5237                 // If the notification is currently enqueued, repost this runnable so it has a
5238                 // chance to notify listeners
5239                 if ((findNotificationByListLocked(mEnqueuedNotifications, mPkg, mTag, mId, mUserId))
5240                         != null) {
5241                     mHandler.post(this);
5242                     return;
5243                 }
5244                 // Look for the notification in the posted list, since we already checked enqueued.
5245                 NotificationRecord r =
5246                         findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId);
5247                 if (r != null) {
5248                     // The notification was found, check if it should be removed.
5249 
5250                     // Ideally we'd do this in the caller of this method. However, that would
5251                     // require the caller to also find the notification.
5252                     if (mReason == REASON_CLICK) {
5253                         mUsageStats.registerClickedByUser(r);
5254                     }
5255 
5256                     if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
5257                         return;
5258                     }
5259                     if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
5260                         return;
5261                     }
5262 
5263                     // Cancel the notification.
5264                     boolean wasPosted = removeFromNotificationListsLocked(r);
5265                     cancelNotificationLocked(
5266                             r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
5267                     cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
5268                             mSendDelete, null);
5269                     updateLightsLocked();
5270                 } else {
5271                     // No notification was found, assume that it is snoozed and cancel it.
5272                     if (mReason != REASON_SNOOZED) {
5273                         final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
5274                         if (wasSnoozed) {
5275                             handleSavePolicyFile();
5276                         }
5277                     }
5278                 }
5279             }
5280         }
5281     }
5282 
5283     protected class EnqueueNotificationRunnable implements Runnable {
5284         private final NotificationRecord r;
5285         private final int userId;
5286 
5287         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
5288             this.userId = userId;
5289             this.r = r;
5290         };
5291 
5292         @Override
5293         public void run() {
5294             synchronized (mNotificationLock) {
5295                 mEnqueuedNotifications.add(r);
5296                 scheduleTimeoutLocked(r);
5297 
5298                 final StatusBarNotification n = r.sbn;
5299                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
5300                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
5301                 if (old != null) {
5302                     // Retain ranking information from previous record
5303                     r.copyRankingInformation(old);
5304                 }
5305 
5306                 final int callingUid = n.getUid();
5307                 final int callingPid = n.getInitialPid();
5308                 final Notification notification = n.getNotification();
5309                 final String pkg = n.getPackageName();
5310                 final int id = n.getId();
5311                 final String tag = n.getTag();
5312 
5313                 // We need to fix the notification up a little for bubbles
5314                 flagNotificationForBubbles(r, pkg, callingUid, old);
5315 
5316                 // Handle grouped notifications and bail out early if we
5317                 // can to avoid extracting signals.
5318                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
5319 
5320                 // if this is a group child, unsnooze parent summary
5321                 if (n.isGroup() && notification.isGroupChild()) {
5322                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
5323                 }
5324 
5325                 // This conditional is a dirty hack to limit the logging done on
5326                 //     behalf of the download manager without affecting other apps.
5327                 if (!pkg.equals("com.android.providers.downloads")
5328                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
5329                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
5330                     if (old != null) {
5331                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
5332                     }
5333                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
5334                             pkg, id, tag, userId, notification.toString(),
5335                             enqueueStatus);
5336                 }
5337 
5338                 // tell the assistant service about the notification
5339                 if (mAssistants.isEnabled()) {
5340                     mAssistants.onNotificationEnqueuedLocked(r);
5341                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
5342                             DELAY_FOR_ASSISTANT_TIME);
5343                 } else {
5344                     mHandler.post(new PostNotificationRunnable(r.getKey()));
5345                 }
5346             }
5347         }
5348     }
5349 
5350     @GuardedBy("mNotificationLock")
5351     private boolean isPackageSuspendedLocked(NotificationRecord r) {
5352         final String pkg = r.sbn.getPackageName();
5353         final int callingUid = r.sbn.getUid();
5354 
5355         return isPackageSuspendedForUser(pkg, callingUid);
5356     }
5357 
5358     protected class PostNotificationRunnable implements Runnable {
5359         private final String key;
5360 
5361         PostNotificationRunnable(String key) {
5362             this.key = key;
5363         }
5364 
5365         @Override
5366         public void run() {
5367             synchronized (mNotificationLock) {
5368                 try {
5369                     NotificationRecord r = null;
5370                     int N = mEnqueuedNotifications.size();
5371                     for (int i = 0; i < N; i++) {
5372                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5373                         if (Objects.equals(key, enqueued.getKey())) {
5374                             r = enqueued;
5375                             break;
5376                         }
5377                     }
5378                     if (r == null) {
5379                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
5380                         return;
5381                     }
5382 
5383                     if (isBlocked(r)) {
5384                         Slog.i(TAG, "notification blocked by assistant request");
5385                         return;
5386                     }
5387 
5388                     final boolean isPackageSuspended = isPackageSuspendedLocked(r);
5389                     r.setHidden(isPackageSuspended);
5390                     if (isPackageSuspended) {
5391                         mUsageStats.registerSuspendedByAdmin(r);
5392                     }
5393                     NotificationRecord old = mNotificationsByKey.get(key);
5394                     final StatusBarNotification n = r.sbn;
5395                     final Notification notification = n.getNotification();
5396                     int index = indexOfNotificationLocked(n.getKey());
5397                     if (index < 0) {
5398                         mNotificationList.add(r);
5399                         mUsageStats.registerPostedByApp(r);
5400                         r.setInterruptive(isVisuallyInterruptive(null, r));
5401                     } else {
5402                         old = mNotificationList.get(index);
5403                         mNotificationList.set(index, r);
5404                         mUsageStats.registerUpdatedByApp(r, old);
5405                         // Make sure we don't lose the foreground service state.
5406                         notification.flags |=
5407                                 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
5408                         r.isUpdate = true;
5409                         r.setTextChanged(isVisuallyInterruptive(old, r));
5410                     }
5411 
5412                     mNotificationsByKey.put(n.getKey(), r);
5413 
5414                     // Ensure if this is a foreground service that the proper additional
5415                     // flags are set.
5416                     if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
5417                         notification.flags |= FLAG_ONGOING_EVENT
5418                                 | FLAG_NO_CLEAR;
5419                     }
5420 
5421                     mRankingHelper.extractSignals(r);
5422                     mRankingHelper.sort(mNotificationList);
5423 
5424                     if (!r.isHidden()) {
5425                         buzzBeepBlinkLocked(r);
5426                     }
5427 
5428                     if (notification.getSmallIcon() != null) {
5429                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
5430                         mListeners.notifyPostedLocked(r, old);
5431                         if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
5432                                 && !isCritical(r)) {
5433                             mHandler.post(new Runnable() {
5434                                 @Override
5435                                 public void run() {
5436                                     mGroupHelper.onNotificationPosted(
5437                                             n, hasAutoGroupSummaryLocked(n));
5438                                 }
5439                             });
5440                         }
5441                     } else {
5442                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
5443                         if (old != null && !old.isCanceled) {
5444                             mListeners.notifyRemovedLocked(r,
5445                                     NotificationListenerService.REASON_ERROR, r.getStats());
5446                             mHandler.post(new Runnable() {
5447                                 @Override
5448                                 public void run() {
5449                                     mGroupHelper.onNotificationRemoved(n);
5450                                 }
5451                             });
5452                         }
5453                         // ATTENTION: in a future release we will bail out here
5454                         // so that we do not play sounds, show lights, etc. for invalid
5455                         // notifications
5456                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
5457                                 + n.getPackageName());
5458                     }
5459 
5460                     maybeRecordInterruptionLocked(r);
5461                 } finally {
5462                     int N = mEnqueuedNotifications.size();
5463                     for (int i = 0; i < N; i++) {
5464                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5465                         if (Objects.equals(key, enqueued.getKey())) {
5466                             mEnqueuedNotifications.remove(i);
5467                             break;
5468                         }
5469                     }
5470                 }
5471             }
5472         }
5473     }
5474 
5475     /**
5476      * If the notification differs enough visually, consider it a new interruptive notification.
5477      */
5478     @GuardedBy("mNotificationLock")
5479     @VisibleForTesting
5480     protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
5481         // Ignore summary updates because we don't display most of the information.
5482         if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
5483             if (DEBUG_INTERRUPTIVENESS) {
5484                 Slog.v(TAG, "INTERRUPTIVENESS: "
5485                         +  r.getKey() + " is not interruptive: summary");
5486             }
5487             return false;
5488         }
5489 
5490         if (old == null) {
5491             if (DEBUG_INTERRUPTIVENESS) {
5492                 Slog.v(TAG, "INTERRUPTIVENESS: "
5493                         +  r.getKey() + " is interruptive: new notification");
5494             }
5495             return true;
5496         }
5497 
5498         if (r == null) {
5499             if (DEBUG_INTERRUPTIVENESS) {
5500                 Slog.v(TAG, "INTERRUPTIVENESS: "
5501                         +  r.getKey() + " is not interruptive: null");
5502             }
5503             return false;
5504         }
5505 
5506         Notification oldN = old.sbn.getNotification();
5507         Notification newN = r.sbn.getNotification();
5508 
5509         if (oldN.extras == null || newN.extras == null) {
5510             if (DEBUG_INTERRUPTIVENESS) {
5511                 Slog.v(TAG, "INTERRUPTIVENESS: "
5512                         +  r.getKey() + " is not interruptive: no extras");
5513             }
5514             return false;
5515         }
5516 
5517         // Ignore visual interruptions from foreground services because users
5518         // consider them one 'session'. Count them for everything else.
5519         if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
5520             if (DEBUG_INTERRUPTIVENESS) {
5521                 Slog.v(TAG, "INTERRUPTIVENESS: "
5522                         +  r.getKey() + " is not interruptive: foreground service");
5523             }
5524             return false;
5525         }
5526 
5527         final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
5528         final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
5529         if (!Objects.equals(oldTitle, newTitle)) {
5530             if (DEBUG_INTERRUPTIVENESS) {
5531                 Slog.v(TAG, "INTERRUPTIVENESS: "
5532                         +  r.getKey() + " is interruptive: changed title");
5533                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old title: %s (%s@0x%08x)",
5534                         oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
5535                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new title: %s (%s@0x%08x)",
5536                         newTitle, newTitle.getClass(), newTitle.hashCode()));
5537             }
5538             return true;
5539         }
5540         // Do not compare Spannables (will always return false); compare unstyled Strings
5541         final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
5542         final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
5543         if (!Objects.equals(oldText, newText)) {
5544             if (DEBUG_INTERRUPTIVENESS) {
5545                 Slog.v(TAG, "INTERRUPTIVENESS: "
5546                         + r.getKey() + " is interruptive: changed text");
5547                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old text: %s (%s@0x%08x)",
5548                         oldText, oldText.getClass(), oldText.hashCode()));
5549                 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new text: %s (%s@0x%08x)",
5550                         newText, newText.getClass(), newText.hashCode()));
5551             }
5552             return true;
5553         }
5554         if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
5555             if (DEBUG_INTERRUPTIVENESS) {
5556                 Slog.v(TAG, "INTERRUPTIVENESS: "
5557                     +  r.getKey() + " is interruptive: completed progress");
5558             }
5559             return true;
5560         }
5561         // Actions
5562         if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
5563             if (DEBUG_INTERRUPTIVENESS) {
5564                 Slog.v(TAG, "INTERRUPTIVENESS: "
5565                         +  r.getKey() + " is interruptive: changed actions");
5566             }
5567             return true;
5568         }
5569 
5570         try {
5571             Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
5572             Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
5573 
5574             // Style based comparisons
5575             if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
5576                 if (DEBUG_INTERRUPTIVENESS) {
5577                     Slog.v(TAG, "INTERRUPTIVENESS: "
5578                             +  r.getKey() + " is interruptive: styles differ");
5579                 }
5580                 return true;
5581             }
5582 
5583             // Remote views
5584             if (Notification.areRemoteViewsChanged(oldB, newB)) {
5585                 if (DEBUG_INTERRUPTIVENESS) {
5586                     Slog.v(TAG, "INTERRUPTIVENESS: "
5587                             +  r.getKey() + " is interruptive: remoteviews differ");
5588                 }
5589                 return true;
5590             }
5591         } catch (Exception e) {
5592             Slog.w(TAG, "error recovering builder", e);
5593         }
5594 
5595         return false;
5596     }
5597 
5598     /**
5599      * Check if the notification is classified as critical.
5600      *
5601      * @param record the record to test for criticality
5602      * @return {@code true} if notification is considered critical
5603      *
5604      * @see CriticalNotificationExtractor for criteria
5605      */
5606     private boolean isCritical(NotificationRecord record) {
5607         // 0 is the most critical
5608         return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
5609     }
5610 
5611     /**
5612      * Ensures that grouped notification receive their special treatment.
5613      *
5614      * <p>Cancels group children if the new notification causes a group to lose
5615      * its summary.</p>
5616      *
5617      * <p>Updates mSummaryByGroupKey.</p>
5618      */
5619     @GuardedBy("mNotificationLock")
5620     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
5621             int callingUid, int callingPid) {
5622         StatusBarNotification sbn = r.sbn;
5623         Notification n = sbn.getNotification();
5624         if (n.isGroupSummary() && !sbn.isAppGroup())  {
5625             // notifications without a group shouldn't be a summary, otherwise autobundling can
5626             // lead to bugs
5627             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
5628         }
5629 
5630         String group = sbn.getGroupKey();
5631         boolean isSummary = n.isGroupSummary();
5632 
5633         Notification oldN = old != null ? old.sbn.getNotification() : null;
5634         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
5635         boolean oldIsSummary = old != null && oldN.isGroupSummary();
5636 
5637         if (oldIsSummary) {
5638             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
5639             if (removedSummary != old) {
5640                 String removedKey =
5641                         removedSummary != null ? removedSummary.getKey() : "<null>";
5642                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
5643                         ", removed=" + removedKey);
5644             }
5645         }
5646         if (isSummary) {
5647             mSummaryByGroupKey.put(group, r);
5648         }
5649 
5650         // Clear out group children of the old notification if the update
5651         // causes the group summary to go away. This happens when the old
5652         // notification was a summary and the new one isn't, or when the old
5653         // notification was a summary and its group key changed.
5654         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
5655             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
5656                     null);
5657         }
5658     }
5659 
5660     @VisibleForTesting
5661     @GuardedBy("mNotificationLock")
5662     void scheduleTimeoutLocked(NotificationRecord record) {
5663         if (record.getNotification().getTimeoutAfter() > 0) {
5664             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5665                     REQUEST_CODE_TIMEOUT,
5666                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
5667                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
5668                                     .appendPath(record.getKey()).build())
5669                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
5670                             .putExtra(EXTRA_KEY, record.getKey()),
5671                     PendingIntent.FLAG_UPDATE_CURRENT);
5672             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
5673                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
5674         }
5675     }
5676 
5677     @VisibleForTesting
5678     @GuardedBy("mNotificationLock")
5679     void buzzBeepBlinkLocked(NotificationRecord record) {
5680         if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
5681             return;
5682         }
5683         boolean buzz = false;
5684         boolean beep = false;
5685         boolean blink = false;
5686 
5687         final Notification notification = record.sbn.getNotification();
5688         final String key = record.getKey();
5689 
5690         // Should this notification make noise, vibe, or use the LED?
5691         final boolean aboveThreshold =
5692                 mIsAutomotive
5693                         ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
5694                         : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
5695 
5696         // Remember if this notification already owns the notification channels.
5697         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
5698         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
5699         // These are set inside the conditional if the notification is allowed to make noise.
5700         boolean hasValidVibrate = false;
5701         boolean hasValidSound = false;
5702         boolean sentAccessibilityEvent = false;
5703         // If the notification will appear in the status bar, it should send an accessibility
5704         // event
5705         if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
5706             sendAccessibilityEvent(notification, record.sbn.getPackageName());
5707             sentAccessibilityEvent = true;
5708         }
5709 
5710         if (aboveThreshold && isNotificationForCurrentUser(record)) {
5711 
5712             if (mSystemReady && mAudioManager != null) {
5713                 Uri soundUri = record.getSound();
5714                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
5715                 long[] vibration = record.getVibration();
5716                 // Demote sound to vibration if vibration missing & phone in vibration mode.
5717                 if (vibration == null
5718                         && hasValidSound
5719                         && (mAudioManager.getRingerModeInternal()
5720                         == AudioManager.RINGER_MODE_VIBRATE)
5721                         && mAudioManager.getStreamVolume(
5722                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
5723                     vibration = mFallbackVibrationPattern;
5724                 }
5725                 hasValidVibrate = vibration != null;
5726 
5727                 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
5728                 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
5729                     if (!sentAccessibilityEvent) {
5730                         sendAccessibilityEvent(notification, record.sbn.getPackageName());
5731                         sentAccessibilityEvent = true;
5732                     }
5733                     if (DBG) Slog.v(TAG, "Interrupting!");
5734                     if (hasValidSound) {
5735                         if (mInCall) {
5736                             playInCallNotification();
5737                             beep = true;
5738                         } else {
5739                             beep = playSound(record, soundUri);
5740                         }
5741                         if(beep) {
5742                             mSoundNotificationKey = key;
5743                         }
5744                     }
5745 
5746                     final boolean ringerModeSilent =
5747                             mAudioManager.getRingerModeInternal()
5748                                     == AudioManager.RINGER_MODE_SILENT;
5749                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
5750                         buzz = playVibration(record, vibration, hasValidSound);
5751                         if(buzz) {
5752                             mVibrateNotificationKey = key;
5753                         }
5754                     }
5755                 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
5756                     hasValidSound = false;
5757                 }
5758             }
5759         }
5760         // If a notification is updated to remove the actively playing sound or vibrate,
5761         // cancel that feedback now
5762         if (wasBeep && !hasValidSound) {
5763             clearSoundLocked();
5764         }
5765         if (wasBuzz && !hasValidVibrate) {
5766             clearVibrateLocked();
5767         }
5768 
5769         // light
5770         // release the light
5771         boolean wasShowLights = mLights.remove(key);
5772         if (canShowLightsLocked(record, aboveThreshold)) {
5773             mLights.add(key);
5774             updateLightsLocked();
5775             if (mUseAttentionLight) {
5776                 mAttentionLight.pulse();
5777             }
5778             blink = true;
5779         } else if (wasShowLights) {
5780             updateLightsLocked();
5781         }
5782         if (buzz || beep || blink) {
5783             // Ignore summary updates because we don't display most of the information.
5784             if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
5785                 if (DEBUG_INTERRUPTIVENESS) {
5786                     Slog.v(TAG, "INTERRUPTIVENESS: "
5787                             + record.getKey() + " is not interruptive: summary");
5788                 }
5789             } else {
5790                 if (DEBUG_INTERRUPTIVENESS) {
5791                     Slog.v(TAG, "INTERRUPTIVENESS: "
5792                             + record.getKey() + " is interruptive: alerted");
5793                 }
5794                 record.setInterruptive(true);
5795             }
5796             MetricsLogger.action(record.getLogMaker()
5797                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
5798                     .setType(MetricsEvent.TYPE_OPEN)
5799                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
5800             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
5801         }
5802         record.setAudiblyAlerted(buzz || beep);
5803     }
5804 
5805     @GuardedBy("mNotificationLock")
5806     boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
5807         // device lacks light
5808         if (!mHasLight) {
5809             return false;
5810         }
5811         // user turned lights off globally
5812         if (!mNotificationPulseEnabled) {
5813             return false;
5814         }
5815         // the notification/channel has no light
5816         if (record.getLight() == null) {
5817             return false;
5818         }
5819         // unimportant notification
5820         if (!aboveThreshold) {
5821             return false;
5822         }
5823         // suppressed due to DND
5824         if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
5825             return false;
5826         }
5827         // Suppressed because it's a silent update
5828         final Notification notification = record.getNotification();
5829         if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
5830             return false;
5831         }
5832         // Suppressed because another notification in its group handles alerting
5833         if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
5834             return false;
5835         }
5836         // not if in call or the screen's on
5837         if (mInCall || mScreenOn) {
5838             return false;
5839         }
5840 
5841         return true;
5842     }
5843 
5844     @GuardedBy("mNotificationLock")
5845     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
5846         // Suppressed because it's a silent update
5847         final Notification notification = record.getNotification();
5848         if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
5849             return true;
5850         }
5851 
5852         // muted by listener
5853         final String disableEffects = disableNotificationEffects(record);
5854         if (disableEffects != null) {
5855             ZenLog.traceDisableEffects(record, disableEffects);
5856             return true;
5857         }
5858 
5859         // suppressed due to DND
5860         if (record.isIntercepted()) {
5861             return true;
5862         }
5863 
5864         // Suppressed because another notification in its group handles alerting
5865         if (record.sbn.isGroup()) {
5866             if (notification.suppressAlertingDueToGrouping()) {
5867                 return true;
5868             }
5869         }
5870 
5871         // Suppressed for being too recently noisy
5872         final String pkg = record.sbn.getPackageName();
5873         if (mUsageStats.isAlertRateLimited(pkg)) {
5874             Slog.e(TAG, "Muting recently noisy " + record.getKey());
5875             return true;
5876         }
5877 
5878         return false;
5879     }
5880 
5881     private boolean playSound(final NotificationRecord record, Uri soundUri) {
5882         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5883         // play notifications if there is no user of exclusive audio focus
5884         // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
5885         //   VIBRATE ringer mode)
5886         if (!mAudioManager.isAudioFocusExclusive()
5887                 && (mAudioManager.getStreamVolume(
5888                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
5889             final long identity = Binder.clearCallingIdentity();
5890             try {
5891                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5892                 if (player != null) {
5893                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
5894                             + " with attributes " + record.getAudioAttributes());
5895                     player.playAsync(soundUri, record.sbn.getUser(), looping,
5896                             record.getAudioAttributes());
5897                     return true;
5898                 }
5899             } catch (RemoteException e) {
5900             } finally {
5901                 Binder.restoreCallingIdentity(identity);
5902             }
5903         }
5904         return false;
5905     }
5906 
5907     private boolean playVibration(final NotificationRecord record, long[] vibration,
5908             boolean delayVibForSound) {
5909         // Escalate privileges so we can use the vibrator even if the
5910         // notifying app does not have the VIBRATE permission.
5911         long identity = Binder.clearCallingIdentity();
5912         try {
5913             final VibrationEffect effect;
5914             try {
5915                 final boolean insistent =
5916                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5917                 effect = VibrationEffect.createWaveform(
5918                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
5919             } catch (IllegalArgumentException e) {
5920                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5921                         Arrays.toString(vibration));
5922                 return false;
5923             }
5924             if (delayVibForSound) {
5925                 new Thread(() -> {
5926                     // delay the vibration by the same amount as the notification sound
5927                     final int waitMs = mAudioManager.getFocusRampTimeMs(
5928                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5929                             record.getAudioAttributes());
5930                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5931                     try {
5932                         Thread.sleep(waitMs);
5933                     } catch (InterruptedException e) { }
5934 
5935                     // Notifications might be canceled before it actually vibrates due to waitMs,
5936                     // so need to check the notification still valide for vibrate.
5937                     synchronized (mNotificationLock) {
5938                         if (mNotificationsByKey.get(record.getKey()) != null) {
5939                             mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5940                                     effect, "Notification (delayed)", record.getAudioAttributes());
5941                         } else {
5942                             Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5943                         }
5944                     }
5945                 }).start();
5946             } else {
5947                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
5948                         effect, "Notification", record.getAudioAttributes());
5949             }
5950             return true;
5951         } finally{
5952             Binder.restoreCallingIdentity(identity);
5953         }
5954     }
5955 
5956     private boolean isNotificationForCurrentUser(NotificationRecord record) {
5957         final int currentUser;
5958         final long token = Binder.clearCallingIdentity();
5959         try {
5960             currentUser = ActivityManager.getCurrentUser();
5961         } finally {
5962             Binder.restoreCallingIdentity(token);
5963         }
5964         return (record.getUserId() == UserHandle.USER_ALL ||
5965                 record.getUserId() == currentUser ||
5966                 mUserProfiles.isCurrentProfile(record.getUserId()));
5967     }
5968 
5969     protected void playInCallNotification() {
5970         if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5971                 && Settings.Secure.getInt(getContext().getContentResolver(),
5972                 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5973             new Thread() {
5974                 @Override
5975                 public void run() {
5976                     final long identity = Binder.clearCallingIdentity();
5977                     try {
5978                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5979                         if (player != null) {
5980                             if (mCallNotificationToken != null) {
5981                                 player.stop(mCallNotificationToken);
5982                             }
5983                             mCallNotificationToken = new Binder();
5984                             player.play(mCallNotificationToken, mInCallNotificationUri,
5985                                     mInCallNotificationAudioAttributes,
5986                                     mInCallNotificationVolume, false);
5987                         }
5988                     } catch (RemoteException e) {
5989                     } finally {
5990                         Binder.restoreCallingIdentity(identity);
5991                     }
5992                 }
5993             }.start();
5994         }
5995     }
5996 
5997     @GuardedBy("mToastQueue")
5998     void showNextToastLocked() {
5999         ToastRecord record = mToastQueue.get(0);
6000         while (record != null) {
6001             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
6002             try {
6003                 record.callback.show(record.token);
6004                 scheduleDurationReachedLocked(record);
6005                 return;
6006             } catch (RemoteException e) {
6007                 Slog.w(TAG, "Object died trying to show notification " + record.callback
6008                         + " in package " + record.pkg);
6009                 // remove it from the list and let the process die
6010                 int index = mToastQueue.indexOf(record);
6011                 if (index >= 0) {
6012                     mToastQueue.remove(index);
6013                 }
6014                 keepProcessAliveIfNeededLocked(record.pid);
6015                 if (mToastQueue.size() > 0) {
6016                     record = mToastQueue.get(0);
6017                 } else {
6018                     record = null;
6019                 }
6020             }
6021         }
6022     }
6023 
6024     @GuardedBy("mToastQueue")
6025     void cancelToastLocked(int index) {
6026         ToastRecord record = mToastQueue.get(index);
6027         try {
6028             record.callback.hide();
6029         } catch (RemoteException e) {
6030             Slog.w(TAG, "Object died trying to hide notification " + record.callback
6031                     + " in package " + record.pkg);
6032             // don't worry about this, we're about to remove it from
6033             // the list anyway
6034         }
6035 
6036         ToastRecord lastToast = mToastQueue.remove(index);
6037 
6038         mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
6039                 lastToast.displayId);
6040         // We passed 'false' for 'removeWindows' so that the client has time to stop
6041         // rendering (as hide above is a one-way message), otherwise we could crash
6042         // a client which was actively using a surface made from the token. However
6043         // we need to schedule a timeout to make sure the token is eventually killed
6044         // one way or another.
6045         scheduleKillTokenTimeout(lastToast);
6046 
6047         keepProcessAliveIfNeededLocked(record.pid);
6048         if (mToastQueue.size() > 0) {
6049             // Show the next one. If the callback fails, this will remove
6050             // it from the list, so don't assume that the list hasn't changed
6051             // after this point.
6052             showNextToastLocked();
6053         }
6054     }
6055 
6056     void finishTokenLocked(IBinder t, int displayId) {
6057         mHandler.removeCallbacksAndMessages(t);
6058         // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
6059         // remaining surfaces as either the client has called finishToken indicating
6060         // it has successfully removed the views, or the client has timed out
6061         // at which point anything goes.
6062         mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
6063     }
6064 
6065     @GuardedBy("mToastQueue")
6066     private void scheduleDurationReachedLocked(ToastRecord r)
6067     {
6068         mHandler.removeCallbacksAndMessages(r);
6069         Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
6070         int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
6071         // Accessibility users may need longer timeout duration. This api compares original delay
6072         // with user's preference and return longer one. It returns original delay if there's no
6073         // preference.
6074         delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
6075                 AccessibilityManager.FLAG_CONTENT_TEXT);
6076         mHandler.sendMessageDelayed(m, delay);
6077     }
6078 
6079     private void handleDurationReached(ToastRecord record)
6080     {
6081         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
6082         synchronized (mToastQueue) {
6083             int index = indexOfToastLocked(record.pkg, record.callback);
6084             if (index >= 0) {
6085                 cancelToastLocked(index);
6086             }
6087         }
6088     }
6089 
6090     @GuardedBy("mToastQueue")
6091     private void scheduleKillTokenTimeout(ToastRecord r)
6092     {
6093         mHandler.removeCallbacksAndMessages(r);
6094         Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
6095         mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
6096     }
6097 
6098     private void handleKillTokenTimeout(ToastRecord record)
6099     {
6100         if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
6101         synchronized (mToastQueue) {
6102             finishTokenLocked(record.token, record.displayId);
6103         }
6104     }
6105 
6106     @GuardedBy("mToastQueue")
6107     int indexOfToastLocked(String pkg, ITransientNotification callback)
6108     {
6109         IBinder cbak = callback.asBinder();
6110         ArrayList<ToastRecord> list = mToastQueue;
6111         int len = list.size();
6112         for (int i=0; i<len; i++) {
6113             ToastRecord r = list.get(i);
6114             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
6115                 return i;
6116             }
6117         }
6118         return -1;
6119     }
6120 
6121     @GuardedBy("mToastQueue")
6122     void keepProcessAliveIfNeededLocked(int pid)
6123     {
6124         int toastCount = 0; // toasts from this pid
6125         ArrayList<ToastRecord> list = mToastQueue;
6126         int N = list.size();
6127         for (int i=0; i<N; i++) {
6128             ToastRecord r = list.get(i);
6129             if (r.pid == pid) {
6130                 toastCount++;
6131             }
6132         }
6133         try {
6134             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
6135         } catch (RemoteException e) {
6136             // Shouldn't happen.
6137         }
6138     }
6139 
6140     private void handleRankingReconsideration(Message message) {
6141         if (!(message.obj instanceof RankingReconsideration)) return;
6142         RankingReconsideration recon = (RankingReconsideration) message.obj;
6143         recon.run();
6144         boolean changed;
6145         synchronized (mNotificationLock) {
6146             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
6147             if (record == null) {
6148                 return;
6149             }
6150             int indexBefore = findNotificationRecordIndexLocked(record);
6151             boolean interceptBefore = record.isIntercepted();
6152             int visibilityBefore = record.getPackageVisibilityOverride();
6153             recon.applyChangesLocked(record);
6154             applyZenModeLocked(record);
6155             mRankingHelper.sort(mNotificationList);
6156             int indexAfter = findNotificationRecordIndexLocked(record);
6157             boolean interceptAfter = record.isIntercepted();
6158             int visibilityAfter = record.getPackageVisibilityOverride();
6159             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
6160                     || visibilityBefore != visibilityAfter;
6161             if (interceptBefore && !interceptAfter
6162                     && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
6163                 buzzBeepBlinkLocked(record);
6164             }
6165         }
6166         if (changed) {
6167             mHandler.scheduleSendRankingUpdate();
6168         }
6169     }
6170 
6171     void handleRankingSort() {
6172         if (mRankingHelper == null) return;
6173         synchronized (mNotificationLock) {
6174             final int N = mNotificationList.size();
6175             // Any field that can change via one of the extractors needs to be added here.
6176             ArrayList<String> orderBefore = new ArrayList<>(N);
6177             int[] visibilities = new int[N];
6178             boolean[] showBadges = new boolean[N];
6179             boolean[] allowBubbles = new boolean[N];
6180             ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
6181             ArrayList<String> groupKeyBefore = new ArrayList<>(N);
6182             ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
6183             ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
6184             ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
6185             ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
6186             ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N);
6187             ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
6188             int[] importancesBefore = new int[N];
6189             for (int i = 0; i < N; i++) {
6190                 final NotificationRecord r = mNotificationList.get(i);
6191                 orderBefore.add(r.getKey());
6192                 visibilities[i] = r.getPackageVisibilityOverride();
6193                 showBadges[i] = r.canShowBadge();
6194                 allowBubbles[i] = r.canBubble();
6195                 channelBefore.add(r.getChannel());
6196                 groupKeyBefore.add(r.getGroupKey());
6197                 overridePeopleBefore.add(r.getPeopleOverride());
6198                 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
6199                 userSentimentBefore.add(r.getUserSentiment());
6200                 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
6201                 systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions());
6202                 smartRepliesBefore.add(r.getSmartReplies());
6203                 importancesBefore[i] = r.getImportance();
6204                 mRankingHelper.extractSignals(r);
6205             }
6206             mRankingHelper.sort(mNotificationList);
6207             for (int i = 0; i < N; i++) {
6208                 final NotificationRecord r = mNotificationList.get(i);
6209                 if (!orderBefore.get(i).equals(r.getKey())
6210                         || visibilities[i] != r.getPackageVisibilityOverride()
6211                         || showBadges[i] != r.canShowBadge()
6212                         || allowBubbles[i] != r.canBubble()
6213                         || !Objects.equals(channelBefore.get(i), r.getChannel())
6214                         || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
6215                         || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
6216                         || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
6217                         || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
6218                         || !Objects.equals(suppressVisuallyBefore.get(i),
6219                         r.getSuppressedVisualEffects())
6220                         || !Objects.equals(systemSmartActionsBefore.get(i),
6221                                 r.getSystemGeneratedSmartActions())
6222                         || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())
6223                         || importancesBefore[i] != r.getImportance()) {
6224                     mHandler.scheduleSendRankingUpdate();
6225                     return;
6226                 }
6227             }
6228         }
6229     }
6230 
6231     @GuardedBy("mNotificationLock")
6232     private void recordCallerLocked(NotificationRecord record) {
6233         if (mZenModeHelper.isCall(record)) {
6234             mZenModeHelper.recordCaller(record);
6235         }
6236     }
6237 
6238     // let zen mode evaluate this record
6239     @GuardedBy("mNotificationLock")
6240     private void applyZenModeLocked(NotificationRecord record) {
6241         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
6242         if (record.isIntercepted()) {
6243             record.setSuppressedVisualEffects(
6244                     mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
6245         } else {
6246             record.setSuppressedVisualEffects(0);
6247         }
6248     }
6249 
6250     @GuardedBy("mNotificationLock")
6251     private int findNotificationRecordIndexLocked(NotificationRecord target) {
6252         return mRankingHelper.indexOf(mNotificationList, target);
6253     }
6254 
6255     private void handleSendRankingUpdate() {
6256         synchronized (mNotificationLock) {
6257             mListeners.notifyRankingUpdateLocked(null);
6258         }
6259     }
6260 
6261     private void scheduleListenerHintsChanged(int state) {
6262         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
6263         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
6264     }
6265 
6266     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
6267         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
6268         mHandler.obtainMessage(
6269                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
6270                 listenerInterruptionFilter,
6271                 0).sendToTarget();
6272     }
6273 
6274     private void handleListenerHintsChanged(int hints) {
6275         synchronized (mNotificationLock) {
6276             mListeners.notifyListenerHintsChangedLocked(hints);
6277         }
6278     }
6279 
6280     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
6281         synchronized (mNotificationLock) {
6282             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
6283         }
6284     }
6285 
6286     private void handleOnPackageChanged(boolean removingPackage, int changeUserId,
6287             String[] pkgList, int[] uidList) {
6288         boolean preferencesChanged = removingPackage;
6289         mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
6290         mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
6291         mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
6292         preferencesChanged |= mPreferencesHelper.onPackagesChanged(
6293                 removingPackage, changeUserId, pkgList, uidList);
6294         if (preferencesChanged) {
6295             handleSavePolicyFile();
6296         }
6297     }
6298 
6299     protected class WorkerHandler extends Handler
6300     {
6301         public WorkerHandler(Looper looper) {
6302             super(looper);
6303         }
6304 
6305         @Override
6306         public void handleMessage(Message msg)
6307         {
6308             switch (msg.what)
6309             {
6310                 case MESSAGE_DURATION_REACHED:
6311                     handleDurationReached((ToastRecord) msg.obj);
6312                     break;
6313                 case MESSAGE_FINISH_TOKEN_TIMEOUT:
6314                     handleKillTokenTimeout((ToastRecord) msg.obj);
6315                     break;
6316                 case MESSAGE_SEND_RANKING_UPDATE:
6317                     handleSendRankingUpdate();
6318                     break;
6319                 case MESSAGE_LISTENER_HINTS_CHANGED:
6320                     handleListenerHintsChanged(msg.arg1);
6321                     break;
6322                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
6323                     handleListenerInterruptionFilterChanged(msg.arg1);
6324                     break;
6325                 case MESSAGE_ON_PACKAGE_CHANGED:
6326                     SomeArgs args = (SomeArgs) msg.obj;
6327                     handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2,
6328                             (int[]) args.arg3);
6329                     args.recycle();
6330                     break;
6331             }
6332         }
6333 
6334         protected void scheduleSendRankingUpdate() {
6335             if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
6336                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
6337                 sendMessage(m);
6338             }
6339         }
6340 
6341         protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
6342             if (!hasCallbacks(cancelRunnable)) {
6343                 sendMessage(Message.obtain(this, cancelRunnable));
6344             }
6345         }
6346 
6347         protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId,
6348                 String[] pkgList, int[] uidList) {
6349             SomeArgs args = SomeArgs.obtain();
6350             args.arg1 = removingPackage;
6351             args.argi1 = changeUserId;
6352             args.arg2 = pkgList;
6353             args.arg3 = uidList;
6354             sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args));
6355         }
6356     }
6357 
6358     private final class RankingHandlerWorker extends Handler implements RankingHandler
6359     {
6360         public RankingHandlerWorker(Looper looper) {
6361             super(looper);
6362         }
6363 
6364         @Override
6365         public void handleMessage(Message msg) {
6366             switch (msg.what) {
6367                 case MESSAGE_RECONSIDER_RANKING:
6368                     handleRankingReconsideration(msg);
6369                     break;
6370                 case MESSAGE_RANKING_SORT:
6371                     handleRankingSort();
6372                     break;
6373             }
6374         }
6375 
6376         public void requestSort() {
6377             removeMessages(MESSAGE_RANKING_SORT);
6378             Message msg = Message.obtain();
6379             msg.what = MESSAGE_RANKING_SORT;
6380             sendMessage(msg);
6381         }
6382 
6383         public void requestReconsideration(RankingReconsideration recon) {
6384             Message m = Message.obtain(this,
6385                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
6386             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
6387             sendMessageDelayed(m, delay);
6388         }
6389     }
6390 
6391     // Notifications
6392     // ============================================================================
6393     static int clamp(int x, int low, int high) {
6394         return (x < low) ? low : ((x > high) ? high : x);
6395     }
6396 
6397     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
6398         if (!mAccessibilityManager.isEnabled()) {
6399             return;
6400         }
6401 
6402         AccessibilityEvent event =
6403             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
6404         event.setPackageName(packageName);
6405         event.setClassName(Notification.class.getName());
6406         event.setParcelableData(notification);
6407         CharSequence tickerText = notification.tickerText;
6408         if (!TextUtils.isEmpty(tickerText)) {
6409             event.getText().add(tickerText);
6410         }
6411 
6412         mAccessibilityManager.sendAccessibilityEvent(event);
6413     }
6414 
6415     /**
6416      * Removes all NotificationsRecords with the same key as the given notification record
6417      * from both lists. Do not call this method while iterating over either list.
6418      */
6419     @GuardedBy("mNotificationLock")
6420     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
6421         // Remove from both lists, either list could have a separate Record for what is
6422         // effectively the same notification.
6423         boolean wasPosted = false;
6424         NotificationRecord recordInList = null;
6425         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
6426                 != null) {
6427             mNotificationList.remove(recordInList);
6428             mNotificationsByKey.remove(recordInList.sbn.getKey());
6429             wasPosted = true;
6430         }
6431         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
6432                 != null) {
6433             mEnqueuedNotifications.remove(recordInList);
6434         }
6435         return wasPosted;
6436     }
6437 
6438     @GuardedBy("mNotificationLock")
6439     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
6440             boolean wasPosted, String listenerName) {
6441         cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
6442     }
6443 
6444     @GuardedBy("mNotificationLock")
6445     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
6446             int rank, int count, boolean wasPosted, String listenerName) {
6447         final String canceledKey = r.getKey();
6448 
6449         // Record caller.
6450         recordCallerLocked(r);
6451 
6452         if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
6453             r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
6454         }
6455 
6456         // tell the app
6457         if (sendDelete) {
6458             final PendingIntent deleteIntent = r.getNotification().deleteIntent;
6459             if (deleteIntent != null) {
6460                 try {
6461                     // make sure deleteIntent cannot be used to start activities from background
6462                     LocalServices.getService(ActivityManagerInternal.class)
6463                             .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(),
6464                             WHITELIST_TOKEN);
6465                     deleteIntent.send();
6466                 } catch (PendingIntent.CanceledException ex) {
6467                     // do nothing - there's no relevant way to recover, and
6468                     //     no reason to let this propagate
6469                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
6470                 }
6471             }
6472         }
6473 
6474         // Only cancel these if this notification actually got to be posted.
6475         if (wasPosted) {
6476             // status bar
6477             if (r.getNotification().getSmallIcon() != null) {
6478                 if (reason != REASON_SNOOZED) {
6479                     r.isCanceled = true;
6480                 }
6481                 mListeners.notifyRemovedLocked(r, reason, r.getStats());
6482                 mHandler.post(new Runnable() {
6483                     @Override
6484                     public void run() {
6485                         mGroupHelper.onNotificationRemoved(r.sbn);
6486                     }
6487                 });
6488             }
6489 
6490             // sound
6491             if (canceledKey.equals(mSoundNotificationKey)) {
6492                 mSoundNotificationKey = null;
6493                 final long identity = Binder.clearCallingIdentity();
6494                 try {
6495                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
6496                     if (player != null) {
6497                         player.stopAsync();
6498                     }
6499                 } catch (RemoteException e) {
6500                 } finally {
6501                     Binder.restoreCallingIdentity(identity);
6502                 }
6503             }
6504 
6505             // vibrate
6506             if (canceledKey.equals(mVibrateNotificationKey)) {
6507                 mVibrateNotificationKey = null;
6508                 long identity = Binder.clearCallingIdentity();
6509                 try {
6510                     mVibrator.cancel();
6511                 }
6512                 finally {
6513                     Binder.restoreCallingIdentity(identity);
6514                 }
6515             }
6516 
6517             // light
6518             mLights.remove(canceledKey);
6519         }
6520 
6521         // Record usage stats
6522         // TODO: add unbundling stats?
6523         switch (reason) {
6524             case REASON_CANCEL:
6525             case REASON_CANCEL_ALL:
6526             case REASON_LISTENER_CANCEL:
6527             case REASON_LISTENER_CANCEL_ALL:
6528                 mUsageStats.registerDismissedByUser(r);
6529                 break;
6530             case REASON_APP_CANCEL:
6531             case REASON_APP_CANCEL_ALL:
6532                 mUsageStats.registerRemovedByApp(r);
6533                 break;
6534         }
6535 
6536         String groupKey = r.getGroupKey();
6537         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
6538         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
6539             mSummaryByGroupKey.remove(groupKey);
6540         }
6541         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
6542         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
6543             summaries.remove(r.sbn.getPackageName());
6544         }
6545 
6546         // Save it for users of getHistoricalNotifications()
6547         mArchive.record(r.sbn);
6548 
6549         final long now = System.currentTimeMillis();
6550         final LogMaker logMaker = r.getItemLogMaker()
6551                 .setType(MetricsEvent.TYPE_DISMISS)
6552                 .setSubtype(reason);
6553         if (rank != -1 && count != -1) {
6554             logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
6555                     .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
6556         }
6557         MetricsLogger.action(logMaker);
6558         EventLogTags.writeNotificationCanceled(canceledKey, reason,
6559                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
6560                 rank, count, listenerName);
6561     }
6562 
6563     @VisibleForTesting
6564     void updateUriPermissions(@Nullable NotificationRecord newRecord,
6565             @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
6566         final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
6567         if (DBG) Slog.d(TAG, key + ": updating permissions");
6568 
6569         final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
6570         final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
6571 
6572         // Shortcut when no Uris involved
6573         if (newUris == null && oldUris == null) {
6574             return;
6575         }
6576 
6577         // Inherit any existing owner
6578         IBinder permissionOwner = null;
6579         if (newRecord != null && permissionOwner == null) {
6580             permissionOwner = newRecord.permissionOwner;
6581         }
6582         if (oldRecord != null && permissionOwner == null) {
6583             permissionOwner = oldRecord.permissionOwner;
6584         }
6585 
6586         // If we have Uris to grant, but no owner yet, go create one
6587         if (newUris != null && permissionOwner == null) {
6588             if (DBG) Slog.d(TAG, key + ": creating owner");
6589             permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
6590         }
6591 
6592         // If we have no Uris to grant, but an existing owner, go destroy it
6593         if (newUris == null && permissionOwner != null) {
6594             final long ident = Binder.clearCallingIdentity();
6595             try {
6596                 if (DBG) Slog.d(TAG, key + ": destroying owner");
6597                 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
6598                         UserHandle.getUserId(oldRecord.getUid()));
6599                 permissionOwner = null;
6600             } finally {
6601                 Binder.restoreCallingIdentity(ident);
6602             }
6603         }
6604 
6605         // Grant access to new Uris
6606         if (newUris != null && permissionOwner != null) {
6607             for (int i = 0; i < newUris.size(); i++) {
6608                 final Uri uri = newUris.valueAt(i);
6609                 if (oldUris == null || !oldUris.contains(uri)) {
6610                     if (DBG) Slog.d(TAG, key + ": granting " + uri);
6611                     grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
6612                             targetUserId);
6613                 }
6614             }
6615         }
6616 
6617         // Revoke access to old Uris
6618         if (oldUris != null && permissionOwner != null) {
6619             for (int i = 0; i < oldUris.size(); i++) {
6620                 final Uri uri = oldUris.valueAt(i);
6621                 if (newUris == null || !newUris.contains(uri)) {
6622                     if (DBG) Slog.d(TAG, key + ": revoking " + uri);
6623                     revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
6624                 }
6625             }
6626         }
6627 
6628         if (newRecord != null) {
6629             newRecord.permissionOwner = permissionOwner;
6630         }
6631     }
6632 
6633     private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
6634             int targetUserId) {
6635         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6636 
6637         final long ident = Binder.clearCallingIdentity();
6638         try {
6639             mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
6640                     ContentProvider.getUriWithoutUserId(uri),
6641                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
6642                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
6643                     targetUserId);
6644         } catch (RemoteException ignored) {
6645             // Ignored because we're in same process
6646         } finally {
6647             Binder.restoreCallingIdentity(ident);
6648         }
6649     }
6650 
6651     private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
6652         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6653 
6654         final long ident = Binder.clearCallingIdentity();
6655         try {
6656             mUgmInternal.revokeUriPermissionFromOwner(
6657                     owner,
6658                     ContentProvider.getUriWithoutUserId(uri),
6659                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
6660                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
6661         } finally {
6662             Binder.restoreCallingIdentity(ident);
6663         }
6664     }
6665 
6666     /**
6667      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
6668      * and none of the {@code mustNotHaveFlags}.
6669      */
6670     void cancelNotification(final int callingUid, final int callingPid,
6671             final String pkg, final String tag, final int id,
6672             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
6673             final int userId, final int reason, final ManagedServiceInfo listener) {
6674         cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
6675                 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
6676     }
6677 
6678     /**
6679      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
6680      * and none of the {@code mustNotHaveFlags}.
6681      */
6682     void cancelNotification(final int callingUid, final int callingPid,
6683             final String pkg, final String tag, final int id,
6684             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
6685             final int userId, final int reason, int rank, int count,
6686             final ManagedServiceInfo listener) {
6687         // In enqueueNotificationInternal notifications are added by scheduling the
6688         // work on the worker handler. Hence, we also schedule the cancel on this
6689         // handler to avoid a scenario where an add notification call followed by a
6690         // remove notification call ends up in not removing the notification.
6691         mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
6692                 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
6693                 count, listener));
6694     }
6695 
6696     /**
6697      * Determine whether the userId applies to the notification in question, either because
6698      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
6699      */
6700     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
6701         return
6702                 // looking for USER_ALL notifications? match everything
6703                    userId == UserHandle.USER_ALL
6704                 // a notification sent to USER_ALL matches any query
6705                 || r.getUserId() == UserHandle.USER_ALL
6706                 // an exact user match
6707                 || r.getUserId() == userId;
6708     }
6709 
6710     /**
6711      * Determine whether the userId applies to the notification in question, either because
6712      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
6713      * because it matches one of the users profiles.
6714      */
6715     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
6716         return notificationMatchesUserId(r, userId)
6717                 || mUserProfiles.isCurrentProfile(r.getUserId());
6718     }
6719 
6720     /**
6721      * Cancels all notifications from a given package that have all of the
6722      * {@code mustHaveFlags}.
6723      */
6724     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
6725             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
6726             ManagedServiceInfo listener) {
6727         mHandler.post(new Runnable() {
6728             @Override
6729             public void run() {
6730                 String listenerName = listener == null ? null : listener.component.toShortString();
6731                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6732                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
6733                         listenerName);
6734 
6735                 // Why does this parameter exist? Do we actually want to execute the above if doit
6736                 // is false?
6737                 if (!doit) {
6738                     return;
6739                 }
6740 
6741                 synchronized (mNotificationLock) {
6742                     FlagChecker flagChecker = (int flags) -> {
6743                         if ((flags & mustHaveFlags) != mustHaveFlags) {
6744                             return false;
6745                         }
6746                         if ((flags & mustNotHaveFlags) != 0) {
6747                             return false;
6748                         }
6749                         return true;
6750                     };
6751                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6752                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
6753                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
6754                             listenerName, true /* wasPosted */);
6755                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6756                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
6757                             flagChecker, false /*includeCurrentProfiles*/, userId,
6758                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
6759                     mSnoozeHelper.cancel(userId, pkg);
6760                 }
6761             }
6762         });
6763     }
6764 
6765     private interface FlagChecker {
6766         // Returns false if these flags do not pass the defined flag test.
6767         public boolean apply(int flags);
6768     }
6769 
6770     @GuardedBy("mNotificationLock")
6771     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
6772             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
6773             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
6774             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
6775         ArrayList<NotificationRecord> canceledNotifications = null;
6776         for (int i = notificationList.size() - 1; i >= 0; --i) {
6777             NotificationRecord r = notificationList.get(i);
6778             if (includeCurrentProfiles) {
6779                 if (!notificationMatchesCurrentProfiles(r, userId)) {
6780                     continue;
6781                 }
6782             } else if (!notificationMatchesUserId(r, userId)) {
6783                 continue;
6784             }
6785             // Don't remove notifications to all, if there's no package name specified
6786             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
6787                 continue;
6788             }
6789             if (!flagChecker.apply(r.getFlags())) {
6790                 continue;
6791             }
6792             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
6793                 continue;
6794             }
6795             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
6796                 continue;
6797             }
6798             if (canceledNotifications == null) {
6799                 canceledNotifications = new ArrayList<>();
6800             }
6801             notificationList.remove(i);
6802             mNotificationsByKey.remove(r.getKey());
6803             r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
6804             canceledNotifications.add(r);
6805             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
6806         }
6807         if (canceledNotifications != null) {
6808             final int M = canceledNotifications.size();
6809             for (int i = 0; i < M; i++) {
6810                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
6811                         listenerName, false /* sendDelete */, flagChecker);
6812             }
6813             updateLightsLocked();
6814         }
6815     }
6816 
6817     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
6818             ManagedServiceInfo listener) {
6819         String listenerName = listener == null ? null : listener.component.toShortString();
6820         if (duration <= 0 && snoozeCriterionId == null || key == null) {
6821             return;
6822         }
6823 
6824         if (DBG) {
6825             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
6826                     snoozeCriterionId, listenerName));
6827         }
6828         // Needs to post so that it can cancel notifications not yet enqueued.
6829         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
6830     }
6831 
6832     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
6833         String listenerName = listener == null ? null : listener.component.toShortString();
6834         if (DBG) {
6835             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
6836         }
6837         mSnoozeHelper.repost(key);
6838         handleSavePolicyFile();
6839     }
6840 
6841     @GuardedBy("mNotificationLock")
6842     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
6843             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
6844         mHandler.post(new Runnable() {
6845             @Override
6846             public void run() {
6847                 synchronized (mNotificationLock) {
6848                     String listenerName =
6849                             listener == null ? null : listener.component.toShortString();
6850                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6851                             null, userId, 0, 0, reason, listenerName);
6852 
6853                     FlagChecker flagChecker = (int flags) -> {
6854                         int flagsToCheck = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
6855                         if (REASON_LISTENER_CANCEL_ALL == reason) {
6856                             flagsToCheck |= FLAG_BUBBLE;
6857                         }
6858                         if ((flags & flagsToCheck) != 0) {
6859                             return false;
6860                         }
6861                         return true;
6862                     };
6863 
6864                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6865                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
6866                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
6867                             listenerName, true);
6868                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6869                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
6870                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
6871                             reason, listenerName, false);
6872                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
6873                 }
6874             }
6875         });
6876     }
6877 
6878     // Warning: The caller is responsible for invoking updateLightsLocked().
6879     @GuardedBy("mNotificationLock")
6880     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
6881             String listenerName, boolean sendDelete, FlagChecker flagChecker) {
6882         Notification n = r.getNotification();
6883         if (!n.isGroupSummary()) {
6884             return;
6885         }
6886 
6887         String pkg = r.sbn.getPackageName();
6888 
6889         if (pkg == null) {
6890             if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey());
6891             return;
6892         }
6893 
6894         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
6895                 sendDelete, true, flagChecker);
6896         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
6897                 listenerName, sendDelete, false, flagChecker);
6898     }
6899 
6900     @GuardedBy("mNotificationLock")
6901     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
6902             NotificationRecord parentNotification, int callingUid, int callingPid,
6903             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
6904         final String pkg = parentNotification.sbn.getPackageName();
6905         final int userId = parentNotification.getUserId();
6906         final int reason = REASON_GROUP_SUMMARY_CANCELED;
6907         for (int i = notificationList.size() - 1; i >= 0; i--) {
6908             final NotificationRecord childR = notificationList.get(i);
6909             final StatusBarNotification childSbn = childR.sbn;
6910             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
6911                     childR.getGroupKey().equals(parentNotification.getGroupKey())
6912                     && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
6913                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
6914                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6915                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
6916                 notificationList.remove(i);
6917                 mNotificationsByKey.remove(childR.getKey());
6918                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
6919             }
6920         }
6921     }
6922 
6923     @GuardedBy("mNotificationLock")
6924     void updateLightsLocked()
6925     {
6926         // handle notification lights
6927         NotificationRecord ledNotification = null;
6928         while (ledNotification == null && !mLights.isEmpty()) {
6929             final String owner = mLights.get(mLights.size() - 1);
6930             ledNotification = mNotificationsByKey.get(owner);
6931             if (ledNotification == null) {
6932                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6933                 mLights.remove(owner);
6934             }
6935         }
6936 
6937         // Don't flash while we are in a call or screen is on
6938         if (ledNotification == null || mInCall || mScreenOn) {
6939             mNotificationLight.turnOff();
6940         } else {
6941             NotificationRecord.Light light = ledNotification.getLight();
6942             if (light != null && mNotificationPulseEnabled) {
6943                 // pulse repeatedly
6944                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6945                         light.onMs, light.offMs);
6946             }
6947         }
6948     }
6949 
6950     @GuardedBy("mNotificationLock")
6951     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6952             String groupKey, int userId) {
6953         List<NotificationRecord> records = new ArrayList<>();
6954         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6955         records.addAll(
6956                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6957         return records;
6958     }
6959 
6960 
6961     @GuardedBy("mNotificationLock")
6962     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6963             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6964         List<NotificationRecord> records = new ArrayList<>();
6965         final int len = list.size();
6966         for (int i = 0; i < len; i++) {
6967             NotificationRecord r = list.get(i);
6968             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6969                     && r.sbn.getPackageName().equals(pkg)) {
6970                 records.add(r);
6971             }
6972         }
6973         return records;
6974     }
6975 
6976     // Searches both enqueued and posted notifications by key.
6977     // TODO: need to combine a bunch of these getters with slightly different behavior.
6978     // TODO: Should enqueuing just add to mNotificationsByKey instead?
6979     @GuardedBy("mNotificationLock")
6980     private NotificationRecord findNotificationByKeyLocked(String key) {
6981         NotificationRecord r;
6982         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6983             return r;
6984         }
6985         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6986             return r;
6987         }
6988         return null;
6989     }
6990 
6991     @GuardedBy("mNotificationLock")
6992     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
6993         NotificationRecord r;
6994         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6995             return r;
6996         }
6997         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6998                 != null) {
6999             return r;
7000         }
7001         return null;
7002     }
7003 
7004     @GuardedBy("mNotificationLock")
7005     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
7006             String pkg, String tag, int id, int userId) {
7007         final int len = list.size();
7008         for (int i = 0; i < len; i++) {
7009             NotificationRecord r = list.get(i);
7010             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
7011                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
7012                 return r;
7013             }
7014         }
7015         return null;
7016     }
7017 
7018     @GuardedBy("mNotificationLock")
7019     private List<NotificationRecord> findNotificationsByListLocked(
7020             ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
7021         List<NotificationRecord> matching = new ArrayList<>();
7022         final int len = list.size();
7023         for (int i = 0; i < len; i++) {
7024             NotificationRecord r = list.get(i);
7025             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
7026                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
7027                 matching.add(r);
7028             }
7029         }
7030         return matching;
7031     }
7032 
7033     @GuardedBy("mNotificationLock")
7034     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
7035             String key) {
7036         final int N = list.size();
7037         for (int i = 0; i < N; i++) {
7038             if (key.equals(list.get(i).getKey())) {
7039                 return list.get(i);
7040             }
7041         }
7042         return null;
7043     }
7044 
7045     @GuardedBy("mNotificationLock")
7046     int indexOfNotificationLocked(String key) {
7047         final int N = mNotificationList.size();
7048         for (int i = 0; i < N; i++) {
7049             if (key.equals(mNotificationList.get(i).getKey())) {
7050                 return i;
7051             }
7052         }
7053         return -1;
7054     }
7055 
7056     @VisibleForTesting
7057     protected void hideNotificationsForPackages(String[] pkgs) {
7058         synchronized (mNotificationLock) {
7059             List<String> pkgList = Arrays.asList(pkgs);
7060             List<NotificationRecord> changedNotifications = new ArrayList<>();
7061             int numNotifications = mNotificationList.size();
7062             for (int i = 0; i < numNotifications; i++) {
7063                 NotificationRecord rec = mNotificationList.get(i);
7064                 if (pkgList.contains(rec.sbn.getPackageName())) {
7065                     rec.setHidden(true);
7066                     changedNotifications.add(rec);
7067                 }
7068             }
7069 
7070             mListeners.notifyHiddenLocked(changedNotifications);
7071         }
7072     }
7073 
7074     @VisibleForTesting
7075     protected void unhideNotificationsForPackages(String[] pkgs) {
7076         synchronized (mNotificationLock) {
7077             List<String> pkgList = Arrays.asList(pkgs);
7078             List<NotificationRecord> changedNotifications = new ArrayList<>();
7079             int numNotifications = mNotificationList.size();
7080             for (int i = 0; i < numNotifications; i++) {
7081                 NotificationRecord rec = mNotificationList.get(i);
7082                 if (pkgList.contains(rec.sbn.getPackageName())) {
7083                     rec.setHidden(false);
7084                     changedNotifications.add(rec);
7085                 }
7086             }
7087 
7088             mListeners.notifyUnhiddenLocked(changedNotifications);
7089         }
7090     }
7091 
7092     private void updateNotificationPulse() {
7093         synchronized (mNotificationLock) {
7094             updateLightsLocked();
7095         }
7096     }
7097 
7098     protected boolean isCallingUidSystem() {
7099         final int uid = Binder.getCallingUid();
7100         return uid == Process.SYSTEM_UID;
7101     }
7102 
7103     protected boolean isUidSystemOrPhone(int uid) {
7104         final int appid = UserHandle.getAppId(uid);
7105         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
7106     }
7107 
7108     // TODO: Most calls should probably move to isCallerSystem.
7109     protected boolean isCallerSystemOrPhone() {
7110         return isUidSystemOrPhone(Binder.getCallingUid());
7111     }
7112 
7113     private void checkCallerIsSystemOrShell() {
7114         if (Binder.getCallingUid() == Process.SHELL_UID) {
7115             return;
7116         }
7117         checkCallerIsSystem();
7118     }
7119 
7120     private void checkCallerIsSystem() {
7121         if (isCallerSystemOrPhone()) {
7122             return;
7123         }
7124         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
7125     }
7126 
7127     private void checkCallerIsSystemOrSystemUiOrShell() {
7128         if (Binder.getCallingUid() == Process.SHELL_UID) {
7129             return;
7130         }
7131         if (isCallerSystemOrPhone()) {
7132             return;
7133         }
7134         getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null);
7135     }
7136 
7137     private void checkCallerIsSystemOrSameApp(String pkg) {
7138         if (isCallerSystemOrPhone()) {
7139             return;
7140         }
7141         checkCallerIsSameApp(pkg);
7142     }
7143 
7144     private boolean isCallerAndroid(String callingPkg, int uid) {
7145         return isUidSystemOrPhone(uid) && callingPkg != null
7146                 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
7147     }
7148 
7149     /**
7150      * Check if the notification is of a category type that is restricted to system use only,
7151      * if so throw SecurityException
7152      */
7153     private void checkRestrictedCategories(final Notification notification) {
7154         try {
7155             if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
7156                 return;
7157             }
7158         } catch (RemoteException re) {
7159             if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
7160                     + "restrictions check thus the check will be done anyway");
7161         }
7162         if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
7163                 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
7164                 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
7165                     checkCallerIsSystem();
7166         }
7167     }
7168 
7169     @VisibleForTesting
7170     boolean isCallerInstantApp(int callingUid, int userId) {
7171         // System is always allowed to act for ephemeral apps.
7172         if (isUidSystemOrPhone(callingUid)) {
7173             return false;
7174         }
7175 
7176         if (userId == UserHandle.USER_ALL) {
7177             userId = USER_SYSTEM;
7178         }
7179 
7180         try {
7181             final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
7182             if (pkgs == null) {
7183                 throw new SecurityException("Unknown uid " + callingUid);
7184             }
7185             final String pkg = pkgs[0];
7186             mAppOps.checkPackage(callingUid, pkg);
7187 
7188             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
7189             if (ai == null) {
7190                 throw new SecurityException("Unknown package " + pkg);
7191             }
7192             return ai.isInstantApp();
7193         } catch (RemoteException re) {
7194             throw new SecurityException("Unknown uid " + callingUid, re);
7195         }
7196     }
7197 
7198     private void checkCallerIsSameApp(String pkg) {
7199         checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
7200     }
7201 
7202     private void checkCallerIsSameApp(String pkg, int uid, int userId) {
7203         try {
7204             ApplicationInfo ai = mPackageManager.getApplicationInfo(
7205                     pkg, 0, userId);
7206             if (ai == null) {
7207                 throw new SecurityException("Unknown package " + pkg);
7208             }
7209             if (!UserHandle.isSameApp(ai.uid, uid)) {
7210                 throw new SecurityException("Calling uid " + uid + " gave package "
7211                         + pkg + " which is owned by uid " + ai.uid);
7212             }
7213         } catch (RemoteException re) {
7214             throw new SecurityException("Unknown package " + pkg + "\n" + re);
7215         }
7216     }
7217 
7218     private boolean isCallerSameApp(String pkg) {
7219         try {
7220             checkCallerIsSameApp(pkg);
7221             return true;
7222         } catch (SecurityException e) {
7223             return false;
7224         }
7225     }
7226 
7227     private boolean isCallerSameApp(String pkg, int uid, int userId) {
7228         try {
7229             checkCallerIsSameApp(pkg, uid, userId);
7230             return true;
7231         } catch (SecurityException e) {
7232             return false;
7233         }
7234     }
7235 
7236     private static String callStateToString(int state) {
7237         switch (state) {
7238             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
7239             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
7240             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
7241             default: return "CALL_STATE_UNKNOWN_" + state;
7242         }
7243     }
7244 
7245     private void listenForCallState() {
7246         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
7247             @Override
7248             public void onCallStateChanged(int state, String incomingNumber) {
7249                 if (mCallState == state) return;
7250                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
7251                 mCallState = state;
7252             }
7253         }, PhoneStateListener.LISTEN_CALL_STATE);
7254     }
7255 
7256     /**
7257      * Generates a NotificationRankingUpdate from 'sbns', considering only
7258      * notifications visible to the given listener.
7259      */
7260     @GuardedBy("mNotificationLock")
7261     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
7262         final int N = mNotificationList.size();
7263         final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>();
7264 
7265         for (int i = 0; i < N; i++) {
7266             NotificationRecord record = mNotificationList.get(i);
7267             if (!isVisibleToListener(record.sbn, info)) {
7268                 continue;
7269             }
7270             final String key = record.sbn.getKey();
7271             final NotificationListenerService.Ranking ranking =
7272                     new NotificationListenerService.Ranking();
7273             ranking.populate(
7274                     key,
7275                     rankings.size(),
7276                     !record.isIntercepted(),
7277                     record.getPackageVisibilityOverride(),
7278                     record.getSuppressedVisualEffects(),
7279                     record.getImportance(),
7280                     record.getImportanceExplanation(),
7281                     record.sbn.getOverrideGroupKey(),
7282                     record.getChannel(),
7283                     record.getPeopleOverride(),
7284                     record.getSnoozeCriteria(),
7285                     record.canShowBadge(),
7286                     record.getUserSentiment(),
7287                     record.isHidden(),
7288                     record.getLastAudiblyAlertedMs(),
7289                     record.getSound() != null || record.getVibration() != null,
7290                     record.getSystemGeneratedSmartActions(),
7291                     record.getSmartReplies(),
7292                     record.canBubble()
7293             );
7294             rankings.add(ranking);
7295         }
7296 
7297         return new NotificationRankingUpdate(
7298                 rankings.toArray(new NotificationListenerService.Ranking[0]));
7299     }
7300 
7301     boolean hasCompanionDevice(ManagedServiceInfo info) {
7302         if (mCompanionManager == null) {
7303             mCompanionManager = getCompanionManager();
7304         }
7305         // Companion mgr doesn't exist on all device types
7306         if (mCompanionManager == null) {
7307             return false;
7308         }
7309         long identity = Binder.clearCallingIdentity();
7310         try {
7311             List<String> associations = mCompanionManager.getAssociations(
7312                     info.component.getPackageName(), info.userid);
7313             if (!ArrayUtils.isEmpty(associations)) {
7314                 return true;
7315             }
7316         } catch (SecurityException se) {
7317             // Not a privileged listener
7318         } catch (RemoteException re) {
7319             Slog.e(TAG, "Cannot reach companion device service", re);
7320         } catch (Exception e) {
7321             Slog.e(TAG, "Cannot verify listener " + info, e);
7322         } finally {
7323             Binder.restoreCallingIdentity(identity);
7324         }
7325         return false;
7326     }
7327 
7328     protected ICompanionDeviceManager getCompanionManager() {
7329         return ICompanionDeviceManager.Stub.asInterface(
7330                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
7331     }
7332 
7333     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
7334         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
7335             return false;
7336         }
7337         // TODO: remove this for older listeners.
7338         return true;
7339     }
7340 
7341     private boolean isPackageSuspendedForUser(String pkg, int uid) {
7342         final long identity = Binder.clearCallingIdentity();
7343         int userId = UserHandle.getUserId(uid);
7344         try {
7345             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
7346         } catch (RemoteException re) {
7347             throw new SecurityException("Could not talk to package manager service");
7348         } catch (IllegalArgumentException ex) {
7349             // Package not found.
7350             return false;
7351         } finally {
7352             Binder.restoreCallingIdentity(identity);
7353         }
7354     }
7355 
7356     @VisibleForTesting
7357     boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
7358         boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
7359                 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
7360 
7361         for (String whitelisted : getContext().getResources().getStringArray(
7362                 R.array.config_allowedManagedServicesOnLowRamDevices)) {
7363             if (whitelisted.equals(pkg)) {
7364                 canUseManagedServices = true;
7365             }
7366         }
7367 
7368         if (requiredPermission != null) {
7369             try {
7370                 if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
7371                     != PackageManager.PERMISSION_GRANTED) {
7372                     canUseManagedServices = false;
7373                 }
7374             } catch (RemoteException e) {
7375                 Slog.e(TAG, "can't talk to pm", e);
7376             }
7377         }
7378 
7379         return canUseManagedServices;
7380     }
7381 
7382     private class TrimCache {
7383         StatusBarNotification heavy;
7384         StatusBarNotification sbnClone;
7385         StatusBarNotification sbnCloneLight;
7386 
7387         TrimCache(StatusBarNotification sbn) {
7388             heavy = sbn;
7389         }
7390 
7391         StatusBarNotification ForListener(ManagedServiceInfo info) {
7392             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
7393                 if (sbnCloneLight == null) {
7394                     sbnCloneLight = heavy.cloneLight();
7395                 }
7396                 return sbnCloneLight;
7397             } else {
7398                 if (sbnClone == null) {
7399                     sbnClone = heavy.clone();
7400                 }
7401                 return sbnClone;
7402             }
7403         }
7404     }
7405 
7406     public class NotificationAssistants extends ManagedServices {
7407         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
7408 
7409         private static final String ATT_USER_SET = "user_set";
7410         private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "q_allowed_adjustments";
7411         private static final String ATT_TYPES = "types";
7412 
7413         private final Object mLock = new Object();
7414 
7415         @GuardedBy("mLock")
7416         private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
7417         private Set<String> mAllowedAdjustments = new ArraySet<>();
7418 
7419         public NotificationAssistants(Context context, Object lock, UserProfiles up,
7420                 IPackageManager pm) {
7421             super(context, lock, up, pm);
7422 
7423             // Add all default allowed adjustment types. Will be overwritten by values in xml,
7424             // if they exist
7425             for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
7426                 mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
7427             }
7428         }
7429 
7430         @Override
7431         protected Config getConfig() {
7432             Config c = new Config();
7433             c.caption = "notification assistant";
7434             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
7435             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
7436             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
7437             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
7438             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
7439             c.clientLabel = R.string.notification_ranker_binding_label;
7440             return c;
7441         }
7442 
7443         @Override
7444         protected IInterface asInterface(IBinder binder) {
7445             return INotificationListener.Stub.asInterface(binder);
7446         }
7447 
7448         @Override
7449         protected boolean checkType(IInterface service) {
7450             return service instanceof INotificationListener;
7451         }
7452 
7453         @Override
7454         protected void onServiceAdded(ManagedServiceInfo info) {
7455             mListeners.registerGuestService(info);
7456         }
7457 
7458         @Override
7459         @GuardedBy("mNotificationLock")
7460         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
7461             mListeners.unregisterService(removed.service, removed.userid);
7462         }
7463 
7464         @Override
7465         public void onUserUnlocked(int user) {
7466             if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
7467             // force rebind the assistant, as it might be keeping its own state in user locked
7468             // storage
7469             rebindServices(true, user);
7470         }
7471 
7472         @Override
7473         protected String getRequiredPermission() {
7474             // only signature/privileged apps can be bound.
7475             return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
7476         }
7477 
7478         @Override
7479         protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
7480             synchronized (mLock) {
7481                 out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
7482                 out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
7483                 out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
7484             }
7485         }
7486 
7487         @Override
7488         protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
7489             if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
7490                 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
7491                 synchronized (mLock) {
7492                     mAllowedAdjustments.clear();
7493                     if (!TextUtils.isEmpty(types)) {
7494                         mAllowedAdjustments.addAll(Arrays.asList(types.split(",")));
7495                     }
7496                 }
7497             }
7498         }
7499 
7500         protected void allowAdjustmentType(String type) {
7501             synchronized (mLock) {
7502                 mAllowedAdjustments.add(type);
7503             }
7504             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7505                 mHandler.post(() -> notifyCapabilitiesChanged(info));
7506             }
7507         }
7508 
7509         protected void disallowAdjustmentType(String type) {
7510             synchronized (mLock) {
7511                 mAllowedAdjustments.remove(type);
7512             }
7513             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7514                     mHandler.post(() -> notifyCapabilitiesChanged(info));
7515             }
7516         }
7517 
7518         protected List<String> getAllowedAssistantAdjustments() {
7519             synchronized (mLock) {
7520                 List<String> types = new ArrayList<>();
7521                 types.addAll(mAllowedAdjustments);
7522                 return types;
7523             }
7524         }
7525 
7526         protected boolean isAdjustmentAllowed(String type) {
7527             synchronized (mLock) {
7528                 return mAllowedAdjustments.contains(type);
7529             }
7530         }
7531 
7532         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
7533             // There should be only one, but it's a list, so while we enforce
7534             // singularity elsewhere, we keep it general here, to avoid surprises.
7535             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7536                 ArrayList<String> keys = new ArrayList<>(records.size());
7537                 for (NotificationRecord r : records) {
7538                     boolean sbnVisible = isVisibleToListener(r.sbn, info)
7539                             && info.isSameUser(r.getUserId());
7540                     if (sbnVisible) {
7541                         keys.add(r.getKey());
7542                     }
7543                 }
7544 
7545                 if (!keys.isEmpty()) {
7546                     mHandler.post(() -> notifySeen(info, keys));
7547                 }
7548             }
7549         }
7550 
7551         boolean hasUserSet(int userId) {
7552             synchronized (mLock) {
7553                 return mUserSetMap.getOrDefault(userId, false);
7554             }
7555         }
7556 
7557         void setUserSet(int userId, boolean set) {
7558             synchronized (mLock) {
7559                 mUserSetMap.put(userId, set);
7560             }
7561         }
7562 
7563         @Override
7564         protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {
7565             out.attribute(null, ATT_USER_SET, Boolean.toString(hasUserSet(userId)));
7566         }
7567 
7568         @Override
7569         protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
7570                 throws IOException {
7571             boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false);
7572             setUserSet(userId, userSet);
7573         }
7574 
7575         private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
7576             final INotificationListener assistant = (INotificationListener) info.service;
7577             try {
7578                 assistant.onAllowedAdjustmentsChanged();
7579             } catch (RemoteException ex) {
7580                 Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
7581             }
7582         }
7583 
7584         private void notifySeen(final ManagedServiceInfo info,
7585                 final ArrayList<String> keys) {
7586             final INotificationListener assistant = (INotificationListener) info.service;
7587             try {
7588                 assistant.onNotificationsSeen(keys);
7589             } catch (RemoteException ex) {
7590                 Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
7591             }
7592         }
7593 
7594         @GuardedBy("mNotificationLock")
7595         private void onNotificationEnqueuedLocked(final NotificationRecord r) {
7596             final boolean debug = isVerboseLogEnabled();
7597             if (debug) {
7598                 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
7599             }
7600             final StatusBarNotification sbn = r.sbn;
7601             notifyAssistantLocked(
7602                     sbn,
7603                     true /* sameUserOnly */,
7604                     (assistant, sbnHolder) -> {
7605                         try {
7606                             if (debug) {
7607                                 Slog.v(TAG,
7608                                         "calling onNotificationEnqueuedWithChannel " + sbnHolder);
7609                             }
7610                             assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
7611                         } catch (RemoteException ex) {
7612                             Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
7613                         }
7614                     });
7615         }
7616 
7617         @GuardedBy("mNotificationLock")
7618         void notifyAssistantExpansionChangedLocked(
7619                 final StatusBarNotification sbn,
7620                 final boolean isUserAction,
7621                 final boolean isExpanded) {
7622             final String key = sbn.getKey();
7623             notifyAssistantLocked(
7624                     sbn,
7625                     false /* sameUserOnly */,
7626                     (assistant, sbnHolder) -> {
7627                         try {
7628                             assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
7629                         } catch (RemoteException ex) {
7630                             Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
7631                         }
7632                     });
7633         }
7634 
7635         @GuardedBy("mNotificationLock")
7636         void notifyAssistantNotificationDirectReplyLocked(
7637                 final StatusBarNotification sbn) {
7638             final String key = sbn.getKey();
7639             notifyAssistantLocked(
7640                     sbn,
7641                     false /* sameUserOnly */,
7642                     (assistant, sbnHolder) -> {
7643                         try {
7644                             assistant.onNotificationDirectReply(key);
7645                         } catch (RemoteException ex) {
7646                             Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
7647                         }
7648                     });
7649         }
7650 
7651         @GuardedBy("mNotificationLock")
7652         void notifyAssistantSuggestedReplySent(
7653                 final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) {
7654             final String key = sbn.getKey();
7655             notifyAssistantLocked(
7656                     sbn,
7657                     false /* sameUserOnly */,
7658                     (assistant, sbnHolder) -> {
7659                         try {
7660                             assistant.onSuggestedReplySent(
7661                                     key,
7662                                     reply,
7663                                     generatedByAssistant
7664                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7665                                             : NotificationAssistantService.SOURCE_FROM_APP);
7666                         } catch (RemoteException ex) {
7667                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
7668                         }
7669                     });
7670         }
7671 
7672         @GuardedBy("mNotificationLock")
7673         void notifyAssistantActionClicked(
7674                 final StatusBarNotification sbn, int actionIndex, Notification.Action action,
7675                 boolean generatedByAssistant) {
7676             final String key = sbn.getKey();
7677             notifyAssistantLocked(
7678                     sbn,
7679                     false /* sameUserOnly */,
7680                     (assistant, sbnHolder) -> {
7681                         try {
7682                             assistant.onActionClicked(
7683                                     key,
7684                                     action,
7685                                     generatedByAssistant
7686                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7687                                             : NotificationAssistantService.SOURCE_FROM_APP);
7688                         } catch (RemoteException ex) {
7689                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
7690                         }
7691                     });
7692         }
7693 
7694         /**
7695          * asynchronously notify the assistant that a notification has been snoozed until a
7696          * context
7697          */
7698         @GuardedBy("mNotificationLock")
7699         private void notifyAssistantSnoozedLocked(
7700                 final StatusBarNotification sbn, final String snoozeCriterionId) {
7701             notifyAssistantLocked(
7702                     sbn,
7703                     false /* sameUserOnly */,
7704                     (assistant, sbnHolder) -> {
7705                         try {
7706                             assistant.onNotificationSnoozedUntilContext(
7707                                     sbnHolder, snoozeCriterionId);
7708                         } catch (RemoteException ex) {
7709                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
7710                         }
7711                     });
7712         }
7713 
7714         /**
7715          * Notifies the assistant something about the specified notification, only assistant
7716          * that is visible to the notification will be notified.
7717          *
7718          * @param sbn          the notification object that the update is about.
7719          * @param sameUserOnly should the update  be sent to the assistant in the same user only.
7720          * @param callback     the callback that provides the assistant to be notified, executed
7721          *                     in WorkerHandler.
7722          */
7723         @GuardedBy("mNotificationLock")
7724         private void notifyAssistantLocked(
7725                 final StatusBarNotification sbn,
7726                 boolean sameUserOnly,
7727                 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
7728             TrimCache trimCache = new TrimCache(sbn);
7729             // There should be only one, but it's a list, so while we enforce
7730             // singularity elsewhere, we keep it general here, to avoid surprises.
7731 
7732             final boolean debug = isVerboseLogEnabled();
7733             if (debug) {
7734                 Slog.v(TAG,
7735                         "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
7736                                 + sameUserOnly + "], callback = [" + callback + "]");
7737             }
7738             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7739                 boolean sbnVisible = isVisibleToListener(sbn, info)
7740                         && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
7741                 if (debug) {
7742                     Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
7743                 }
7744                 if (!sbnVisible) {
7745                     continue;
7746                 }
7747                 final INotificationListener assistant = (INotificationListener) info.service;
7748                 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7749                 final StatusBarNotificationHolder sbnHolder =
7750                         new StatusBarNotificationHolder(sbnToPost);
7751                 mHandler.post(() -> callback.accept(assistant, sbnHolder));
7752             }
7753         }
7754 
7755         public boolean isEnabled() {
7756             return !getServices().isEmpty();
7757         }
7758 
7759         protected void resetDefaultAssistantsIfNecessary() {
7760             final List<UserInfo> activeUsers = mUm.getUsers(true);
7761             for (UserInfo userInfo : activeUsers) {
7762                 int userId = userInfo.getUserHandle().getIdentifier();
7763                 if (!hasUserSet(userId)) {
7764                     Slog.d(TAG, "Approving default notification assistant for user " + userId);
7765                     setDefaultAssistantForUser(userId);
7766                 }
7767             }
7768         }
7769 
7770         @Override
7771         protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
7772                 boolean isPrimary, boolean enabled) {
7773             // Ensures that only one component is enabled at a time
7774             if (enabled) {
7775                 List<ComponentName> allowedComponents = getAllowedComponents(userId);
7776                 if (!allowedComponents.isEmpty()) {
7777                     ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
7778                     if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
7779                     setNotificationAssistantAccessGrantedForUserInternal(
7780                             currentComponent, userId, false);
7781                 }
7782             }
7783             super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
7784         }
7785 
7786         @Override
7787         public void dump(PrintWriter pw, DumpFilter filter) {
7788             super.dump(pw, filter);
7789             pw.println("    Has user set:");
7790             synchronized (mLock) {
7791                 Set<Integer> userIds = mUserSetMap.keySet();
7792                 for (int userId : userIds) {
7793                     pw.println("      userId=" + userId + " value=" + mUserSetMap.get(userId));
7794                 }
7795             }
7796         }
7797 
7798         private boolean isVerboseLogEnabled() {
7799             return Log.isLoggable("notification_assistant", Log.VERBOSE);
7800         }
7801     }
7802 
7803     public class NotificationListeners extends ManagedServices {
7804         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
7805 
7806         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
7807 
7808         public NotificationListeners(IPackageManager pm) {
7809             super(getContext(), mNotificationLock, mUserProfiles, pm);
7810 
7811         }
7812 
7813         @Override
7814         protected int getBindFlags() {
7815             // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE
7816             // because too many 3P apps could be kept in memory as notification listeners and
7817             // cause extreme memory pressure.
7818             // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
7819             return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
7820                     | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
7821         }
7822 
7823         @Override
7824         protected Config getConfig() {
7825             Config c = new Config();
7826             c.caption = "notification listener";
7827             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
7828             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
7829             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
7830             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
7831             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
7832             c.clientLabel = R.string.notification_listener_binding_label;
7833             return c;
7834         }
7835 
7836         @Override
7837         protected IInterface asInterface(IBinder binder) {
7838             return INotificationListener.Stub.asInterface(binder);
7839         }
7840 
7841         @Override
7842         protected boolean checkType(IInterface service) {
7843             return service instanceof INotificationListener;
7844         }
7845 
7846         @Override
7847         public void onServiceAdded(ManagedServiceInfo info) {
7848             final INotificationListener listener = (INotificationListener) info.service;
7849             final NotificationRankingUpdate update;
7850             synchronized (mNotificationLock) {
7851                 update = makeRankingUpdateLocked(info);
7852             }
7853             try {
7854                 listener.onListenerConnected(update);
7855             } catch (RemoteException e) {
7856                 // we tried
7857             }
7858         }
7859 
7860         @Override
7861         @GuardedBy("mNotificationLock")
7862         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
7863             if (removeDisabledHints(removed)) {
7864                 updateListenerHintsLocked();
7865                 updateEffectsSuppressorLocked();
7866             }
7867             mLightTrimListeners.remove(removed);
7868         }
7869 
7870         @Override
7871         protected String getRequiredPermission() {
7872             return null;
7873         }
7874 
7875         @GuardedBy("mNotificationLock")
7876         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
7877             if (trim == TRIM_LIGHT) {
7878                 mLightTrimListeners.add(info);
7879             } else {
7880                 mLightTrimListeners.remove(info);
7881             }
7882         }
7883 
7884         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
7885             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
7886         }
7887 
7888         public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
7889             for (final ManagedServiceInfo info : getServices()) {
7890                 mHandler.post(() -> {
7891                     final INotificationListener listener = (INotificationListener) info.service;
7892                      try {
7893                         listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
7894                     } catch (RemoteException ex) {
7895                         Slog.e(TAG, "unable to notify listener "
7896                                 + "(hideSilentStatusIcons): " + listener, ex);
7897                     }
7898                 });
7899             }
7900         }
7901 
7902         /**
7903          * asynchronously notify all listeners about a new notification
7904          *
7905          * <p>
7906          * Also takes care of removing a notification that has been visible to a listener before,
7907          * but isn't anymore.
7908          */
7909         @GuardedBy("mNotificationLock")
7910         public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
7911             notifyPostedLocked(r, old, true);
7912         }
7913 
7914         /**
7915          * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
7916          *                           targetting <= O_MR1
7917          */
7918         @GuardedBy("mNotificationLock")
7919         private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
7920                 boolean notifyAllListeners) {
7921             // Lazily initialized snapshots of the notification.
7922             StatusBarNotification sbn = r.sbn;
7923             StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
7924             TrimCache trimCache = new TrimCache(sbn);
7925 
7926             for (final ManagedServiceInfo info : getServices()) {
7927                 boolean sbnVisible = isVisibleToListener(sbn, info);
7928                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
7929                 // This notification hasn't been and still isn't visible -> ignore.
7930                 if (!oldSbnVisible && !sbnVisible) {
7931                     continue;
7932                 }
7933                 // If the notification is hidden, don't notifyPosted listeners targeting < P.
7934                 // Instead, those listeners will receive notifyPosted when the notification is
7935                 // unhidden.
7936                 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
7937                     continue;
7938                 }
7939 
7940                 // If we shouldn't notify all listeners, this means the hidden state of
7941                 // a notification was changed.  Don't notifyPosted listeners targeting >= P.
7942                 // Instead, those listeners will receive notifyRankingUpdate.
7943                 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7944                     continue;
7945                 }
7946 
7947                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
7948 
7949                 // This notification became invisible -> remove the old one.
7950                 if (oldSbnVisible && !sbnVisible) {
7951                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
7952                     mHandler.post(new Runnable() {
7953                         @Override
7954                         public void run() {
7955                             notifyRemoved(
7956                                     info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
7957                         }
7958                     });
7959                     continue;
7960                 }
7961 
7962                 // Grant access before listener is notified
7963                 final int targetUserId = (info.userid == UserHandle.USER_ALL)
7964                         ? UserHandle.USER_SYSTEM : info.userid;
7965                 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
7966 
7967                 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7968                 mHandler.post(new Runnable() {
7969                     @Override
7970                     public void run() {
7971                         notifyPosted(info, sbnToPost, update);
7972                     }
7973                 });
7974             }
7975         }
7976 
7977         /**
7978          * asynchronously notify all listeners about a removed notification
7979          */
7980         @GuardedBy("mNotificationLock")
7981         public void notifyRemovedLocked(NotificationRecord r, int reason,
7982                 NotificationStats notificationStats) {
7983             final StatusBarNotification sbn = r.sbn;
7984 
7985             // make a copy in case changes are made to the underlying Notification object
7986             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
7987             // notification
7988             final StatusBarNotification sbnLight = sbn.cloneLight();
7989             for (final ManagedServiceInfo info : getServices()) {
7990                 if (!isVisibleToListener(sbn, info)) {
7991                     continue;
7992                 }
7993 
7994                 // don't notifyRemoved for listeners targeting < P
7995                 // if not for reason package suspended
7996                 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
7997                         && info.targetSdkVersion < Build.VERSION_CODES.P) {
7998                     continue;
7999                 }
8000 
8001                 // don't notifyRemoved for listeners targeting >= P
8002                 // if the reason is package suspended
8003                 if (reason == REASON_PACKAGE_SUSPENDED
8004                         && info.targetSdkVersion >= Build.VERSION_CODES.P) {
8005                     continue;
8006                 }
8007 
8008                 // Only assistants can get stats
8009                 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
8010                         ? notificationStats : null;
8011                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
8012                 mHandler.post(new Runnable() {
8013                     @Override
8014                     public void run() {
8015                         notifyRemoved(info, sbnLight, update, stats, reason);
8016                     }
8017                 });
8018             }
8019 
8020             // Revoke access after all listeners have been updated
8021             mHandler.post(() -> {
8022                 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
8023             });
8024         }
8025 
8026         /**
8027          * Asynchronously notify all listeners about a reordering of notifications
8028          * unless changedHiddenNotifications is populated.
8029          * If changedHiddenNotifications is populated, there was a change in the hidden state
8030          * of the notifications.  In this case, we only send updates to listeners that
8031          * target >= P.
8032          */
8033         @GuardedBy("mNotificationLock")
8034         public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
8035             boolean isHiddenRankingUpdate = changedHiddenNotifications != null
8036                     && changedHiddenNotifications.size() > 0;
8037 
8038             for (final ManagedServiceInfo serviceInfo : getServices()) {
8039                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8040                     continue;
8041                 }
8042 
8043                 boolean notifyThisListener = false;
8044                 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
8045                         Build.VERSION_CODES.P) {
8046                     for (NotificationRecord rec : changedHiddenNotifications) {
8047                         if (isVisibleToListener(rec.sbn, serviceInfo)) {
8048                             notifyThisListener = true;
8049                             break;
8050                         }
8051                     }
8052                 }
8053 
8054                 if (notifyThisListener || !isHiddenRankingUpdate) {
8055                     final NotificationRankingUpdate update = makeRankingUpdateLocked(
8056                             serviceInfo);
8057 
8058                     mHandler.post(new Runnable() {
8059                         @Override
8060                         public void run() {
8061                             notifyRankingUpdate(serviceInfo, update);
8062                         }
8063                     });
8064                 }
8065             }
8066         }
8067 
8068         @GuardedBy("mNotificationLock")
8069         public void notifyListenerHintsChangedLocked(final int hints) {
8070             for (final ManagedServiceInfo serviceInfo : getServices()) {
8071                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8072                     continue;
8073                 }
8074                 mHandler.post(new Runnable() {
8075                     @Override
8076                     public void run() {
8077                         notifyListenerHintsChanged(serviceInfo, hints);
8078                     }
8079                 });
8080             }
8081         }
8082 
8083         /**
8084          * asynchronously notify relevant listeners their notification is hidden
8085          * NotificationListenerServices that target P+:
8086          *      NotificationListenerService#notifyRankingUpdateLocked()
8087          * NotificationListenerServices that target <= P:
8088          *      NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
8089          */
8090         @GuardedBy("mNotificationLock")
8091         public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
8092             if (changedNotifications == null || changedNotifications.size() == 0) {
8093                 return;
8094             }
8095 
8096             notifyRankingUpdateLocked(changedNotifications);
8097 
8098             // for listeners that target < P, notifyRemoveLocked
8099             int numChangedNotifications = changedNotifications.size();
8100             for (int i = 0; i < numChangedNotifications; i++) {
8101                 NotificationRecord rec = changedNotifications.get(i);
8102                 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
8103             }
8104         }
8105 
8106         /**
8107          * asynchronously notify relevant listeners their notification is unhidden
8108          * NotificationListenerServices that target P+:
8109          *      NotificationListenerService#notifyRankingUpdateLocked()
8110          * NotificationListenerServices that target <= P:
8111          *      NotificationListeners#notifyPostedLocked()
8112          */
8113         @GuardedBy("mNotificationLock")
8114         public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
8115             if (changedNotifications == null || changedNotifications.size() == 0) {
8116                 return;
8117             }
8118 
8119             notifyRankingUpdateLocked(changedNotifications);
8120 
8121             // for listeners that target < P, notifyPostedLocked
8122             int numChangedNotifications = changedNotifications.size();
8123             for (int i = 0; i < numChangedNotifications; i++) {
8124                 NotificationRecord rec = changedNotifications.get(i);
8125                 mListeners.notifyPostedLocked(rec, rec, false);
8126             }
8127         }
8128 
8129         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
8130             for (final ManagedServiceInfo serviceInfo : getServices()) {
8131                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8132                     continue;
8133                 }
8134                 mHandler.post(new Runnable() {
8135                     @Override
8136                     public void run() {
8137                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
8138                     }
8139                 });
8140             }
8141         }
8142 
8143         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
8144                 final NotificationChannel channel, final int modificationType) {
8145             if (channel == null) {
8146                 return;
8147             }
8148             for (final ManagedServiceInfo serviceInfo : getServices()) {
8149                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
8150                     continue;
8151                 }
8152 
8153                 BackgroundThread.getHandler().post(() -> {
8154                     if (hasCompanionDevice(serviceInfo)) {
8155                         notifyNotificationChannelChanged(
8156                                 serviceInfo, pkg, user, channel, modificationType);
8157                     }
8158                 });
8159             }
8160         }
8161 
8162         protected void notifyNotificationChannelGroupChanged(
8163                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
8164                 final int modificationType) {
8165             if (group == null) {
8166                 return;
8167             }
8168             for (final ManagedServiceInfo serviceInfo : getServices()) {
8169                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
8170                     continue;
8171                 }
8172 
8173                 BackgroundThread.getHandler().post(() -> {
8174                     if (hasCompanionDevice(serviceInfo)) {
8175                         notifyNotificationChannelGroupChanged(
8176                                 serviceInfo, pkg, user, group, modificationType);
8177                     }
8178                 });
8179             }
8180         }
8181 
8182         private void notifyPosted(final ManagedServiceInfo info,
8183                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
8184             final INotificationListener listener = (INotificationListener) info.service;
8185             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
8186             try {
8187                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
8188             } catch (RemoteException ex) {
8189                 Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
8190             }
8191         }
8192 
8193         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
8194                 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
8195             if (!info.enabledAndUserMatches(sbn.getUserId())) {
8196                 return;
8197             }
8198             final INotificationListener listener = (INotificationListener) info.service;
8199             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
8200             try {
8201                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
8202             } catch (RemoteException ex) {
8203                 Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
8204             }
8205         }
8206 
8207         private void notifyRankingUpdate(ManagedServiceInfo info,
8208                                          NotificationRankingUpdate rankingUpdate) {
8209             final INotificationListener listener = (INotificationListener) info.service;
8210             try {
8211                 listener.onNotificationRankingUpdate(rankingUpdate);
8212             } catch (RemoteException ex) {
8213                 Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
8214             }
8215         }
8216 
8217         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
8218             final INotificationListener listener = (INotificationListener) info.service;
8219             try {
8220                 listener.onListenerHintsChanged(hints);
8221             } catch (RemoteException ex) {
8222                 Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
8223             }
8224         }
8225 
8226         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
8227                 int interruptionFilter) {
8228             final INotificationListener listener = (INotificationListener) info.service;
8229             try {
8230                 listener.onInterruptionFilterChanged(interruptionFilter);
8231             } catch (RemoteException ex) {
8232                 Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
8233             }
8234         }
8235 
8236         void notifyNotificationChannelChanged(ManagedServiceInfo info,
8237                 final String pkg, final UserHandle user, final NotificationChannel channel,
8238                 final int modificationType) {
8239             final INotificationListener listener = (INotificationListener) info.service;
8240             try {
8241                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
8242             } catch (RemoteException ex) {
8243                 Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
8244             }
8245         }
8246 
8247         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
8248                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
8249                 final int modificationType) {
8250             final INotificationListener listener = (INotificationListener) info.service;
8251             try {
8252                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
8253             } catch (RemoteException ex) {
8254                 Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
8255             }
8256         }
8257 
8258         public boolean isListenerPackage(String packageName) {
8259             if (packageName == null) {
8260                 return false;
8261             }
8262             // TODO: clean up locking object later
8263             synchronized (mNotificationLock) {
8264                 for (final ManagedServiceInfo serviceInfo : getServices()) {
8265                     if (packageName.equals(serviceInfo.component.getPackageName())) {
8266                         return true;
8267                     }
8268                 }
8269             }
8270             return false;
8271         }
8272     }
8273 
8274     class RoleObserver implements OnRoleHoldersChangedListener {
8275         // Role name : user id : list of approved packages
8276         private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
8277 
8278         private final RoleManager mRm;
8279         private final IPackageManager mPm;
8280         private final Executor mExecutor;
8281 
8282         RoleObserver(@NonNull RoleManager roleManager,
8283                 @NonNull IPackageManager pkgMgr,
8284                 @NonNull @CallbackExecutor Executor executor) {
8285             mRm = roleManager;
8286             mPm = pkgMgr;
8287             mExecutor = executor;
8288         }
8289 
8290         public void init() {
8291             List<UserInfo> users = mUm.getUsers();
8292             mNonBlockableDefaultApps = new ArrayMap<>();
8293             for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
8294                 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
8295                 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
8296                 for (int j = 0; j < users.size(); j++) {
8297                     Integer userId = users.get(j).getUserHandle().getIdentifier();
8298                     ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
8299                             NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
8300                     ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
8301                     for (String pkg : approvedForUserId) {
8302                         approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
8303                     }
8304                     userToApprovedList.put(userId, approvedForUserId);
8305                     mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
8306                 }
8307             }
8308 
8309             mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
8310         }
8311 
8312         @VisibleForTesting
8313         public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
8314             return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
8315         }
8316 
8317         /**
8318          * Convert the assistant-role holder into settings. The rest of the system uses the
8319          * settings.
8320          *
8321          * @param roleName the name of the role whose holders are changed
8322          * @param user the user for this role holder change
8323          */
8324         @Override
8325         public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
8326             // we only care about a couple of the roles they'll tell us about
8327             boolean relevantChange = false;
8328             for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
8329                 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
8330                     relevantChange = true;
8331                     break;
8332                 }
8333             }
8334 
8335             if (!relevantChange) {
8336                 return;
8337             }
8338 
8339             ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
8340 
8341             // find the diff
8342             ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
8343                     mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
8344             ArraySet<String> previouslyApproved =
8345                     prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
8346 
8347             ArraySet<String> toRemove = new ArraySet<>();
8348             ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
8349 
8350             for (String previous : previouslyApproved) {
8351                 if (!roleHolders.contains(previous)) {
8352                     toRemove.add(previous);
8353                 }
8354             }
8355             for (String nowApproved : roleHolders) {
8356                 if (!previouslyApproved.contains(nowApproved)) {
8357                     toAdd.add(new Pair(nowApproved,
8358                             getUidForPackage(nowApproved, user.getIdentifier())));
8359                 }
8360             }
8361 
8362             // store newly approved apps
8363             prevApprovedForRole.put(user.getIdentifier(), roleHolders);
8364             mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
8365 
8366             // update what apps can be blocked
8367             mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
8368 
8369             // RoleManager is the source of truth for this data so we don't need to trigger a
8370             // write of the notification policy xml for this change
8371         }
8372 
8373         private int getUidForPackage(String pkg, int userId) {
8374             try {
8375                 return mPm.getPackageUid(pkg, MATCH_ALL, userId);
8376             } catch (RemoteException e) {
8377                 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
8378             }
8379             return -1;
8380         }
8381     }
8382 
8383     public static final class DumpFilter {
8384         public boolean filtered = false;
8385         public String pkgFilter;
8386         public boolean zen;
8387         public long since;
8388         public boolean stats;
8389         public boolean redact = true;
8390         public boolean proto = false;
8391         public boolean criticalPriority = false;
8392         public boolean normalPriority = false;
8393 
8394         @NonNull
8395         public static DumpFilter parseFromArguments(String[] args) {
8396             final DumpFilter filter = new DumpFilter();
8397             for (int ai = 0; ai < args.length; ai++) {
8398                 final String a = args[ai];
8399                 if ("--proto".equals(a)) {
8400                     filter.proto = true;
8401                 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
8402                     filter.redact = false;
8403                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
8404                     if (ai < args.length-1) {
8405                         ai++;
8406                         filter.pkgFilter = args[ai].trim().toLowerCase();
8407                         if (filter.pkgFilter.isEmpty()) {
8408                             filter.pkgFilter = null;
8409                         } else {
8410                             filter.filtered = true;
8411                         }
8412                     }
8413                 } else if ("--zen".equals(a) || "zen".equals(a)) {
8414                     filter.filtered = true;
8415                     filter.zen = true;
8416                 } else if ("--stats".equals(a)) {
8417                     filter.stats = true;
8418                     if (ai < args.length-1) {
8419                         ai++;
8420                         filter.since = Long.parseLong(args[ai]);
8421                     } else {
8422                         filter.since = 0;
8423                     }
8424                 } else if (PRIORITY_ARG.equals(a)) {
8425                     // Bugreport will call the service twice with priority arguments, first to dump
8426                     // critical sections and then non critical ones. Set approriate filters
8427                     // to generate the desired data.
8428                     if (ai < args.length - 1) {
8429                         ai++;
8430                         switch (args[ai]) {
8431                             case PRIORITY_ARG_CRITICAL:
8432                                 filter.criticalPriority = true;
8433                                 break;
8434                             case PRIORITY_ARG_NORMAL:
8435                                 filter.normalPriority = true;
8436                                 break;
8437                         }
8438                     }
8439                 }
8440             }
8441             return filter;
8442         }
8443 
8444         public boolean matches(StatusBarNotification sbn) {
8445             if (!filtered) return true;
8446             return zen ? true : sbn != null
8447                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
8448         }
8449 
8450         public boolean matches(ComponentName component) {
8451             if (!filtered) return true;
8452             return zen ? true : component != null && matches(component.getPackageName());
8453         }
8454 
8455         public boolean matches(String pkg) {
8456             if (!filtered) return true;
8457             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
8458         }
8459 
8460         @Override
8461         public String toString() {
8462             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
8463         }
8464     }
8465 
8466     @VisibleForTesting
8467     void resetAssistantUserSet(int userId) {
8468         mAssistants.setUserSet(userId, false);
8469         handleSavePolicyFile();
8470     }
8471 
8472     @VisibleForTesting
8473     @Nullable
8474     ComponentName getApprovedAssistant(int userId) {
8475         List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
8476         return CollectionUtils.firstOrNull(allowedComponents);
8477     }
8478 
8479     @VisibleForTesting
8480     protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
8481         checkCallerIsSystemOrShell();
8482         // only use for testing: mimic receive broadcast that package is (un)suspended
8483         // but does not actually (un)suspend the package
8484         final Bundle extras = new Bundle();
8485         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
8486                 new String[]{pkg});
8487 
8488         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
8489                 : Intent.ACTION_PACKAGES_UNSUSPENDED;
8490         final Intent intent = new Intent(action);
8491         intent.putExtras(extras);
8492 
8493         mPackageIntentReceiver.onReceive(getContext(), intent);
8494     }
8495 
8496     @VisibleForTesting
8497     protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
8498         // only use for testing: mimic receive broadcast that package is (un)distracting
8499         // but does not actually register that info with packagemanager
8500         final Bundle extras = new Bundle();
8501         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
8502         extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
8503 
8504         final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
8505         intent.putExtras(extras);
8506 
8507         mPackageIntentReceiver.onReceive(getContext(), intent);
8508     }
8509 
8510     /**
8511      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
8512      * binder without sending large amounts of data over a oneway transaction.
8513      */
8514     private static final class StatusBarNotificationHolder
8515             extends IStatusBarNotificationHolder.Stub {
8516         private StatusBarNotification mValue;
8517 
8518         public StatusBarNotificationHolder(StatusBarNotification value) {
8519             mValue = value;
8520         }
8521 
8522         /** Get the held value and clear it. This function should only be called once per holder */
8523         @Override
8524         public StatusBarNotification get() {
8525             StatusBarNotification value = mValue;
8526             mValue = null;
8527             return value;
8528         }
8529     }
8530 
8531     private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
8532         out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
8533         out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
8534                 Boolean.toString(mLockScreenAllowSecureNotifications));
8535         out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
8536     }
8537 
8538     private static boolean safeBoolean(String val, boolean defValue) {
8539         if (TextUtils.isEmpty(val)) return defValue;
8540         return Boolean.parseBoolean(val);
8541     }
8542 }
8543