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