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