OSDN Git Service

7e04d3337e684f8e535bed69e213730d23a59414
[android-x86/frameworks-base.git] / services / core / java / com / android / server / notification / NotificationManagerService.java
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.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
20 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
21 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
22 import static android.app.NotificationManager.IMPORTANCE_LOW;
23 import static android.app.NotificationManager.IMPORTANCE_MIN;
24 import static android.app.NotificationManager.IMPORTANCE_NONE;
25 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
26 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
27 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
28 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
29 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
30 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
31 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
32 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
33 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
34 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
35 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
36 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
37 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
38 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
39 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
40 import static android.os.UserHandle.USER_ALL;
41 import static android.os.UserHandle.USER_NULL;
42 import static android.os.UserHandle.USER_SYSTEM;
43 import static android.service.notification.NotificationListenerService
44         .HINT_HOST_DISABLE_CALL_EFFECTS;
45 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
46 import static android.service.notification.NotificationListenerService
47         .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
48 import static android.service.notification.NotificationListenerService
49         .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
50 import static android.service.notification.NotificationListenerService
51         .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
52 import static android.service.notification.NotificationListenerService
53         .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
54 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
55 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
56 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
57 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
58 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
59 import static android.service.notification.NotificationListenerService.REASON_CLICK;
60 import static android.service.notification.NotificationListenerService.REASON_ERROR;
61 import static android.service.notification.NotificationListenerService
62         .REASON_GROUP_SUMMARY_CANCELED;
63 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
64 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
65 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
66 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
67 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
68 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
69 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
70 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
71 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
72 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
73 import static android.service.notification.NotificationListenerService.TRIM_FULL;
74 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
75 import static android.view.Display.DEFAULT_DISPLAY;
76 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
77
78 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
79 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
80 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
81
82 import android.Manifest;
83 import android.annotation.NonNull;
84 import android.annotation.Nullable;
85 import android.app.ActivityManager;
86 import android.app.ActivityManagerInternal;
87 import android.app.AlarmManager;
88 import android.app.AppGlobals;
89 import android.app.AppOpsManager;
90 import android.app.AutomaticZenRule;
91 import android.app.IActivityManager;
92 import android.app.INotificationManager;
93 import android.app.ITransientNotification;
94 import android.app.Notification;
95 import android.app.NotificationChannel;
96 import android.app.NotificationChannelGroup;
97 import android.app.NotificationManager;
98 import android.app.NotificationManager.Policy;
99 import android.app.PendingIntent;
100 import android.app.StatusBarManager;
101 import android.app.backup.BackupManager;
102 import android.app.usage.UsageEvents;
103 import android.app.usage.UsageStatsManagerInternal;
104 import android.companion.ICompanionDeviceManager;
105 import android.content.BroadcastReceiver;
106 import android.content.ComponentName;
107 import android.content.ContentProvider;
108 import android.content.ContentResolver;
109 import android.content.Context;
110 import android.content.Intent;
111 import android.content.IntentFilter;
112 import android.content.pm.ApplicationInfo;
113 import android.content.pm.IPackageManager;
114 import android.content.pm.PackageManager;
115 import android.content.pm.PackageManager.NameNotFoundException;
116 import android.content.pm.ParceledListSlice;
117 import android.content.pm.UserInfo;
118 import android.content.res.Resources;
119 import android.database.ContentObserver;
120 import android.media.AudioAttributes;
121 import android.media.AudioManager;
122 import android.media.AudioManagerInternal;
123 import android.media.IRingtonePlayer;
124 import android.net.Uri;
125 import android.os.Binder;
126 import android.os.Build;
127 import android.os.Bundle;
128 import android.os.Environment;
129 import android.os.Handler;
130 import android.os.HandlerThread;
131 import android.os.IBinder;
132 import android.os.IDeviceIdleController;
133 import android.os.IInterface;
134 import android.os.Looper;
135 import android.os.Message;
136 import android.os.Process;
137 import android.os.RemoteException;
138 import android.os.ResultReceiver;
139 import android.os.ServiceManager;
140 import android.os.ShellCallback;
141 import android.os.ShellCommand;
142 import android.os.SystemClock;
143 import android.os.SystemProperties;
144 import android.os.UserHandle;
145 import android.os.VibrationEffect;
146 import android.os.Vibrator;
147 import android.provider.Settings;
148 import android.service.notification.Adjustment;
149 import android.service.notification.Condition;
150 import android.service.notification.IConditionProvider;
151 import android.service.notification.INotificationListener;
152 import android.service.notification.IStatusBarNotificationHolder;
153 import android.service.notification.ListenersDisablingEffectsProto;
154 import android.service.notification.NotificationAssistantService;
155 import android.service.notification.NotificationListenerService;
156 import android.service.notification.NotificationRankingUpdate;
157 import android.service.notification.NotificationRecordProto;
158 import android.service.notification.NotificationServiceDumpProto;
159 import android.service.notification.NotificationStats;
160 import android.service.notification.NotifyingApp;
161 import android.service.notification.SnoozeCriterion;
162 import android.service.notification.StatusBarNotification;
163 import android.service.notification.ZenModeConfig;
164 import android.service.notification.ZenModeProto;
165 import android.telephony.PhoneStateListener;
166 import android.telephony.TelephonyManager;
167 import android.text.TextUtils;
168 import android.util.ArrayMap;
169 import android.util.ArraySet;
170 import android.util.AtomicFile;
171 import android.util.Log;
172 import android.util.Slog;
173 import android.util.SparseArray;
174 import android.util.Xml;
175 import android.util.proto.ProtoOutputStream;
176 import android.view.accessibility.AccessibilityEvent;
177 import android.view.accessibility.AccessibilityManager;
178 import android.widget.Toast;
179
180 import com.android.internal.R;
181 import com.android.internal.annotations.GuardedBy;
182 import com.android.internal.annotations.VisibleForTesting;
183 import com.android.internal.logging.MetricsLogger;
184 import com.android.internal.logging.nano.MetricsProto;
185 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
186 import com.android.internal.notification.SystemNotificationChannels;
187 import com.android.internal.os.BackgroundThread;
188 import com.android.internal.statusbar.NotificationVisibility;
189 import com.android.internal.util.ArrayUtils;
190 import com.android.internal.util.DumpUtils;
191 import com.android.internal.util.FastXmlSerializer;
192 import com.android.internal.util.Preconditions;
193 import com.android.internal.util.XmlUtils;
194 import com.android.server.DeviceIdleController;
195 import com.android.server.EventLogTags;
196 import com.android.server.LocalServices;
197 import com.android.server.SystemService;
198 import com.android.server.lights.Light;
199 import com.android.server.lights.LightsManager;
200 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
201 import com.android.server.notification.ManagedServices.UserProfiles;
202 import com.android.server.policy.PhoneWindowManager;
203 import com.android.server.statusbar.StatusBarManagerInternal;
204 import com.android.server.wm.WindowManagerInternal;
205
206 import libcore.io.IoUtils;
207
208 import org.json.JSONException;
209 import org.json.JSONObject;
210 import org.xmlpull.v1.XmlPullParser;
211 import org.xmlpull.v1.XmlPullParserException;
212 import org.xmlpull.v1.XmlSerializer;
213
214 import java.io.ByteArrayInputStream;
215 import java.io.ByteArrayOutputStream;
216 import java.io.File;
217 import java.io.FileDescriptor;
218 import java.io.FileNotFoundException;
219 import java.io.FileOutputStream;
220 import java.io.IOException;
221 import java.io.InputStream;
222 import java.io.OutputStream;
223 import java.io.PrintWriter;
224 import java.nio.charset.StandardCharsets;
225 import java.util.ArrayDeque;
226 import java.util.ArrayList;
227 import java.util.Arrays;
228 import java.util.HashSet;
229 import java.util.Iterator;
230 import java.util.List;
231 import java.util.Map.Entry;
232 import java.util.Objects;
233 import java.util.Set;
234 import java.util.concurrent.TimeUnit;
235
236 /** {@hide} */
237 public class NotificationManagerService extends SystemService {
238     static final String TAG = "NotificationService";
239     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
240     public static final boolean ENABLE_CHILD_NOTIFICATIONS
241             = SystemProperties.getBoolean("debug.child_notifs", true);
242
243     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
244     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
245
246     // message codes
247     static final int MESSAGE_DURATION_REACHED = 2;
248     static final int MESSAGE_SAVE_POLICY_FILE = 3;
249     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
250     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
251     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
252     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
253
254     // ranking thread messages
255     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
256     private static final int MESSAGE_RANKING_SORT = 1001;
257
258     static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
259     static final int SHORT_DELAY = 2000; // 2 seconds
260
261     // 1 second past the ANR timeout.
262     static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
263
264     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
265
266     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
267
268     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
269
270     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
271
272     static final boolean ENABLE_BLOCKED_TOASTS = true;
273
274     // When #matchesCallFilter is called from the ringer, wait at most
275     // 3s to resolve the contacts. This timeout is required since
276     // ContactsProvider might take a long time to start up.
277     //
278     // Return STARRED_CONTACT when the timeout is hit in order to avoid
279     // missed calls in ZEN mode "Important".
280     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
281     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
282             ValidateNotificationPeople.STARRED_CONTACT;
283
284     /** notification_enqueue status value for a newly enqueued notification. */
285     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
286
287     /** notification_enqueue status value for an existing notification. */
288     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
289
290     /** notification_enqueue status value for an ignored notification. */
291     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
292     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
293
294     private static final long DELAY_FOR_ASSISTANT_TIME = 100;
295
296     private static final String ACTION_NOTIFICATION_TIMEOUT =
297             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
298     private static final int REQUEST_CODE_TIMEOUT = 1;
299     private static final String SCHEME_TIMEOUT = "timeout";
300     private static final String EXTRA_KEY = "key";
301
302     private IActivityManager mAm;
303     private ActivityManager mActivityManager;
304     private IPackageManager mPackageManager;
305     private PackageManager mPackageManagerClient;
306     AudioManager mAudioManager;
307     AudioManagerInternal mAudioManagerInternal;
308     @Nullable StatusBarManagerInternal mStatusBar;
309     Vibrator mVibrator;
310     private WindowManagerInternal mWindowManagerInternal;
311     private AlarmManager mAlarmManager;
312     private ICompanionDeviceManager mCompanionManager;
313     private AccessibilityManager mAccessibilityManager;
314     private IDeviceIdleController mDeviceIdleController;
315     private IBinder mPermissionOwner;
316
317     final IBinder mForegroundToken = new Binder();
318     private WorkerHandler mHandler;
319     private final HandlerThread mRankingThread = new HandlerThread("ranker",
320             Process.THREAD_PRIORITY_BACKGROUND);
321
322     private Light mNotificationLight;
323     Light mAttentionLight;
324
325     private long[] mFallbackVibrationPattern;
326     private boolean mUseAttentionLight;
327     boolean mSystemReady;
328
329     private boolean mDisableNotificationEffects;
330     private int mCallState;
331     private String mSoundNotificationKey;
332     private String mVibrateNotificationKey;
333
334     private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
335             new SparseArray<>();
336     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
337     private int mListenerHints;  // right now, all hints are global
338     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
339
340     // for enabling and disabling notification pulse behavior
341     private boolean mScreenOn = true;
342     protected boolean mInCall = false;
343     private boolean mNotificationPulseEnabled;
344
345     private Uri mInCallNotificationUri;
346     private AudioAttributes mInCallNotificationAudioAttributes;
347     private float mInCallNotificationVolume;
348
349     // used as a mutex for access to all active notifications & listeners
350     final Object mNotificationLock = new Object();
351     @GuardedBy("mNotificationLock")
352     final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
353     @GuardedBy("mNotificationLock")
354     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
355     @GuardedBy("mNotificationLock")
356     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
357     @GuardedBy("mNotificationLock")
358     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
359     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
360     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
361     final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
362
363     // The last key in this list owns the hardware.
364     ArrayList<String> mLights = new ArrayList<>();
365
366     private AppOpsManager mAppOps;
367     private UsageStatsManagerInternal mAppUsageStats;
368
369     private Archive mArchive;
370
371     // Persistent storage for notification policy
372     private AtomicFile mPolicyFile;
373
374     private static final int DB_VERSION = 1;
375
376     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
377     private static final String ATTR_VERSION = "version";
378
379     private RankingHelper mRankingHelper;
380
381     private final UserProfiles mUserProfiles = new UserProfiles();
382     private NotificationListeners mListeners;
383     private NotificationAssistants mAssistants;
384     private ConditionProviders mConditionProviders;
385     private NotificationUsageStats mUsageStats;
386
387     private static final int MY_UID = Process.myUid();
388     private static final int MY_PID = Process.myPid();
389     private static final IBinder WHITELIST_TOKEN = new Binder();
390     private RankingHandler mRankingHandler;
391     private long mLastOverRateLogTime;
392     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
393
394     private SnoozeHelper mSnoozeHelper;
395     private GroupHelper mGroupHelper;
396     private boolean mIsTelevision;
397
398     private static class Archive {
399         final int mBufferSize;
400         final ArrayDeque<StatusBarNotification> mBuffer;
401
402         public Archive(int size) {
403             mBufferSize = size;
404             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
405         }
406
407         public String toString() {
408             final StringBuilder sb = new StringBuilder();
409             final int N = mBuffer.size();
410             sb.append("Archive (");
411             sb.append(N);
412             sb.append(" notification");
413             sb.append((N==1)?")":"s)");
414             return sb.toString();
415         }
416
417         public void record(StatusBarNotification nr) {
418             if (mBuffer.size() == mBufferSize) {
419                 mBuffer.removeFirst();
420             }
421
422             // We don't want to store the heavy bits of the notification in the archive,
423             // but other clients in the system process might be using the object, so we
424             // store a (lightened) copy.
425             mBuffer.addLast(nr.cloneLight());
426         }
427
428         public Iterator<StatusBarNotification> descendingIterator() {
429             return mBuffer.descendingIterator();
430         }
431
432         public StatusBarNotification[] getArray(int count) {
433             if (count == 0) count = mBufferSize;
434             final StatusBarNotification[] a
435                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
436             Iterator<StatusBarNotification> iter = descendingIterator();
437             int i=0;
438             while (iter.hasNext() && i < count) {
439                 a[i++] = iter.next();
440             }
441             return a;
442         }
443
444     }
445
446     protected void readDefaultApprovedServices(int userId) {
447         String defaultListenerAccess = getContext().getResources().getString(
448                 com.android.internal.R.string.config_defaultListenerAccessPackages);
449         if (defaultListenerAccess != null) {
450             for (String whitelisted :
451                     defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
452                 // Gather all notification listener components for candidate pkgs.
453                 Set<ComponentName> approvedListeners =
454                         mListeners.queryPackageForServices(whitelisted,
455                                 PackageManager.MATCH_DIRECT_BOOT_AWARE
456                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
457                 for (ComponentName cn : approvedListeners) {
458                     try {
459                         getBinderService().setNotificationListenerAccessGrantedForUser(cn,
460                                     userId, true);
461                     } catch (RemoteException e) {
462                         e.printStackTrace();
463                     }
464                 }
465             }
466         }
467
468         String defaultDndAccess = getContext().getResources().getString(
469                 com.android.internal.R.string.config_defaultDndAccessPackages);
470         if (defaultListenerAccess != null) {
471             for (String whitelisted :
472                     defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
473                 try {
474                     getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
475                 } catch (RemoteException e) {
476                     e.printStackTrace();
477                 }
478             }
479         }
480
481         readDefaultAssistant(userId);
482     }
483
484     protected void readDefaultAssistant(int userId) {
485         String defaultAssistantAccess = getContext().getResources().getString(
486                 com.android.internal.R.string.config_defaultAssistantAccessPackage);
487         if (defaultAssistantAccess != null) {
488             // Gather all notification assistant components for candidate pkg. There should
489             // only be one
490             Set<ComponentName> approvedAssistants =
491                     mAssistants.queryPackageForServices(defaultAssistantAccess,
492                             PackageManager.MATCH_DIRECT_BOOT_AWARE
493                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
494             for (ComponentName cn : approvedAssistants) {
495                 try {
496                     getBinderService().setNotificationAssistantAccessGrantedForUser(
497                             cn, userId, true);
498                 } catch (RemoteException e) {
499                     e.printStackTrace();
500                 }
501             }
502         }
503     }
504
505     void readPolicyXml(InputStream stream, boolean forRestore)
506             throws XmlPullParserException, NumberFormatException, IOException {
507         final XmlPullParser parser = Xml.newPullParser();
508         parser.setInput(stream, StandardCharsets.UTF_8.name());
509         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
510         boolean migratedManagedServices = false;
511         int outerDepth = parser.getDepth();
512         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
513             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
514                 mZenModeHelper.readXml(parser, forRestore);
515             } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
516                 mRankingHelper.readXml(parser, forRestore);
517             }
518             // No non-system managed services are allowed on low ram devices
519             if (canUseManagedServices()) {
520                 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
521                     mListeners.readXml(parser);
522                     migratedManagedServices = true;
523                 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
524                     mAssistants.readXml(parser);
525                     migratedManagedServices = true;
526                 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
527                     mConditionProviders.readXml(parser);
528                     migratedManagedServices = true;
529                 }
530             }
531         }
532
533         if (!migratedManagedServices) {
534             mListeners.migrateToXml();
535             mAssistants.migrateToXml();
536             mConditionProviders.migrateToXml();
537             savePolicyFile();
538         }
539
540         mAssistants.ensureAssistant();
541     }
542
543     private void loadPolicyFile() {
544         if (DBG) Slog.d(TAG, "loadPolicyFile");
545         synchronized (mPolicyFile) {
546
547             InputStream infile = null;
548             try {
549                 infile = mPolicyFile.openRead();
550                 readPolicyXml(infile, false /*forRestore*/);
551             } catch (FileNotFoundException e) {
552                 // No data yet
553                 // Load default managed services approvals
554                 readDefaultApprovedServices(USER_SYSTEM);
555             } catch (IOException e) {
556                 Log.wtf(TAG, "Unable to read notification policy", e);
557             } catch (NumberFormatException e) {
558                 Log.wtf(TAG, "Unable to parse notification policy", e);
559             } catch (XmlPullParserException e) {
560                 Log.wtf(TAG, "Unable to parse notification policy", e);
561             } finally {
562                 IoUtils.closeQuietly(infile);
563             }
564         }
565     }
566
567     public void savePolicyFile() {
568         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
569         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
570     }
571
572     private void handleSavePolicyFile() {
573         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
574         synchronized (mPolicyFile) {
575             final FileOutputStream stream;
576             try {
577                 stream = mPolicyFile.startWrite();
578             } catch (IOException e) {
579                 Slog.w(TAG, "Failed to save policy file", e);
580                 return;
581             }
582
583             try {
584                 writePolicyXml(stream, false /*forBackup*/);
585                 mPolicyFile.finishWrite(stream);
586             } catch (IOException e) {
587                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
588                 mPolicyFile.failWrite(stream);
589             }
590         }
591         BackupManager.dataChanged(getContext().getPackageName());
592     }
593
594     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
595         final XmlSerializer out = new FastXmlSerializer();
596         out.setOutput(stream, StandardCharsets.UTF_8.name());
597         out.startDocument(null, true);
598         out.startTag(null, TAG_NOTIFICATION_POLICY);
599         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
600         mZenModeHelper.writeXml(out, forBackup, null);
601         mRankingHelper.writeXml(out, forBackup);
602         mListeners.writeXml(out, forBackup);
603         mAssistants.writeXml(out, forBackup);
604         mConditionProviders.writeXml(out, forBackup);
605         out.endTag(null, TAG_NOTIFICATION_POLICY);
606         out.endDocument();
607     }
608
609     private static final class ToastRecord
610     {
611         final int pid;
612         final String pkg;
613         ITransientNotification callback;
614         int duration;
615         Binder token;
616
617         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
618                     Binder token) {
619             this.pid = pid;
620             this.pkg = pkg;
621             this.callback = callback;
622             this.duration = duration;
623             this.token = token;
624         }
625
626         void update(int duration) {
627             this.duration = duration;
628         }
629
630         void update(ITransientNotification callback) {
631             this.callback = callback;
632         }
633
634         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
635             if (filter != null && !filter.matches(pkg)) return;
636             pw.println(prefix + this);
637         }
638
639         @Override
640         public final String toString()
641         {
642             return "ToastRecord{"
643                 + Integer.toHexString(System.identityHashCode(this))
644                 + " pkg=" + pkg
645                 + " callback=" + callback
646                 + " duration=" + duration;
647         }
648     }
649
650     @VisibleForTesting
651     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
652
653         @Override
654         public void onSetDisabled(int status) {
655             synchronized (mNotificationLock) {
656                 mDisableNotificationEffects =
657                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
658                 if (disableNotificationEffects(null) != null) {
659                     // cancel whatever's going on
660                     long identity = Binder.clearCallingIdentity();
661                     try {
662                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
663                         if (player != null) {
664                             player.stopAsync();
665                         }
666                     } catch (RemoteException e) {
667                     } finally {
668                         Binder.restoreCallingIdentity(identity);
669                     }
670
671                     identity = Binder.clearCallingIdentity();
672                     try {
673                         mVibrator.cancel();
674                     } finally {
675                         Binder.restoreCallingIdentity(identity);
676                     }
677                 }
678             }
679         }
680
681         @Override
682         public void onClearAll(int callingUid, int callingPid, int userId) {
683             synchronized (mNotificationLock) {
684                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
685                         /*includeCurrentProfiles*/ true);
686             }
687         }
688
689         @Override
690         public void onNotificationClick(int callingUid, int callingPid, String key) {
691             exitIdle();
692             synchronized (mNotificationLock) {
693                 NotificationRecord r = mNotificationsByKey.get(key);
694                 if (r == null) {
695                     Log.w(TAG, "No notification with key: " + key);
696                     return;
697                 }
698                 final long now = System.currentTimeMillis();
699                 MetricsLogger.action(r.getLogMaker(now)
700                         .setCategory(MetricsEvent.NOTIFICATION_ITEM)
701                         .setType(MetricsEvent.TYPE_ACTION));
702                 EventLogTags.writeNotificationClicked(key,
703                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
704
705                 StatusBarNotification sbn = r.sbn;
706                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
707                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
708                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
709                         REASON_CLICK, null);
710                 reportUserInteraction(r);
711             }
712         }
713
714         @Override
715         public void onNotificationActionClick(int callingUid, int callingPid, String key,
716                 int actionIndex) {
717             exitIdle();
718             synchronized (mNotificationLock) {
719                 NotificationRecord r = mNotificationsByKey.get(key);
720                 if (r == null) {
721                     Log.w(TAG, "No notification with key: " + key);
722                     return;
723                 }
724                 final long now = System.currentTimeMillis();
725                 MetricsLogger.action(r.getLogMaker(now)
726                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
727                         .setType(MetricsEvent.TYPE_ACTION)
728                         .setSubtype(actionIndex));
729                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
730                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
731                 reportUserInteraction(r);
732             }
733         }
734
735         @Override
736         public void onNotificationClear(int callingUid, int callingPid,
737                 String pkg, String tag, int id, int userId, String key,
738                 @NotificationStats.DismissalSurface int dismissalSurface) {
739             synchronized (mNotificationLock) {
740                 NotificationRecord r = mNotificationsByKey.get(key);
741                 if (r != null) {
742                     r.recordDismissalSurface(dismissalSurface);
743                 }
744             }
745             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
746                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
747                     true, userId, REASON_CANCEL, null);
748         }
749
750         @Override
751         public void onPanelRevealed(boolean clearEffects, int items) {
752             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
753             MetricsLogger.histogram(getContext(), "note_load", items);
754             EventLogTags.writeNotificationPanelRevealed(items);
755             if (clearEffects) {
756                 clearEffects();
757             }
758         }
759
760         @Override
761         public void onPanelHidden() {
762             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
763             EventLogTags.writeNotificationPanelHidden();
764         }
765
766         @Override
767         public void clearEffects() {
768             synchronized (mNotificationLock) {
769                 if (DBG) Slog.d(TAG, "clearEffects");
770                 clearSoundLocked();
771                 clearVibrateLocked();
772                 clearLightsLocked();
773             }
774         }
775
776         @Override
777         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
778                 int uid, int initialPid, String message, int userId) {
779             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
780                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
781             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
782                     REASON_ERROR, null);
783             long ident = Binder.clearCallingIdentity();
784             try {
785                 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
786                         "Bad notification posted from package " + pkg
787                         + ": " + message);
788             } catch (RemoteException e) {
789             }
790             Binder.restoreCallingIdentity(ident);
791         }
792
793         @Override
794         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
795                 NotificationVisibility[] noLongerVisibleKeys) {
796             synchronized (mNotificationLock) {
797                 for (NotificationVisibility nv : newlyVisibleKeys) {
798                     NotificationRecord r = mNotificationsByKey.get(nv.key);
799                     if (r == null) continue;
800                     if (!r.isSeen()) {
801                         // Report to usage stats that notification was made visible
802                         if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
803                         reportSeen(r);
804                     }
805                     r.setVisibility(true, nv.rank);
806                     nv.recycle();
807                 }
808                 // Note that we might receive this event after notifications
809                 // have already left the system, e.g. after dismissing from the
810                 // shade. Hence not finding notifications in
811                 // mNotificationsByKey is not an exceptional condition.
812                 for (NotificationVisibility nv : noLongerVisibleKeys) {
813                     NotificationRecord r = mNotificationsByKey.get(nv.key);
814                     if (r == null) continue;
815                     r.setVisibility(false, nv.rank);
816                     nv.recycle();
817                 }
818             }
819         }
820
821         @Override
822         public void onNotificationExpansionChanged(String key,
823                 boolean userAction, boolean expanded) {
824             synchronized (mNotificationLock) {
825                 NotificationRecord r = mNotificationsByKey.get(key);
826                 if (r != null) {
827                     r.stats.onExpansionChanged(userAction, expanded);
828                     final long now = System.currentTimeMillis();
829                     if (userAction) {
830                         MetricsLogger.action(r.getLogMaker(now)
831                                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
832                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
833                                         : MetricsEvent.TYPE_COLLAPSE));
834                     }
835                     if (expanded && userAction) {
836                         r.recordExpanded();
837                     }
838                     EventLogTags.writeNotificationExpansion(key,
839                             userAction ? 1 : 0, expanded ? 1 : 0,
840                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
841                 }
842             }
843         }
844
845         @Override
846         public void onNotificationDirectReplied(String key) {
847             exitIdle();
848             synchronized (mNotificationLock) {
849                 NotificationRecord r = mNotificationsByKey.get(key);
850                 if (r != null) {
851                     r.recordDirectReplied();
852                     reportUserInteraction(r);
853                 }
854             }
855         }
856
857         @Override
858         public void onNotificationSettingsViewed(String key) {
859             synchronized (mNotificationLock) {
860                 NotificationRecord r = mNotificationsByKey.get(key);
861                 if (r != null) {
862                     r.recordViewedSettings();
863                 }
864             }
865         }
866     };
867
868     @GuardedBy("mNotificationLock")
869     private void clearSoundLocked() {
870         mSoundNotificationKey = null;
871         long identity = Binder.clearCallingIdentity();
872         try {
873             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
874             if (player != null) {
875                 player.stopAsync();
876             }
877         } catch (RemoteException e) {
878         } finally {
879             Binder.restoreCallingIdentity(identity);
880         }
881     }
882
883     @GuardedBy("mNotificationLock")
884     private void clearVibrateLocked() {
885         mVibrateNotificationKey = null;
886         long identity = Binder.clearCallingIdentity();
887         try {
888             mVibrator.cancel();
889         } finally {
890             Binder.restoreCallingIdentity(identity);
891         }
892     }
893
894     @GuardedBy("mNotificationLock")
895     private void clearLightsLocked() {
896         // light
897         mLights.clear();
898         updateLightsLocked();
899     }
900
901     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
902         @Override
903         public void onReceive(Context context, Intent intent) {
904             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
905                 // update system notification channels
906                 SystemNotificationChannels.createAll(context);
907                 mZenModeHelper.updateDefaultZenRules();
908                 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
909             }
910         }
911     };
912
913     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
914         @Override
915         public void onReceive(Context context, Intent intent) {
916             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
917                 try {
918                     String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
919                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
920                     int restoredFromSdkInt = intent.getIntExtra(
921                             Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
922                     mListeners.onSettingRestored(
923                             element, newValue, restoredFromSdkInt, getSendingUserId());
924                     mConditionProviders.onSettingRestored(
925                             element, newValue, restoredFromSdkInt, getSendingUserId());
926                 } catch (Exception e) {
927                     Slog.wtf(TAG, "Cannot restore managed services from settings", e);
928                 }
929             }
930         }
931     };
932
933     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
934         @Override
935         public void onReceive(Context context, Intent intent) {
936             String action = intent.getAction();
937             if (action == null) {
938                 return;
939             }
940             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
941                 final NotificationRecord record;
942                 synchronized (mNotificationLock) {
943                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
944                 }
945                 if (record != null) {
946                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
947                             record.sbn.getPackageName(), record.sbn.getTag(),
948                             record.sbn.getId(), 0,
949                             Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
950                             REASON_TIMEOUT, null);
951                 }
952             }
953         }
954     };
955
956     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
957         @Override
958         public void onReceive(Context context, Intent intent) {
959             String action = intent.getAction();
960             if (action == null) {
961                 return;
962             }
963
964             boolean queryRestart = false;
965             boolean queryRemove = false;
966             boolean packageChanged = false;
967             boolean cancelNotifications = true;
968             boolean hideNotifications = false;
969             boolean unhideNotifications = false;
970             int reason = REASON_PACKAGE_CHANGED;
971
972             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
973                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
974                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
975                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
976                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
977                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
978                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
979                     || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
980                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
981                         UserHandle.USER_ALL);
982                 String pkgList[] = null;
983                 int uidList[] = null;
984                 boolean removingPackage = queryRemove &&
985                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
986                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
987                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
988                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
989                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
990                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
991                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
992                     cancelNotifications = false;
993                     hideNotifications = true;
994                 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
995                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
996                     cancelNotifications = false;
997                     unhideNotifications = true;
998                 } else if (queryRestart) {
999                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1000                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
1001                 } else {
1002                     Uri uri = intent.getData();
1003                     if (uri == null) {
1004                         return;
1005                     }
1006                     String pkgName = uri.getSchemeSpecificPart();
1007                     if (pkgName == null) {
1008                         return;
1009                     }
1010                     if (packageChanged) {
1011                         // We cancel notifications for packages which have just been disabled
1012                         try {
1013                             final int enabled = mPackageManager.getApplicationEnabledSetting(
1014                                     pkgName,
1015                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
1016                                             USER_SYSTEM);
1017                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1018                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1019                                 cancelNotifications = false;
1020                             }
1021                         } catch (IllegalArgumentException e) {
1022                             // Package doesn't exist; probably racing with uninstall.
1023                             // cancelNotifications is already true, so nothing to do here.
1024                             if (DBG) {
1025                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1026                             }
1027                         } catch (RemoteException e) {
1028                             // Failed to talk to PackageManagerService Should never happen!
1029                         }
1030                     }
1031                     pkgList = new String[]{pkgName};
1032                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
1033                 }
1034                 if (pkgList != null && (pkgList.length > 0)) {
1035                     for (String pkgName : pkgList) {
1036                         if (cancelNotifications) {
1037                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1038                                     !queryRestart, changeUserId, reason, null);
1039                         } else if (hideNotifications) {
1040                             hideNotificationsForPackages(pkgList);
1041                         } else if (unhideNotifications) {
1042                             unhideNotificationsForPackages(pkgList);
1043                         }
1044
1045                     }
1046                 }
1047
1048                 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
1049                 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
1050                 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
1051                 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
1052                 savePolicyFile();
1053             }
1054         }
1055     };
1056
1057     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1058         @Override
1059         public void onReceive(Context context, Intent intent) {
1060             String action = intent.getAction();
1061
1062             if (action.equals(Intent.ACTION_SCREEN_ON)) {
1063                 // Keep track of screen on/off state, but do not turn off the notification light
1064                 // until user passes through the lock screen or views the notification.
1065                 mScreenOn = true;
1066                 updateNotificationPulse();
1067             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1068                 mScreenOn = false;
1069                 updateNotificationPulse();
1070             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
1071                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1072                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
1073                 updateNotificationPulse();
1074             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1075                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1076                 if (userHandle >= 0) {
1077                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
1078                             REASON_USER_STOPPED, null);
1079                 }
1080             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
1081                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1082                 if (userHandle >= 0) {
1083                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
1084                             REASON_PROFILE_TURNED_OFF, null);
1085                 }
1086             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1087                 // turn off LED when user passes through lock screen
1088                 mNotificationLight.turnOff();
1089             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
1090                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1091                 // reload per-user settings
1092                 mSettingsObserver.update(null);
1093                 mUserProfiles.updateCache(context);
1094                 // Refresh managed services
1095                 mConditionProviders.onUserSwitched(user);
1096                 mListeners.onUserSwitched(user);
1097                 mAssistants.onUserSwitched(user);
1098                 mZenModeHelper.onUserSwitched(user);
1099             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
1100                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1101                 if (userId != USER_NULL) {
1102                     mUserProfiles.updateCache(context);
1103                     if (!mUserProfiles.isManagedProfile(userId)) {
1104                         readDefaultApprovedServices(userId);
1105                     }
1106                 }
1107             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
1108                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1109                 mUserProfiles.updateCache(context);
1110                 mZenModeHelper.onUserRemoved(user);
1111                 mRankingHelper.onUserRemoved(user);
1112                 mListeners.onUserRemoved(user);
1113                 mConditionProviders.onUserRemoved(user);
1114                 mAssistants.onUserRemoved(user);
1115                 savePolicyFile();
1116             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1117                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1118                 mConditionProviders.onUserUnlocked(user);
1119                 mListeners.onUserUnlocked(user);
1120                 mAssistants.onUserUnlocked(user);
1121                 mZenModeHelper.onUserUnlocked(user);
1122             }
1123         }
1124     };
1125
1126     private final class SettingsObserver extends ContentObserver {
1127         private final Uri NOTIFICATION_BADGING_URI
1128                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
1129         private final Uri NOTIFICATION_LIGHT_PULSE_URI
1130                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
1131         private final Uri NOTIFICATION_RATE_LIMIT_URI
1132                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
1133
1134         SettingsObserver(Handler handler) {
1135             super(handler);
1136         }
1137
1138         void observe() {
1139             ContentResolver resolver = getContext().getContentResolver();
1140             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1141                     false, this, UserHandle.USER_ALL);
1142             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
1143                     false, this, UserHandle.USER_ALL);
1144             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1145                     false, this, UserHandle.USER_ALL);
1146             update(null);
1147         }
1148
1149         @Override public void onChange(boolean selfChange, Uri uri) {
1150             update(uri);
1151         }
1152
1153         public void update(Uri uri) {
1154             ContentResolver resolver = getContext().getContentResolver();
1155             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
1156                 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1157                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
1158                 if (mNotificationPulseEnabled != pulseEnabled) {
1159                     mNotificationPulseEnabled = pulseEnabled;
1160                     updateNotificationPulse();
1161                 }
1162             }
1163             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1164                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1165                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1166             }
1167             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1168                 mRankingHelper.updateBadgingEnabled();
1169             }
1170         }
1171     }
1172
1173     private SettingsObserver mSettingsObserver;
1174     protected ZenModeHelper mZenModeHelper;
1175
1176     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1177         int[] ar = r.getIntArray(resid);
1178         if (ar == null) {
1179             return def;
1180         }
1181         final int len = ar.length > maxlen ? maxlen : ar.length;
1182         long[] out = new long[len];
1183         for (int i=0; i<len; i++) {
1184             out[i] = ar[i];
1185         }
1186         return out;
1187     }
1188
1189     public NotificationManagerService(Context context) {
1190         super(context);
1191         Notification.processWhitelistToken = WHITELIST_TOKEN;
1192     }
1193
1194     // TODO - replace these methods with a single VisibleForTesting constructor
1195     @VisibleForTesting
1196     void setAudioManager(AudioManager audioMananger) {
1197         mAudioManager = audioMananger;
1198     }
1199
1200     @VisibleForTesting
1201     void setVibrator(Vibrator vibrator) {
1202         mVibrator = vibrator;
1203     }
1204
1205     @VisibleForTesting
1206     void setLights(Light light) {
1207         mNotificationLight = light;
1208         mAttentionLight = light;
1209         mNotificationPulseEnabled = true;
1210     }
1211
1212     @VisibleForTesting
1213     void setScreenOn(boolean on) {
1214         mScreenOn = on;
1215     }
1216
1217     @VisibleForTesting
1218     int getNotificationRecordCount() {
1219         synchronized (mNotificationLock) {
1220             int count = mNotificationList.size() + mNotificationsByKey.size()
1221                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1222             // subtract duplicates
1223             for (NotificationRecord posted : mNotificationList) {
1224                 if (mNotificationsByKey.containsKey(posted.getKey())) {
1225                     count--;
1226                 }
1227                 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1228                     count--;
1229                 }
1230             }
1231
1232             return count;
1233         }
1234     }
1235
1236     @VisibleForTesting
1237     void clearNotifications() {
1238         mEnqueuedNotifications.clear();
1239         mNotificationList.clear();
1240         mNotificationsByKey.clear();
1241         mSummaryByGroupKey.clear();
1242     }
1243
1244     @VisibleForTesting
1245     void addNotification(NotificationRecord r) {
1246         mNotificationList.add(r);
1247         mNotificationsByKey.put(r.sbn.getKey(), r);
1248         if (r.sbn.isGroup()) {
1249             mSummaryByGroupKey.put(r.getGroupKey(), r);
1250         }
1251     }
1252
1253     @VisibleForTesting
1254     void addEnqueuedNotification(NotificationRecord r) {
1255         mEnqueuedNotifications.add(r);
1256     }
1257
1258     @VisibleForTesting
1259     NotificationRecord getNotificationRecord(String key) {
1260         return mNotificationsByKey.get(key);
1261     }
1262
1263
1264     @VisibleForTesting
1265     void setSystemReady(boolean systemReady) {
1266         mSystemReady = systemReady;
1267     }
1268
1269     @VisibleForTesting
1270     void setHandler(WorkerHandler handler) {
1271         mHandler = handler;
1272     }
1273
1274     @VisibleForTesting
1275     void setFallbackVibrationPattern(long[] vibrationPattern) {
1276         mFallbackVibrationPattern = vibrationPattern;
1277     }
1278
1279     @VisibleForTesting
1280     void setPackageManager(IPackageManager packageManager) {
1281         mPackageManager = packageManager;
1282     }
1283
1284     @VisibleForTesting
1285     void setRankingHelper(RankingHelper rankingHelper) {
1286         mRankingHelper = rankingHelper;
1287     }
1288
1289     @VisibleForTesting
1290     void setRankingHandler(RankingHandler rankingHandler) {
1291         mRankingHandler = rankingHandler;
1292     }
1293
1294     @VisibleForTesting
1295     void setIsTelevision(boolean isTelevision) {
1296         mIsTelevision = isTelevision;
1297     }
1298
1299     @VisibleForTesting
1300     void setUsageStats(NotificationUsageStats us) {
1301         mUsageStats = us;
1302     }
1303
1304     @VisibleForTesting
1305     void setAccessibilityManager(AccessibilityManager am) {
1306         mAccessibilityManager = am;
1307     }
1308
1309     // TODO: All tests should use this init instead of the one-off setters above.
1310     @VisibleForTesting
1311     void init(Looper looper, IPackageManager packageManager,
1312             PackageManager packageManagerClient,
1313             LightsManager lightsManager, NotificationListeners notificationListeners,
1314             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
1315             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1316             NotificationUsageStats usageStats, AtomicFile policyFile,
1317             ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
1318             UsageStatsManagerInternal appUsageStats) {
1319         Resources resources = getContext().getResources();
1320         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1321                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1322                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1323
1324         mAccessibilityManager =
1325                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
1326         mAm = am;
1327         mPackageManager = packageManager;
1328         mPackageManagerClient = packageManagerClient;
1329         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1330         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1331         mAppUsageStats = appUsageStats;
1332         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1333         mCompanionManager = companionManager;
1334         mActivityManager = activityManager;
1335         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1336                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
1337         try {
1338             mPermissionOwner = mAm.newUriPermissionOwner("notification");
1339         } catch (RemoteException e) {
1340             Slog.w(TAG, "AM dead", e);
1341         }
1342
1343         mHandler = new WorkerHandler(looper);
1344         mRankingThread.start();
1345         String[] extractorNames;
1346         try {
1347             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1348         } catch (Resources.NotFoundException e) {
1349             extractorNames = new String[0];
1350         }
1351         mUsageStats = usageStats;
1352         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1353         mConditionProviders = conditionProviders;
1354         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1355         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1356             @Override
1357             public void onConfigChanged() {
1358                 savePolicyFile();
1359             }
1360
1361             @Override
1362             void onZenModeChanged() {
1363                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1364                 getContext().sendBroadcastAsUser(
1365                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1366                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1367                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1368                 synchronized (mNotificationLock) {
1369                     updateInterruptionFilterLocked();
1370                 }
1371                 mRankingHandler.requestSort();
1372             }
1373
1374             @Override
1375             void onPolicyChanged() {
1376                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1377                 mRankingHandler.requestSort();
1378             }
1379         });
1380         mRankingHelper = new RankingHelper(getContext(),
1381                 mPackageManagerClient,
1382                 mRankingHandler,
1383                 mZenModeHelper,
1384                 mUsageStats,
1385                 extractorNames);
1386         mSnoozeHelper = snoozeHelper;
1387         mGroupHelper = groupHelper;
1388
1389         // This is a ManagedServices object that keeps track of the listeners.
1390         mListeners = notificationListeners;
1391
1392         // This is a MangedServices object that keeps track of the assistant.
1393         mAssistants = notificationAssistants;
1394
1395         mPolicyFile = policyFile;
1396         loadPolicyFile();
1397
1398         mStatusBar = getLocalService(StatusBarManagerInternal.class);
1399         if (mStatusBar != null) {
1400             mStatusBar.setNotificationDelegate(mNotificationDelegate);
1401         }
1402
1403         mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1404         mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1405
1406         mFallbackVibrationPattern = getLongArray(resources,
1407                 R.array.config_notificationFallbackVibePattern,
1408                 VIBRATE_PATTERN_MAXLEN,
1409                 DEFAULT_VIBRATE_PATTERN);
1410         mInCallNotificationUri = Uri.parse("file://" +
1411                 resources.getString(R.string.config_inCallNotificationSound));
1412         mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1413                 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1414                 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1415                 .build();
1416         mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1417
1418         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1419
1420         // Don't start allowing notifications until the setup wizard has run once.
1421         // After that, including subsequent boots, init with notifications turned on.
1422         // This works on the first boot because the setup wizard will toggle this
1423         // flag at least once and we'll go back to 0 after that.
1424         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1425                     Settings.Global.DEVICE_PROVISIONED, 0)) {
1426             mDisableNotificationEffects = true;
1427         }
1428         mZenModeHelper.initZenMode();
1429         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1430
1431         mUserProfiles.updateCache(getContext());
1432         listenForCallState();
1433
1434         mSettingsObserver = new SettingsObserver(mHandler);
1435
1436         mArchive = new Archive(resources.getInteger(
1437                 R.integer.config_notificationServiceArchiveSize));
1438
1439         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1440                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1441     }
1442
1443     @Override
1444     public void onStart() {
1445         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1446             @Override
1447             public void repost(int userId, NotificationRecord r) {
1448                 try {
1449                     if (DBG) {
1450                         Slog.d(TAG, "Reposting " + r.getKey());
1451                     }
1452                     enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1453                             r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1454                             r.sbn.getNotification(), userId);
1455                 } catch (Exception e) {
1456                     Slog.e(TAG, "Cannot un-snooze notification", e);
1457                 }
1458             }
1459         }, mUserProfiles);
1460
1461         final File systemDir = new File(Environment.getDataDirectory(), "system");
1462
1463         init(Looper.myLooper(),
1464                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1465                 getLocalService(LightsManager.class),
1466                 new NotificationListeners(AppGlobals.getPackageManager()),
1467                 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1468                         AppGlobals.getPackageManager()),
1469                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1470                 null, snoozeHelper, new NotificationUsageStats(getContext()),
1471                 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
1472                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1473                 getGroupHelper(), ActivityManager.getService(),
1474                 LocalServices.getService(UsageStatsManagerInternal.class));
1475
1476         // register for various Intents
1477         IntentFilter filter = new IntentFilter();
1478         filter.addAction(Intent.ACTION_SCREEN_ON);
1479         filter.addAction(Intent.ACTION_SCREEN_OFF);
1480         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1481         filter.addAction(Intent.ACTION_USER_PRESENT);
1482         filter.addAction(Intent.ACTION_USER_STOPPED);
1483         filter.addAction(Intent.ACTION_USER_SWITCHED);
1484         filter.addAction(Intent.ACTION_USER_ADDED);
1485         filter.addAction(Intent.ACTION_USER_REMOVED);
1486         filter.addAction(Intent.ACTION_USER_UNLOCKED);
1487         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1488         getContext().registerReceiver(mIntentReceiver, filter);
1489
1490         IntentFilter pkgFilter = new IntentFilter();
1491         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1492         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1493         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1494         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1495         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1496         pkgFilter.addDataScheme("package");
1497         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1498                 null);
1499
1500         IntentFilter suspendedPkgFilter = new IntentFilter();
1501         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1502         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
1503         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1504                 suspendedPkgFilter, null, null);
1505
1506         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1507         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1508                 null);
1509
1510         IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1511         timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1512         getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1513
1514         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1515         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1516
1517         IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1518         getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1519
1520         publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1521                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
1522         publishLocalService(NotificationManagerInternal.class, mInternalService);
1523     }
1524
1525     private GroupHelper getGroupHelper() {
1526         return new GroupHelper(new GroupHelper.Callback() {
1527             @Override
1528             public void addAutoGroup(String key) {
1529                 synchronized (mNotificationLock) {
1530                     addAutogroupKeyLocked(key);
1531                 }
1532             }
1533
1534             @Override
1535             public void removeAutoGroup(String key) {
1536                 synchronized (mNotificationLock) {
1537                     removeAutogroupKeyLocked(key);
1538                 }
1539             }
1540
1541             @Override
1542             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1543                 createAutoGroupSummary(userId, pkg, triggeringKey);
1544             }
1545
1546             @Override
1547             public void removeAutoGroupSummary(int userId, String pkg) {
1548                 synchronized (mNotificationLock) {
1549                     clearAutogroupSummaryLocked(userId, pkg);
1550                 }
1551             }
1552         });
1553     }
1554
1555     private void sendRegisteredOnlyBroadcast(String action) {
1556         getContext().sendBroadcastAsUser(new Intent(action)
1557                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1558     }
1559
1560     @Override
1561     public void onBootPhase(int phase) {
1562         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1563             // no beeping until we're basically done booting
1564             mSystemReady = true;
1565
1566             // Grab our optional AudioService
1567             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1568             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1569             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1570             mZenModeHelper.onSystemReady();
1571         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1572             // This observer will force an update when observe is called, causing us to
1573             // bind to listener services.
1574             mSettingsObserver.observe();
1575             mListeners.onBootPhaseAppsCanStart();
1576             mAssistants.onBootPhaseAppsCanStart();
1577             mConditionProviders.onBootPhaseAppsCanStart();
1578         }
1579     }
1580
1581     @GuardedBy("mNotificationLock")
1582     private void updateListenerHintsLocked() {
1583         final int hints = calculateHints();
1584         if (hints == mListenerHints) return;
1585         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1586         mListenerHints = hints;
1587         scheduleListenerHintsChanged(hints);
1588     }
1589
1590     @GuardedBy("mNotificationLock")
1591     private void updateEffectsSuppressorLocked() {
1592         final long updatedSuppressedEffects = calculateSuppressedEffects();
1593         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1594         final List<ComponentName> suppressors = getSuppressors();
1595         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1596         mEffectsSuppressors = suppressors;
1597         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1598         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1599     }
1600
1601     private void exitIdle() {
1602         try {
1603             if (mDeviceIdleController != null) {
1604                 mDeviceIdleController.exitIdle("notification interaction");
1605             }
1606         } catch (RemoteException e) {
1607         }
1608     }
1609
1610     private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1611             boolean fromListener) {
1612         if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1613             // cancel
1614             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1615                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
1616                     null);
1617             if (isUidSystemOrPhone(uid)) {
1618                 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1619                 int N = profileIds.length;
1620                 for (int i = 0; i < N; i++) {
1621                     int profileId = profileIds[i];
1622                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1623                             profileId, REASON_CHANNEL_BANNED,
1624                             null);
1625                 }
1626             }
1627         }
1628         final NotificationChannel preUpdate =
1629                 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1630
1631         mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
1632         maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
1633
1634         if (!fromListener) {
1635             final NotificationChannel modifiedChannel =
1636                     mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1637             mListeners.notifyNotificationChannelChanged(
1638                     pkg, UserHandle.getUserHandleForUid(uid),
1639                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1640         }
1641
1642         savePolicyFile();
1643     }
1644
1645     private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1646             NotificationChannel update) {
1647         try {
1648             if ((preUpdate.getImportance() == IMPORTANCE_NONE
1649                     && update.getImportance() != IMPORTANCE_NONE)
1650                     || (preUpdate.getImportance() != IMPORTANCE_NONE
1651                     && update.getImportance() == IMPORTANCE_NONE)) {
1652                 getContext().sendBroadcastAsUser(
1653                         new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
1654                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
1655                                         update.getId())
1656                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1657                                         update.getImportance() == IMPORTANCE_NONE)
1658                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1659                                 .setPackage(pkg),
1660                         UserHandle.of(UserHandle.getUserId(uid)), null);
1661             }
1662         } catch (SecurityException e) {
1663             Slog.w(TAG, "Can't notify app about channel change", e);
1664         }
1665     }
1666
1667     private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1668             boolean fromApp, boolean fromListener) {
1669         Preconditions.checkNotNull(group);
1670         Preconditions.checkNotNull(pkg);
1671
1672         final NotificationChannelGroup preUpdate =
1673                 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
1674         mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1675                 fromApp);
1676         if (!fromApp) {
1677             maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1678         }
1679         if (!fromListener) {
1680             mListeners.notifyNotificationChannelGroupChanged(pkg,
1681                     UserHandle.of(UserHandle.getCallingUserId()), group,
1682                     NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1683         }
1684     }
1685
1686     private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1687             NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1688         try {
1689             if (preUpdate.isBlocked() != update.isBlocked()) {
1690                 getContext().sendBroadcastAsUser(
1691                         new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
1692                                 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
1693                                         update.getId())
1694                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1695                                         update.isBlocked())
1696                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1697                                 .setPackage(pkg),
1698                         UserHandle.of(UserHandle.getUserId(uid)), null);
1699             }
1700         } catch (SecurityException e) {
1701             Slog.w(TAG, "Can't notify app about group change", e);
1702         }
1703     }
1704
1705     private ArrayList<ComponentName> getSuppressors() {
1706         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1707         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1708             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1709
1710             for (ManagedServiceInfo info : serviceInfoList) {
1711                 names.add(info.component);
1712             }
1713         }
1714
1715         return names;
1716     }
1717
1718     private boolean removeDisabledHints(ManagedServiceInfo info) {
1719         return removeDisabledHints(info, 0);
1720     }
1721
1722     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1723         boolean removed = false;
1724
1725         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1726             final int hint = mListenersDisablingEffects.keyAt(i);
1727             final ArraySet<ManagedServiceInfo> listeners =
1728                     mListenersDisablingEffects.valueAt(i);
1729
1730             if (hints == 0 || (hint & hints) == hint) {
1731                 removed = removed || listeners.remove(info);
1732             }
1733         }
1734
1735         return removed;
1736     }
1737
1738     private void addDisabledHints(ManagedServiceInfo info, int hints) {
1739         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1740             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1741         }
1742
1743         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1744             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1745         }
1746
1747         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1748             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1749         }
1750     }
1751
1752     private void addDisabledHint(ManagedServiceInfo info, int hint) {
1753         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1754             mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1755         }
1756
1757         ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1758         hintListeners.add(info);
1759     }
1760
1761     private int calculateHints() {
1762         int hints = 0;
1763         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1764             int hint = mListenersDisablingEffects.keyAt(i);
1765             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1766
1767             if (!serviceInfoList.isEmpty()) {
1768                 hints |= hint;
1769             }
1770         }
1771
1772         return hints;
1773     }
1774
1775     private long calculateSuppressedEffects() {
1776         int hints = calculateHints();
1777         long suppressedEffects = 0;
1778
1779         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1780             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1781         }
1782
1783         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1784             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1785         }
1786
1787         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1788             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1789         }
1790
1791         return suppressedEffects;
1792     }
1793
1794     @GuardedBy("mNotificationLock")
1795     private void updateInterruptionFilterLocked() {
1796         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1797         if (interruptionFilter == mInterruptionFilter) return;
1798         mInterruptionFilter = interruptionFilter;
1799         scheduleInterruptionFilterChanged(interruptionFilter);
1800     }
1801
1802     @VisibleForTesting
1803     INotificationManager getBinderService() {
1804         return INotificationManager.Stub.asInterface(mService);
1805     }
1806
1807     /**
1808      * Report to usage stats that the notification was seen.
1809      * @param r notification record
1810      */
1811     @GuardedBy("mNotificationLock")
1812     protected void reportSeen(NotificationRecord r) {
1813         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1814                 getRealUserId(r.sbn.getUserId()),
1815                 UsageEvents.Event.NOTIFICATION_SEEN);
1816     }
1817
1818     protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1819             int targetSdkVersion) {
1820         if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1821             return incomingPolicy.suppressedVisualEffects;
1822         }
1823         final int[] effectsIntroducedInP = {
1824                 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1825                 SUPPRESSED_EFFECT_LIGHTS,
1826                 SUPPRESSED_EFFECT_PEEK,
1827                 SUPPRESSED_EFFECT_STATUS_BAR,
1828                 SUPPRESSED_EFFECT_BADGE,
1829                 SUPPRESSED_EFFECT_AMBIENT,
1830                 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1831         };
1832
1833         int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
1834         if (targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
1835             // unset higher order bits introduced in P, maintain the user's higher order bits
1836             for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1837                 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1838                 newSuppressedVisualEffects |=
1839                         (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1840             }
1841             // set higher order bits according to lower order bits
1842             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1843                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1844                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1845                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1846             }
1847             if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1848                 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1849             }
1850         } else {
1851             boolean hasNewEffects = (newSuppressedVisualEffects
1852                     - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1853             // if any of the new effects introduced in P are set
1854             if (hasNewEffects) {
1855                 // clear out the deprecated effects
1856                 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1857                         | SUPPRESSED_EFFECT_SCREEN_OFF);
1858
1859                 // set the deprecated effects according to the new more specific effects
1860                 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1861                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1862                 }
1863                 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1864                         && (newSuppressedVisualEffects
1865                         & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1866                         && (newSuppressedVisualEffects
1867                         & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1868                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1869                 }
1870             } else {
1871                 // set higher order bits according to lower order bits
1872                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1873                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1874                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1875                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1876                 }
1877                 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1878                     newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1879                 }
1880             }
1881         }
1882
1883         return newSuppressedVisualEffects;
1884     }
1885
1886     @GuardedBy("mNotificationLock")
1887     protected void maybeRecordInterruptionLocked(NotificationRecord r) {
1888         if (r.isInterruptive()) {
1889             mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1890                     r.getChannel().getId(),
1891                     getRealUserId(r.sbn.getUserId()));
1892             logRecentLocked(r);
1893         }
1894     }
1895
1896     /**
1897      * Report to usage stats that the notification was clicked.
1898      * @param r notification record
1899      */
1900     protected void reportUserInteraction(NotificationRecord r) {
1901         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1902                 getRealUserId(r.sbn.getUserId()),
1903                 UsageEvents.Event.USER_INTERACTION);
1904     }
1905
1906     private int getRealUserId(int userId) {
1907         return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1908     }
1909
1910     @VisibleForTesting
1911     NotificationManagerInternal getInternalService() {
1912         return mInternalService;
1913     }
1914
1915     private final IBinder mService = new INotificationManager.Stub() {
1916         // Toasts
1917         // ============================================================================
1918
1919         @Override
1920         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1921         {
1922             if (DBG) {
1923                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1924                         + " duration=" + duration);
1925             }
1926
1927             if (pkg == null || callback == null) {
1928                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1929                 return ;
1930             }
1931             final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1932             final boolean isPackageSuspended =
1933                     isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1934
1935             if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1936                     (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1937                             || isPackageSuspended)) {
1938                 Slog.e(TAG, "Suppressing toast from package " + pkg
1939                         + (isPackageSuspended
1940                                 ? " due to package suspended by administrator."
1941                                 : " by user request."));
1942                 return;
1943             }
1944
1945             synchronized (mToastQueue) {
1946                 int callingPid = Binder.getCallingPid();
1947                 long callingId = Binder.clearCallingIdentity();
1948                 try {
1949                     ToastRecord record;
1950                     int index;
1951                     // All packages aside from the android package can enqueue one toast at a time
1952                     if (!isSystemToast) {
1953                         index = indexOfToastPackageLocked(pkg);
1954                     } else {
1955                         index = indexOfToastLocked(pkg, callback);
1956                     }
1957
1958                     // If the package already has a toast, we update its toast
1959                     // in the queue, we don't move it to the end of the queue.
1960                     if (index >= 0) {
1961                         record = mToastQueue.get(index);
1962                         record.update(duration);
1963                         try {
1964                             record.callback.hide();
1965                         } catch (RemoteException e) {
1966                         }
1967                         record.update(callback);
1968                     } else {
1969                         Binder token = new Binder();
1970                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1971                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
1972                         mToastQueue.add(record);
1973                         index = mToastQueue.size() - 1;
1974                     }
1975                     keepProcessAliveIfNeededLocked(callingPid);
1976                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
1977                     // new or just been updated.  Call back and tell it to show itself.
1978                     // If the callback fails, this will remove it from the list, so don't
1979                     // assume that it's valid after this.
1980                     if (index == 0) {
1981                         showNextToastLocked();
1982                     }
1983                 } finally {
1984                     Binder.restoreCallingIdentity(callingId);
1985                 }
1986             }
1987         }
1988
1989         @Override
1990         public void cancelToast(String pkg, ITransientNotification callback) {
1991             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1992
1993             if (pkg == null || callback == null) {
1994                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1995                 return ;
1996             }
1997
1998             synchronized (mToastQueue) {
1999                 long callingId = Binder.clearCallingIdentity();
2000                 try {
2001                     int index = indexOfToastLocked(pkg, callback);
2002                     if (index >= 0) {
2003                         cancelToastLocked(index);
2004                     } else {
2005                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2006                                 + " callback=" + callback);
2007                     }
2008                 } finally {
2009                     Binder.restoreCallingIdentity(callingId);
2010                 }
2011             }
2012         }
2013
2014         @Override
2015         public void finishToken(String pkg, ITransientNotification callback) {
2016             synchronized (mToastQueue) {
2017                 long callingId = Binder.clearCallingIdentity();
2018                 try {
2019                     int index = indexOfToastLocked(pkg, callback);
2020                     if (index >= 0) {
2021                         ToastRecord record = mToastQueue.get(index);
2022                         finishTokenLocked(record.token);
2023                     } else {
2024                         Slog.w(TAG, "Toast already killed. pkg=" + pkg
2025                                 + " callback=" + callback);
2026                     }
2027                 } finally {
2028                     Binder.restoreCallingIdentity(callingId);
2029                 }
2030             }
2031         }
2032
2033         @Override
2034         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
2035                 Notification notification, int userId) throws RemoteException {
2036             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
2037                     Binder.getCallingPid(), tag, id, notification, userId);
2038         }
2039
2040         @Override
2041         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
2042             checkCallerIsSystemOrSameApp(pkg);
2043             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2044                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
2045             // Don't allow client applications to cancel foreground service notis or autobundled
2046             // summaries.
2047             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
2048                     (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
2049             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
2050                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
2051         }
2052
2053         @Override
2054         public void cancelAllNotifications(String pkg, int userId) {
2055             checkCallerIsSystemOrSameApp(pkg);
2056
2057             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2058                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2059
2060             // Calling from user space, don't allow the canceling of actively
2061             // running foreground services.
2062             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
2063                     pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
2064                     REASON_APP_CANCEL_ALL, null);
2065         }
2066
2067         @Override
2068         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
2069             enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
2070
2071             mRankingHelper.setEnabled(pkg, uid, enabled);
2072             // Now, cancel any outstanding notifications that are part of a just-disabled app
2073             if (!enabled) {
2074                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2075                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2076             }
2077
2078             try {
2079                 getContext().sendBroadcastAsUser(
2080                         new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2081                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2082                                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2083                                 .setPackage(pkg),
2084                         UserHandle.of(UserHandle.getUserId(uid)), null);
2085             } catch (SecurityException e) {
2086                 Slog.w(TAG, "Can't notify app about app block change", e);
2087             }
2088
2089             savePolicyFile();
2090         }
2091
2092         /**
2093          * Use this when you just want to know if notifications are OK for this package.
2094          */
2095         @Override
2096         public boolean areNotificationsEnabled(String pkg) {
2097             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2098         }
2099
2100         /**
2101          * Use this when you just want to know if notifications are OK for this package.
2102          */
2103         @Override
2104         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
2105             checkCallerIsSystemOrSameApp(pkg);
2106
2107             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
2108         }
2109
2110         @Override
2111         public int getPackageImportance(String pkg) {
2112             checkCallerIsSystemOrSameApp(pkg);
2113             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
2114         }
2115
2116         @Override
2117         public boolean canShowBadge(String pkg, int uid) {
2118             checkCallerIsSystem();
2119             return mRankingHelper.canShowBadge(pkg, uid);
2120         }
2121
2122         @Override
2123         public void setShowBadge(String pkg, int uid, boolean showBadge) {
2124             checkCallerIsSystem();
2125             mRankingHelper.setShowBadge(pkg, uid, showBadge);
2126             savePolicyFile();
2127         }
2128
2129         @Override
2130         public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2131                 NotificationChannelGroup group) throws RemoteException {
2132             enforceSystemOrSystemUI("Caller not system or systemui");
2133             createNotificationChannelGroup(pkg, uid, group, false, false);
2134             savePolicyFile();
2135         }
2136
2137         @Override
2138         public void createNotificationChannelGroups(String pkg,
2139                 ParceledListSlice channelGroupList) throws RemoteException {
2140             checkCallerIsSystemOrSameApp(pkg);
2141             List<NotificationChannelGroup> groups = channelGroupList.getList();
2142             final int groupSize = groups.size();
2143             for (int i = 0; i < groupSize; i++) {
2144                 final NotificationChannelGroup group = groups.get(i);
2145                 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
2146             }
2147             savePolicyFile();
2148         }
2149
2150         private void createNotificationChannelsImpl(String pkg, int uid,
2151                 ParceledListSlice channelsList) {
2152             List<NotificationChannel> channels = channelsList.getList();
2153             final int channelsSize = channels.size();
2154             for (int i = 0; i < channelsSize; i++) {
2155                 final NotificationChannel channel = channels.get(i);
2156                 Preconditions.checkNotNull(channel, "channel in list is null");
2157                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
2158                         true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2159                                 pkg, UserHandle.getUserId(uid)));
2160                 mListeners.notifyNotificationChannelChanged(pkg,
2161                         UserHandle.getUserHandleForUid(uid),
2162                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2163                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2164             }
2165             savePolicyFile();
2166         }
2167
2168         @Override
2169         public void createNotificationChannels(String pkg,
2170                 ParceledListSlice channelsList) throws RemoteException {
2171             checkCallerIsSystemOrSameApp(pkg);
2172             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2173         }
2174
2175         @Override
2176         public void createNotificationChannelsForPackage(String pkg, int uid,
2177                 ParceledListSlice channelsList) throws RemoteException {
2178             checkCallerIsSystem();
2179             createNotificationChannelsImpl(pkg, uid, channelsList);
2180         }
2181
2182         @Override
2183         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
2184             checkCallerIsSystemOrSameApp(pkg);
2185             return mRankingHelper.getNotificationChannel(
2186                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
2187         }
2188
2189         @Override
2190         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
2191                 String channelId, boolean includeDeleted) {
2192             checkCallerIsSystem();
2193             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
2194         }
2195
2196         @Override
2197         public void deleteNotificationChannel(String pkg, String channelId) {
2198             checkCallerIsSystemOrSameApp(pkg);
2199             final int callingUid = Binder.getCallingUid();
2200             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2201                 throw new IllegalArgumentException("Cannot delete default channel");
2202             }
2203             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
2204                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2205             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2206             mListeners.notifyNotificationChannelChanged(pkg,
2207                     UserHandle.getUserHandleForUid(callingUid),
2208                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2209                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2210             savePolicyFile();
2211         }
2212
2213         @Override
2214         public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2215             checkCallerIsSystemOrSameApp(pkg);
2216             return mRankingHelper.getNotificationChannelGroupWithChannels(
2217                     pkg, Binder.getCallingUid(), groupId, false);
2218         }
2219
2220         @Override
2221         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2222                 String pkg) {
2223             checkCallerIsSystemOrSameApp(pkg);
2224             return mRankingHelper.getNotificationChannelGroups(
2225                     pkg, Binder.getCallingUid(), false, false);
2226         }
2227
2228         @Override
2229         public void deleteNotificationChannelGroup(String pkg, String groupId) {
2230             checkCallerIsSystemOrSameApp(pkg);
2231
2232             final int callingUid = Binder.getCallingUid();
2233             NotificationChannelGroup groupToDelete =
2234                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2235             if (groupToDelete != null) {
2236                 List<NotificationChannel> deletedChannels =
2237                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2238                 for (int i = 0; i < deletedChannels.size(); i++) {
2239                     final NotificationChannel deletedChannel = deletedChannels.get(i);
2240                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2241                             true,
2242                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2243                             null);
2244                     mListeners.notifyNotificationChannelChanged(pkg,
2245                             UserHandle.getUserHandleForUid(callingUid),
2246                             deletedChannel,
2247                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2248                 }
2249                 mListeners.notifyNotificationChannelGroupChanged(
2250                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2251                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2252                 savePolicyFile();
2253             }
2254         }
2255
2256         @Override
2257         public void updateNotificationChannelForPackage(String pkg, int uid,
2258                 NotificationChannel channel) {
2259             enforceSystemOrSystemUI("Caller not system or systemui");
2260             Preconditions.checkNotNull(channel);
2261             updateNotificationChannelInt(pkg, uid, channel, false);
2262         }
2263
2264         @Override
2265         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
2266                 int uid, boolean includeDeleted) {
2267             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
2268             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
2269         }
2270
2271         @Override
2272         public int getNumNotificationChannelsForPackage(String pkg, int uid,
2273                 boolean includeDeleted) {
2274             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2275             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2276                     .getList().size();
2277         }
2278
2279         @Override
2280         public boolean onlyHasDefaultChannel(String pkg, int uid) {
2281             enforceSystemOrSystemUI("onlyHasDefaultChannel");
2282             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2283         }
2284
2285         @Override
2286         public int getDeletedChannelCount(String pkg, int uid) {
2287             enforceSystemOrSystemUI("getDeletedChannelCount");
2288             return mRankingHelper.getDeletedChannelCount(pkg, uid);
2289         }
2290
2291         @Override
2292         public int getBlockedChannelCount(String pkg, int uid) {
2293             enforceSystemOrSystemUI("getBlockedChannelCount");
2294             return mRankingHelper.getBlockedChannelCount(pkg, uid);
2295         }
2296
2297         @Override
2298         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2299                 String pkg, int uid, boolean includeDeleted) {
2300             checkCallerIsSystem();
2301             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
2302         }
2303
2304         @Override
2305         public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2306                 String pkg, int uid, String groupId, boolean includeDeleted) {
2307             enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2308             return mRankingHelper.getNotificationChannelGroupWithChannels(
2309                     pkg, uid, groupId, includeDeleted);
2310         }
2311
2312         @Override
2313         public NotificationChannelGroup getNotificationChannelGroupForPackage(
2314                 String groupId, String pkg, int uid) {
2315             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2316             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2317         }
2318
2319         @Override
2320         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2321             checkCallerIsSystemOrSameApp(pkg);
2322             return mRankingHelper.getNotificationChannels(
2323                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
2324         }
2325
2326         @Override
2327         public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2328             checkCallerIsSystem();
2329             synchronized (mNotificationLock) {
2330                 List<NotifyingApp> apps = new ArrayList<>(
2331                         mRecentApps.getOrDefault(userId, new ArrayList<>()));
2332                 return new ParceledListSlice<>(apps);
2333             }
2334         }
2335
2336         @Override
2337         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
2338             checkCallerIsSystem();
2339
2340             // Cancel posted notifications
2341             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2342                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2343
2344             final String[] packages = new String[] {packageName};
2345             final int[] uids = new int[] {uid};
2346
2347             // Listener & assistant
2348             mListeners.onPackagesChanged(true, packages, uids);
2349             mAssistants.onPackagesChanged(true, packages, uids);
2350
2351             // Zen
2352             mConditionProviders.onPackagesChanged(true, packages, uids);
2353
2354             // Reset notification preferences
2355             if (!fromApp) {
2356                 mRankingHelper.onPackagesChanged(
2357                         true, UserHandle.getCallingUserId(), packages, uids);
2358             }
2359
2360             savePolicyFile();
2361         }
2362
2363
2364         /**
2365          * System-only API for getting a list of current (i.e. not cleared) notifications.
2366          *
2367          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2368          * @returns A list of all the notifications, in natural order.
2369          */
2370         @Override
2371         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2372             // enforce() will ensure the calling uid has the correct permission
2373             getContext().enforceCallingOrSelfPermission(
2374                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2375                     "NotificationManagerService.getActiveNotifications");
2376
2377             StatusBarNotification[] tmp = null;
2378             int uid = Binder.getCallingUid();
2379
2380             // noteOp will check to make sure the callingPkg matches the uid
2381             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2382                     == AppOpsManager.MODE_ALLOWED) {
2383                 synchronized (mNotificationLock) {
2384                     tmp = new StatusBarNotification[mNotificationList.size()];
2385                     final int N = mNotificationList.size();
2386                     for (int i=0; i<N; i++) {
2387                         tmp[i] = mNotificationList.get(i).sbn;
2388                     }
2389                 }
2390             }
2391             return tmp;
2392         }
2393
2394         /**
2395          * Public API for getting a list of current notifications for the calling package/uid.
2396          *
2397          * Note that since notification posting is done asynchronously, this will not return
2398          * notifications that are in the process of being posted.
2399          *
2400          * @returns A list of all the package's notifications, in natural order.
2401          */
2402         @Override
2403         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2404                 int incomingUserId) {
2405             checkCallerIsSystemOrSameApp(pkg);
2406             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2407                     Binder.getCallingUid(), incomingUserId, true, false,
2408                     "getAppActiveNotifications", pkg);
2409             synchronized (mNotificationLock) {
2410                 final ArrayMap<String, StatusBarNotification> map
2411                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2412                 final int N = mNotificationList.size();
2413                 for (int i = 0; i < N; i++) {
2414                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2415                             mNotificationList.get(i).sbn);
2416                     if (sbn != null) {
2417                         map.put(sbn.getKey(), sbn);
2418                     }
2419                 }
2420                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2421                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2422                     if (sbn != null) {
2423                         map.put(sbn.getKey(), sbn);
2424                     }
2425                 }
2426                 final int M = mEnqueuedNotifications.size();
2427                 for (int i = 0; i < M; i++) {
2428                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2429                             mEnqueuedNotifications.get(i).sbn);
2430                     if (sbn != null) {
2431                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
2432                     }
2433                 }
2434                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2435                 list.addAll(map.values());
2436                 return new ParceledListSlice<StatusBarNotification>(list);
2437             }
2438         }
2439
2440         private StatusBarNotification sanitizeSbn(String pkg, int userId,
2441                 StatusBarNotification sbn) {
2442             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
2443                 // We could pass back a cloneLight() but clients might get confused and
2444                 // try to send this thing back to notify() again, which would not work
2445                 // very well.
2446                 return new StatusBarNotification(
2447                         sbn.getPackageName(),
2448                         sbn.getOpPkg(),
2449                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2450                         sbn.getNotification().clone(),
2451                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2452             }
2453             return null;
2454         }
2455
2456         /**
2457          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2458          *
2459          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2460          */
2461         @Override
2462         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2463             // enforce() will ensure the calling uid has the correct permission
2464             getContext().enforceCallingOrSelfPermission(
2465                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2466                     "NotificationManagerService.getHistoricalNotifications");
2467
2468             StatusBarNotification[] tmp = null;
2469             int uid = Binder.getCallingUid();
2470
2471             // noteOp will check to make sure the callingPkg matches the uid
2472             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2473                     == AppOpsManager.MODE_ALLOWED) {
2474                 synchronized (mArchive) {
2475                     tmp = mArchive.getArray(count);
2476                 }
2477             }
2478             return tmp;
2479         }
2480
2481         /**
2482          * Register a listener binder directly with the notification manager.
2483          *
2484          * Only works with system callers. Apps should extend
2485          * {@link android.service.notification.NotificationListenerService}.
2486          */
2487         @Override
2488         public void registerListener(final INotificationListener listener,
2489                 final ComponentName component, final int userid) {
2490             enforceSystemOrSystemUI("INotificationManager.registerListener");
2491             mListeners.registerService(listener, component, userid);
2492         }
2493
2494         /**
2495          * Remove a listener binder directly
2496          */
2497         @Override
2498         public void unregisterListener(INotificationListener token, int userid) {
2499             mListeners.unregisterService(token, userid);
2500         }
2501
2502         /**
2503          * Allow an INotificationListener to simulate a "clear all" operation.
2504          *
2505          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2506          *
2507          * @param token The binder for the listener, to check that the caller is allowed
2508          */
2509         @Override
2510         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2511             final int callingUid = Binder.getCallingUid();
2512             final int callingPid = Binder.getCallingPid();
2513             long identity = Binder.clearCallingIdentity();
2514             try {
2515                 synchronized (mNotificationLock) {
2516                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2517
2518                     if (keys != null) {
2519                         final int N = keys.length;
2520                         for (int i = 0; i < N; i++) {
2521                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2522                             if (r == null) continue;
2523                             final int userId = r.sbn.getUserId();
2524                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2525                                     !mUserProfiles.isCurrentProfile(userId)) {
2526                                 throw new SecurityException("Disallowed call from listener: "
2527                                         + info.service);
2528                             }
2529                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2530                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2531                                     userId);
2532                         }
2533                     } else {
2534                         cancelAllLocked(callingUid, callingPid, info.userid,
2535                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2536                     }
2537                 }
2538             } finally {
2539                 Binder.restoreCallingIdentity(identity);
2540             }
2541         }
2542
2543         /**
2544          * Handle request from an approved listener to re-enable itself.
2545          *
2546          * @param component The componenet to be re-enabled, caller must match package.
2547          */
2548         @Override
2549         public void requestBindListener(ComponentName component) {
2550             checkCallerIsSystemOrSameApp(component.getPackageName());
2551             long identity = Binder.clearCallingIdentity();
2552             try {
2553                 ManagedServices manager =
2554                         mAssistants.isComponentEnabledForCurrentProfiles(component)
2555                         ? mAssistants
2556                         : mListeners;
2557                 manager.setComponentState(component, true);
2558             } finally {
2559                 Binder.restoreCallingIdentity(identity);
2560             }
2561         }
2562
2563         @Override
2564         public void requestUnbindListener(INotificationListener token) {
2565             long identity = Binder.clearCallingIdentity();
2566             try {
2567                 // allow bound services to disable themselves
2568                 synchronized (mNotificationLock) {
2569                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2570                     info.getOwner().setComponentState(info.component, false);
2571                 }
2572             } finally {
2573                 Binder.restoreCallingIdentity(identity);
2574             }
2575         }
2576
2577         @Override
2578         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2579             long identity = Binder.clearCallingIdentity();
2580             try {
2581                 synchronized (mNotificationLock) {
2582                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2583                     if (keys != null) {
2584                         final int N = keys.length;
2585                         for (int i = 0; i < N; i++) {
2586                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2587                             if (r == null) continue;
2588                             final int userId = r.sbn.getUserId();
2589                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2590                                     !mUserProfiles.isCurrentProfile(userId)) {
2591                                 throw new SecurityException("Disallowed call from listener: "
2592                                         + info.service);
2593                             }
2594                             if (!r.isSeen()) {
2595                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2596                                 reportSeen(r);
2597                                 r.setSeen();
2598                             }
2599                         }
2600                     }
2601                 }
2602             } finally {
2603                 Binder.restoreCallingIdentity(identity);
2604             }
2605         }
2606
2607         /**
2608          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2609          *
2610          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2611          *
2612          * @param info The binder for the listener, to check that the caller is allowed
2613          */
2614         @GuardedBy("mNotificationLock")
2615         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2616                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2617             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2618                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2619                     true,
2620                     userId, REASON_LISTENER_CANCEL, info);
2621         }
2622
2623         /**
2624          * Allow an INotificationListener to snooze a single notification until a context.
2625          *
2626          * @param token The binder for the listener, to check that the caller is allowed
2627          */
2628         @Override
2629         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2630                 String key, String snoozeCriterionId) {
2631             long identity = Binder.clearCallingIdentity();
2632             try {
2633                 synchronized (mNotificationLock) {
2634                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2635                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2636                 }
2637             } finally {
2638                 Binder.restoreCallingIdentity(identity);
2639             }
2640         }
2641
2642         /**
2643          * Allow an INotificationListener to snooze a single notification until a time.
2644          *
2645          * @param token The binder for the listener, to check that the caller is allowed
2646          */
2647         @Override
2648         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2649                 long duration) {
2650             long identity = Binder.clearCallingIdentity();
2651             try {
2652                 synchronized (mNotificationLock) {
2653                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2654                     snoozeNotificationInt(key, duration, null, info);
2655                 }
2656             } finally {
2657                 Binder.restoreCallingIdentity(identity);
2658             }
2659         }
2660
2661         /**
2662          * Allows the notification assistant to un-snooze a single notification.
2663          *
2664          * @param token The binder for the assistant, to check that the caller is allowed
2665          */
2666         @Override
2667         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2668             long identity = Binder.clearCallingIdentity();
2669             try {
2670                 synchronized (mNotificationLock) {
2671                     final ManagedServiceInfo info =
2672                             mAssistants.checkServiceTokenLocked(token);
2673                     unsnoozeNotificationInt(key, info);
2674                 }
2675             } finally {
2676                 Binder.restoreCallingIdentity(identity);
2677             }
2678         }
2679
2680         /**
2681          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2682          *
2683          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2684          *
2685          * @param token The binder for the listener, to check that the caller is allowed
2686          */
2687         @Override
2688         public void cancelNotificationFromListener(INotificationListener token, String pkg,
2689                 String tag, int id) {
2690             final int callingUid = Binder.getCallingUid();
2691             final int callingPid = Binder.getCallingPid();
2692             long identity = Binder.clearCallingIdentity();
2693             try {
2694                 synchronized (mNotificationLock) {
2695                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2696                     if (info.supportsProfiles()) {
2697                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2698                                 + "from " + info.component
2699                                 + " use cancelNotification(key) instead.");
2700                     } else {
2701                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2702                                 pkg, tag, id, info.userid);
2703                     }
2704                 }
2705             } finally {
2706                 Binder.restoreCallingIdentity(identity);
2707             }
2708         }
2709
2710         /**
2711          * Allow an INotificationListener to request the list of outstanding notifications seen by
2712          * the current user. Useful when starting up, after which point the listener callbacks
2713          * should be used.
2714          *
2715          * @param token The binder for the listener, to check that the caller is allowed
2716          * @param keys An array of notification keys to fetch, or null to fetch everything
2717          * @returns The return value will contain the notifications specified in keys, in that
2718          *      order, or if keys is null, all the notifications, in natural order.
2719          */
2720         @Override
2721         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2722                 INotificationListener token, String[] keys, int trim) {
2723             synchronized (mNotificationLock) {
2724                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2725                 final boolean getKeys = keys != null;
2726                 final int N = getKeys ? keys.length : mNotificationList.size();
2727                 final ArrayList<StatusBarNotification> list
2728                         = new ArrayList<StatusBarNotification>(N);
2729                 for (int i=0; i<N; i++) {
2730                     final NotificationRecord r = getKeys
2731                             ? mNotificationsByKey.get(keys[i])
2732                             : mNotificationList.get(i);
2733                     if (r == null) continue;
2734                     StatusBarNotification sbn = r.sbn;
2735                     if (!isVisibleToListener(sbn, info)) continue;
2736                     StatusBarNotification sbnToSend =
2737                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2738                     list.add(sbnToSend);
2739                 }
2740                 return new ParceledListSlice<StatusBarNotification>(list);
2741             }
2742         }
2743
2744         /**
2745          * Allow an INotificationListener to request the list of outstanding snoozed notifications
2746          * seen by the current user. Useful when starting up, after which point the listener
2747          * callbacks should be used.
2748          *
2749          * @param token The binder for the listener, to check that the caller is allowed
2750          * @returns The return value will contain the notifications specified in keys, in that
2751          *      order, or if keys is null, all the notifications, in natural order.
2752          */
2753         @Override
2754         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2755                 INotificationListener token, int trim) {
2756             synchronized (mNotificationLock) {
2757                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2758                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2759                 final int N = snoozedRecords.size();
2760                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2761                 for (int i=0; i < N; i++) {
2762                     final NotificationRecord r = snoozedRecords.get(i);
2763                     if (r == null) continue;
2764                     StatusBarNotification sbn = r.sbn;
2765                     if (!isVisibleToListener(sbn, info)) continue;
2766                     StatusBarNotification sbnToSend =
2767                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2768                     list.add(sbnToSend);
2769                 }
2770                 return new ParceledListSlice<>(list);
2771             }
2772         }
2773
2774         @Override
2775         public void requestHintsFromListener(INotificationListener token, int hints) {
2776             final long identity = Binder.clearCallingIdentity();
2777             try {
2778                 synchronized (mNotificationLock) {
2779                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2780                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2781                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2782                             | HINT_HOST_DISABLE_CALL_EFFECTS;
2783                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
2784                     if (disableEffects) {
2785                         addDisabledHints(info, hints);
2786                     } else {
2787                         removeDisabledHints(info, hints);
2788                     }
2789                     updateListenerHintsLocked();
2790                     updateEffectsSuppressorLocked();
2791                 }
2792             } finally {
2793                 Binder.restoreCallingIdentity(identity);
2794             }
2795         }
2796
2797         @Override
2798         public int getHintsFromListener(INotificationListener token) {
2799             synchronized (mNotificationLock) {
2800                 return mListenerHints;
2801             }
2802         }
2803
2804         @Override
2805         public void requestInterruptionFilterFromListener(INotificationListener token,
2806                 int interruptionFilter) throws RemoteException {
2807             final long identity = Binder.clearCallingIdentity();
2808             try {
2809                 synchronized (mNotificationLock) {
2810                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2811                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2812                     updateInterruptionFilterLocked();
2813                 }
2814             } finally {
2815                 Binder.restoreCallingIdentity(identity);
2816             }
2817         }
2818
2819         @Override
2820         public int getInterruptionFilterFromListener(INotificationListener token)
2821                 throws RemoteException {
2822             synchronized (mNotificationLight) {
2823                 return mInterruptionFilter;
2824             }
2825         }
2826
2827         @Override
2828         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2829                 throws RemoteException {
2830             synchronized (mNotificationLock) {
2831                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2832                 if (info == null) return;
2833                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2834             }
2835         }
2836
2837         @Override
2838         public int getZenMode() {
2839             return mZenModeHelper.getZenMode();
2840         }
2841
2842         @Override
2843         public ZenModeConfig getZenModeConfig() {
2844             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2845             return mZenModeHelper.getConfig();
2846         }
2847
2848         @Override
2849         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2850             enforceSystemOrSystemUI("INotificationManager.setZenMode");
2851             final long identity = Binder.clearCallingIdentity();
2852             try {
2853                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2854             } finally {
2855                 Binder.restoreCallingIdentity(identity);
2856             }
2857         }
2858
2859         @Override
2860         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2861             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2862             return mZenModeHelper.getZenRules();
2863         }
2864
2865         @Override
2866         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2867             Preconditions.checkNotNull(id, "Id is null");
2868             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2869             return mZenModeHelper.getAutomaticZenRule(id);
2870         }
2871
2872         @Override
2873         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2874                 throws RemoteException {
2875             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2876             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2877             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2878             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2879             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2880
2881             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2882                     "addAutomaticZenRule");
2883         }
2884
2885         @Override
2886         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2887                 throws RemoteException {
2888             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2889             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2890             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2891             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2892             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2893
2894             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2895                     "updateAutomaticZenRule");
2896         }
2897
2898         @Override
2899         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2900             Preconditions.checkNotNull(id, "Id is null");
2901             // Verify that they can modify zen rules.
2902             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2903
2904             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2905         }
2906
2907         @Override
2908         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2909             Preconditions.checkNotNull(packageName, "Package name is null");
2910             enforceSystemOrSystemUI("removeAutomaticZenRules");
2911
2912             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2913         }
2914
2915         @Override
2916         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2917             Preconditions.checkNotNull(owner, "Owner is null");
2918             enforceSystemOrSystemUI("getRuleInstanceCount");
2919
2920             return mZenModeHelper.getCurrentInstanceCount(owner);
2921         }
2922
2923         @Override
2924         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2925             enforcePolicyAccess(pkg, "setInterruptionFilter");
2926             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2927             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2928             final long identity = Binder.clearCallingIdentity();
2929             try {
2930                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2931             } finally {
2932                 Binder.restoreCallingIdentity(identity);
2933             }
2934         }
2935
2936         @Override
2937         public void notifyConditions(final String pkg, IConditionProvider provider,
2938                 final Condition[] conditions) {
2939             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2940             checkCallerIsSystemOrSameApp(pkg);
2941             mHandler.post(new Runnable() {
2942                 @Override
2943                 public void run() {
2944                     mConditionProviders.notifyConditions(pkg, info, conditions);
2945                 }
2946             });
2947         }
2948
2949         @Override
2950         public void requestUnbindProvider(IConditionProvider provider) {
2951             long identity = Binder.clearCallingIdentity();
2952             try {
2953                 // allow bound services to disable themselves
2954                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2955                 info.getOwner().setComponentState(info.component, false);
2956             } finally {
2957                 Binder.restoreCallingIdentity(identity);
2958             }
2959         }
2960
2961         @Override
2962         public void requestBindProvider(ComponentName component) {
2963             checkCallerIsSystemOrSameApp(component.getPackageName());
2964             long identity = Binder.clearCallingIdentity();
2965             try {
2966                 mConditionProviders.setComponentState(component, true);
2967             } finally {
2968                 Binder.restoreCallingIdentity(identity);
2969             }
2970         }
2971
2972         private void enforceSystemOrSystemUI(String message) {
2973             if (isCallerSystemOrPhone()) return;
2974             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2975                     message);
2976         }
2977
2978         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2979             try {
2980                 checkCallerIsSystemOrSameApp(pkg);
2981             } catch (SecurityException e) {
2982                 getContext().enforceCallingPermission(
2983                         android.Manifest.permission.STATUS_BAR_SERVICE,
2984                         message);
2985             }
2986         }
2987
2988         private void enforcePolicyAccess(int uid, String method) {
2989             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2990                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2991                 return;
2992             }
2993             boolean accessAllowed = false;
2994             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2995             final int packageCount = packages.length;
2996             for (int i = 0; i < packageCount; i++) {
2997                 if (mConditionProviders.isPackageOrComponentAllowed(
2998                         packages[i], UserHandle.getUserId(uid))) {
2999                     accessAllowed = true;
3000                 }
3001             }
3002             if (!accessAllowed) {
3003                 Slog.w(TAG, "Notification policy access denied calling " + method);
3004                 throw new SecurityException("Notification policy access denied");
3005             }
3006         }
3007
3008         private void enforcePolicyAccess(String pkg, String method) {
3009             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3010                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3011                 return;
3012             }
3013             checkCallerIsSameApp(pkg);
3014             if (!checkPolicyAccess(pkg)) {
3015                 Slog.w(TAG, "Notification policy access denied calling " + method);
3016                 throw new SecurityException("Notification policy access denied");
3017             }
3018         }
3019
3020         private boolean checkPackagePolicyAccess(String pkg) {
3021             return mConditionProviders.isPackageOrComponentAllowed(
3022                     pkg, getCallingUserHandle().getIdentifier());
3023         }
3024
3025         private boolean checkPolicyAccess(String pkg) {
3026             try {
3027                 int uid = getContext().getPackageManager().getPackageUidAsUser(
3028                         pkg, UserHandle.getCallingUserId());
3029                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3030                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3031                         -1, true)) {
3032                     return true;
3033                 }
3034             } catch (NameNotFoundException e) {
3035                 return false;
3036             }
3037             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
3038         }
3039
3040         @Override
3041         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3042             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
3043             final DumpFilter filter = DumpFilter.parseFromArguments(args);
3044             if (filter.stats) {
3045                 dumpJson(pw, filter);
3046             } else if (filter.proto) {
3047                 dumpProto(fd, filter);
3048             } else if (filter.criticalPriority) {
3049                 dumpNotificationRecords(pw, filter);
3050             } else {
3051                 dumpImpl(pw, filter);
3052             }
3053         }
3054
3055         @Override
3056         public ComponentName getEffectsSuppressor() {
3057             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
3058         }
3059
3060         @Override
3061         public boolean matchesCallFilter(Bundle extras) {
3062             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
3063             return mZenModeHelper.matchesCallFilter(
3064                     Binder.getCallingUserHandle(),
3065                     extras,
3066                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3067                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3068                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
3069         }
3070
3071         @Override
3072         public boolean isSystemConditionProviderEnabled(String path) {
3073             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
3074             return mConditionProviders.isSystemProviderEnabled(path);
3075         }
3076
3077         // Backup/restore interface
3078         @Override
3079         public byte[] getBackupPayload(int user) {
3080             checkCallerIsSystem();
3081             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
3082             //TODO: http://b/22388012
3083             if (user != USER_SYSTEM) {
3084                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3085                 return null;
3086             }
3087             synchronized(mPolicyFile) {
3088                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3089                 try {
3090                     writePolicyXml(baos, true /*forBackup*/);
3091                     return baos.toByteArray();
3092                 } catch (IOException e) {
3093                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3094                 }
3095             }
3096             return null;
3097         }
3098
3099         @Override
3100         public void applyRestore(byte[] payload, int user) {
3101             checkCallerIsSystem();
3102             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3103                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3104             if (payload == null) {
3105                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3106                 return;
3107             }
3108             //TODO: http://b/22388012
3109             if (user != USER_SYSTEM) {
3110                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3111                 return;
3112             }
3113             synchronized(mPolicyFile) {
3114                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3115                 try {
3116                     readPolicyXml(bais, true /*forRestore*/);
3117                     savePolicyFile();
3118                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3119                     Slog.w(TAG, "applyRestore: error reading payload", e);
3120                 }
3121             }
3122         }
3123
3124         @Override
3125         public boolean isNotificationPolicyAccessGranted(String pkg) {
3126             return checkPolicyAccess(pkg);
3127         }
3128
3129         @Override
3130         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3131             enforceSystemOrSystemUIOrSamePackage(pkg,
3132                     "request policy access status for another package");
3133             return checkPolicyAccess(pkg);
3134         }
3135
3136         @Override
3137         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3138                 throws RemoteException {
3139             setNotificationPolicyAccessGrantedForUser(
3140                     pkg, getCallingUserHandle().getIdentifier(), granted);
3141         }
3142
3143         @Override
3144         public void setNotificationPolicyAccessGrantedForUser(
3145                 String pkg, int userId, boolean granted) {
3146             checkCallerIsSystemOrShell();
3147             final long identity = Binder.clearCallingIdentity();
3148             try {
3149                 if (canUseManagedServices()) {
3150                     mConditionProviders.setPackageOrComponentEnabled(
3151                             pkg, userId, true, granted);
3152
3153                     getContext().sendBroadcastAsUser(new Intent(
3154                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3155                                     .setPackage(pkg)
3156                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3157                             UserHandle.of(userId), null);
3158                     savePolicyFile();
3159                 }
3160             } finally {
3161                 Binder.restoreCallingIdentity(identity);
3162             }
3163         }
3164
3165         @Override
3166         public Policy getNotificationPolicy(String pkg) {
3167             final long identity = Binder.clearCallingIdentity();
3168             try {
3169                 return mZenModeHelper.getNotificationPolicy();
3170             } finally {
3171                 Binder.restoreCallingIdentity(identity);
3172             }
3173         }
3174
3175         /**
3176          * Sets the notification policy.  Apps that target API levels below
3177          * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
3178          * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3179          * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3180          * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
3181          */
3182         @Override
3183         public void setNotificationPolicy(String pkg, Policy policy) {
3184             enforcePolicyAccess(pkg, "setNotificationPolicy");
3185             final long identity = Binder.clearCallingIdentity();
3186             try {
3187                 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3188                         0, UserHandle.getUserId(MY_UID));
3189                 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
3190
3191                 if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
3192                     int priorityCategories = policy.priorityCategories;
3193                     // ignore alarm and media values from new policy
3194                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
3195                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3196                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
3197                     // use user-designated values
3198                     priorityCategories |= currPolicy.priorityCategories
3199                             & Policy.PRIORITY_CATEGORY_ALARMS;
3200                     priorityCategories |= currPolicy.priorityCategories
3201                             & Policy.PRIORITY_CATEGORY_MEDIA;
3202                     priorityCategories |= currPolicy.priorityCategories
3203                             & Policy.PRIORITY_CATEGORY_SYSTEM;
3204
3205                     policy = new Policy(priorityCategories,
3206                             policy.priorityCallSenders, policy.priorityMessageSenders,
3207                             policy.suppressedVisualEffects);
3208                 }
3209                 int newVisualEffects = calculateSuppressedVisualEffects(
3210                             policy, currPolicy, applicationInfo.targetSdkVersion);
3211                 policy = new Policy(policy.priorityCategories,
3212                         policy.priorityCallSenders, policy.priorityMessageSenders,
3213                         newVisualEffects);
3214
3215                 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
3216                 mZenModeHelper.setNotificationPolicy(policy);
3217             } catch (RemoteException e) {
3218             } finally {
3219                 Binder.restoreCallingIdentity(identity);
3220             }
3221         }
3222
3223         @Override
3224         public List<String> getEnabledNotificationListenerPackages() {
3225             checkCallerIsSystem();
3226             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3227         }
3228
3229         @Override
3230         public List<ComponentName> getEnabledNotificationListeners(int userId) {
3231             checkCallerIsSystem();
3232             return mListeners.getAllowedComponents(userId);
3233         }
3234
3235         @Override
3236         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3237             Preconditions.checkNotNull(listener);
3238             checkCallerIsSystemOrSameApp(listener.getPackageName());
3239             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3240                     getCallingUserHandle().getIdentifier());
3241         }
3242
3243         @Override
3244         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3245                 int userId) {
3246             Preconditions.checkNotNull(listener);
3247             checkCallerIsSystem();
3248             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3249                     userId);
3250         }
3251
3252         @Override
3253         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3254             Preconditions.checkNotNull(assistant);
3255             checkCallerIsSystemOrSameApp(assistant.getPackageName());
3256             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
3257                     getCallingUserHandle().getIdentifier());
3258         }
3259
3260         @Override
3261         public void setNotificationListenerAccessGranted(ComponentName listener,
3262                 boolean granted) throws RemoteException {
3263             setNotificationListenerAccessGrantedForUser(
3264                     listener, getCallingUserHandle().getIdentifier(), granted);
3265         }
3266
3267         @Override
3268         public void setNotificationAssistantAccessGranted(ComponentName assistant,
3269                 boolean granted) throws RemoteException {
3270             setNotificationAssistantAccessGrantedForUser(
3271                     assistant, getCallingUserHandle().getIdentifier(), granted);
3272         }
3273
3274         @Override
3275         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3276                 boolean granted) throws RemoteException {
3277             Preconditions.checkNotNull(listener);
3278             checkCallerIsSystemOrShell();
3279             final long identity = Binder.clearCallingIdentity();
3280             try {
3281                 if (canUseManagedServices()) {
3282                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3283                             userId, false, granted);
3284                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3285                             userId, true, granted);
3286
3287                     getContext().sendBroadcastAsUser(new Intent(
3288                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3289                                     .setPackage(listener.getPackageName())
3290                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3291                             UserHandle.of(userId), null);
3292
3293                     savePolicyFile();
3294                 }
3295             } finally {
3296                 Binder.restoreCallingIdentity(identity);
3297             }
3298         }
3299
3300         @Override
3301         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3302                 int userId, boolean granted) throws RemoteException {
3303             Preconditions.checkNotNull(assistant);
3304             checkCallerIsSystemOrShell();
3305             final long identity = Binder.clearCallingIdentity();
3306             try {
3307                 if (canUseManagedServices()) {
3308                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3309                             userId, false, granted);
3310                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3311                             userId, true, granted);
3312
3313                     getContext().sendBroadcastAsUser(new Intent(
3314                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3315                                     .setPackage(assistant.getPackageName())
3316                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3317                             UserHandle.of(userId), null);
3318
3319                     savePolicyFile();
3320                 }
3321             } finally {
3322                 Binder.restoreCallingIdentity(identity);
3323             }
3324         }
3325
3326         @Override
3327         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3328                 Adjustment adjustment) throws RemoteException {
3329             final long identity = Binder.clearCallingIdentity();
3330             try {
3331                 synchronized (mNotificationLock) {
3332                     mAssistants.checkServiceTokenLocked(token);
3333                     int N = mEnqueuedNotifications.size();
3334                     for (int i = 0; i < N; i++) {
3335                         final NotificationRecord n = mEnqueuedNotifications.get(i);
3336                         if (Objects.equals(adjustment.getKey(), n.getKey())
3337                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3338                             applyAdjustment(n, adjustment);
3339                             break;
3340                         }
3341                     }
3342                 }
3343             } finally {
3344                 Binder.restoreCallingIdentity(identity);
3345             }
3346         }
3347
3348         @Override
3349         public void applyAdjustmentFromAssistant(INotificationListener token,
3350                 Adjustment adjustment) throws RemoteException {
3351             final long identity = Binder.clearCallingIdentity();
3352             try {
3353                 synchronized (mNotificationLock) {
3354                     mAssistants.checkServiceTokenLocked(token);
3355                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3356                     applyAdjustment(n, adjustment);
3357                 }
3358                 mRankingHandler.requestSort();
3359             } finally {
3360                 Binder.restoreCallingIdentity(identity);
3361             }
3362         }
3363
3364         @Override
3365         public void applyAdjustmentsFromAssistant(INotificationListener token,
3366                 List<Adjustment> adjustments) throws RemoteException {
3367
3368             final long identity = Binder.clearCallingIdentity();
3369             try {
3370                 synchronized (mNotificationLock) {
3371                     mAssistants.checkServiceTokenLocked(token);
3372                     for (Adjustment adjustment : adjustments) {
3373                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3374                         applyAdjustment(n, adjustment);
3375                     }
3376                 }
3377                 mRankingHandler.requestSort();
3378             } finally {
3379                 Binder.restoreCallingIdentity(identity);
3380             }
3381         }
3382
3383         @Override
3384         public void updateNotificationChannelGroupFromPrivilegedListener(
3385                 INotificationListener token, String pkg, UserHandle user,
3386                 NotificationChannelGroup group) throws RemoteException {
3387             Preconditions.checkNotNull(user);
3388             verifyPrivilegedListener(token, user);
3389             createNotificationChannelGroup(
3390                     pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3391             savePolicyFile();
3392         }
3393
3394         @Override
3395         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
3396                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
3397             Preconditions.checkNotNull(channel);
3398             Preconditions.checkNotNull(pkg);
3399             Preconditions.checkNotNull(user);
3400
3401             verifyPrivilegedListener(token, user);
3402             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
3403         }
3404
3405         @Override
3406         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
3407                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3408             Preconditions.checkNotNull(pkg);
3409             Preconditions.checkNotNull(user);
3410             verifyPrivilegedListener(token, user);
3411
3412             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3413                     false /* includeDeleted */);
3414         }
3415
3416         @Override
3417         public ParceledListSlice<NotificationChannelGroup>
3418                 getNotificationChannelGroupsFromPrivilegedListener(
3419                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3420             Preconditions.checkNotNull(pkg);
3421             Preconditions.checkNotNull(user);
3422             verifyPrivilegedListener(token, user);
3423
3424             List<NotificationChannelGroup> groups = new ArrayList<>();
3425             groups.addAll(mRankingHelper.getNotificationChannelGroups(
3426                     pkg, getUidForPackageAndUser(pkg, user)));
3427             return new ParceledListSlice<>(groups);
3428         }
3429
3430         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
3431             ManagedServiceInfo info;
3432             synchronized (mNotificationLock) {
3433                 info = mListeners.checkServiceTokenLocked(token);
3434             }
3435             if (!hasCompanionDevice(info)) {
3436                 throw new SecurityException(info + " does not have access");
3437             }
3438             if (!info.enabledAndUserMatches(user.getIdentifier())) {
3439                 throw new SecurityException(info + " does not have access");
3440             }
3441         }
3442
3443         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3444             int uid = 0;
3445             long identity = Binder.clearCallingIdentity();
3446             try {
3447                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3448             } finally {
3449                 Binder.restoreCallingIdentity(identity);
3450             }
3451             return uid;
3452         }
3453
3454         @Override
3455         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3456                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3457                 throws RemoteException {
3458             new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3459         }
3460     };
3461
3462     private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3463         if (r == null) {
3464             return;
3465         }
3466         if (adjustment.getSignals() != null) {
3467             Bundle.setDefusable(adjustment.getSignals(), true);
3468             r.addAdjustment(adjustment);
3469         }
3470     }
3471
3472     @GuardedBy("mNotificationLock")
3473     void addAutogroupKeyLocked(String key) {
3474         NotificationRecord r = mNotificationsByKey.get(key);
3475         if (r == null) {
3476             return;
3477         }
3478         if (r.sbn.getOverrideGroupKey() == null) {
3479             addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3480             EventLogTags.writeNotificationAutogrouped(key);
3481             mRankingHandler.requestSort();
3482         }
3483     }
3484
3485     @GuardedBy("mNotificationLock")
3486     void removeAutogroupKeyLocked(String key) {
3487         NotificationRecord r = mNotificationsByKey.get(key);
3488         if (r == null) {
3489             return;
3490         }
3491         if (r.sbn.getOverrideGroupKey() != null) {
3492             addAutoGroupAdjustment(r, null);
3493             EventLogTags.writeNotificationUnautogrouped(key);
3494             mRankingHandler.requestSort();
3495         }
3496     }
3497
3498     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3499         Bundle signals = new Bundle();
3500         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3501         Adjustment adjustment =
3502                 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3503         r.addAdjustment(adjustment);
3504     }
3505
3506     // Clears the 'fake' auto-group summary.
3507     @GuardedBy("mNotificationLock")
3508     private void clearAutogroupSummaryLocked(int userId, String pkg) {
3509         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3510         if (summaries != null && summaries.containsKey(pkg)) {
3511             // Clear summary.
3512             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
3513             if (removed != null) {
3514                 boolean wasPosted = removeFromNotificationListsLocked(removed);
3515                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
3516             }
3517         }
3518     }
3519
3520     @GuardedBy("mNotificationLock")
3521     private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3522         ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3523         return summaries != null && summaries.containsKey(sbn.getPackageName());
3524     }
3525
3526     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
3527     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3528         NotificationRecord summaryRecord = null;
3529         synchronized (mNotificationLock) {
3530             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3531             if (notificationRecord == null) {
3532                 // The notification could have been cancelled again already. A successive
3533                 // adjustment will post a summary if needed.
3534                 return;
3535             }
3536             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3537             userId = adjustedSbn.getUser().getIdentifier();
3538             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3539             if (summaries == null) {
3540                 summaries = new ArrayMap<>();
3541             }
3542             mAutobundledSummaries.put(userId, summaries);
3543             if (!summaries.containsKey(pkg)) {
3544                 // Add summary
3545                 final ApplicationInfo appInfo =
3546                        adjustedSbn.getNotification().extras.getParcelable(
3547                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
3548                 final Bundle extras = new Bundle();
3549                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
3550                 final String channelId = notificationRecord.getChannel().getId();
3551                 final Notification summaryNotification =
3552                         new Notification.Builder(getContext(), channelId)
3553                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
3554                                 .setGroupSummary(true)
3555                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
3556                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
3557                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3558                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3559                                 .setColor(adjustedSbn.getNotification().color)
3560                                 .setLocalOnly(true)
3561                                 .build();
3562                 summaryNotification.extras.putAll(extras);
3563                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3564                 if (appIntent != null) {
3565                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3566                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3567                 }
3568                 final StatusBarNotification summarySbn =
3569                         new StatusBarNotification(adjustedSbn.getPackageName(),
3570                                 adjustedSbn.getOpPkg(),
3571                                 Integer.MAX_VALUE,
3572                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3573                                 adjustedSbn.getInitialPid(), summaryNotification,
3574                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3575                                 System.currentTimeMillis());
3576                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
3577                         notificationRecord.getChannel());
3578                 summaries.put(pkg, summarySbn.getKey());
3579             }
3580         }
3581         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
3582                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
3583             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
3584         }
3585     }
3586
3587     private String disableNotificationEffects(NotificationRecord record) {
3588         if (mDisableNotificationEffects) {
3589             return "booleanState";
3590         }
3591         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3592             return "listenerHints";
3593         }
3594         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3595             return "callState";
3596         }
3597         return null;
3598     };
3599
3600     private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
3601         JSONObject dump = new JSONObject();
3602         try {
3603             dump.put("service", "Notification Manager");
3604             dump.put("bans", mRankingHelper.dumpBansJson(filter));
3605             dump.put("ranking", mRankingHelper.dumpJson(filter));
3606             dump.put("stats", mUsageStats.dumpJson(filter));
3607             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
3608         } catch (JSONException e) {
3609             e.printStackTrace();
3610         }
3611         pw.println(dump);
3612     }
3613
3614     private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
3615         final ProtoOutputStream proto = new ProtoOutputStream(fd);
3616         synchronized (mNotificationLock) {
3617             int N = mNotificationList.size();
3618             for (int i = 0; i < N; i++) {
3619                 final NotificationRecord nr = mNotificationList.get(i);
3620                 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3621                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3622                         NotificationRecordProto.POSTED);
3623             }
3624             N = mEnqueuedNotifications.size();
3625             for (int i = 0; i < N; i++) {
3626                 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3627                 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3628                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3629                         NotificationRecordProto.ENQUEUED);
3630             }
3631             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3632             N = snoozed.size();
3633             for (int i = 0; i < N; i++) {
3634                 final NotificationRecord nr = snoozed.get(i);
3635                 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3636                 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3637                         NotificationRecordProto.SNOOZED);
3638             }
3639
3640             long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3641             mZenModeHelper.dump(proto);
3642             for (ComponentName suppressor : mEffectsSuppressors) {
3643                 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
3644             }
3645             proto.end(zenLog);
3646
3647             long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3648             mListeners.dump(proto, filter);
3649             proto.end(listenersToken);
3650
3651             proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3652
3653             for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3654                 long effectsToken = proto.start(
3655                     NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3656
3657                 proto.write(
3658                     ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3659                 final ArraySet<ManagedServiceInfo> listeners =
3660                     mListenersDisablingEffects.valueAt(i);
3661                 for (int j = 0; j < listeners.size(); j++) {
3662                     final ManagedServiceInfo listener = listeners.valueAt(i);
3663                     listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
3664                 }
3665
3666                 proto.end(effectsToken);
3667             }
3668
3669             long assistantsToken = proto.start(
3670                 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3671             mAssistants.dump(proto, filter);
3672             proto.end(assistantsToken);
3673
3674             long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3675             mConditionProviders.dump(proto, filter);
3676             proto.end(conditionsToken);
3677
3678             long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3679             mRankingHelper.dump(proto, filter);
3680             proto.end(rankingToken);
3681         }
3682
3683         proto.flush();
3684     }
3685
3686     private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3687         synchronized (mNotificationLock) {
3688             int N;
3689             N = mNotificationList.size();
3690             if (N > 0) {
3691                 pw.println("  Notification List:");
3692                 for (int i = 0; i < N; i++) {
3693                     final NotificationRecord nr = mNotificationList.get(i);
3694                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3695                     nr.dump(pw, "    ", getContext(), filter.redact);
3696                 }
3697                 pw.println("  ");
3698             }
3699         }
3700     }
3701
3702     void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
3703         pw.print("Current Notification Manager state");
3704         if (filter.filtered) {
3705             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
3706         }
3707         pw.println(':');
3708         int N;
3709         final boolean zenOnly = filter.filtered && filter.zen;
3710
3711         if (!zenOnly) {
3712             synchronized (mToastQueue) {
3713                 N = mToastQueue.size();
3714                 if (N > 0) {
3715                     pw.println("  Toast Queue:");
3716                     for (int i=0; i<N; i++) {
3717                         mToastQueue.get(i).dump(pw, "    ", filter);
3718                     }
3719                     pw.println("  ");
3720                 }
3721             }
3722         }
3723
3724         synchronized (mNotificationLock) {
3725             if (!zenOnly) {
3726                 // Priority filters are only set when called via bugreport. If set
3727                 // skip sections that are part of the critical section.
3728                 if (!filter.normalPriority) {
3729                     dumpNotificationRecords(pw, filter);
3730                 }
3731                 if (!filter.filtered) {
3732                     N = mLights.size();
3733                     if (N > 0) {
3734                         pw.println("  Lights List:");
3735                         for (int i=0; i<N; i++) {
3736                             if (i == N - 1) {
3737                                 pw.print("  > ");
3738                             } else {
3739                                 pw.print("    ");
3740                             }
3741                             pw.println(mLights.get(i));
3742                         }
3743                         pw.println("  ");
3744                     }
3745                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
3746                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3747                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
3748                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
3749                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
3750                     pw.println("  mCallState=" + callStateToString(mCallState));
3751                     pw.println("  mSystemReady=" + mSystemReady);
3752                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3753                 }
3754                 pw.println("  mArchive=" + mArchive.toString());
3755                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3756                 int j=0;
3757                 while (iter.hasNext()) {
3758                     final StatusBarNotification sbn = iter.next();
3759                     if (filter != null && !filter.matches(sbn)) continue;
3760                     pw.println("    " + sbn);
3761                     if (++j >= 5) {
3762                         if (iter.hasNext()) pw.println("    ...");
3763                         break;
3764                     }
3765                 }
3766
3767                 if (!zenOnly) {
3768                     N = mEnqueuedNotifications.size();
3769                     if (N > 0) {
3770                         pw.println("  Enqueued Notification List:");
3771                         for (int i = 0; i < N; i++) {
3772                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
3773                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
3774                             nr.dump(pw, "    ", getContext(), filter.redact);
3775                         }
3776                         pw.println("  ");
3777                     }
3778
3779                     mSnoozeHelper.dump(pw, filter);
3780                 }
3781             }
3782
3783             if (!zenOnly) {
3784                 pw.println("\n  Ranking Config:");
3785                 mRankingHelper.dump(pw, "    ", filter);
3786
3787                 pw.println("\n  Notification listeners:");
3788                 mListeners.dump(pw, filter);
3789                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
3790                 pw.print("    mListenersDisablingEffects: (");
3791                 N = mListenersDisablingEffects.size();
3792                 for (int i = 0; i < N; i++) {
3793                     final int hint = mListenersDisablingEffects.keyAt(i);
3794                     if (i > 0) pw.print(';');
3795                     pw.print("hint[" + hint + "]:");
3796
3797                     final ArraySet<ManagedServiceInfo> listeners =
3798                             mListenersDisablingEffects.valueAt(i);
3799                     final int listenerSize = listeners.size();
3800
3801                     for (int j = 0; j < listenerSize; j++) {
3802                         if (i > 0) pw.print(',');
3803                         final ManagedServiceInfo listener = listeners.valueAt(i);
3804                         pw.print(listener.component);
3805                     }
3806                 }
3807                 pw.println(')');
3808                 pw.println("\n  Notification assistant services:");
3809                 mAssistants.dump(pw, filter);
3810             }
3811
3812             if (!filter.filtered || zenOnly) {
3813                 pw.println("\n  Zen Mode:");
3814                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3815                 mZenModeHelper.dump(pw, "    ");
3816
3817                 pw.println("\n  Zen Log:");
3818                 ZenLog.dump(pw, "    ");
3819             }
3820
3821             pw.println("\n  Condition providers:");
3822             mConditionProviders.dump(pw, filter);
3823
3824             pw.println("\n  Group summaries:");
3825             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3826                 NotificationRecord r = entry.getValue();
3827                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
3828                 if (mNotificationsByKey.get(r.getKey()) != r) {
3829                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3830                     r.dump(pw, "      ", getContext(), filter.redact);
3831                 }
3832             }
3833
3834             if (!zenOnly) {
3835                 pw.println("\n  Usage Stats:");
3836                 mUsageStats.dump(pw, "    ", filter);
3837             }
3838         }
3839     }
3840
3841     /**
3842      * The private API only accessible to the system process.
3843      */
3844     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3845         @Override
3846         public NotificationChannel getNotificationChannel(String pkg, int uid, String
3847                 channelId) {
3848             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3849         }
3850
3851         @Override
3852         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3853                 String tag, int id, Notification notification, int userId) {
3854             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3855                     userId);
3856         }
3857
3858         @Override
3859         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3860                 int userId) {
3861             checkCallerIsSystem();
3862             mHandler.post(new Runnable() {
3863                 @Override
3864                 public void run() {
3865                     synchronized (mNotificationLock) {
3866                         removeForegroundServiceFlagByListLocked(
3867                                 mEnqueuedNotifications, pkg, notificationId, userId);
3868                         removeForegroundServiceFlagByListLocked(
3869                                 mNotificationList, pkg, notificationId, userId);
3870                     }
3871                 }
3872             });
3873         }
3874
3875         @GuardedBy("mNotificationLock")
3876         private void removeForegroundServiceFlagByListLocked(
3877                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3878                 int userId) {
3879             NotificationRecord r = findNotificationByListLocked(
3880                     notificationList, pkg, null, notificationId, userId);
3881             if (r == null) {
3882                 return;
3883             }
3884             StatusBarNotification sbn = r.sbn;
3885             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3886             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3887             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3888             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3889             sbn.getNotification().flags =
3890                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3891             mRankingHelper.sort(mNotificationList);
3892             mListeners.notifyPostedLocked(r, sbn /* oldSbn */);
3893         }
3894     };
3895
3896     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3897             final int callingPid, final String tag, final int id, final Notification notification,
3898             int incomingUserId) {
3899         if (DBG) {
3900             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3901                     + " notification=" + notification);
3902         }
3903         checkCallerIsSystemOrSameApp(pkg);
3904
3905         final int userId = ActivityManager.handleIncomingUser(callingPid,
3906                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3907         final UserHandle user = new UserHandle(userId);
3908
3909         if (pkg == null || notification == null) {
3910             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3911                     + " id=" + id + " notification=" + notification);
3912         }
3913
3914         // The system can post notifications for any package, let us resolve that.
3915         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3916
3917         // Fix the notification as best we can.
3918         try {
3919             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3920                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3921                     (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
3922             Notification.addFieldsFromContext(ai, notification);
3923
3924             int canColorize = mPackageManagerClient.checkPermission(
3925                     android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3926             if (canColorize == PERMISSION_GRANTED) {
3927                 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3928             } else {
3929                 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3930             }
3931
3932         } catch (NameNotFoundException e) {
3933             Slog.e(TAG, "Cannot create a context for sending app", e);
3934             return;
3935         }
3936
3937         mUsageStats.registerEnqueuedByApp(pkg);
3938
3939         // setup local book-keeping
3940         String channelId = notification.getChannelId();
3941         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3942             channelId = (new Notification.TvExtender(notification)).getChannelId();
3943         }
3944         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3945                 notificationUid, channelId, false /* includeDeleted */);
3946         if (channel == null) {
3947             final String noChannelStr = "No Channel found for "
3948                     + "pkg=" + pkg
3949                     + ", channelId=" + channelId
3950                     + ", id=" + id
3951                     + ", tag=" + tag
3952                     + ", opPkg=" + opPkg
3953                     + ", callingUid=" + callingUid
3954                     + ", userId=" + userId
3955                     + ", incomingUserId=" + incomingUserId
3956                     + ", notificationUid=" + notificationUid
3957                     + ", notification=" + notification;
3958             Log.e(TAG, noChannelStr);
3959             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3960                     "Failed to post notification on channel \"" + channelId + "\"\n" +
3961                     "See log for more details");
3962             return;
3963         }
3964
3965         final StatusBarNotification n = new StatusBarNotification(
3966                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3967                 user, null, System.currentTimeMillis());
3968         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3969
3970         if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3971                 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3972                 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3973             // Increase the importance of foreground service notifications unless the user had an
3974             // opinion otherwise
3975             if (TextUtils.isEmpty(channelId)
3976                     || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3977                 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3978             } else {
3979                 channel.setImportance(IMPORTANCE_LOW);
3980                 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3981                 r.updateNotificationChannel(channel);
3982             }
3983         }
3984
3985         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3986                 r.sbn.getOverrideGroupKey() != null)) {
3987             return;
3988         }
3989
3990         // Whitelist pending intents.
3991         if (notification.allPendingIntents != null) {
3992             final int intentCount = notification.allPendingIntents.size();
3993             if (intentCount > 0) {
3994                 final ActivityManagerInternal am = LocalServices
3995                         .getService(ActivityManagerInternal.class);
3996                 final long duration = LocalServices.getService(
3997                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3998                 for (int i = 0; i < intentCount; i++) {
3999                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4000                     if (pendingIntent != null) {
4001                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4002                                 WHITELIST_TOKEN, duration);
4003                     }
4004                 }
4005             }
4006         }
4007
4008         mHandler.post(new EnqueueNotificationRunnable(userId, r));
4009     }
4010
4011     private void doChannelWarningToast(CharSequence toastText) {
4012         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4013         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4014                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4015         if (warningEnabled) {
4016             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4017                     Toast.LENGTH_SHORT);
4018             toast.show();
4019         }
4020     }
4021
4022     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4023         // The system can post notifications on behalf of any package it wants
4024         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
4025             try {
4026                 return getContext().getPackageManager()
4027                         .getPackageUidAsUser(opPackageName, userId);
4028             } catch (NameNotFoundException e) {
4029                 /* ignore */
4030             }
4031         }
4032         return callingUid;
4033     }
4034
4035     /**
4036      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4037      *
4038      * Has side effects.
4039      */
4040     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
4041             NotificationRecord r, boolean isAutogroup) {
4042         final String pkg = r.sbn.getPackageName();
4043         final boolean isSystemNotification =
4044                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
4045         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4046
4047         // Limit the number of notifications that any given package except the android
4048         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
4049         if (!isSystemNotification && !isNotificationFromListener) {
4050             synchronized (mNotificationLock) {
4051                 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4052                     // Ephemeral apps have some special constraints for notifications.
4053                     // They are not allowed to create new notifications however they are allowed to
4054                     // update notifications created by the system (e.g. a foreground service
4055                     // notification).
4056                     throw new SecurityException("Instant app " + pkg
4057                             + " cannot create notifications");
4058                 }
4059
4060                 // rate limit updates that aren't completed progress notifications
4061                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
4062                         && !r.getNotification().hasCompletedProgress()
4063                         && !isAutogroup) {
4064
4065                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4066                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
4067                         mUsageStats.registerOverRateQuota(pkg);
4068                         final long now = SystemClock.elapsedRealtime();
4069                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4070                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
4071                                     + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
4072                             mLastOverRateLogTime = now;
4073                         }
4074                         return false;
4075                     }
4076                 }
4077
4078                 // limit the number of outstanding notificationrecords an app can have
4079                 int count = getNotificationCountLocked(pkg, userId, id, tag);
4080                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4081                     mUsageStats.registerOverCountQuota(pkg);
4082                     Slog.e(TAG, "Package has already posted or enqueued " + count
4083                             + " notifications.  Not showing more.  package=" + pkg);
4084                     return false;
4085                 }
4086             }
4087         }
4088
4089         // snoozed apps
4090         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
4091             MetricsLogger.action(r.getLogMaker()
4092                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4093                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
4094             if (DBG) {
4095                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4096             }
4097             mSnoozeHelper.update(userId, r);
4098             savePolicyFile();
4099             return false;
4100         }
4101
4102
4103         // blocked apps
4104         if (isBlocked(r, mUsageStats)) {
4105             return false;
4106         }
4107
4108         return true;
4109     }
4110
4111     @GuardedBy("mNotificationLock")
4112     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4113             String excludedTag) {
4114         int count = 0;
4115         final int N = mNotificationList.size();
4116         for (int i = 0; i < N; i++) {
4117             final NotificationRecord existing = mNotificationList.get(i);
4118             if (existing.sbn.getPackageName().equals(pkg)
4119                     && existing.sbn.getUserId() == userId) {
4120                 if (existing.sbn.getId() == excludedId
4121                         && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4122                     continue;
4123                 }
4124                 count++;
4125             }
4126         }
4127         final int M = mEnqueuedNotifications.size();
4128         for (int i = 0; i < M; i++) {
4129             final NotificationRecord existing = mEnqueuedNotifications.get(i);
4130             if (existing.sbn.getPackageName().equals(pkg)
4131                     && existing.sbn.getUserId() == userId) {
4132                 count++;
4133             }
4134         }
4135         return count;
4136     }
4137
4138     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4139         final String pkg = r.sbn.getPackageName();
4140         final int callingUid = r.sbn.getUid();
4141
4142         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
4143         if (isPackageSuspended) {
4144             Slog.e(TAG, "Suppressing notification from package due to package "
4145                     + "suspended by administrator.");
4146             usageStats.registerSuspendedByAdmin(r);
4147             return isPackageSuspended;
4148         }
4149         final boolean isBlocked =
4150                 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4151                 || mRankingHelper.getImportance(pkg, callingUid)
4152                         == NotificationManager.IMPORTANCE_NONE
4153                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
4154         if (isBlocked) {
4155             Slog.e(TAG, "Suppressing notification from package by user request.");
4156             usageStats.registerBlocked(r);
4157         }
4158         return isBlocked;
4159     }
4160
4161     protected class SnoozeNotificationRunnable implements Runnable {
4162         private final String mKey;
4163         private final long mDuration;
4164         private final String mSnoozeCriterionId;
4165
4166         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4167             mKey = key;
4168             mDuration = duration;
4169             mSnoozeCriterionId = snoozeCriterionId;
4170         }
4171
4172         @Override
4173         public void run() {
4174             synchronized (mNotificationLock) {
4175                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4176                 if (r != null) {
4177                     snoozeLocked(r);
4178                 }
4179             }
4180         }
4181
4182         @GuardedBy("mNotificationLock")
4183         void snoozeLocked(NotificationRecord r) {
4184             if (r.sbn.isGroup()) {
4185                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4186                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4187                 if (r.getNotification().isGroupSummary()) {
4188                     // snooze summary and all children
4189                     for (int i = 0; i < groupNotifications.size(); i++) {
4190                         snoozeNotificationLocked(groupNotifications.get(i));
4191                     }
4192                 } else {
4193                     // if there is a valid summary for this group, and we are snoozing the only
4194                     // child, also snooze the summary
4195                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4196                         if (groupNotifications.size() != 2) {
4197                             snoozeNotificationLocked(r);
4198                         } else {
4199                             // snooze summary and the one child
4200                             for (int i = 0; i < groupNotifications.size(); i++) {
4201                                 snoozeNotificationLocked(groupNotifications.get(i));
4202                             }
4203                         }
4204                     } else {
4205                         snoozeNotificationLocked(r);
4206                     }
4207                 }
4208             } else {
4209                 // just snooze the one notification
4210                 snoozeNotificationLocked(r);
4211             }
4212         }
4213
4214         @GuardedBy("mNotificationLock")
4215         void snoozeNotificationLocked(NotificationRecord r) {
4216             MetricsLogger.action(r.getLogMaker()
4217                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4218                     .setType(MetricsEvent.TYPE_CLOSE)
4219                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4220                             mDuration)
4221                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4222                             mSnoozeCriterionId == null ? 0 : 1));
4223             boolean wasPosted = removeFromNotificationListsLocked(r);
4224             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
4225             updateLightsLocked();
4226             if (mSnoozeCriterionId != null) {
4227                 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
4228                 mSnoozeHelper.snooze(r);
4229             } else {
4230                 mSnoozeHelper.snooze(r, mDuration);
4231             }
4232             r.recordSnoozed();
4233             savePolicyFile();
4234         }
4235     }
4236
4237     protected class EnqueueNotificationRunnable implements Runnable {
4238         private final NotificationRecord r;
4239         private final int userId;
4240
4241         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4242             this.userId = userId;
4243             this.r = r;
4244         };
4245
4246         @Override
4247         public void run() {
4248             synchronized (mNotificationLock) {
4249                 mEnqueuedNotifications.add(r);
4250                 scheduleTimeoutLocked(r);
4251
4252                 final StatusBarNotification n = r.sbn;
4253                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4254                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4255                 if (old != null) {
4256                     // Retain ranking information from previous record
4257                     r.copyRankingInformation(old);
4258                 }
4259
4260                 final int callingUid = n.getUid();
4261                 final int callingPid = n.getInitialPid();
4262                 final Notification notification = n.getNotification();
4263                 final String pkg = n.getPackageName();
4264                 final int id = n.getId();
4265                 final String tag = n.getTag();
4266
4267                 // Handle grouped notifications and bail out early if we
4268                 // can to avoid extracting signals.
4269                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4270
4271                 // if this is a group child, unsnooze parent summary
4272                 if (n.isGroup() && notification.isGroupChild()) {
4273                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4274                 }
4275
4276                 // This conditional is a dirty hack to limit the logging done on
4277                 //     behalf of the download manager without affecting other apps.
4278                 if (!pkg.equals("com.android.providers.downloads")
4279                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4280                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
4281                     if (old != null) {
4282                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
4283                     }
4284                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4285                             pkg, id, tag, userId, notification.toString(),
4286                             enqueueStatus);
4287                 }
4288
4289                 mRankingHelper.extractSignals(r);
4290
4291                 // tell the assistant service about the notification
4292                 if (mAssistants.isEnabled()) {
4293                     mAssistants.onNotificationEnqueued(r);
4294                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
4295                             DELAY_FOR_ASSISTANT_TIME);
4296                 } else {
4297                     mHandler.post(new PostNotificationRunnable(r.getKey()));
4298                 }
4299             }
4300         }
4301     }
4302
4303     @GuardedBy("mNotificationLock")
4304     private boolean isPackageSuspendedLocked(NotificationRecord r) {
4305         final String pkg = r.sbn.getPackageName();
4306         final int callingUid = r.sbn.getUid();
4307
4308         return isPackageSuspendedForUser(pkg, callingUid);
4309     }
4310
4311     protected class PostNotificationRunnable implements Runnable {
4312         private final String key;
4313
4314         PostNotificationRunnable(String key) {
4315             this.key = key;
4316         }
4317
4318         @Override
4319         public void run() {
4320             synchronized (mNotificationLock) {
4321                 try {
4322                     NotificationRecord r = null;
4323                     int N = mEnqueuedNotifications.size();
4324                     for (int i = 0; i < N; i++) {
4325                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4326                         if (Objects.equals(key, enqueued.getKey())) {
4327                             r = enqueued;
4328                             break;
4329                         }
4330                     }
4331                     if (r == null) {
4332                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4333                         return;
4334                     }
4335
4336                     r.setHidden(isPackageSuspendedLocked(r));
4337                     NotificationRecord old = mNotificationsByKey.get(key);
4338                     final StatusBarNotification n = r.sbn;
4339                     final Notification notification = n.getNotification();
4340                     int index = indexOfNotificationLocked(n.getKey());
4341                     if (index < 0) {
4342                         mNotificationList.add(r);
4343                         mUsageStats.registerPostedByApp(r);
4344                         r.setInterruptive(true);
4345                     } else {
4346                         old = mNotificationList.get(index);
4347                         mNotificationList.set(index, r);
4348                         mUsageStats.registerUpdatedByApp(r, old);
4349                         // Make sure we don't lose the foreground service state.
4350                         notification.flags |=
4351                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
4352                         // revoke uri permissions for changed uris
4353                         revokeUriPermissions(r, old);
4354                         r.isUpdate = true;
4355                         r.setInterruptive(isVisuallyInterruptive(old, r));
4356                     }
4357
4358                     mNotificationsByKey.put(n.getKey(), r);
4359
4360                     // Ensure if this is a foreground service that the proper additional
4361                     // flags are set.
4362                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4363                         notification.flags |= Notification.FLAG_ONGOING_EVENT
4364                                 | Notification.FLAG_NO_CLEAR;
4365                     }
4366
4367                     applyZenModeLocked(r);
4368                     mRankingHelper.sort(mNotificationList);
4369
4370                     if (notification.getSmallIcon() != null) {
4371                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
4372                         mListeners.notifyPostedLocked(r, oldSbn);
4373                         if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4374                             mHandler.post(new Runnable() {
4375                                 @Override
4376                                 public void run() {
4377                                     mGroupHelper.onNotificationPosted(
4378                                             n, hasAutoGroupSummaryLocked(n));
4379                                 }
4380                             });
4381                         }
4382                     } else {
4383                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
4384                         if (old != null && !old.isCanceled) {
4385                             mListeners.notifyRemovedLocked(r,
4386                                     NotificationListenerService.REASON_ERROR, null);
4387                             mHandler.post(new Runnable() {
4388                                 @Override
4389                                 public void run() {
4390                                     mGroupHelper.onNotificationRemoved(n);
4391                                 }
4392                             });
4393                         }
4394                         // ATTENTION: in a future release we will bail out here
4395                         // so that we do not play sounds, show lights, etc. for invalid
4396                         // notifications
4397                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4398                                 + n.getPackageName());
4399                     }
4400
4401                     if (!r.isHidden()) {
4402                         buzzBeepBlinkLocked(r);
4403                     }
4404                     maybeRecordInterruptionLocked(r);
4405                 } finally {
4406                     int N = mEnqueuedNotifications.size();
4407                     for (int i = 0; i < N; i++) {
4408                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4409                         if (Objects.equals(key, enqueued.getKey())) {
4410                             mEnqueuedNotifications.remove(i);
4411                             break;
4412                         }
4413                     }
4414                 }
4415             }
4416         }
4417     }
4418
4419     /**
4420      * If the notification differs enough visually, consider it a new interruptive notification.
4421      */
4422     @GuardedBy("mNotificationLock")
4423     @VisibleForTesting
4424     protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
4425         Notification oldN = old.sbn.getNotification();
4426         Notification newN = r.sbn.getNotification();
4427         if (oldN.extras == null || newN.extras == null) {
4428             return false;
4429         }
4430         if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
4431                 newN.extras.get(Notification.EXTRA_TITLE))) {
4432             return true;
4433         }
4434         if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TEXT),
4435                 newN.extras.get(Notification.EXTRA_TEXT))) {
4436             return true;
4437         }
4438         if (oldN.extras.containsKey(Notification.EXTRA_PROGRESS) && newN.hasCompletedProgress()) {
4439             return true;
4440         }
4441         // Actions
4442         if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
4443             return true;
4444         }
4445
4446         try {
4447             Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4448             Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4449
4450             // Style based comparisons
4451             if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
4452                 return true;
4453             }
4454
4455             // Remote views
4456             if (Notification.areRemoteViewsChanged(oldB, newB)) {
4457                 return true;
4458             }
4459         } catch (Exception e) {
4460             Slog.w(TAG, "error recovering builder", e);
4461         }
4462         return false;
4463     }
4464
4465     /**
4466      * Keeps the last 5 packages that have notified, by user.
4467      */
4468     @GuardedBy("mNotificationLock")
4469     @VisibleForTesting
4470     protected void logRecentLocked(NotificationRecord r) {
4471         if (r.isUpdate) {
4472             return;
4473         }
4474         ArrayList<NotifyingApp> recentAppsForUser =
4475                 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4476         NotifyingApp na = new NotifyingApp()
4477                 .setPackage(r.sbn.getPackageName())
4478                 .setUid(r.sbn.getUid())
4479                 .setLastNotified(r.sbn.getPostTime());
4480         // A new notification gets an app moved to the front of the list
4481         for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4482             NotifyingApp naExisting = recentAppsForUser.get(i);
4483             if (na.getPackage().equals(naExisting.getPackage())
4484                     && na.getUid() == naExisting.getUid()) {
4485                 recentAppsForUser.remove(i);
4486                 break;
4487             }
4488         }
4489         // time is always increasing, so always add to the front of the list
4490         recentAppsForUser.add(0, na);
4491         if (recentAppsForUser.size() > 5) {
4492             recentAppsForUser.remove(recentAppsForUser.size() -1);
4493         }
4494         mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4495     }
4496
4497     /**
4498      * Ensures that grouped notification receive their special treatment.
4499      *
4500      * <p>Cancels group children if the new notification causes a group to lose
4501      * its summary.</p>
4502      *
4503      * <p>Updates mSummaryByGroupKey.</p>
4504      */
4505     @GuardedBy("mNotificationLock")
4506     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4507             int callingUid, int callingPid) {
4508         StatusBarNotification sbn = r.sbn;
4509         Notification n = sbn.getNotification();
4510         if (n.isGroupSummary() && !sbn.isAppGroup())  {
4511             // notifications without a group shouldn't be a summary, otherwise autobundling can
4512             // lead to bugs
4513             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4514         }
4515
4516         String group = sbn.getGroupKey();
4517         boolean isSummary = n.isGroupSummary();
4518
4519         Notification oldN = old != null ? old.sbn.getNotification() : null;
4520         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4521         boolean oldIsSummary = old != null && oldN.isGroupSummary();
4522
4523         if (oldIsSummary) {
4524             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4525             if (removedSummary != old) {
4526                 String removedKey =
4527                         removedSummary != null ? removedSummary.getKey() : "<null>";
4528                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4529                         ", removed=" + removedKey);
4530             }
4531         }
4532         if (isSummary) {
4533             mSummaryByGroupKey.put(group, r);
4534         }
4535
4536         // Clear out group children of the old notification if the update
4537         // causes the group summary to go away. This happens when the old
4538         // notification was a summary and the new one isn't, or when the old
4539         // notification was a summary and its group key changed.
4540         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
4541             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4542                     null);
4543         }
4544     }
4545
4546     @VisibleForTesting
4547     @GuardedBy("mNotificationLock")
4548     void scheduleTimeoutLocked(NotificationRecord record) {
4549         if (record.getNotification().getTimeoutAfter() > 0) {
4550             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4551                     REQUEST_CODE_TIMEOUT,
4552                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
4553                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4554                                     .appendPath(record.getKey()).build())
4555                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4556                             .putExtra(EXTRA_KEY, record.getKey()),
4557                     PendingIntent.FLAG_UPDATE_CURRENT);
4558             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4559                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
4560         }
4561     }
4562
4563     @VisibleForTesting
4564     @GuardedBy("mNotificationLock")
4565     void buzzBeepBlinkLocked(NotificationRecord record) {
4566         boolean buzz = false;
4567         boolean beep = false;
4568         boolean blink = false;
4569
4570         final Notification notification = record.sbn.getNotification();
4571         final String key = record.getKey();
4572
4573         // Should this notification make noise, vibe, or use the LED?
4574         final boolean aboveThreshold =
4575                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
4576
4577         // Remember if this notification already owns the notification channels.
4578         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4579         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
4580         // These are set inside the conditional if the notification is allowed to make noise.
4581         boolean hasValidVibrate = false;
4582         boolean hasValidSound = false;
4583         boolean sentAccessibilityEvent = false;
4584         // If the notification will appear in the status bar, it should send an accessibility
4585         // event
4586         if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4587             sendAccessibilityEvent(notification, record.sbn.getPackageName());
4588             sentAccessibilityEvent = true;
4589         }
4590
4591         if (aboveThreshold && isNotificationForCurrentUser(record)) {
4592
4593             if (mSystemReady && mAudioManager != null) {
4594                 Uri soundUri = record.getSound();
4595                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4596                 long[] vibration = record.getVibration();
4597                 // Demote sound to vibration if vibration missing & phone in vibration mode.
4598                 if (vibration == null
4599                         && hasValidSound
4600                         && (mAudioManager.getRingerModeInternal()
4601                         == AudioManager.RINGER_MODE_VIBRATE)
4602                         && mAudioManager.getStreamVolume(
4603                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
4604                     vibration = mFallbackVibrationPattern;
4605                 }
4606                 hasValidVibrate = vibration != null;
4607
4608                 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
4609                 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
4610                     if (!sentAccessibilityEvent) {
4611                         sendAccessibilityEvent(notification, record.sbn.getPackageName());
4612                         sentAccessibilityEvent = true;
4613                     }
4614                     if (DBG) Slog.v(TAG, "Interrupting!");
4615                     if (hasValidSound) {
4616                         mSoundNotificationKey = key;
4617                         if (mInCall) {
4618                             playInCallNotification();
4619                             beep = true;
4620                         } else {
4621                             beep = playSound(record, soundUri);
4622                         }
4623                     }
4624
4625                     final boolean ringerModeSilent =
4626                             mAudioManager.getRingerModeInternal()
4627                                     == AudioManager.RINGER_MODE_SILENT;
4628                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4629                         mVibrateNotificationKey = key;
4630
4631                         buzz = playVibration(record, vibration, hasValidSound);
4632                     }
4633                 }
4634             }
4635         }
4636         // If a notification is updated to remove the actively playing sound or vibrate,
4637         // cancel that feedback now
4638         if (wasBeep && !hasValidSound) {
4639             clearSoundLocked();
4640         }
4641         if (wasBuzz && !hasValidVibrate) {
4642             clearVibrateLocked();
4643         }
4644
4645         // light
4646         // release the light
4647         boolean wasShowLights = mLights.remove(key);
4648         if (record.getLight() != null && aboveThreshold
4649                 && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
4650             mLights.add(key);
4651             updateLightsLocked();
4652             if (mUseAttentionLight) {
4653                 mAttentionLight.pulse();
4654             }
4655             blink = true;
4656         } else if (wasShowLights) {
4657             updateLightsLocked();
4658         }
4659         if (buzz || beep || blink) {
4660             record.setInterruptive(true);
4661             MetricsLogger.action(record.getLogMaker()
4662                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4663                     .setType(MetricsEvent.TYPE_OPEN)
4664                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4665             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
4666         }
4667     }
4668
4669     @GuardedBy("mNotificationLock")
4670     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
4671         // Suppressed because it's a silent update
4672         final Notification notification = record.getNotification();
4673         if(record.isUpdate
4674                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4675             return true;
4676         }
4677
4678         // muted by listener
4679         final String disableEffects = disableNotificationEffects(record);
4680         if (disableEffects != null) {
4681             ZenLog.traceDisableEffects(record, disableEffects);
4682             return true;
4683         }
4684
4685         // suppressed due to DND
4686         if (record.isIntercepted()) {
4687             return true;
4688         }
4689
4690         // Suppressed because another notification in its group handles alerting
4691         if (record.sbn.isGroup()) {
4692             return notification.suppressAlertingDueToGrouping();
4693         }
4694
4695         // Suppressed for being too recently noisy
4696         final String pkg = record.sbn.getPackageName();
4697         if (mUsageStats.isAlertRateLimited(pkg)) {
4698             Slog.e(TAG, "Muting recently noisy " + record.getKey());
4699             return true;
4700         }
4701
4702         return false;
4703     }
4704
4705     private boolean playSound(final NotificationRecord record, Uri soundUri) {
4706         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4707         // play notifications if there is no user of exclusive audio focus
4708         // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4709         //   VIBRATE ringer mode)
4710         if (!mAudioManager.isAudioFocusExclusive()
4711                 && (mAudioManager.getStreamVolume(
4712                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
4713             final long identity = Binder.clearCallingIdentity();
4714             try {
4715                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4716                 if (player != null) {
4717                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4718                             + " with attributes " + record.getAudioAttributes());
4719                     player.playAsync(soundUri, record.sbn.getUser(), looping,
4720                             record.getAudioAttributes());
4721                     return true;
4722                 }
4723             } catch (RemoteException e) {
4724             } finally {
4725                 Binder.restoreCallingIdentity(identity);
4726             }
4727         }
4728         return false;
4729     }
4730
4731     private boolean playVibration(final NotificationRecord record, long[] vibration,
4732             boolean delayVibForSound) {
4733         // Escalate privileges so we can use the vibrator even if the
4734         // notifying app does not have the VIBRATE permission.
4735         long identity = Binder.clearCallingIdentity();
4736         try {
4737             final VibrationEffect effect;
4738             try {
4739                 final boolean insistent =
4740                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4741                 effect = VibrationEffect.createWaveform(
4742                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
4743             } catch (IllegalArgumentException e) {
4744                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4745                         Arrays.toString(vibration));
4746                 return false;
4747             }
4748             if (delayVibForSound) {
4749                 new Thread(() -> {
4750                     // delay the vibration by the same amount as the notification sound
4751                     final int waitMs = mAudioManager.getFocusRampTimeMs(
4752                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4753                             record.getAudioAttributes());
4754                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4755                     try {
4756                         Thread.sleep(waitMs);
4757                     } catch (InterruptedException e) { }
4758                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4759                             effect, record.getAudioAttributes());
4760                 }).start();
4761             } else {
4762                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4763                         effect, record.getAudioAttributes());
4764             }
4765             return true;
4766         } finally{
4767             Binder.restoreCallingIdentity(identity);
4768         }
4769     }
4770
4771     private boolean isNotificationForCurrentUser(NotificationRecord record) {
4772         final int currentUser;
4773         final long token = Binder.clearCallingIdentity();
4774         try {
4775             currentUser = ActivityManager.getCurrentUser();
4776         } finally {
4777             Binder.restoreCallingIdentity(token);
4778         }
4779         return (record.getUserId() == UserHandle.USER_ALL ||
4780                 record.getUserId() == currentUser ||
4781                 mUserProfiles.isCurrentProfile(record.getUserId()));
4782     }
4783
4784     protected void playInCallNotification() {
4785         new Thread() {
4786             @Override
4787             public void run() {
4788                 final long identity = Binder.clearCallingIdentity();
4789                 try {
4790                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4791                     if (player != null) {
4792                         player.play(new Binder(), mInCallNotificationUri,
4793                                 mInCallNotificationAudioAttributes,
4794                                 mInCallNotificationVolume, false);
4795                     }
4796                 } catch (RemoteException e) {
4797                 } finally {
4798                     Binder.restoreCallingIdentity(identity);
4799                 }
4800             }
4801         }.start();
4802     }
4803
4804     @GuardedBy("mToastQueue")
4805     void showNextToastLocked() {
4806         ToastRecord record = mToastQueue.get(0);
4807         while (record != null) {
4808             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4809             try {
4810                 record.callback.show(record.token);
4811                 scheduleDurationReachedLocked(record);
4812                 return;
4813             } catch (RemoteException e) {
4814                 Slog.w(TAG, "Object died trying to show notification " + record.callback
4815                         + " in package " + record.pkg);
4816                 // remove it from the list and let the process die
4817                 int index = mToastQueue.indexOf(record);
4818                 if (index >= 0) {
4819                     mToastQueue.remove(index);
4820                 }
4821                 keepProcessAliveIfNeededLocked(record.pid);
4822                 if (mToastQueue.size() > 0) {
4823                     record = mToastQueue.get(0);
4824                 } else {
4825                     record = null;
4826                 }
4827             }
4828         }
4829     }
4830
4831     @GuardedBy("mToastQueue")
4832     void cancelToastLocked(int index) {
4833         ToastRecord record = mToastQueue.get(index);
4834         try {
4835             record.callback.hide();
4836         } catch (RemoteException e) {
4837             Slog.w(TAG, "Object died trying to hide notification " + record.callback
4838                     + " in package " + record.pkg);
4839             // don't worry about this, we're about to remove it from
4840             // the list anyway
4841         }
4842
4843         ToastRecord lastToast = mToastQueue.remove(index);
4844
4845         mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
4846                 DEFAULT_DISPLAY);
4847         // We passed 'false' for 'removeWindows' so that the client has time to stop
4848         // rendering (as hide above is a one-way message), otherwise we could crash
4849         // a client which was actively using a surface made from the token. However
4850         // we need to schedule a timeout to make sure the token is eventually killed
4851         // one way or another.
4852         scheduleKillTokenTimeout(lastToast.token);
4853
4854         keepProcessAliveIfNeededLocked(record.pid);
4855         if (mToastQueue.size() > 0) {
4856             // Show the next one. If the callback fails, this will remove
4857             // it from the list, so don't assume that the list hasn't changed
4858             // after this point.
4859             showNextToastLocked();
4860         }
4861     }
4862
4863     void finishTokenLocked(IBinder t) {
4864         mHandler.removeCallbacksAndMessages(t);
4865         // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
4866         // remaining surfaces as either the client has called finishToken indicating
4867         // it has successfully removed the views, or the client has timed out
4868         // at which point anything goes.
4869         mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
4870                 DEFAULT_DISPLAY);
4871     }
4872
4873     @GuardedBy("mToastQueue")
4874     private void scheduleDurationReachedLocked(ToastRecord r)
4875     {
4876         mHandler.removeCallbacksAndMessages(r);
4877         Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
4878         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4879         mHandler.sendMessageDelayed(m, delay);
4880     }
4881
4882     private void handleDurationReached(ToastRecord record)
4883     {
4884         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4885         synchronized (mToastQueue) {
4886             int index = indexOfToastLocked(record.pkg, record.callback);
4887             if (index >= 0) {
4888                 cancelToastLocked(index);
4889             }
4890         }
4891     }
4892
4893     @GuardedBy("mToastQueue")
4894     private void scheduleKillTokenTimeout(IBinder token)
4895     {
4896         mHandler.removeCallbacksAndMessages(token);
4897         Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
4898         mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
4899     }
4900
4901     private void handleKillTokenTimeout(IBinder token)
4902     {
4903         if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
4904         synchronized (mToastQueue) {
4905             finishTokenLocked(token);
4906         }
4907     }
4908
4909     @GuardedBy("mToastQueue")
4910     int indexOfToastLocked(String pkg, ITransientNotification callback)
4911     {
4912         IBinder cbak = callback.asBinder();
4913         ArrayList<ToastRecord> list = mToastQueue;
4914         int len = list.size();
4915         for (int i=0; i<len; i++) {
4916             ToastRecord r = list.get(i);
4917             if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4918                 return i;
4919             }
4920         }
4921         return -1;
4922     }
4923
4924     @GuardedBy("mToastQueue")
4925     int indexOfToastPackageLocked(String pkg)
4926     {
4927         ArrayList<ToastRecord> list = mToastQueue;
4928         int len = list.size();
4929         for (int i=0; i<len; i++) {
4930             ToastRecord r = list.get(i);
4931             if (r.pkg.equals(pkg)) {
4932                 return i;
4933             }
4934         }
4935         return -1;
4936     }
4937
4938     @GuardedBy("mToastQueue")
4939     void keepProcessAliveIfNeededLocked(int pid)
4940     {
4941         int toastCount = 0; // toasts from this pid
4942         ArrayList<ToastRecord> list = mToastQueue;
4943         int N = list.size();
4944         for (int i=0; i<N; i++) {
4945             ToastRecord r = list.get(i);
4946             if (r.pid == pid) {
4947                 toastCount++;
4948             }
4949         }
4950         try {
4951             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4952         } catch (RemoteException e) {
4953             // Shouldn't happen.
4954         }
4955     }
4956
4957     private void handleRankingReconsideration(Message message) {
4958         if (!(message.obj instanceof RankingReconsideration)) return;
4959         RankingReconsideration recon = (RankingReconsideration) message.obj;
4960         recon.run();
4961         boolean changed;
4962         synchronized (mNotificationLock) {
4963             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4964             if (record == null) {
4965                 return;
4966             }
4967             int indexBefore = findNotificationRecordIndexLocked(record);
4968             boolean interceptBefore = record.isIntercepted();
4969             float contactAffinityBefore = record.getContactAffinity();
4970             int visibilityBefore = record.getPackageVisibilityOverride();
4971             recon.applyChangesLocked(record);
4972             applyZenModeLocked(record);
4973             mRankingHelper.sort(mNotificationList);
4974             int indexAfter = findNotificationRecordIndexLocked(record);
4975             boolean interceptAfter = record.isIntercepted();
4976             float contactAffinityAfter = record.getContactAffinity();
4977             int visibilityAfter = record.getPackageVisibilityOverride();
4978             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4979                     || visibilityBefore != visibilityAfter;
4980             if (interceptBefore && !interceptAfter
4981                     && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4982                 buzzBeepBlinkLocked(record);
4983             }
4984         }
4985         if (changed) {
4986             mHandler.scheduleSendRankingUpdate();
4987         }
4988     }
4989
4990     void handleRankingSort() {
4991         if (mRankingHelper == null) return;
4992         synchronized (mNotificationLock) {
4993             final int N = mNotificationList.size();
4994             // Any field that can change via one of the extractors needs to be added here.
4995             ArrayList<String> orderBefore = new ArrayList<>(N);
4996             int[] visibilities = new int[N];
4997             boolean[] showBadges = new boolean[N];
4998             ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4999             ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5000             ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5001             ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
5002             ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
5003             ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
5004             for (int i = 0; i < N; i++) {
5005                 final NotificationRecord r = mNotificationList.get(i);
5006                 orderBefore.add(r.getKey());
5007                 visibilities[i] = r.getPackageVisibilityOverride();
5008                 showBadges[i] = r.canShowBadge();
5009                 channelBefore.add(r.getChannel());
5010                 groupKeyBefore.add(r.getGroupKey());
5011                 overridePeopleBefore.add(r.getPeopleOverride());
5012                 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
5013                 userSentimentBefore.add(r.getUserSentiment());
5014                 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
5015                 mRankingHelper.extractSignals(r);
5016             }
5017             mRankingHelper.sort(mNotificationList);
5018             for (int i = 0; i < N; i++) {
5019                 final NotificationRecord r = mNotificationList.get(i);
5020                 if (!orderBefore.get(i).equals(r.getKey())
5021                         || visibilities[i] != r.getPackageVisibilityOverride()
5022                         || showBadges[i] != r.canShowBadge()
5023                         || !Objects.equals(channelBefore.get(i), r.getChannel())
5024                         || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5025                         || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
5026                         || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
5027                         || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5028                         || !Objects.equals(suppressVisuallyBefore.get(i),
5029                         r.getSuppressedVisualEffects())) {
5030                     mHandler.scheduleSendRankingUpdate();
5031                     return;
5032                 }
5033             }
5034         }
5035     }
5036
5037     @GuardedBy("mNotificationLock")
5038     private void recordCallerLocked(NotificationRecord record) {
5039         if (mZenModeHelper.isCall(record)) {
5040             mZenModeHelper.recordCaller(record);
5041         }
5042     }
5043
5044     // let zen mode evaluate this record
5045     @GuardedBy("mNotificationLock")
5046     private void applyZenModeLocked(NotificationRecord record) {
5047         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
5048         if (record.isIntercepted()) {
5049             record.setSuppressedVisualEffects(
5050                     mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
5051         } else {
5052             record.setSuppressedVisualEffects(0);
5053         }
5054     }
5055
5056     @GuardedBy("mNotificationLock")
5057     private int findNotificationRecordIndexLocked(NotificationRecord target) {
5058         return mRankingHelper.indexOf(mNotificationList, target);
5059     }
5060
5061     private void handleSendRankingUpdate() {
5062         synchronized (mNotificationLock) {
5063             mListeners.notifyRankingUpdateLocked(null);
5064         }
5065     }
5066
5067     private void scheduleListenerHintsChanged(int state) {
5068         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5069         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
5070     }
5071
5072     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5073         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5074         mHandler.obtainMessage(
5075                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5076                 listenerInterruptionFilter,
5077                 0).sendToTarget();
5078     }
5079
5080     private void handleListenerHintsChanged(int hints) {
5081         synchronized (mNotificationLock) {
5082             mListeners.notifyListenerHintsChangedLocked(hints);
5083         }
5084     }
5085
5086     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
5087         synchronized (mNotificationLock) {
5088             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5089         }
5090     }
5091
5092     protected class WorkerHandler extends Handler
5093     {
5094         public WorkerHandler(Looper looper) {
5095             super(looper);
5096         }
5097
5098         @Override
5099         public void handleMessage(Message msg)
5100         {
5101             switch (msg.what)
5102             {
5103                 case MESSAGE_DURATION_REACHED:
5104                     handleDurationReached((ToastRecord)msg.obj);
5105                     break;
5106                 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5107                     handleKillTokenTimeout((IBinder)msg.obj);
5108                     break;
5109                 case MESSAGE_SAVE_POLICY_FILE:
5110                     handleSavePolicyFile();
5111                     break;
5112                 case MESSAGE_SEND_RANKING_UPDATE:
5113                     handleSendRankingUpdate();
5114                     break;
5115                 case MESSAGE_LISTENER_HINTS_CHANGED:
5116                     handleListenerHintsChanged(msg.arg1);
5117                     break;
5118                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5119                     handleListenerInterruptionFilterChanged(msg.arg1);
5120                     break;
5121             }
5122         }
5123
5124         protected void scheduleSendRankingUpdate() {
5125             if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5126                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5127                 sendMessage(m);
5128             }
5129         }
5130
5131     }
5132
5133     private final class RankingHandlerWorker extends Handler implements RankingHandler
5134     {
5135         public RankingHandlerWorker(Looper looper) {
5136             super(looper);
5137         }
5138
5139         @Override
5140         public void handleMessage(Message msg) {
5141             switch (msg.what) {
5142                 case MESSAGE_RECONSIDER_RANKING:
5143                     handleRankingReconsideration(msg);
5144                     break;
5145                 case MESSAGE_RANKING_SORT:
5146                     handleRankingSort();
5147                     break;
5148             }
5149         }
5150
5151         public void requestSort() {
5152             removeMessages(MESSAGE_RANKING_SORT);
5153             Message msg = Message.obtain();
5154             msg.what = MESSAGE_RANKING_SORT;
5155             sendMessage(msg);
5156         }
5157
5158         public void requestReconsideration(RankingReconsideration recon) {
5159             Message m = Message.obtain(this,
5160                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5161             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5162             sendMessageDelayed(m, delay);
5163         }
5164     }
5165
5166     // Notifications
5167     // ============================================================================
5168     static int clamp(int x, int low, int high) {
5169         return (x < low) ? low : ((x > high) ? high : x);
5170     }
5171
5172     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
5173         if (!mAccessibilityManager.isEnabled()) {
5174             return;
5175         }
5176
5177         AccessibilityEvent event =
5178             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5179         event.setPackageName(packageName);
5180         event.setClassName(Notification.class.getName());
5181         event.setParcelableData(notification);
5182         CharSequence tickerText = notification.tickerText;
5183         if (!TextUtils.isEmpty(tickerText)) {
5184             event.getText().add(tickerText);
5185         }
5186
5187         mAccessibilityManager.sendAccessibilityEvent(event);
5188     }
5189
5190     /**
5191      * Removes all NotificationsRecords with the same key as the given notification record
5192      * from both lists. Do not call this method while iterating over either list.
5193      */
5194     @GuardedBy("mNotificationLock")
5195     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5196         // Remove from both lists, either list could have a separate Record for what is
5197         // effectively the same notification.
5198         boolean wasPosted = false;
5199         NotificationRecord recordInList = null;
5200         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5201                 != null) {
5202             mNotificationList.remove(recordInList);
5203             mNotificationsByKey.remove(recordInList.sbn.getKey());
5204             wasPosted = true;
5205         }
5206         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
5207                 != null) {
5208             mEnqueuedNotifications.remove(recordInList);
5209         }
5210         return wasPosted;
5211     }
5212
5213     @GuardedBy("mNotificationLock")
5214     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5215             boolean wasPosted, String listenerName) {
5216         final String canceledKey = r.getKey();
5217
5218         // Record caller.
5219         recordCallerLocked(r);
5220
5221         if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5222             r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5223         }
5224
5225         // Revoke permissions
5226         revokeUriPermissions(null, r);
5227
5228         // tell the app
5229         if (sendDelete) {
5230             if (r.getNotification().deleteIntent != null) {
5231                 try {
5232                     r.getNotification().deleteIntent.send();
5233                 } catch (PendingIntent.CanceledException ex) {
5234                     // do nothing - there's no relevant way to recover, and
5235                     //     no reason to let this propagate
5236                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
5237                 }
5238             }
5239         }
5240
5241         // Only cancel these if this notification actually got to be posted.
5242         if (wasPosted) {
5243             // status bar
5244             if (r.getNotification().getSmallIcon() != null) {
5245                 if (reason != REASON_SNOOZED) {
5246                     r.isCanceled = true;
5247                 }
5248                 mListeners.notifyRemovedLocked(r, reason, r.getStats());
5249                 mHandler.post(new Runnable() {
5250                     @Override
5251                     public void run() {
5252                         mGroupHelper.onNotificationRemoved(r.sbn);
5253                     }
5254                 });
5255             }
5256
5257             // sound
5258             if (canceledKey.equals(mSoundNotificationKey)) {
5259                 mSoundNotificationKey = null;
5260                 final long identity = Binder.clearCallingIdentity();
5261                 try {
5262                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5263                     if (player != null) {
5264                         player.stopAsync();
5265                     }
5266                 } catch (RemoteException e) {
5267                 } finally {
5268                     Binder.restoreCallingIdentity(identity);
5269                 }
5270             }
5271
5272             // vibrate
5273             if (canceledKey.equals(mVibrateNotificationKey)) {
5274                 mVibrateNotificationKey = null;
5275                 long identity = Binder.clearCallingIdentity();
5276                 try {
5277                     mVibrator.cancel();
5278                 }
5279                 finally {
5280                     Binder.restoreCallingIdentity(identity);
5281                 }
5282             }
5283
5284             // light
5285             mLights.remove(canceledKey);
5286         }
5287
5288         // Record usage stats
5289         // TODO: add unbundling stats?
5290         switch (reason) {
5291             case REASON_CANCEL:
5292             case REASON_CANCEL_ALL:
5293             case REASON_LISTENER_CANCEL:
5294             case REASON_LISTENER_CANCEL_ALL:
5295                 mUsageStats.registerDismissedByUser(r);
5296                 break;
5297             case REASON_APP_CANCEL:
5298             case REASON_APP_CANCEL_ALL:
5299                 mUsageStats.registerRemovedByApp(r);
5300                 break;
5301         }
5302
5303         String groupKey = r.getGroupKey();
5304         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
5305         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
5306             mSummaryByGroupKey.remove(groupKey);
5307         }
5308         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5309         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5310             summaries.remove(r.sbn.getPackageName());
5311         }
5312
5313         // Save it for users of getHistoricalNotifications()
5314         mArchive.record(r.sbn);
5315
5316         final long now = System.currentTimeMillis();
5317         MetricsLogger.action(r.getLogMaker(now)
5318                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5319                 .setType(MetricsEvent.TYPE_DISMISS)
5320                 .setSubtype(reason));
5321         EventLogTags.writeNotificationCanceled(canceledKey, reason,
5322                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
5323     }
5324
5325     void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) {
5326         Set<Uri> oldUris = oldRecord.getNotificationUris();
5327         Set<Uri> newUris = newRecord == null ? new HashSet<>() : newRecord.getNotificationUris();
5328         oldUris.removeAll(newUris);
5329
5330         long ident = Binder.clearCallingIdentity();
5331         try {
5332             for (Uri uri : oldUris) {
5333                 if (uri != null) {
5334                     int notiUserId = oldRecord.getUserId();
5335                     int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
5336                             : ContentProvider.getUserIdFromUri(uri, notiUserId);
5337                     uri = ContentProvider.getUriWithoutUserId(uri);
5338                     mAm.revokeUriPermissionFromOwner(mPermissionOwner,
5339                             uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId);
5340                 }
5341             }
5342         } catch (RemoteException e) {
5343             Log.e(TAG, "Count not revoke uri permissions", e);
5344         } finally {
5345             Binder.restoreCallingIdentity(ident);
5346         }
5347     }
5348
5349     /**
5350      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5351      * and none of the {@code mustNotHaveFlags}.
5352      */
5353     void cancelNotification(final int callingUid, final int callingPid,
5354             final String pkg, final String tag, final int id,
5355             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5356             final int userId, final int reason, final ManagedServiceInfo listener) {
5357
5358         // In enqueueNotificationInternal notifications are added by scheduling the
5359         // work on the worker handler. Hence, we also schedule the cancel on this
5360         // handler to avoid a scenario where an add notification call followed by a
5361         // remove notification call ends up in not removing the notification.
5362         mHandler.post(new Runnable() {
5363             @Override
5364             public void run() {
5365                 String listenerName = listener == null ? null : listener.component.toShortString();
5366                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5367                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
5368
5369                 synchronized (mNotificationLock) {
5370                     // Look for the notification, searching both the posted and enqueued lists.
5371                     NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5372                     if (r != null) {
5373                         // The notification was found, check if it should be removed.
5374
5375                         // Ideally we'd do this in the caller of this method. However, that would
5376                         // require the caller to also find the notification.
5377                         if (reason == REASON_CLICK) {
5378                             mUsageStats.registerClickedByUser(r);
5379                         }
5380
5381                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5382                             return;
5383                         }
5384                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5385                             return;
5386                         }
5387
5388                         // Cancel the notification.
5389                         boolean wasPosted = removeFromNotificationListsLocked(r);
5390                         cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
5391                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
5392                                 sendDelete, null);
5393                         updateLightsLocked();
5394                     } else {
5395                         // No notification was found, assume that it is snoozed and cancel it.
5396                         if (reason != REASON_SNOOZED) {
5397                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5398                             if (wasSnoozed) {
5399                                 savePolicyFile();
5400                             }
5401                         }
5402                     }
5403                 }
5404             }
5405         });
5406     }
5407
5408     /**
5409      * Determine whether the userId applies to the notification in question, either because
5410      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5411      */
5412     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5413         return
5414                 // looking for USER_ALL notifications? match everything
5415                    userId == UserHandle.USER_ALL
5416                 // a notification sent to USER_ALL matches any query
5417                 || r.getUserId() == UserHandle.USER_ALL
5418                 // an exact user match
5419                 || r.getUserId() == userId;
5420     }
5421
5422     /**
5423      * Determine whether the userId applies to the notification in question, either because
5424      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
5425      * because it matches one of the users profiles.
5426      */
5427     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
5428         return notificationMatchesUserId(r, userId)
5429                 || mUserProfiles.isCurrentProfile(r.getUserId());
5430     }
5431
5432     /**
5433      * Cancels all notifications from a given package that have all of the
5434      * {@code mustHaveFlags}.
5435      */
5436     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
5437             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
5438             ManagedServiceInfo listener) {
5439         mHandler.post(new Runnable() {
5440             @Override
5441             public void run() {
5442                 String listenerName = listener == null ? null : listener.component.toShortString();
5443                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5444                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5445                         listenerName);
5446
5447                 // Why does this parameter exist? Do we actually want to execute the above if doit
5448                 // is false?
5449                 if (!doit) {
5450                     return;
5451                 }
5452
5453                 synchronized (mNotificationLock) {
5454                     FlagChecker flagChecker = (int flags) -> {
5455                         if ((flags & mustHaveFlags) != mustHaveFlags) {
5456                             return false;
5457                         }
5458                         if ((flags & mustNotHaveFlags) != 0) {
5459                             return false;
5460                         }
5461                         return true;
5462                     };
5463                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5464                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5465                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
5466                             listenerName, true /* wasPosted */);
5467                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5468                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5469                             flagChecker, false /*includeCurrentProfiles*/, userId,
5470                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
5471                     mSnoozeHelper.cancel(userId, pkg);
5472                 }
5473             }
5474         });
5475     }
5476
5477     private interface FlagChecker {
5478         // Returns false if these flags do not pass the defined flag test.
5479         public boolean apply(int flags);
5480     }
5481
5482     @GuardedBy("mNotificationLock")
5483     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5484             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5485             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
5486             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
5487         ArrayList<NotificationRecord> canceledNotifications = null;
5488         for (int i = notificationList.size() - 1; i >= 0; --i) {
5489             NotificationRecord r = notificationList.get(i);
5490             if (includeCurrentProfiles) {
5491                 if (!notificationMatchesCurrentProfiles(r, userId)) {
5492                     continue;
5493                 }
5494             } else if (!notificationMatchesUserId(r, userId)) {
5495                 continue;
5496             }
5497             // Don't remove notifications to all, if there's no package name specified
5498             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5499                 continue;
5500             }
5501             if (!flagChecker.apply(r.getFlags())) {
5502                 continue;
5503             }
5504             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5505                 continue;
5506             }
5507             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5508                 continue;
5509             }
5510             if (canceledNotifications == null) {
5511                 canceledNotifications = new ArrayList<>();
5512             }
5513             notificationList.remove(i);
5514             mNotificationsByKey.remove(r.getKey());
5515             canceledNotifications.add(r);
5516             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
5517         }
5518         if (canceledNotifications != null) {
5519             final int M = canceledNotifications.size();
5520             for (int i = 0; i < M; i++) {
5521                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
5522                         listenerName, false /* sendDelete */, flagChecker);
5523             }
5524             updateLightsLocked();
5525         }
5526     }
5527
5528     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
5529             ManagedServiceInfo listener) {
5530         String listenerName = listener == null ? null : listener.component.toShortString();
5531         if (duration <= 0 && snoozeCriterionId == null || key == null) {
5532             return;
5533         }
5534
5535         if (DBG) {
5536             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5537                     snoozeCriterionId, listenerName));
5538         }
5539         // Needs to post so that it can cancel notifications not yet enqueued.
5540         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
5541     }
5542
5543     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5544         String listenerName = listener == null ? null : listener.component.toShortString();
5545         if (DBG) {
5546             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5547         }
5548         mSnoozeHelper.repost(key);
5549         savePolicyFile();
5550     }
5551
5552     @GuardedBy("mNotificationLock")
5553     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
5554             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
5555         mHandler.post(new Runnable() {
5556             @Override
5557             public void run() {
5558                 synchronized (mNotificationLock) {
5559                     String listenerName =
5560                             listener == null ? null : listener.component.toShortString();
5561                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5562                             null, userId, 0, 0, reason, listenerName);
5563
5564                     FlagChecker flagChecker = (int flags) -> {
5565                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5566                                 != 0) {
5567                             return false;
5568                         }
5569                         return true;
5570                     };
5571
5572                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5573                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5574                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
5575                             listenerName, true);
5576                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5577                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5578                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
5579                             reason, listenerName, false);
5580                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
5581                 }
5582             }
5583         });
5584     }
5585
5586     // Warning: The caller is responsible for invoking updateLightsLocked().
5587     @GuardedBy("mNotificationLock")
5588     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
5589             String listenerName, boolean sendDelete, FlagChecker flagChecker) {
5590         Notification n = r.getNotification();
5591         if (!n.isGroupSummary()) {
5592             return;
5593         }
5594
5595         String pkg = r.sbn.getPackageName();
5596
5597         if (pkg == null) {
5598             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5599             return;
5600         }
5601
5602         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
5603                 sendDelete, true, flagChecker);
5604         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
5605                 listenerName, sendDelete, false, flagChecker);
5606     }
5607
5608     @GuardedBy("mNotificationLock")
5609     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5610             NotificationRecord parentNotification, int callingUid, int callingPid,
5611             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
5612         final String pkg = parentNotification.sbn.getPackageName();
5613         final int userId = parentNotification.getUserId();
5614         final int reason = REASON_GROUP_SUMMARY_CANCELED;
5615         for (int i = notificationList.size() - 1; i >= 0; i--) {
5616             final NotificationRecord childR = notificationList.get(i);
5617             final StatusBarNotification childSbn = childR.sbn;
5618             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
5619                     childR.getGroupKey().equals(parentNotification.getGroupKey())
5620                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5621                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
5622                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5623                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
5624                 notificationList.remove(i);
5625                 mNotificationsByKey.remove(childR.getKey());
5626                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5627             }
5628         }
5629     }
5630
5631     @GuardedBy("mNotificationLock")
5632     void updateLightsLocked()
5633     {
5634         // handle notification lights
5635         NotificationRecord ledNotification = null;
5636         while (ledNotification == null && !mLights.isEmpty()) {
5637             final String owner = mLights.get(mLights.size() - 1);
5638             ledNotification = mNotificationsByKey.get(owner);
5639             if (ledNotification == null) {
5640                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5641                 mLights.remove(owner);
5642             }
5643         }
5644
5645         // Don't flash while we are in a call or screen is on
5646         if (ledNotification == null || mInCall || mScreenOn) {
5647             mNotificationLight.turnOff();
5648         } else {
5649             NotificationRecord.Light light = ledNotification.getLight();
5650             if (light != null && mNotificationPulseEnabled) {
5651                 // pulse repeatedly
5652                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5653                         light.onMs, light.offMs);
5654             }
5655         }
5656     }
5657
5658     @GuardedBy("mNotificationLock")
5659     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5660             String groupKey, int userId) {
5661         List<NotificationRecord> records = new ArrayList<>();
5662         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5663         records.addAll(
5664                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5665         return records;
5666     }
5667
5668
5669     @GuardedBy("mNotificationLock")
5670     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5671             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5672         List<NotificationRecord> records = new ArrayList<>();
5673         final int len = list.size();
5674         for (int i = 0; i < len; i++) {
5675             NotificationRecord r = list.get(i);
5676             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5677                     && r.sbn.getPackageName().equals(pkg)) {
5678                 records.add(r);
5679             }
5680         }
5681         return records;
5682     }
5683
5684     // Searches both enqueued and posted notifications by key.
5685     // TODO: need to combine a bunch of these getters with slightly different behavior.
5686     // TODO: Should enqueuing just add to mNotificationsByKey instead?
5687     @GuardedBy("mNotificationLock")
5688     private NotificationRecord findNotificationByKeyLocked(String key) {
5689         NotificationRecord r;
5690         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5691             return r;
5692         }
5693         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5694             return r;
5695         }
5696         return null;
5697     }
5698
5699     @GuardedBy("mNotificationLock")
5700     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5701         NotificationRecord r;
5702         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5703             return r;
5704         }
5705         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5706                 != null) {
5707             return r;
5708         }
5709         return null;
5710     }
5711
5712     @GuardedBy("mNotificationLock")
5713     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5714             String pkg, String tag, int id, int userId) {
5715         final int len = list.size();
5716         for (int i = 0; i < len; i++) {
5717             NotificationRecord r = list.get(i);
5718             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5719                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5720                 return r;
5721             }
5722         }
5723         return null;
5724     }
5725
5726     @GuardedBy("mNotificationLock")
5727     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5728             String key) {
5729         final int N = list.size();
5730         for (int i = 0; i < N; i++) {
5731             if (key.equals(list.get(i).getKey())) {
5732                 return list.get(i);
5733             }
5734         }
5735         return null;
5736     }
5737
5738     @GuardedBy("mNotificationLock")
5739     int indexOfNotificationLocked(String key) {
5740         final int N = mNotificationList.size();
5741         for (int i = 0; i < N; i++) {
5742             if (key.equals(mNotificationList.get(i).getKey())) {
5743                 return i;
5744             }
5745         }
5746         return -1;
5747     }
5748
5749     @VisibleForTesting
5750     protected void hideNotificationsForPackages(String[] pkgs) {
5751         synchronized (mNotificationLock) {
5752             List<String> pkgList = Arrays.asList(pkgs);
5753             List<NotificationRecord> changedNotifications = new ArrayList<>();
5754             int numNotifications = mNotificationList.size();
5755             for (int i = 0; i < numNotifications; i++) {
5756                 NotificationRecord rec = mNotificationList.get(i);
5757                 if (pkgList.contains(rec.sbn.getPackageName())) {
5758                     rec.setHidden(true);
5759                     changedNotifications.add(rec);
5760                 }
5761             }
5762
5763             mListeners.notifyHiddenLocked(changedNotifications);
5764         }
5765     }
5766
5767     @VisibleForTesting
5768     protected void unhideNotificationsForPackages(String[] pkgs) {
5769         synchronized (mNotificationLock) {
5770             List<String> pkgList = Arrays.asList(pkgs);
5771             List<NotificationRecord> changedNotifications = new ArrayList<>();
5772             int numNotifications = mNotificationList.size();
5773             for (int i = 0; i < numNotifications; i++) {
5774                 NotificationRecord rec = mNotificationList.get(i);
5775                 if (pkgList.contains(rec.sbn.getPackageName())) {
5776                     rec.setHidden(false);
5777                     changedNotifications.add(rec);
5778                 }
5779             }
5780
5781             mListeners.notifyUnhiddenLocked(changedNotifications);
5782         }
5783     }
5784
5785     private void updateNotificationPulse() {
5786         synchronized (mNotificationLock) {
5787             updateLightsLocked();
5788         }
5789     }
5790
5791     protected boolean isCallingUidSystem() {
5792         final int uid = Binder.getCallingUid();
5793         return uid == Process.SYSTEM_UID;
5794     }
5795
5796     protected boolean isUidSystemOrPhone(int uid) {
5797         final int appid = UserHandle.getAppId(uid);
5798         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5799     }
5800
5801     // TODO: Most calls should probably move to isCallerSystem.
5802     protected boolean isCallerSystemOrPhone() {
5803         return isUidSystemOrPhone(Binder.getCallingUid());
5804     }
5805
5806     private void checkCallerIsSystemOrShell() {
5807         if (Binder.getCallingUid() == Process.SHELL_UID) {
5808             return;
5809         }
5810         checkCallerIsSystem();
5811     }
5812
5813     private void checkCallerIsSystem() {
5814         if (isCallerSystemOrPhone()) {
5815             return;
5816         }
5817         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5818     }
5819
5820     private void checkCallerIsSystemOrSameApp(String pkg) {
5821         if (isCallerSystemOrPhone()) {
5822             return;
5823         }
5824         checkCallerIsSameApp(pkg);
5825     }
5826
5827     private boolean isCallerInstantApp(String pkg) {
5828         // System is always allowed to act for ephemeral apps.
5829         if (isCallerSystemOrPhone()) {
5830             return false;
5831         }
5832
5833         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5834
5835         try {
5836             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5837                     UserHandle.getCallingUserId());
5838             if (ai == null) {
5839                 throw new SecurityException("Unknown package " + pkg);
5840             }
5841             return ai.isInstantApp();
5842         } catch (RemoteException re) {
5843             throw new SecurityException("Unknown package " + pkg, re);
5844         }
5845
5846     }
5847
5848     private void checkCallerIsSameApp(String pkg) {
5849         final int uid = Binder.getCallingUid();
5850         try {
5851             ApplicationInfo ai = mPackageManager.getApplicationInfo(
5852                     pkg, 0, UserHandle.getCallingUserId());
5853             if (ai == null) {
5854                 throw new SecurityException("Unknown package " + pkg);
5855             }
5856             if (!UserHandle.isSameApp(ai.uid, uid)) {
5857                 throw new SecurityException("Calling uid " + uid + " gave package "
5858                         + pkg + " which is owned by uid " + ai.uid);
5859             }
5860         } catch (RemoteException re) {
5861             throw new SecurityException("Unknown package " + pkg + "\n" + re);
5862         }
5863     }
5864
5865     private static String callStateToString(int state) {
5866         switch (state) {
5867             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5868             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5869             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5870             default: return "CALL_STATE_UNKNOWN_" + state;
5871         }
5872     }
5873
5874     private void listenForCallState() {
5875         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5876             @Override
5877             public void onCallStateChanged(int state, String incomingNumber) {
5878                 if (mCallState == state) return;
5879                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5880                 mCallState = state;
5881             }
5882         }, PhoneStateListener.LISTEN_CALL_STATE);
5883     }
5884
5885     /**
5886      * Generates a NotificationRankingUpdate from 'sbns', considering only
5887      * notifications visible to the given listener.
5888      */
5889     @GuardedBy("mNotificationLock")
5890     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5891         final int N = mNotificationList.size();
5892         ArrayList<String> keys = new ArrayList<String>(N);
5893         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5894         ArrayList<Integer> importance = new ArrayList<>(N);
5895         Bundle overrideGroupKeys = new Bundle();
5896         Bundle visibilityOverrides = new Bundle();
5897         Bundle suppressedVisualEffects = new Bundle();
5898         Bundle explanation = new Bundle();
5899         Bundle channels = new Bundle();
5900         Bundle overridePeople = new Bundle();
5901         Bundle snoozeCriteria = new Bundle();
5902         Bundle showBadge = new Bundle();
5903         Bundle userSentiment = new Bundle();
5904         Bundle hidden = new Bundle();
5905         for (int i = 0; i < N; i++) {
5906             NotificationRecord record = mNotificationList.get(i);
5907             if (!isVisibleToListener(record.sbn, info)) {
5908                 continue;
5909             }
5910             final String key = record.sbn.getKey();
5911             keys.add(key);
5912             importance.add(record.getImportance());
5913             if (record.getImportanceExplanation() != null) {
5914                 explanation.putCharSequence(key, record.getImportanceExplanation());
5915             }
5916             if (record.isIntercepted()) {
5917                 interceptedKeys.add(key);
5918
5919             }
5920             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5921             if (record.getPackageVisibilityOverride()
5922                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5923                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5924             }
5925             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5926             channels.putParcelable(key, record.getChannel());
5927             overridePeople.putStringArrayList(key, record.getPeopleOverride());
5928             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5929             showBadge.putBoolean(key, record.canShowBadge());
5930             userSentiment.putInt(key, record.getUserSentiment());
5931             hidden.putBoolean(key, record.isHidden());
5932         }
5933         final int M = keys.size();
5934         String[] keysAr = keys.toArray(new String[M]);
5935         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5936         int[] importanceAr = new int[M];
5937         for (int i = 0; i < M; i++) {
5938             importanceAr[i] = importance.get(i);
5939         }
5940         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5941                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5942                 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
5943     }
5944
5945     boolean hasCompanionDevice(ManagedServiceInfo info) {
5946         if (mCompanionManager == null) {
5947             mCompanionManager = getCompanionManager();
5948         }
5949         // Companion mgr doesn't exist on all device types
5950         if (mCompanionManager == null) {
5951             return false;
5952         }
5953         long identity = Binder.clearCallingIdentity();
5954         try {
5955             List<String> associations = mCompanionManager.getAssociations(
5956                     info.component.getPackageName(), info.userid);
5957             if (!ArrayUtils.isEmpty(associations)) {
5958                 return true;
5959             }
5960         } catch (SecurityException se) {
5961             // Not a privileged listener
5962         } catch (RemoteException re) {
5963             Slog.e(TAG, "Cannot reach companion device service", re);
5964         } catch (Exception e) {
5965             Slog.e(TAG, "Cannot verify listener " + info, e);
5966         } finally {
5967             Binder.restoreCallingIdentity(identity);
5968         }
5969         return false;
5970     }
5971
5972     protected ICompanionDeviceManager getCompanionManager() {
5973         return ICompanionDeviceManager.Stub.asInterface(
5974                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5975     }
5976
5977     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5978         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5979             return false;
5980         }
5981         // TODO: remove this for older listeners.
5982         return true;
5983     }
5984
5985     private boolean isPackageSuspendedForUser(String pkg, int uid) {
5986         final long identity = Binder.clearCallingIdentity();
5987         int userId = UserHandle.getUserId(uid);
5988         try {
5989             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5990         } catch (RemoteException re) {
5991             throw new SecurityException("Could not talk to package manager service");
5992         } catch (IllegalArgumentException ex) {
5993             // Package not found.
5994             return false;
5995         } finally {
5996             Binder.restoreCallingIdentity(identity);
5997         }
5998     }
5999
6000     private boolean canUseManagedServices() {
6001         return !mActivityManager.isLowRamDevice()
6002                 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
6003     }
6004
6005     private class TrimCache {
6006         StatusBarNotification heavy;
6007         StatusBarNotification sbnClone;
6008         StatusBarNotification sbnCloneLight;
6009
6010         TrimCache(StatusBarNotification sbn) {
6011             heavy = sbn;
6012         }
6013
6014         StatusBarNotification ForListener(ManagedServiceInfo info) {
6015             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6016                 if (sbnCloneLight == null) {
6017                     sbnCloneLight = heavy.cloneLight();
6018                 }
6019                 return sbnCloneLight;
6020             } else {
6021                 if (sbnClone == null) {
6022                     sbnClone = heavy.clone();
6023                 }
6024                 return sbnClone;
6025             }
6026         }
6027     }
6028
6029     public class NotificationAssistants extends ManagedServices {
6030         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
6031
6032         public NotificationAssistants(Context context, Object lock, UserProfiles up,
6033                 IPackageManager pm) {
6034             super(context, lock, up, pm);
6035         }
6036
6037         @Override
6038         protected Config getConfig() {
6039             Config c = new Config();
6040             c.caption = "notification assistant";
6041             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
6042             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
6043             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6044             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
6045             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
6046             c.clientLabel = R.string.notification_ranker_binding_label;
6047             return c;
6048         }
6049
6050         @Override
6051         protected IInterface asInterface(IBinder binder) {
6052             return INotificationListener.Stub.asInterface(binder);
6053         }
6054
6055         @Override
6056         protected boolean checkType(IInterface service) {
6057             return service instanceof INotificationListener;
6058         }
6059
6060         @Override
6061         protected void onServiceAdded(ManagedServiceInfo info) {
6062             mListeners.registerGuestService(info);
6063         }
6064
6065         @Override
6066         @GuardedBy("mNotificationLock")
6067         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6068             mListeners.unregisterService(removed.service, removed.userid);
6069         }
6070
6071         @Override
6072         public void onUserUnlocked(int user) {
6073             if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6074             rebindServices(true);
6075         }
6076
6077         public void onNotificationEnqueued(final NotificationRecord r) {
6078             final StatusBarNotification sbn = r.sbn;
6079             TrimCache trimCache = new TrimCache(sbn);
6080
6081             // There should be only one, but it's a list, so while we enforce
6082             // singularity elsewhere, we keep it general here, to avoid surprises.
6083             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
6084                 boolean sbnVisible = isVisibleToListener(sbn, info);
6085                 if (!sbnVisible) {
6086                     continue;
6087                 }
6088
6089                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
6090                 mHandler.post(new Runnable() {
6091                     @Override
6092                     public void run() {
6093                         notifyEnqueued(info, sbnToPost);
6094                     }
6095                 });
6096             }
6097         }
6098
6099         private void notifyEnqueued(final ManagedServiceInfo info,
6100                 final StatusBarNotification sbn) {
6101             final INotificationListener assistant = (INotificationListener) info.service;
6102             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6103             try {
6104                 assistant.onNotificationEnqueued(sbnHolder);
6105             } catch (RemoteException ex) {
6106                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
6107             }
6108         }
6109
6110         /**
6111          * asynchronously notify the assistant that a notification has been snoozed until a
6112          * context
6113          */
6114         @GuardedBy("mNotificationLock")
6115         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6116                 final String snoozeCriterionId) {
6117             TrimCache trimCache = new TrimCache(sbn);
6118             for (final ManagedServiceInfo info : getServices()) {
6119                 boolean sbnVisible = isVisibleToListener(sbn, info);
6120                 if (!sbnVisible) {
6121                     continue;
6122                 }
6123                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
6124                 mHandler.post(new Runnable() {
6125                     @Override
6126                     public void run() {
6127                         final INotificationListener assistant =
6128                                 (INotificationListener) info.service;
6129                         StatusBarNotificationHolder sbnHolder
6130                                 = new StatusBarNotificationHolder(sbnToPost);
6131                         try {
6132                             assistant.onNotificationSnoozedUntilContext(
6133                                     sbnHolder, snoozeCriterionId);
6134                         } catch (RemoteException ex) {
6135                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6136                         }
6137                     }
6138                 });
6139             }
6140         }
6141
6142         public boolean isEnabled() {
6143             return !getServices().isEmpty();
6144         }
6145
6146         protected void ensureAssistant() {
6147             final List<UserInfo> activeUsers = mUm.getUsers(true);
6148             for (UserInfo userInfo : activeUsers) {
6149                 int userId = userInfo.getUserHandle().getIdentifier();
6150                 if (getAllowedPackages(userId).isEmpty()) {
6151                     Slog.d(TAG, "Approving default notification assistant for user " + userId);
6152                     readDefaultAssistant(userId);
6153                 }
6154             }
6155         }
6156     }
6157
6158     public class NotificationListeners extends ManagedServices {
6159         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
6160
6161         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6162
6163         public NotificationListeners(IPackageManager pm) {
6164             super(getContext(), mNotificationLock, mUserProfiles, pm);
6165
6166         }
6167
6168         @Override
6169         protected Config getConfig() {
6170             Config c = new Config();
6171             c.caption = "notification listener";
6172             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
6173             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
6174             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6175             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6176             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6177             c.clientLabel = R.string.notification_listener_binding_label;
6178             return c;
6179         }
6180
6181         @Override
6182         protected IInterface asInterface(IBinder binder) {
6183             return INotificationListener.Stub.asInterface(binder);
6184         }
6185
6186         @Override
6187         protected boolean checkType(IInterface service) {
6188             return service instanceof INotificationListener;
6189         }
6190
6191         @Override
6192         public void onServiceAdded(ManagedServiceInfo info) {
6193             final INotificationListener listener = (INotificationListener) info.service;
6194             final NotificationRankingUpdate update;
6195             synchronized (mNotificationLock) {
6196                 update = makeRankingUpdateLocked(info);
6197             }
6198             try {
6199                 listener.onListenerConnected(update);
6200             } catch (RemoteException e) {
6201                 // we tried
6202             }
6203         }
6204
6205         @Override
6206         @GuardedBy("mNotificationLock")
6207         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6208             if (removeDisabledHints(removed)) {
6209                 updateListenerHintsLocked();
6210                 updateEffectsSuppressorLocked();
6211             }
6212             mLightTrimListeners.remove(removed);
6213         }
6214
6215         @GuardedBy("mNotificationLock")
6216         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6217             if (trim == TRIM_LIGHT) {
6218                 mLightTrimListeners.add(info);
6219             } else {
6220                 mLightTrimListeners.remove(info);
6221             }
6222         }
6223
6224         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6225             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
6226         }
6227
6228         /**
6229          * asynchronously notify all listeners about a new notification
6230          *
6231          * <p>
6232          * Also takes care of removing a notification that has been visible to a listener before,
6233          * but isn't anymore.
6234          */
6235         @GuardedBy("mNotificationLock")
6236         public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) {
6237             notifyPostedLocked(r, oldSbn, true);
6238         }
6239
6240         /**
6241          * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6242          *                           targetting <= O_MR1
6243          */
6244         @GuardedBy("mNotificationLock")
6245         private void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn,
6246                 boolean notifyAllListeners) {
6247             // Lazily initialized snapshots of the notification.
6248             StatusBarNotification sbn = r.sbn;
6249             TrimCache trimCache = new TrimCache(sbn);
6250
6251             Set<Uri> uris = r.getNotificationUris();
6252
6253             for (final ManagedServiceInfo info : getServices()) {
6254                 boolean sbnVisible = isVisibleToListener(sbn, info);
6255                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6256                 // This notification hasn't been and still isn't visible -> ignore.
6257                 if (!oldSbnVisible && !sbnVisible) {
6258                     continue;
6259                 }
6260
6261                 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6262                 // Instead, those listeners will receive notifyPosted when the notification is
6263                 // unhidden.
6264                 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6265                     continue;
6266                 }
6267
6268                 // If we shouldn't notify all listeners, this means the hidden state of
6269                 // a notification was changed.  Don't notifyPosted listeners targeting >= P.
6270                 // Instead, those listeners will receive notifyRankingUpdate.
6271                 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6272                     continue;
6273                 }
6274
6275                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
6276
6277                 // This notification became invisible -> remove the old one.
6278                 if (oldSbnVisible && !sbnVisible) {
6279                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6280                     mHandler.post(new Runnable() {
6281                         @Override
6282                         public void run() {
6283                             notifyRemoved(
6284                                     info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
6285                         }
6286                     });
6287                     continue;
6288                 }
6289
6290                 grantUriPermissions(uris, sbn.getUserId(), info.component.getPackageName(),
6291                         info.userid);
6292
6293                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
6294                 mHandler.post(new Runnable() {
6295                     @Override
6296                     public void run() {
6297                         notifyPosted(info, sbnToPost, update);
6298                     }
6299                 });
6300             }
6301         }
6302
6303         private void grantUriPermissions(Set<Uri> uris, int notiUserId, String listenerPkg,
6304                 int listenerUserId) {
6305             long ident = Binder.clearCallingIdentity();
6306             try {
6307                 for (Uri uri : uris) {
6308                     if (uri != null) {
6309                         int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
6310                                 : ContentProvider.getUserIdFromUri(uri, notiUserId);
6311                         uri = ContentProvider.getUriWithoutUserId(uri);
6312                         mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(),
6313                                 listenerPkg,
6314                                 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId,
6315                                 listenerUserId == USER_ALL ? USER_SYSTEM : listenerUserId);
6316                     }
6317                 }
6318             } catch (RemoteException e) {
6319                 Log.e(TAG, "Count not grant uri permission to " + listenerPkg, e);
6320             } finally {
6321                 Binder.restoreCallingIdentity(ident);
6322             }
6323         }
6324
6325         /**
6326          * asynchronously notify all listeners about a removed notification
6327          */
6328         @GuardedBy("mNotificationLock")
6329         public void notifyRemovedLocked(NotificationRecord r, int reason,
6330                 NotificationStats notificationStats) {
6331             final StatusBarNotification sbn = r.sbn;
6332             // make a copy in case changes are made to the underlying Notification object
6333             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6334             // notification
6335             final StatusBarNotification sbnLight = sbn.cloneLight();
6336             for (final ManagedServiceInfo info : getServices()) {
6337                 if (!isVisibleToListener(sbn, info)) {
6338                     continue;
6339                 }
6340
6341                 // don't notifyRemoved for listeners targeting < P
6342                 // if not for reason package suspended
6343                 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6344                         && info.targetSdkVersion < Build.VERSION_CODES.P) {
6345                     continue;
6346                 }
6347
6348                 // don't notifyRemoved for listeners targeting >= P
6349                 // if the reason is package suspended
6350                 if (reason == REASON_PACKAGE_SUSPENDED
6351                         && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6352                     continue;
6353                 }
6354
6355                 // Only assistants can get stats
6356                 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6357                         ? notificationStats : null;
6358                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
6359                 mHandler.post(new Runnable() {
6360                     @Override
6361                     public void run() {
6362                         notifyRemoved(info, sbnLight, update, stats, reason);
6363                     }
6364                 });
6365             }
6366         }
6367
6368         /**
6369          * Asynchronously notify all listeners about a reordering of notifications
6370          * unless changedHiddenNotifications is populated.
6371          * If changedHiddenNotifications is populated, there was a change in the hidden state
6372          * of the notifications.  In this case, we only send updates to listeners that
6373          * target >= P.
6374          */
6375         @GuardedBy("mNotificationLock")
6376         public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6377             boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6378                     && changedHiddenNotifications.size() > 0;
6379
6380             for (final ManagedServiceInfo serviceInfo : getServices()) {
6381                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6382                     continue;
6383                 }
6384
6385                 boolean notifyThisListener = false;
6386                 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6387                         Build.VERSION_CODES.P) {
6388                     for (NotificationRecord rec : changedHiddenNotifications) {
6389                         if (isVisibleToListener(rec.sbn, serviceInfo)) {
6390                             notifyThisListener = true;
6391                             break;
6392                         }
6393                     }
6394                 }
6395
6396                 if (notifyThisListener || !isHiddenRankingUpdate) {
6397                     final NotificationRankingUpdate update = makeRankingUpdateLocked(
6398                             serviceInfo);
6399
6400                     mHandler.post(new Runnable() {
6401                         @Override
6402                         public void run() {
6403                             notifyRankingUpdate(serviceInfo, update);
6404                         }
6405                     });
6406                 }
6407             }
6408         }
6409
6410         @GuardedBy("mNotificationLock")
6411         public void notifyListenerHintsChangedLocked(final int hints) {
6412             for (final ManagedServiceInfo serviceInfo : getServices()) {
6413                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6414                     continue;
6415                 }
6416                 mHandler.post(new Runnable() {
6417                     @Override
6418                     public void run() {
6419                         notifyListenerHintsChanged(serviceInfo, hints);
6420                     }
6421                 });
6422             }
6423         }
6424
6425         /**
6426          * asynchronously notify relevant listeners their notification is hidden
6427          * NotificationListenerServices that target P+:
6428          *      NotificationListenerService#notifyRankingUpdateLocked()
6429          * NotificationListenerServices that target <= P:
6430          *      NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6431          */
6432         @GuardedBy("mNotificationLock")
6433         public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6434             if (changedNotifications == null || changedNotifications.size() == 0) {
6435                 return;
6436             }
6437
6438             notifyRankingUpdateLocked(changedNotifications);
6439
6440             // for listeners that target < P, notifyRemoveLocked
6441             int numChangedNotifications = changedNotifications.size();
6442             for (int i = 0; i < numChangedNotifications; i++) {
6443                 NotificationRecord rec = changedNotifications.get(i);
6444                 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6445             }
6446         }
6447
6448         /**
6449          * asynchronously notify relevant listeners their notification is unhidden
6450          * NotificationListenerServices that target P+:
6451          *      NotificationListenerService#notifyRankingUpdateLocked()
6452          * NotificationListenerServices that target <= P:
6453          *      NotificationListeners#notifyPostedLocked()
6454          */
6455         @GuardedBy("mNotificationLock")
6456         public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6457             if (changedNotifications == null || changedNotifications.size() == 0) {
6458                 return;
6459             }
6460
6461             notifyRankingUpdateLocked(changedNotifications);
6462
6463             // for listeners that target < P, notifyPostedLocked
6464             int numChangedNotifications = changedNotifications.size();
6465             for (int i = 0; i < numChangedNotifications; i++) {
6466                 NotificationRecord rec = changedNotifications.get(i);
6467                 mListeners.notifyPostedLocked(rec, rec.sbn, false);
6468             }
6469         }
6470
6471         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
6472             for (final ManagedServiceInfo serviceInfo : getServices()) {
6473                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6474                     continue;
6475                 }
6476                 mHandler.post(new Runnable() {
6477                     @Override
6478                     public void run() {
6479                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6480                     }
6481                 });
6482             }
6483         }
6484
6485         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
6486                 final NotificationChannel channel, final int modificationType) {
6487             if (channel == null) {
6488                 return;
6489             }
6490             for (final ManagedServiceInfo serviceInfo : getServices()) {
6491                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
6492                     continue;
6493                 }
6494
6495                 BackgroundThread.getHandler().post(() -> {
6496                     if (hasCompanionDevice(serviceInfo)) {
6497                         notifyNotificationChannelChanged(
6498                                 serviceInfo, pkg, user, channel, modificationType);
6499                     }
6500                 });
6501             }
6502         }
6503
6504         protected void notifyNotificationChannelGroupChanged(
6505                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6506                 final int modificationType) {
6507             if (group == null) {
6508                 return;
6509             }
6510             for (final ManagedServiceInfo serviceInfo : getServices()) {
6511                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
6512                     continue;
6513                 }
6514
6515                 BackgroundThread.getHandler().post(() -> {
6516                     if (hasCompanionDevice(serviceInfo)) {
6517                         notifyNotificationChannelGroupChanged(
6518                                 serviceInfo, pkg, user, group, modificationType);
6519                     }
6520                 });
6521             }
6522         }
6523
6524         private void notifyPosted(final ManagedServiceInfo info,
6525                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
6526             final INotificationListener listener = (INotificationListener) info.service;
6527             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6528             try {
6529                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
6530             } catch (RemoteException ex) {
6531                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6532             }
6533         }
6534
6535         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
6536                 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
6537             if (!info.enabledAndUserMatches(sbn.getUserId())) {
6538                 return;
6539             }
6540             final INotificationListener listener = (INotificationListener) info.service;
6541             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6542             try {
6543                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
6544             } catch (RemoteException ex) {
6545                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
6546             }
6547         }
6548
6549         private void notifyRankingUpdate(ManagedServiceInfo info,
6550                                          NotificationRankingUpdate rankingUpdate) {
6551             final INotificationListener listener = (INotificationListener) info.service;
6552             try {
6553                 listener.onNotificationRankingUpdate(rankingUpdate);
6554             } catch (RemoteException ex) {
6555                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6556             }
6557         }
6558
6559         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
6560             final INotificationListener listener = (INotificationListener) info.service;
6561             try {
6562                 listener.onListenerHintsChanged(hints);
6563             } catch (RemoteException ex) {
6564                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
6565             }
6566         }
6567
6568         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6569                 int interruptionFilter) {
6570             final INotificationListener listener = (INotificationListener) info.service;
6571             try {
6572                 listener.onInterruptionFilterChanged(interruptionFilter);
6573             } catch (RemoteException ex) {
6574                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6575             }
6576         }
6577
6578         void notifyNotificationChannelChanged(ManagedServiceInfo info,
6579                 final String pkg, final UserHandle user, final NotificationChannel channel,
6580                 final int modificationType) {
6581             final INotificationListener listener = (INotificationListener) info.service;
6582             try {
6583                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
6584             } catch (RemoteException ex) {
6585                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6586             }
6587         }
6588
6589         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
6590                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6591                 final int modificationType) {
6592             final INotificationListener listener = (INotificationListener) info.service;
6593             try {
6594                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
6595             } catch (RemoteException ex) {
6596                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6597             }
6598         }
6599
6600         public boolean isListenerPackage(String packageName) {
6601             if (packageName == null) {
6602                 return false;
6603             }
6604             // TODO: clean up locking object later
6605             synchronized (mNotificationLock) {
6606                 for (final ManagedServiceInfo serviceInfo : getServices()) {
6607                     if (packageName.equals(serviceInfo.component.getPackageName())) {
6608                         return true;
6609                     }
6610                 }
6611             }
6612             return false;
6613         }
6614     }
6615
6616     public static final class DumpFilter {
6617         public boolean filtered = false;
6618         public String pkgFilter;
6619         public boolean zen;
6620         public long since;
6621         public boolean stats;
6622         public boolean redact = true;
6623         public boolean proto = false;
6624         public boolean criticalPriority = false;
6625         public boolean normalPriority = false;
6626
6627         @NonNull
6628         public static DumpFilter parseFromArguments(String[] args) {
6629             final DumpFilter filter = new DumpFilter();
6630             for (int ai = 0; ai < args.length; ai++) {
6631                 final String a = args[ai];
6632                 if ("--proto".equals(a)) {
6633                     filter.proto = true;
6634                 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
6635                     filter.redact = false;
6636                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6637                     if (ai < args.length-1) {
6638                         ai++;
6639                         filter.pkgFilter = args[ai].trim().toLowerCase();
6640                         if (filter.pkgFilter.isEmpty()) {
6641                             filter.pkgFilter = null;
6642                         } else {
6643                             filter.filtered = true;
6644                         }
6645                     }
6646                 } else if ("--zen".equals(a) || "zen".equals(a)) {
6647                     filter.filtered = true;
6648                     filter.zen = true;
6649                 } else if ("--stats".equals(a)) {
6650                     filter.stats = true;
6651                     if (ai < args.length-1) {
6652                         ai++;
6653                         filter.since = Long.parseLong(args[ai]);
6654                     } else {
6655                         filter.since = 0;
6656                     }
6657                 } else if (PRIORITY_ARG.equals(a)) {
6658                     // Bugreport will call the service twice with priority arguments, first to dump
6659                     // critical sections and then non critical ones. Set approriate filters
6660                     // to generate the desired data.
6661                     if (ai < args.length - 1) {
6662                         ai++;
6663                         switch (args[ai]) {
6664                             case PRIORITY_ARG_CRITICAL:
6665                                 filter.criticalPriority = true;
6666                                 break;
6667                             case PRIORITY_ARG_NORMAL:
6668                                 filter.normalPriority = true;
6669                                 break;
6670                         }
6671                     }
6672                 }
6673             }
6674             return filter;
6675         }
6676
6677         public boolean matches(StatusBarNotification sbn) {
6678             if (!filtered) return true;
6679             return zen ? true : sbn != null
6680                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
6681         }
6682
6683         public boolean matches(ComponentName component) {
6684             if (!filtered) return true;
6685             return zen ? true : component != null && matches(component.getPackageName());
6686         }
6687
6688         public boolean matches(String pkg) {
6689             if (!filtered) return true;
6690             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
6691         }
6692
6693         @Override
6694         public String toString() {
6695             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
6696         }
6697     }
6698
6699     @VisibleForTesting
6700     protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
6701         // only use for testing: mimic receive broadcast that package is (un)suspended
6702         // but does not actually (un)suspend the package
6703         final Bundle extras = new Bundle();
6704         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
6705                 new String[]{pkg});
6706
6707         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
6708             : Intent.ACTION_PACKAGES_UNSUSPENDED;
6709         final Intent intent = new Intent(action);
6710         intent.putExtras(extras);
6711
6712         mPackageIntentReceiver.onReceive(getContext(), intent);
6713     }
6714
6715     /**
6716      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
6717      * binder without sending large amounts of data over a oneway transaction.
6718      */
6719     private static final class StatusBarNotificationHolder
6720             extends IStatusBarNotificationHolder.Stub {
6721         private StatusBarNotification mValue;
6722
6723         public StatusBarNotificationHolder(StatusBarNotification value) {
6724             mValue = value;
6725         }
6726
6727         /** Get the held value and clear it. This function should only be called once per holder */
6728         @Override
6729         public StatusBarNotification get() {
6730             StatusBarNotification value = mValue;
6731             mValue = null;
6732             return value;
6733         }
6734     }
6735
6736     private class ShellCmd extends ShellCommand {
6737         public static final String USAGE = "help\n"
6738                 + "allow_listener COMPONENT [user_id]\n"
6739                 + "disallow_listener COMPONENT [user_id]\n"
6740                 + "allow_assistant COMPONENT\n"
6741                 + "remove_assistant COMPONENT\n"
6742                 + "allow_dnd PACKAGE\n"
6743                 + "disallow_dnd PACKAGE\n"
6744                 + "suspend_package PACKAGE\n"
6745                 + "unsuspend_package PACKAGE";
6746
6747         @Override
6748         public int onCommand(String cmd) {
6749             if (cmd == null) {
6750                 return handleDefaultCommands(cmd);
6751             }
6752             final PrintWriter pw = getOutPrintWriter();
6753             try {
6754                 switch (cmd) {
6755                     case "allow_dnd": {
6756                         getBinderService().setNotificationPolicyAccessGranted(
6757                                 getNextArgRequired(), true);
6758                     }
6759                     break;
6760
6761                     case "disallow_dnd": {
6762                         getBinderService().setNotificationPolicyAccessGranted(
6763                                 getNextArgRequired(), false);
6764                     }
6765                     break;
6766                     case "allow_listener": {
6767                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6768                         if (cn == null) {
6769                             pw.println("Invalid listener - must be a ComponentName");
6770                             return -1;
6771                         }
6772                         String userId = getNextArg();
6773                         if (userId == null) {
6774                             getBinderService().setNotificationListenerAccessGranted(cn, true);
6775                         } else {
6776                             getBinderService().setNotificationListenerAccessGrantedForUser(
6777                                     cn, Integer.parseInt(userId), true);
6778                         }
6779                     }
6780                     break;
6781                     case "disallow_listener": {
6782                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6783                         if (cn == null) {
6784                             pw.println("Invalid listener - must be a ComponentName");
6785                             return -1;
6786                         }
6787                         String userId = getNextArg();
6788                         if (userId == null) {
6789                             getBinderService().setNotificationListenerAccessGranted(cn, false);
6790                         } else {
6791                             getBinderService().setNotificationListenerAccessGrantedForUser(
6792                                     cn, Integer.parseInt(userId), false);
6793                         }
6794                     }
6795                     break;
6796                     case "allow_assistant": {
6797                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6798                         if (cn == null) {
6799                             pw.println("Invalid assistant - must be a ComponentName");
6800                             return -1;
6801                         }
6802                         getBinderService().setNotificationAssistantAccessGranted(cn, true);
6803                     }
6804                     break;
6805                     case "disallow_assistant": {
6806                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6807                         if (cn == null) {
6808                             pw.println("Invalid assistant - must be a ComponentName");
6809                             return -1;
6810                         }
6811                         getBinderService().setNotificationAssistantAccessGranted(cn, false);
6812                     }
6813                     break;
6814                     case "suspend_package": {
6815                         // only use for testing
6816                         simulatePackageSuspendBroadcast(true, getNextArgRequired());
6817                     }
6818                     break;
6819                     case "unsuspend_package": {
6820                         // only use for testing
6821                         simulatePackageSuspendBroadcast(false, getNextArgRequired());
6822                     }
6823                     break;
6824                     default:
6825                         return handleDefaultCommands(cmd);
6826                 }
6827             } catch (Exception e) {
6828                 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
6829                 Slog.e(TAG, "Error running shell command", e);
6830             }
6831             return 0;
6832         }
6833
6834         @Override
6835         public void onHelp() {
6836             getOutPrintWriter().println(USAGE);
6837         }
6838     }
6839 }