NotificationManagerService.java revision 87237d70a5fb2f3343e35604eed3ea079c439769
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.NotificationManager.IMPORTANCE_NONE;
20import static android.content.pm.PackageManager.FEATURE_LEANBACK;
21import static android.content.pm.PackageManager.FEATURE_TELEVISION;
22import static android.service.notification.NotificationListenerService
23        .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
24import static android.service.notification.NotificationListenerService
25        .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
26import static android.service.notification.NotificationListenerService
27        .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
28import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
29import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
30import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
31import static android.service.notification.NotificationListenerService.REASON_CANCEL;
32import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
33import static android.service.notification.NotificationListenerService.REASON_CLICK;
34import static android.service.notification.NotificationListenerService.REASON_ERROR;
35import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
36import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
37import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
38import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
39import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
40import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
41import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
42import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
43import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
44import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
45import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
46import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
47import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
48import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
49import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
50import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
51import static android.service.notification.NotificationListenerService.TRIM_FULL;
52import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
53
54import static android.view.Display.DEFAULT_DISPLAY;
55import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
56import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
57
58import android.Manifest;
59import android.annotation.Nullable;
60import android.app.ActivityManager;
61import android.app.ActivityManagerInternal;
62import android.app.AlarmManager;
63import android.app.AppGlobals;
64import android.app.AppOpsManager;
65import android.app.AutomaticZenRule;
66import android.app.NotificationChannelGroup;
67import android.app.backup.BackupManager;
68import android.app.IActivityManager;
69import android.app.INotificationManager;
70import android.app.ITransientNotification;
71import android.app.Notification;
72import android.app.NotificationChannel;
73import android.app.NotificationManager.Policy;
74import android.app.NotificationManager;
75import android.app.PendingIntent;
76import android.app.StatusBarManager;
77import android.app.usage.UsageEvents;
78import android.app.usage.UsageStatsManagerInternal;
79import android.companion.ICompanionDeviceManager;
80import android.content.BroadcastReceiver;
81import android.content.ComponentName;
82import android.content.ContentResolver;
83import android.content.Context;
84import android.content.Intent;
85import android.content.IntentFilter;
86import android.content.pm.ApplicationInfo;
87import android.content.pm.IPackageManager;
88import android.content.pm.PackageInfo;
89import android.content.pm.PackageManager;
90import android.content.pm.PackageManager.NameNotFoundException;
91import android.content.pm.ParceledListSlice;
92import android.content.pm.UserInfo;
93import android.content.res.Resources;
94import android.database.ContentObserver;
95import android.media.AudioManager;
96import android.media.AudioManagerInternal;
97import android.media.IRingtonePlayer;
98import android.net.Uri;
99import android.os.Binder;
100import android.os.Bundle;
101import android.os.Environment;
102import android.os.Handler;
103import android.os.HandlerThread;
104import android.os.IBinder;
105import android.os.IInterface;
106import android.os.Looper;
107import android.os.Message;
108import android.os.Process;
109import android.os.RemoteException;
110import android.os.ServiceManager;
111import android.os.SystemClock;
112import android.os.SystemProperties;
113import android.os.UserHandle;
114import android.os.UserManager;
115import android.os.Vibrator;
116import android.os.VibrationEffect;
117import android.provider.Settings;
118import android.service.notification.Adjustment;
119import android.service.notification.Condition;
120import android.service.notification.IConditionProvider;
121import android.service.notification.INotificationListener;
122import android.service.notification.IStatusBarNotificationHolder;
123import android.service.notification.NotificationAssistantService;
124import android.service.notification.NotificationListenerService;
125import android.service.notification.NotificationRankingUpdate;
126import android.service.notification.NotificationRecordProto;
127import android.service.notification.NotificationServiceDumpProto;
128import android.service.notification.NotificationServiceProto;
129import android.service.notification.SnoozeCriterion;
130import android.service.notification.StatusBarNotification;
131import android.service.notification.ZenModeConfig;
132import android.service.notification.ZenModeProto;
133import android.telephony.PhoneStateListener;
134import android.telephony.TelephonyManager;
135import android.text.TextUtils;
136import android.util.ArrayMap;
137import android.util.ArraySet;
138import android.util.AtomicFile;
139import android.util.Log;
140import android.util.Slog;
141import android.util.SparseArray;
142import android.util.Xml;
143import android.util.proto.ProtoOutputStream;
144import android.view.WindowManagerInternal;
145import android.view.accessibility.AccessibilityEvent;
146import android.view.accessibility.AccessibilityManager;
147import android.widget.Toast;
148
149import com.android.internal.R;
150import com.android.internal.annotations.VisibleForTesting;
151import com.android.internal.logging.MetricsLogger;
152import com.android.internal.logging.nano.MetricsProto;
153import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
154import com.android.internal.statusbar.NotificationVisibility;
155import com.android.internal.util.ArrayUtils;
156import com.android.internal.util.DumpUtils;
157import com.android.internal.util.FastXmlSerializer;
158import com.android.internal.util.Preconditions;
159import com.android.server.DeviceIdleController;
160import com.android.server.EventLogTags;
161import com.android.server.LocalServices;
162import com.android.server.SystemService;
163import com.android.server.lights.Light;
164import com.android.server.lights.LightsManager;
165import com.android.server.notification.ManagedServices.ManagedServiceInfo;
166import com.android.server.policy.PhoneWindowManager;
167import com.android.server.statusbar.StatusBarManagerInternal;
168import com.android.server.notification.ManagedServices.UserProfiles;
169
170import libcore.io.IoUtils;
171
172import org.json.JSONException;
173import org.json.JSONObject;
174import org.xmlpull.v1.XmlPullParser;
175import org.xmlpull.v1.XmlPullParserException;
176import org.xmlpull.v1.XmlSerializer;
177
178import java.io.ByteArrayInputStream;
179import java.io.ByteArrayOutputStream;
180import java.io.File;
181import java.io.FileDescriptor;
182import java.io.FileInputStream;
183import java.io.FileNotFoundException;
184import java.io.FileOutputStream;
185import java.io.IOException;
186import java.io.InputStream;
187import java.io.OutputStream;
188import java.io.PrintWriter;
189import java.nio.charset.StandardCharsets;
190import java.util.ArrayDeque;
191import java.util.ArrayList;
192import java.util.Arrays;
193import java.util.Iterator;
194import java.util.List;
195import java.util.Map;
196import java.util.Map.Entry;
197import java.util.Objects;
198import java.util.concurrent.TimeUnit;
199
200/** {@hide} */
201public class NotificationManagerService extends SystemService {
202    static final String TAG = "NotificationService";
203    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
204    public static final boolean ENABLE_CHILD_NOTIFICATIONS
205            = SystemProperties.getBoolean("debug.child_notifs", true);
206
207    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
208    static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
209
210    // message codes
211    static final int MESSAGE_TIMEOUT = 2;
212    static final int MESSAGE_SAVE_POLICY_FILE = 3;
213    static final int MESSAGE_SEND_RANKING_UPDATE = 4;
214    static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
215    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
216
217    // ranking thread messages
218    private static final int MESSAGE_RECONSIDER_RANKING = 1000;
219    private static final int MESSAGE_RANKING_SORT = 1001;
220
221    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
222    static final int SHORT_DELAY = 2000; // 2 seconds
223
224    static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
225
226    static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
227
228    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
229
230    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
231
232    static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
233    static final boolean ENABLE_BLOCKED_TOASTS = true;
234
235    // When #matchesCallFilter is called from the ringer, wait at most
236    // 3s to resolve the contacts. This timeout is required since
237    // ContactsProvider might take a long time to start up.
238    //
239    // Return STARRED_CONTACT when the timeout is hit in order to avoid
240    // missed calls in ZEN mode "Important".
241    static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
242    static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
243            ValidateNotificationPeople.STARRED_CONTACT;
244
245    /** notification_enqueue status value for a newly enqueued notification. */
246    private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
247
248    /** notification_enqueue status value for an existing notification. */
249    private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
250
251    /** notification_enqueue status value for an ignored notification. */
252    private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
253    private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
254
255    private static final long DELAY_FOR_ASSISTANT_TIME = 100;
256
257    private static final String ACTION_NOTIFICATION_TIMEOUT =
258            NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
259    private static final int REQUEST_CODE_TIMEOUT = 1;
260    private static final String SCHEME_TIMEOUT = "timeout";
261    private static final String EXTRA_KEY = "key";
262
263    private IActivityManager mAm;
264    private IPackageManager mPackageManager;
265    private PackageManager mPackageManagerClient;
266    AudioManager mAudioManager;
267    AudioManagerInternal mAudioManagerInternal;
268    @Nullable StatusBarManagerInternal mStatusBar;
269    Vibrator mVibrator;
270    private WindowManagerInternal mWindowManagerInternal;
271    private AlarmManager mAlarmManager;
272    private ICompanionDeviceManager mCompanionManager;
273
274    final IBinder mForegroundToken = new Binder();
275    private Handler mHandler;
276    private final HandlerThread mRankingThread = new HandlerThread("ranker",
277            Process.THREAD_PRIORITY_BACKGROUND);
278
279    private Light mNotificationLight;
280    Light mAttentionLight;
281
282    private long[] mFallbackVibrationPattern;
283    private boolean mUseAttentionLight;
284    boolean mSystemReady;
285
286    private boolean mDisableNotificationEffects;
287    private int mCallState;
288    private String mSoundNotificationKey;
289    private String mVibrateNotificationKey;
290
291    private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
292            new SparseArray<ArraySet<ManagedServiceInfo>>();
293    private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
294    private int mListenerHints;  // right now, all hints are global
295    private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
296
297    // for enabling and disabling notification pulse behavior
298    private boolean mScreenOn = true;
299    private boolean mInCall = false;
300    private boolean mNotificationPulseEnabled;
301
302    // used as a mutex for access to all active notifications & listeners
303    final Object mNotificationLock = new Object();
304    final ArrayList<NotificationRecord> mNotificationList =
305            new ArrayList<NotificationRecord>();
306    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
307            new ArrayMap<String, NotificationRecord>();
308    final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
309    final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
310    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
311    final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
312    final PolicyAccess mPolicyAccess = new PolicyAccess();
313
314    // The last key in this list owns the hardware.
315    ArrayList<String> mLights = new ArrayList<>();
316
317    private AppOpsManager mAppOps;
318    private UsageStatsManagerInternal mAppUsageStats;
319
320    private Archive mArchive;
321
322    // Persistent storage for notification policy
323    private AtomicFile mPolicyFile;
324
325    private static final int DB_VERSION = 1;
326
327    private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
328    private static final String ATTR_VERSION = "version";
329
330    private RankingHelper mRankingHelper;
331
332    private final UserProfiles mUserProfiles = new UserProfiles();
333    private NotificationListeners mListeners;
334    private NotificationAssistants mNotificationAssistants;
335    private ConditionProviders mConditionProviders;
336    private NotificationUsageStats mUsageStats;
337
338    private static final int MY_UID = Process.myUid();
339    private static final int MY_PID = Process.myPid();
340    private RankingHandler mRankingHandler;
341    private long mLastOverRateLogTime;
342    private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
343
344    private SnoozeHelper mSnoozeHelper;
345    private GroupHelper mGroupHelper;
346    private boolean mIsTelevision;
347
348    private static class Archive {
349        final int mBufferSize;
350        final ArrayDeque<StatusBarNotification> mBuffer;
351
352        public Archive(int size) {
353            mBufferSize = size;
354            mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
355        }
356
357        public String toString() {
358            final StringBuilder sb = new StringBuilder();
359            final int N = mBuffer.size();
360            sb.append("Archive (");
361            sb.append(N);
362            sb.append(" notification");
363            sb.append((N==1)?")":"s)");
364            return sb.toString();
365        }
366
367        public void record(StatusBarNotification nr) {
368            if (mBuffer.size() == mBufferSize) {
369                mBuffer.removeFirst();
370            }
371
372            // We don't want to store the heavy bits of the notification in the archive,
373            // but other clients in the system process might be using the object, so we
374            // store a (lightened) copy.
375            mBuffer.addLast(nr.cloneLight());
376        }
377
378        public Iterator<StatusBarNotification> descendingIterator() {
379            return mBuffer.descendingIterator();
380        }
381
382        public StatusBarNotification[] getArray(int count) {
383            if (count == 0) count = mBufferSize;
384            final StatusBarNotification[] a
385                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
386            Iterator<StatusBarNotification> iter = descendingIterator();
387            int i=0;
388            while (iter.hasNext() && i < count) {
389                a[i++] = iter.next();
390            }
391            return a;
392        }
393
394    }
395
396    private void readPolicyXml(InputStream stream, boolean forRestore)
397            throws XmlPullParserException, NumberFormatException, IOException {
398        final XmlPullParser parser = Xml.newPullParser();
399        parser.setInput(stream, StandardCharsets.UTF_8.name());
400
401        while (parser.next() != END_DOCUMENT) {
402            mZenModeHelper.readXml(parser, forRestore);
403            mRankingHelper.readXml(parser, forRestore);
404        }
405    }
406
407    private void loadPolicyFile() {
408        if (DBG) Slog.d(TAG, "loadPolicyFile");
409        synchronized (mPolicyFile) {
410
411            FileInputStream infile = null;
412            try {
413                infile = mPolicyFile.openRead();
414                readPolicyXml(infile, false /*forRestore*/);
415            } catch (FileNotFoundException e) {
416                // No data yet
417            } catch (IOException e) {
418                Log.wtf(TAG, "Unable to read notification policy", e);
419            } catch (NumberFormatException e) {
420                Log.wtf(TAG, "Unable to parse notification policy", e);
421            } catch (XmlPullParserException e) {
422                Log.wtf(TAG, "Unable to parse notification policy", e);
423            } finally {
424                IoUtils.closeQuietly(infile);
425            }
426        }
427    }
428
429    public void savePolicyFile() {
430        mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
431        mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
432    }
433
434    private void handleSavePolicyFile() {
435        if (DBG) Slog.d(TAG, "handleSavePolicyFile");
436        synchronized (mPolicyFile) {
437            final FileOutputStream stream;
438            try {
439                stream = mPolicyFile.startWrite();
440            } catch (IOException e) {
441                Slog.w(TAG, "Failed to save policy file", e);
442                return;
443            }
444
445            try {
446                writePolicyXml(stream, false /*forBackup*/);
447                mPolicyFile.finishWrite(stream);
448            } catch (IOException e) {
449                Slog.w(TAG, "Failed to save policy file, restoring backup", e);
450                mPolicyFile.failWrite(stream);
451            }
452        }
453        BackupManager.dataChanged(getContext().getPackageName());
454    }
455
456    private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
457        final XmlSerializer out = new FastXmlSerializer();
458        out.setOutput(stream, StandardCharsets.UTF_8.name());
459        out.startDocument(null, true);
460        out.startTag(null, TAG_NOTIFICATION_POLICY);
461        out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
462        mZenModeHelper.writeXml(out, forBackup);
463        mRankingHelper.writeXml(out, forBackup);
464        out.endTag(null, TAG_NOTIFICATION_POLICY);
465        out.endDocument();
466    }
467
468    /** Use this when you actually want to post a notification or toast.
469     *
470     * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
471     */
472    private boolean noteNotificationOp(String pkg, int uid) {
473        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
474                != AppOpsManager.MODE_ALLOWED) {
475            Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
476            return false;
477        }
478        return true;
479    }
480
481    /** Use this to check if a package can post a notification or toast. */
482    private boolean checkNotificationOp(String pkg, int uid) {
483        return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
484                == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
485    }
486
487    private static final class ToastRecord
488    {
489        final int pid;
490        final String pkg;
491        final ITransientNotification callback;
492        int duration;
493        Binder token;
494
495        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
496                    Binder token) {
497            this.pid = pid;
498            this.pkg = pkg;
499            this.callback = callback;
500            this.duration = duration;
501            this.token = token;
502        }
503
504        void update(int duration) {
505            this.duration = duration;
506        }
507
508        void dump(PrintWriter pw, String prefix, DumpFilter filter) {
509            if (filter != null && !filter.matches(pkg)) return;
510            pw.println(prefix + this);
511        }
512
513        @Override
514        public final String toString()
515        {
516            return "ToastRecord{"
517                + Integer.toHexString(System.identityHashCode(this))
518                + " pkg=" + pkg
519                + " callback=" + callback
520                + " duration=" + duration;
521        }
522    }
523
524    private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
525
526        @Override
527        public void onSetDisabled(int status) {
528            synchronized (mNotificationLock) {
529                mDisableNotificationEffects =
530                        (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
531                if (disableNotificationEffects(null) != null) {
532                    // cancel whatever's going on
533                    long identity = Binder.clearCallingIdentity();
534                    try {
535                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
536                        if (player != null) {
537                            player.stopAsync();
538                        }
539                    } catch (RemoteException e) {
540                    } finally {
541                        Binder.restoreCallingIdentity(identity);
542                    }
543
544                    identity = Binder.clearCallingIdentity();
545                    try {
546                        mVibrator.cancel();
547                    } finally {
548                        Binder.restoreCallingIdentity(identity);
549                    }
550                }
551            }
552        }
553
554        @Override
555        public void onClearAll(int callingUid, int callingPid, int userId) {
556            synchronized (mNotificationLock) {
557                cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
558                        /*includeCurrentProfiles*/ true);
559            }
560        }
561
562        @Override
563        public void onNotificationClick(int callingUid, int callingPid, String key) {
564            synchronized (mNotificationLock) {
565                NotificationRecord r = mNotificationsByKey.get(key);
566                if (r == null) {
567                    Log.w(TAG, "No notification with key: " + key);
568                    return;
569                }
570                final long now = System.currentTimeMillis();
571                MetricsLogger.action(r.getLogMaker(now)
572                        .setCategory(MetricsEvent.NOTIFICATION_ITEM)
573                        .setType(MetricsEvent.TYPE_ACTION));
574                EventLogTags.writeNotificationClicked(key,
575                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
576
577                StatusBarNotification sbn = r.sbn;
578                cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
579                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
580                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
581                        REASON_CLICK, null);
582            }
583        }
584
585        @Override
586        public void onNotificationActionClick(int callingUid, int callingPid, String key,
587                int actionIndex) {
588            synchronized (mNotificationLock) {
589                NotificationRecord r = mNotificationsByKey.get(key);
590                if (r == null) {
591                    Log.w(TAG, "No notification with key: " + key);
592                    return;
593                }
594                final long now = System.currentTimeMillis();
595                MetricsLogger.action(r.getLogMaker(now)
596                        .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
597                        .setType(MetricsEvent.TYPE_ACTION)
598                        .setSubtype(actionIndex));
599                EventLogTags.writeNotificationActionClicked(key, actionIndex,
600                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
601                // TODO: Log action click via UsageStats.
602            }
603        }
604
605        @Override
606        public void onNotificationClear(int callingUid, int callingPid,
607                String pkg, String tag, int id, int userId) {
608            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
609                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
610                    true, userId, REASON_CANCEL, null);
611        }
612
613        @Override
614        public void onPanelRevealed(boolean clearEffects, int items) {
615            MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
616            MetricsLogger.histogram(getContext(), "notification_load", items);
617            EventLogTags.writeNotificationPanelRevealed(items);
618            if (clearEffects) {
619                clearEffects();
620            }
621        }
622
623        @Override
624        public void onPanelHidden() {
625            MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
626            EventLogTags.writeNotificationPanelHidden();
627        }
628
629        @Override
630        public void clearEffects() {
631            synchronized (mNotificationLock) {
632                if (DBG) Slog.d(TAG, "clearEffects");
633                clearSoundLocked();
634                clearVibrateLocked();
635                clearLightsLocked();
636            }
637        }
638
639        @Override
640        public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
641                int uid, int initialPid, String message, int userId) {
642            Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
643                    + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
644            cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
645                    REASON_ERROR, null);
646            long ident = Binder.clearCallingIdentity();
647            try {
648                ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
649                        "Bad notification posted from package " + pkg
650                        + ": " + message);
651            } catch (RemoteException e) {
652            }
653            Binder.restoreCallingIdentity(ident);
654        }
655
656        @Override
657        public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
658                NotificationVisibility[] noLongerVisibleKeys) {
659            synchronized (mNotificationLock) {
660                for (NotificationVisibility nv : newlyVisibleKeys) {
661                    NotificationRecord r = mNotificationsByKey.get(nv.key);
662                    if (r == null) continue;
663                    r.setVisibility(true, nv.rank);
664                    nv.recycle();
665                }
666                // Note that we might receive this event after notifications
667                // have already left the system, e.g. after dismissing from the
668                // shade. Hence not finding notifications in
669                // mNotificationsByKey is not an exceptional condition.
670                for (NotificationVisibility nv : noLongerVisibleKeys) {
671                    NotificationRecord r = mNotificationsByKey.get(nv.key);
672                    if (r == null) continue;
673                    r.setVisibility(false, nv.rank);
674                    nv.recycle();
675                }
676            }
677        }
678
679        @Override
680        public void onNotificationExpansionChanged(String key,
681                boolean userAction, boolean expanded) {
682            synchronized (mNotificationLock) {
683                NotificationRecord r = mNotificationsByKey.get(key);
684                if (r != null) {
685                    r.stats.onExpansionChanged(userAction, expanded);
686                    final long now = System.currentTimeMillis();
687                    MetricsLogger.action(r.getLogMaker(now)
688                            .setCategory(MetricsEvent.NOTIFICATION_ITEM)
689                            .setType(MetricsEvent.TYPE_DETAIL));
690                    EventLogTags.writeNotificationExpansion(key,
691                            userAction ? 1 : 0, expanded ? 1 : 0,
692                            r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
693                }
694            }
695        }
696    };
697
698    private void clearSoundLocked() {
699        mSoundNotificationKey = null;
700        long identity = Binder.clearCallingIdentity();
701        try {
702            final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
703            if (player != null) {
704                player.stopAsync();
705            }
706        } catch (RemoteException e) {
707        } finally {
708            Binder.restoreCallingIdentity(identity);
709        }
710    }
711
712    private void clearVibrateLocked() {
713        mVibrateNotificationKey = null;
714        long identity = Binder.clearCallingIdentity();
715        try {
716            mVibrator.cancel();
717        } finally {
718            Binder.restoreCallingIdentity(identity);
719        }
720    }
721
722    private void clearLightsLocked() {
723        // light
724        mLights.clear();
725        updateLightsLocked();
726    }
727
728    private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
729        @Override
730        public void onReceive(Context context, Intent intent) {
731            String action = intent.getAction();
732            if (action == null) {
733                return;
734            }
735            if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
736                final NotificationRecord record;
737                synchronized (mNotificationLock) {
738                    record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
739                }
740                if (record != null) {
741                    cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
742                            record.sbn.getPackageName(), record.sbn.getTag(),
743                            record.sbn.getId(), 0,
744                            Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
745                            REASON_TIMEOUT, null);
746                }
747            }
748        }
749    };
750
751    private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
752        @Override
753        public void onReceive(Context context, Intent intent) {
754            String action = intent.getAction();
755            if (action == null) {
756                return;
757            }
758
759            boolean queryRestart = false;
760            boolean queryRemove = false;
761            boolean packageChanged = false;
762            boolean cancelNotifications = true;
763            int reason = REASON_PACKAGE_CHANGED;
764
765            if (action.equals(Intent.ACTION_PACKAGE_ADDED)
766                    || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
767                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
768                    || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
769                    || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
770                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
771                    || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
772                int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
773                        UserHandle.USER_ALL);
774                String pkgList[] = null;
775                int uidList[] = null;
776                boolean removingPackage = queryRemove &&
777                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
778                if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
779                if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
780                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
781                    uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
782                } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
783                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
784                    reason = REASON_PACKAGE_SUSPENDED;
785                } else if (queryRestart) {
786                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
787                    uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
788                } else {
789                    Uri uri = intent.getData();
790                    if (uri == null) {
791                        return;
792                    }
793                    String pkgName = uri.getSchemeSpecificPart();
794                    if (pkgName == null) {
795                        return;
796                    }
797                    if (packageChanged) {
798                        // We cancel notifications for packages which have just been disabled
799                        try {
800                            final int enabled = mPackageManager.getApplicationEnabledSetting(
801                                    pkgName,
802                                    changeUserId != UserHandle.USER_ALL ? changeUserId :
803                                            UserHandle.USER_SYSTEM);
804                            if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
805                                    || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
806                                cancelNotifications = false;
807                            }
808                        } catch (IllegalArgumentException e) {
809                            // Package doesn't exist; probably racing with uninstall.
810                            // cancelNotifications is already true, so nothing to do here.
811                            if (DBG) {
812                                Slog.i(TAG, "Exception trying to look up app enabled setting", e);
813                            }
814                        } catch (RemoteException e) {
815                            // Failed to talk to PackageManagerService Should never happen!
816                        }
817                    }
818                    pkgList = new String[]{pkgName};
819                    uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
820                }
821                if (pkgList != null && (pkgList.length > 0)) {
822                    for (String pkgName : pkgList) {
823                        if (cancelNotifications) {
824                            cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
825                                    !queryRestart, changeUserId, reason, null);
826                        }
827                    }
828                }
829                mListeners.onPackagesChanged(removingPackage, pkgList);
830                mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
831                mConditionProviders.onPackagesChanged(removingPackage, pkgList);
832                mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
833                savePolicyFile();
834            }
835        }
836    };
837
838    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
839        @Override
840        public void onReceive(Context context, Intent intent) {
841            String action = intent.getAction();
842
843            if (action.equals(Intent.ACTION_SCREEN_ON)) {
844                // Keep track of screen on/off state, but do not turn off the notification light
845                // until user passes through the lock screen or views the notification.
846                mScreenOn = true;
847                updateNotificationPulse();
848            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
849                mScreenOn = false;
850                updateNotificationPulse();
851            } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
852                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
853                        .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
854                updateNotificationPulse();
855            } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
856                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
857                if (userHandle >= 0) {
858                    cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
859                            REASON_USER_STOPPED, null);
860                }
861            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
862                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
863                if (userHandle >= 0) {
864                    cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
865                            REASON_PROFILE_TURNED_OFF, null);
866                }
867            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
868                // turn off LED when user passes through lock screen
869                mNotificationLight.turnOff();
870            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
871                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
872                // reload per-user settings
873                mSettingsObserver.update(null);
874                mUserProfiles.updateCache(context);
875                // Refresh managed services
876                mConditionProviders.onUserSwitched(user);
877                mListeners.onUserSwitched(user);
878                mNotificationAssistants.onUserSwitched(user);
879                mZenModeHelper.onUserSwitched(user);
880            } else if (action.equals(Intent.ACTION_USER_ADDED)) {
881                mUserProfiles.updateCache(context);
882            } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
883                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
884                mZenModeHelper.onUserRemoved(user);
885            } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
886                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
887                mConditionProviders.onUserUnlocked(user);
888                mListeners.onUserUnlocked(user);
889                mNotificationAssistants.onUserUnlocked(user);
890                mZenModeHelper.onUserUnlocked(user);
891            }
892        }
893    };
894
895    private final class SettingsObserver extends ContentObserver {
896        private final Uri NOTIFICATION_LIGHT_PULSE_URI
897                = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
898        private final Uri NOTIFICATION_RATE_LIMIT_URI
899                = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
900
901        SettingsObserver(Handler handler) {
902            super(handler);
903        }
904
905        void observe() {
906            ContentResolver resolver = getContext().getContentResolver();
907            resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
908                    false, this, UserHandle.USER_ALL);
909            resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
910                    false, this, UserHandle.USER_ALL);
911            update(null);
912        }
913
914        @Override public void onChange(boolean selfChange, Uri uri) {
915            update(uri);
916        }
917
918        public void update(Uri uri) {
919            ContentResolver resolver = getContext().getContentResolver();
920            if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
921                boolean pulseEnabled = Settings.System.getInt(resolver,
922                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
923                if (mNotificationPulseEnabled != pulseEnabled) {
924                    mNotificationPulseEnabled = pulseEnabled;
925                    updateNotificationPulse();
926                }
927            }
928            if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
929                mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
930                            Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
931            }
932        }
933    }
934
935    private SettingsObserver mSettingsObserver;
936    private ZenModeHelper mZenModeHelper;
937
938    static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
939        int[] ar = r.getIntArray(resid);
940        if (ar == null) {
941            return def;
942        }
943        final int len = ar.length > maxlen ? maxlen : ar.length;
944        long[] out = new long[len];
945        for (int i=0; i<len; i++) {
946            out[i] = ar[i];
947        }
948        return out;
949    }
950
951    public NotificationManagerService(Context context) {
952        super(context);
953    }
954
955    // TODO - replace these methods with a single VisibleForTesting constructor
956    @VisibleForTesting
957    void setAudioManager(AudioManager audioMananger) {
958        mAudioManager = audioMananger;
959    }
960
961    @VisibleForTesting
962    void setVibrator(Vibrator vibrator) {
963        mVibrator = vibrator;
964    }
965
966    @VisibleForTesting
967    void setLights(Light light) {
968        mNotificationLight = light;
969        mAttentionLight = light;
970        mNotificationPulseEnabled = true;
971    }
972
973    @VisibleForTesting
974    void setScreenOn(boolean on) {
975        mScreenOn = on;
976    }
977
978    @VisibleForTesting
979    void addNotification(NotificationRecord r) {
980        mNotificationList.add(r);
981        mNotificationsByKey.put(r.sbn.getKey(), r);
982    }
983
984    @VisibleForTesting
985    void setSystemReady(boolean systemReady) {
986        mSystemReady = systemReady;
987    }
988
989    @VisibleForTesting
990    void setHandler(Handler handler) {
991        mHandler = handler;
992    }
993
994    @VisibleForTesting
995    void setFallbackVibrationPattern(long[] vibrationPattern) {
996        mFallbackVibrationPattern = vibrationPattern;
997    }
998
999    @VisibleForTesting
1000    void setPackageManager(IPackageManager packageManager) {
1001        mPackageManager = packageManager;
1002    }
1003
1004    @VisibleForTesting
1005    void setRankingHelper(RankingHelper rankingHelper) {
1006        mRankingHelper = rankingHelper;
1007    }
1008
1009    @VisibleForTesting
1010    void setIsTelevision(boolean isTelevision) {
1011        mIsTelevision = isTelevision;
1012    }
1013
1014    // TODO: Tests should call onStart instead once the methods above are removed.
1015    @VisibleForTesting
1016    void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
1017            LightsManager lightsManager, NotificationListeners notificationListeners,
1018            ICompanionDeviceManager companionManager) {
1019        Resources resources = getContext().getResources();
1020        mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1021                Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1022                DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1023
1024        mAm = ActivityManager.getService();
1025        mPackageManager = packageManager;
1026        mPackageManagerClient = packageManagerClient;
1027        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1028        mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1029        mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1030        mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1031        mCompanionManager = companionManager;
1032
1033        mHandler = new WorkerHandler(looper);
1034        mRankingThread.start();
1035        String[] extractorNames;
1036        try {
1037            extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1038        } catch (Resources.NotFoundException e) {
1039            extractorNames = new String[0];
1040        }
1041        mUsageStats = new NotificationUsageStats(getContext());
1042        mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1043        mRankingHelper = new RankingHelper(getContext(),
1044                getContext().getPackageManager(),
1045                mRankingHandler,
1046                mUsageStats,
1047                extractorNames);
1048        mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
1049        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1050        mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1051            @Override
1052            public void onConfigChanged() {
1053                savePolicyFile();
1054            }
1055
1056            @Override
1057            void onZenModeChanged() {
1058                sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1059                getContext().sendBroadcastAsUser(
1060                        new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1061                                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1062                        UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1063                synchronized (mNotificationLock) {
1064                    updateInterruptionFilterLocked();
1065                }
1066            }
1067
1068            @Override
1069            void onPolicyChanged() {
1070                sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1071            }
1072        });
1073        mSnoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1074            @Override
1075            public void repost(int userId, NotificationRecord r) {
1076                try {
1077                    if (DBG) {
1078                        Slog.d(TAG, "Reposting " + r.getKey());
1079                    }
1080                    enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1081                            r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1082                            r.sbn.getNotification(), new int[1], userId);
1083                } catch (Exception e) {
1084                    Slog.e(TAG, "Cannot un-snooze notification", e);
1085                }
1086            }
1087        }, mUserProfiles);
1088        mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
1089            @Override
1090            public void addAutoGroup(String key) {
1091                synchronized (mNotificationLock) {
1092                    addAutogroupKeyLocked(key);
1093                }
1094                mRankingHandler.requestSort(false);
1095            }
1096
1097            @Override
1098            public void removeAutoGroup(String key) {
1099                synchronized (mNotificationLock) {
1100                    removeAutogroupKeyLocked(key);
1101                }
1102                mRankingHandler.requestSort(false);
1103            }
1104
1105            @Override
1106            public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1107                createAutoGroupSummary(userId, pkg, triggeringKey);
1108            }
1109
1110            @Override
1111            public void removeAutoGroupSummary(int userId, String pkg) {
1112                synchronized (mNotificationLock) {
1113                    clearAutogroupSummaryLocked(userId, pkg);
1114                }
1115            }
1116        });
1117
1118        final File systemDir = new File(Environment.getDataDirectory(), "system");
1119        mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
1120
1121        syncBlockDb();
1122
1123        // This is a ManagedServices object that keeps track of the listeners.
1124        mListeners = notificationListeners;
1125
1126        // This is a MangedServices object that keeps track of the assistant.
1127        mNotificationAssistants = new NotificationAssistants();
1128
1129        mStatusBar = getLocalService(StatusBarManagerInternal.class);
1130        if (mStatusBar != null) {
1131            mStatusBar.setNotificationDelegate(mNotificationDelegate);
1132        }
1133
1134        mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1135        mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1136
1137        mFallbackVibrationPattern = getLongArray(resources,
1138                R.array.config_notificationFallbackVibePattern,
1139                VIBRATE_PATTERN_MAXLEN,
1140                DEFAULT_VIBRATE_PATTERN);
1141
1142        mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1143
1144        // Don't start allowing notifications until the setup wizard has run once.
1145        // After that, including subsequent boots, init with notifications turned on.
1146        // This works on the first boot because the setup wizard will toggle this
1147        // flag at least once and we'll go back to 0 after that.
1148        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1149                    Settings.Global.DEVICE_PROVISIONED, 0)) {
1150            mDisableNotificationEffects = true;
1151        }
1152        mZenModeHelper.initZenMode();
1153        mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1154
1155        mUserProfiles.updateCache(getContext());
1156        listenForCallState();
1157
1158        // register for various Intents
1159        IntentFilter filter = new IntentFilter();
1160        filter.addAction(Intent.ACTION_SCREEN_ON);
1161        filter.addAction(Intent.ACTION_SCREEN_OFF);
1162        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1163        filter.addAction(Intent.ACTION_USER_PRESENT);
1164        filter.addAction(Intent.ACTION_USER_STOPPED);
1165        filter.addAction(Intent.ACTION_USER_SWITCHED);
1166        filter.addAction(Intent.ACTION_USER_ADDED);
1167        filter.addAction(Intent.ACTION_USER_REMOVED);
1168        filter.addAction(Intent.ACTION_USER_UNLOCKED);
1169        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1170        getContext().registerReceiver(mIntentReceiver, filter);
1171
1172        IntentFilter pkgFilter = new IntentFilter();
1173        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1174        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1175        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1176        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1177        pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1178        pkgFilter.addDataScheme("package");
1179        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1180                null);
1181
1182        IntentFilter suspendedPkgFilter = new IntentFilter();
1183        suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1184        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1185                suspendedPkgFilter, null, null);
1186
1187        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1188        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1189                null);
1190
1191        IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1192        timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1193        getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1194
1195        mSettingsObserver = new SettingsObserver(mHandler);
1196
1197        mArchive = new Archive(resources.getInteger(
1198                R.integer.config_notificationServiceArchiveSize));
1199
1200        mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1201                || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1202    }
1203
1204    @Override
1205    public void onStart() {
1206        init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
1207                getLocalService(LightsManager.class), new NotificationListeners(),
1208                null);
1209        publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1210        publishLocalService(NotificationManagerInternal.class, mInternalService);
1211    }
1212
1213    private void sendRegisteredOnlyBroadcast(String action) {
1214        getContext().sendBroadcastAsUser(new Intent(action)
1215                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1216    }
1217
1218    /**
1219     * Make sure the XML config and the the AppOps system agree about blocks.
1220     */
1221    private void syncBlockDb() {
1222        loadPolicyFile();
1223
1224        // sync bans from ranker into app opps
1225        Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1226        for(Entry<Integer, String> ban : packageBans.entrySet()) {
1227            final int uid = ban.getKey();
1228            final String packageName = ban.getValue();
1229            setNotificationsEnabledForPackageImpl(packageName, uid, false);
1230        }
1231
1232        // sync bans from app opps into ranker
1233        packageBans.clear();
1234        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1235            final int userId = user.getUserHandle().getIdentifier();
1236            final PackageManager packageManager = getContext().getPackageManager();
1237            List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1238            final int packageCount = packages.size();
1239            for (int p = 0; p < packageCount; p++) {
1240                final String packageName = packages.get(p).packageName;
1241                try {
1242                    final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1243                    if (!checkNotificationOp(packageName, uid)) {
1244                        packageBans.put(uid, packageName);
1245                    }
1246                } catch (NameNotFoundException e) {
1247                    // forget you
1248                }
1249            }
1250        }
1251        for (Entry<Integer, String> ban : packageBans.entrySet()) {
1252            mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1253        }
1254
1255        savePolicyFile();
1256    }
1257
1258    @Override
1259    public void onBootPhase(int phase) {
1260        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1261            // no beeping until we're basically done booting
1262            mSystemReady = true;
1263
1264            // Grab our optional AudioService
1265            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1266            mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1267            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1268            mZenModeHelper.onSystemReady();
1269        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1270            // This observer will force an update when observe is called, causing us to
1271            // bind to listener services.
1272            mSettingsObserver.observe();
1273            mListeners.onBootPhaseAppsCanStart();
1274            mNotificationAssistants.onBootPhaseAppsCanStart();
1275            mConditionProviders.onBootPhaseAppsCanStart();
1276        }
1277    }
1278
1279    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1280        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1281
1282        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1283                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1284
1285        // Now, cancel any outstanding notifications that are part of a just-disabled app
1286        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1287            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1288                    UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1289        }
1290    }
1291
1292    private void updateListenerHintsLocked() {
1293        final int hints = calculateHints();
1294        if (hints == mListenerHints) return;
1295        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1296        mListenerHints = hints;
1297        scheduleListenerHintsChanged(hints);
1298    }
1299
1300    private void updateEffectsSuppressorLocked() {
1301        final long updatedSuppressedEffects = calculateSuppressedEffects();
1302        if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1303        final List<ComponentName> suppressors = getSuppressors();
1304        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1305        mEffectsSuppressors = suppressors;
1306        mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1307        sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1308    }
1309
1310    private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1311            boolean fromListener) {
1312        if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1313            // cancel
1314            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1315                    UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1316                    null);
1317        }
1318        mRankingHelper.updateNotificationChannel(pkg, uid, channel);
1319
1320        final NotificationChannel modifiedChannel =
1321                mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1322
1323        if (!fromListener) {
1324            mListeners.notifyNotificationChannelChanged(
1325                    pkg, modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1326        }
1327
1328        synchronized (mNotificationLock) {
1329            final int N = mNotificationList.size();
1330            for (int i = N - 1; i >= 0; --i) {
1331                NotificationRecord r = mNotificationList.get(i);
1332                if (r.sbn.getPackageName().equals(pkg)
1333                        && r.sbn.getUid() == uid
1334                        && channel.getId() != null
1335                        && channel.getId().equals(r.getChannel().getId())) {
1336                    r.updateNotificationChannel(modifiedChannel);
1337                }
1338            }
1339        }
1340        mRankingHandler.requestSort(true);
1341        savePolicyFile();
1342    }
1343
1344    private ArrayList<ComponentName> getSuppressors() {
1345        ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1346        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1347            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1348
1349            for (ManagedServiceInfo info : serviceInfoList) {
1350                names.add(info.component);
1351            }
1352        }
1353
1354        return names;
1355    }
1356
1357    private boolean removeDisabledHints(ManagedServiceInfo info) {
1358        return removeDisabledHints(info, 0);
1359    }
1360
1361    private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1362        boolean removed = false;
1363
1364        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1365            final int hint = mListenersDisablingEffects.keyAt(i);
1366            final ArraySet<ManagedServiceInfo> listeners =
1367                    mListenersDisablingEffects.valueAt(i);
1368
1369            if (hints == 0 || (hint & hints) == hint) {
1370                removed = removed || listeners.remove(info);
1371            }
1372        }
1373
1374        return removed;
1375    }
1376
1377    private void addDisabledHints(ManagedServiceInfo info, int hints) {
1378        if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1379            addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1380        }
1381
1382        if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1383            addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1384        }
1385
1386        if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1387            addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1388        }
1389    }
1390
1391    private void addDisabledHint(ManagedServiceInfo info, int hint) {
1392        if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1393            mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1394        }
1395
1396        ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1397        hintListeners.add(info);
1398    }
1399
1400    private int calculateHints() {
1401        int hints = 0;
1402        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1403            int hint = mListenersDisablingEffects.keyAt(i);
1404            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1405
1406            if (!serviceInfoList.isEmpty()) {
1407                hints |= hint;
1408            }
1409        }
1410
1411        return hints;
1412    }
1413
1414    private long calculateSuppressedEffects() {
1415        int hints = calculateHints();
1416        long suppressedEffects = 0;
1417
1418        if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1419            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1420        }
1421
1422        if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1423            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1424        }
1425
1426        if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1427            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1428        }
1429
1430        return suppressedEffects;
1431    }
1432
1433    private void updateInterruptionFilterLocked() {
1434        int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1435        if (interruptionFilter == mInterruptionFilter) return;
1436        mInterruptionFilter = interruptionFilter;
1437        scheduleInterruptionFilterChanged(interruptionFilter);
1438    }
1439
1440    @VisibleForTesting
1441    INotificationManager getBinderService() {
1442        return INotificationManager.Stub.asInterface(mService);
1443    }
1444
1445    @VisibleForTesting
1446    NotificationManagerInternal getInternalService() {
1447        return mInternalService;
1448    }
1449
1450    private final IBinder mService = new INotificationManager.Stub() {
1451        // Toasts
1452        // ============================================================================
1453
1454        @Override
1455        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1456        {
1457            if (DBG) {
1458                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1459                        + " duration=" + duration);
1460            }
1461
1462            if (pkg == null || callback == null) {
1463                Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1464                return ;
1465            }
1466
1467            final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1468            final boolean isPackageSuspended =
1469                    isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1470
1471            if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1472                    || isPackageSuspended)) {
1473                if (!isSystemToast) {
1474                    Slog.e(TAG, "Suppressing toast from package " + pkg
1475                            + (isPackageSuspended
1476                                    ? " due to package suspended by administrator."
1477                                    : " by user request."));
1478                    return;
1479                }
1480            }
1481
1482            synchronized (mToastQueue) {
1483                int callingPid = Binder.getCallingPid();
1484                long callingId = Binder.clearCallingIdentity();
1485                try {
1486                    ToastRecord record;
1487                    int index = indexOfToastLocked(pkg, callback);
1488                    // If it's already in the queue, we update it in place, we don't
1489                    // move it to the end of the queue.
1490                    if (index >= 0) {
1491                        record = mToastQueue.get(index);
1492                        record.update(duration);
1493                    } else {
1494                        // Limit the number of toasts that any given package except the android
1495                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
1496                        if (!isSystemToast) {
1497                            int count = 0;
1498                            final int N = mToastQueue.size();
1499                            for (int i=0; i<N; i++) {
1500                                 final ToastRecord r = mToastQueue.get(i);
1501                                 if (r.pkg.equals(pkg)) {
1502                                     count++;
1503                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1504                                         Slog.e(TAG, "Package has already posted " + count
1505                                                + " toasts. Not showing more. Package=" + pkg);
1506                                         return;
1507                                     }
1508                                 }
1509                            }
1510                        }
1511
1512                        Binder token = new Binder();
1513                        mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1514                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
1515                        mToastQueue.add(record);
1516                        index = mToastQueue.size() - 1;
1517                        keepProcessAliveIfNeededLocked(callingPid);
1518                    }
1519                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
1520                    // new or just been updated.  Call back and tell it to show itself.
1521                    // If the callback fails, this will remove it from the list, so don't
1522                    // assume that it's valid after this.
1523                    if (index == 0) {
1524                        showNextToastLocked();
1525                    }
1526                } finally {
1527                    Binder.restoreCallingIdentity(callingId);
1528                }
1529            }
1530        }
1531
1532        @Override
1533        public void cancelToast(String pkg, ITransientNotification callback) {
1534            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1535
1536            if (pkg == null || callback == null) {
1537                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1538                return ;
1539            }
1540
1541            synchronized (mToastQueue) {
1542                long callingId = Binder.clearCallingIdentity();
1543                try {
1544                    int index = indexOfToastLocked(pkg, callback);
1545                    if (index >= 0) {
1546                        cancelToastLocked(index);
1547                    } else {
1548                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1549                                + " callback=" + callback);
1550                    }
1551                } finally {
1552                    Binder.restoreCallingIdentity(callingId);
1553                }
1554            }
1555        }
1556
1557        @Override
1558        public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1559                Notification notification, int[] idOut, int userId) throws RemoteException {
1560            enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1561                    Binder.getCallingPid(), tag, id, notification, idOut, userId);
1562        }
1563
1564        @Override
1565        public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1566            checkCallerIsSystemOrSameApp(pkg);
1567            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1568                    Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1569            // Don't allow client applications to cancel foreground service notis or autobundled
1570            // summaries.
1571            cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1572                    (Binder.getCallingUid() == Process.SYSTEM_UID
1573                            ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1574                            | (Binder.getCallingUid() == Process.SYSTEM_UID
1575                            ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1576                    REASON_APP_CANCEL, null);
1577        }
1578
1579        @Override
1580        public void cancelAllNotifications(String pkg, int userId) {
1581            checkCallerIsSystemOrSameApp(pkg);
1582
1583            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1584                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1585
1586            // Calling from user space, don't allow the canceling of actively
1587            // running foreground services.
1588            cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1589                    pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1590                    REASON_APP_CANCEL_ALL, null);
1591        }
1592
1593        @Override
1594        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1595            checkCallerIsSystem();
1596
1597            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1598            mRankingHelper.setEnabled(pkg, uid, enabled);
1599            savePolicyFile();
1600        }
1601
1602        /**
1603         * Use this when you just want to know if notifications are OK for this package.
1604         */
1605        @Override
1606        public boolean areNotificationsEnabled(String pkg) {
1607            return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1608        }
1609
1610        /**
1611         * Use this when you just want to know if notifications are OK for this package.
1612         */
1613        @Override
1614        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1615            checkCallerIsSystemOrSameApp(pkg);
1616            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1617                    == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1618        }
1619
1620        @Override
1621        public int getPackageImportance(String pkg) {
1622            checkCallerIsSystemOrSameApp(pkg);
1623            return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1624        }
1625
1626        @Override
1627        public boolean canShowBadge(String pkg, int uid) {
1628            checkCallerIsSystem();
1629            return mRankingHelper.canShowBadge(pkg, uid);
1630        }
1631
1632        @Override
1633        public void setShowBadge(String pkg, int uid, boolean showBadge) {
1634            checkCallerIsSystem();
1635            mRankingHelper.setShowBadge(pkg, uid, showBadge);
1636            savePolicyFile();
1637        }
1638
1639        @Override
1640        public void createNotificationChannelGroups(String pkg,
1641                ParceledListSlice channelGroupList) throws RemoteException {
1642            checkCallerIsSystemOrSameApp(pkg);
1643            List<NotificationChannelGroup> groups = channelGroupList.getList();
1644            final int groupSize = groups.size();
1645            for (int i = 0; i < groupSize; i++) {
1646                final NotificationChannelGroup group = groups.get(i);
1647                Preconditions.checkNotNull(group, "group in list is null");
1648                mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1649                        true /* fromTargetApp */);
1650                mListeners.notifyNotificationChannelGroupChanged(pkg, group,
1651                        NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1652            }
1653            savePolicyFile();
1654        }
1655
1656        private void createNotificationChannelsImpl(String pkg, int uid,
1657                ParceledListSlice channelsList) {
1658            List<NotificationChannel> channels = channelsList.getList();
1659            final int channelsSize = channels.size();
1660            for (int i = 0; i < channelsSize; i++) {
1661                final NotificationChannel channel = channels.get(i);
1662                Preconditions.checkNotNull(channel, "channel in list is null");
1663                mRankingHelper.createNotificationChannel(pkg, uid, channel,
1664                        true /* fromTargetApp */);
1665                mListeners.notifyNotificationChannelChanged(pkg,
1666                        mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1667                        NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1668            }
1669            savePolicyFile();
1670        }
1671
1672        @Override
1673        public void createNotificationChannels(String pkg,
1674                ParceledListSlice channelsList) throws RemoteException {
1675            checkCallerIsSystemOrSameApp(pkg);
1676            createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1677        }
1678
1679        @Override
1680        public void createNotificationChannelsForPackage(String pkg, int uid,
1681                ParceledListSlice channelsList) throws RemoteException {
1682            checkCallerIsSystem();
1683            createNotificationChannelsImpl(pkg, uid, channelsList);
1684        }
1685
1686        @Override
1687        public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1688            checkCallerIsSystemOrSameApp(pkg);
1689            return mRankingHelper.getNotificationChannel(
1690                    pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1691        }
1692
1693        @Override
1694        public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1695                String channelId, boolean includeDeleted) {
1696            checkCallerIsSystem();
1697            return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1698        }
1699
1700        @Override
1701        public void deleteNotificationChannel(String pkg, String channelId) {
1702            checkCallerIsSystemOrSameApp(pkg);
1703            final int callingUid = Binder.getCallingUid();
1704            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1705                throw new IllegalArgumentException("Cannot delete default channel");
1706            }
1707            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1708                    UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1709            mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1710            mListeners.notifyNotificationChannelChanged(pkg,
1711                    mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1712                    NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1713            savePolicyFile();
1714        }
1715
1716        @Override
1717        public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1718                String pkg) {
1719            checkCallerIsSystemOrSameApp(pkg);
1720            return new ParceledListSlice<>(new ArrayList(
1721                    mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1722        }
1723
1724        @Override
1725        public void deleteNotificationChannelGroup(String pkg, String groupId) {
1726            checkCallerIsSystemOrSameApp(pkg);
1727
1728            final int callingUid = Binder.getCallingUid();
1729            NotificationChannelGroup groupToDelete =
1730                    mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1731            if (groupToDelete != null) {
1732                List<NotificationChannel> deletedChannels =
1733                        mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1734                for (int i = 0; i < deletedChannels.size(); i++) {
1735                    final NotificationChannel deletedChannel = deletedChannels.get(i);
1736                    cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1737                            true,
1738                            UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1739                            null);
1740                    mListeners.notifyNotificationChannelChanged(pkg, deletedChannel,
1741                            NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1742                }
1743                mListeners.notifyNotificationChannelGroupChanged(
1744                        pkg, groupToDelete, NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1745                savePolicyFile();
1746            }
1747        }
1748
1749        @Override
1750        public void updateNotificationChannelForPackage(String pkg, int uid,
1751                NotificationChannel channel) {
1752            enforceSystemOrSystemUI("Caller not system or systemui");
1753            Preconditions.checkNotNull(channel);
1754            updateNotificationChannelInt(pkg, uid, channel, false);
1755        }
1756
1757        @Override
1758        public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1759                int uid, boolean includeDeleted) {
1760            enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1761            return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1762        }
1763
1764        @Override
1765        public int getNumNotificationChannelsForPackage(String pkg, int uid,
1766                boolean includeDeleted) {
1767            enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1768            return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1769                    .getList().size();
1770        }
1771
1772        @Override
1773        public int getDeletedChannelCount(String pkg, int uid) {
1774            enforceSystemOrSystemUI("getDeletedChannelCount");
1775            return mRankingHelper.getDeletedChannelCount(pkg, uid);
1776        }
1777
1778        @Override
1779        public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1780                String pkg, int uid, boolean includeDeleted) {
1781            checkCallerIsSystem();
1782            return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1783        }
1784
1785        @Override
1786        public NotificationChannelGroup getNotificationChannelGroupForPackage(
1787                String groupId, String pkg, int uid) {
1788            enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1789            return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1790        }
1791
1792        @Override
1793        public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1794            checkCallerIsSystemOrSameApp(pkg);
1795            return mRankingHelper.getNotificationChannels(
1796                    pkg, Binder.getCallingUid(), false /* includeDeleted */);
1797        }
1798
1799        @Override
1800        public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1801            checkCallerIsSystem();
1802
1803            // Cancel posted notifications
1804            cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1805                    UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1806
1807            // Listener & assistant
1808            mListeners.onPackagesChanged(true, new String[] {packageName});
1809            mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
1810
1811            // Zen
1812            mConditionProviders.onPackagesChanged(true, new String[] {packageName});
1813
1814            // Reset notification preferences
1815            if (!fromApp) {
1816                mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
1817                        new String[]{packageName}, new int[]{uid});
1818            }
1819
1820            savePolicyFile();
1821        }
1822
1823
1824        /**
1825         * System-only API for getting a list of current (i.e. not cleared) notifications.
1826         *
1827         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1828         * @returns A list of all the notifications, in natural order.
1829         */
1830        @Override
1831        public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1832            // enforce() will ensure the calling uid has the correct permission
1833            getContext().enforceCallingOrSelfPermission(
1834                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1835                    "NotificationManagerService.getActiveNotifications");
1836
1837            StatusBarNotification[] tmp = null;
1838            int uid = Binder.getCallingUid();
1839
1840            // noteOp will check to make sure the callingPkg matches the uid
1841            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1842                    == AppOpsManager.MODE_ALLOWED) {
1843                synchronized (mNotificationLock) {
1844                    tmp = new StatusBarNotification[mNotificationList.size()];
1845                    final int N = mNotificationList.size();
1846                    for (int i=0; i<N; i++) {
1847                        tmp[i] = mNotificationList.get(i).sbn;
1848                    }
1849                }
1850            }
1851            return tmp;
1852        }
1853
1854        /**
1855         * Public API for getting a list of current notifications for the calling package/uid.
1856         *
1857         * Note that since notification posting is done asynchronously, this will not return
1858         * notifications that are in the process of being posted.
1859         *
1860         * @returns A list of all the package's notifications, in natural order.
1861         */
1862        @Override
1863        public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1864                int incomingUserId) {
1865            checkCallerIsSystemOrSameApp(pkg);
1866            int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1867                    Binder.getCallingUid(), incomingUserId, true, false,
1868                    "getAppActiveNotifications", pkg);
1869            final ArrayMap<String, StatusBarNotification> map
1870                    = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
1871
1872            synchronized (mNotificationLock) {
1873                final int N = mNotificationList.size();
1874                for (int i = 0; i < N; i++) {
1875                    StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1876                            mNotificationList.get(i).sbn);
1877                    if (sbn != null) {
1878                        map.put(sbn.getKey(), sbn);
1879                    }
1880                }
1881                for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
1882                    StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
1883                    if (sbn != null) {
1884                        map.put(sbn.getKey(), sbn);
1885                    }
1886                }
1887                final int M = mEnqueuedNotifications.size();
1888                for (int i = 0; i < M; i++) {
1889                    StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1890                            mEnqueuedNotifications.get(i).sbn);
1891                    if (sbn != null) {
1892                        map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
1893                    }
1894                }
1895            }
1896
1897            final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
1898            list.addAll(map.values());
1899            return new ParceledListSlice<StatusBarNotification>(list);
1900        }
1901
1902        private StatusBarNotification sanitizeSbn(String pkg, int userId,
1903                StatusBarNotification sbn) {
1904            if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1905                    && (sbn.getNotification().flags
1906                    & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1907                // We could pass back a cloneLight() but clients might get confused and
1908                // try to send this thing back to notify() again, which would not work
1909                // very well.
1910                return new StatusBarNotification(
1911                        sbn.getPackageName(),
1912                        sbn.getOpPkg(),
1913                        sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1914                        sbn.getNotification().clone(),
1915                        sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1916            }
1917            return null;
1918        }
1919
1920        /**
1921         * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1922         *
1923         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1924         */
1925        @Override
1926        public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1927            // enforce() will ensure the calling uid has the correct permission
1928            getContext().enforceCallingOrSelfPermission(
1929                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1930                    "NotificationManagerService.getHistoricalNotifications");
1931
1932            StatusBarNotification[] tmp = null;
1933            int uid = Binder.getCallingUid();
1934
1935            // noteOp will check to make sure the callingPkg matches the uid
1936            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1937                    == AppOpsManager.MODE_ALLOWED) {
1938                synchronized (mArchive) {
1939                    tmp = mArchive.getArray(count);
1940                }
1941            }
1942            return tmp;
1943        }
1944
1945        /**
1946         * Register a listener binder directly with the notification manager.
1947         *
1948         * Only works with system callers. Apps should extend
1949         * {@link android.service.notification.NotificationListenerService}.
1950         */
1951        @Override
1952        public void registerListener(final INotificationListener listener,
1953                final ComponentName component, final int userid) {
1954            enforceSystemOrSystemUI("INotificationManager.registerListener");
1955            mListeners.registerService(listener, component, userid);
1956        }
1957
1958        /**
1959         * Remove a listener binder directly
1960         */
1961        @Override
1962        public void unregisterListener(INotificationListener token, int userid) {
1963            mListeners.unregisterService(token, userid);
1964        }
1965
1966        /**
1967         * Allow an INotificationListener to simulate a "clear all" operation.
1968         *
1969         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1970         *
1971         * @param token The binder for the listener, to check that the caller is allowed
1972         */
1973        @Override
1974        public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1975            final int callingUid = Binder.getCallingUid();
1976            final int callingPid = Binder.getCallingPid();
1977            long identity = Binder.clearCallingIdentity();
1978            try {
1979                synchronized (mNotificationLock) {
1980                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1981                    if (keys != null) {
1982                        final int N = keys.length;
1983                        for (int i = 0; i < N; i++) {
1984                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
1985                            if (r == null) continue;
1986                            final int userId = r.sbn.getUserId();
1987                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
1988                                    !mUserProfiles.isCurrentProfile(userId)) {
1989                                throw new SecurityException("Disallowed call from listener: "
1990                                        + info.service);
1991                            }
1992                            cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1993                                    r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1994                                    userId);
1995                        }
1996                    } else {
1997                        cancelAllLocked(callingUid, callingPid, info.userid,
1998                                REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1999                    }
2000                }
2001            } finally {
2002                Binder.restoreCallingIdentity(identity);
2003            }
2004        }
2005
2006        /**
2007         * Handle request from an approved listener to re-enable itself.
2008         *
2009         * @param component The componenet to be re-enabled, caller must match package.
2010         */
2011        @Override
2012        public void requestBindListener(ComponentName component) {
2013            checkCallerIsSystemOrSameApp(component.getPackageName());
2014            long identity = Binder.clearCallingIdentity();
2015            try {
2016                ManagedServices manager =
2017                        mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
2018                        ? mNotificationAssistants
2019                        : mListeners;
2020                manager.setComponentState(component, true);
2021            } finally {
2022                Binder.restoreCallingIdentity(identity);
2023            }
2024        }
2025
2026        @Override
2027        public void requestUnbindListener(INotificationListener token) {
2028            long identity = Binder.clearCallingIdentity();
2029            try {
2030                // allow bound services to disable themselves
2031                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2032                info.getOwner().setComponentState(info.component, false);
2033            } finally {
2034                Binder.restoreCallingIdentity(identity);
2035            }
2036        }
2037
2038        @Override
2039        public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2040            long identity = Binder.clearCallingIdentity();
2041            try {
2042                synchronized (mNotificationLock) {
2043                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2044                    if (keys != null) {
2045                        final int N = keys.length;
2046                        for (int i = 0; i < N; i++) {
2047                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
2048                            if (r == null) continue;
2049                            final int userId = r.sbn.getUserId();
2050                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
2051                                    !mUserProfiles.isCurrentProfile(userId)) {
2052                                throw new SecurityException("Disallowed call from listener: "
2053                                        + info.service);
2054                            }
2055                            if (!r.isSeen()) {
2056                                if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2057                                mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2058                                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2059                                                : userId,
2060                                        UsageEvents.Event.USER_INTERACTION);
2061                                r.setSeen();
2062                            }
2063                        }
2064                    }
2065                }
2066            } finally {
2067                Binder.restoreCallingIdentity(identity);
2068            }
2069        }
2070
2071        /**
2072         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2073         *
2074         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2075         *
2076         * @param info The binder for the listener, to check that the caller is allowed
2077         */
2078        private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2079                int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2080            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2081                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2082                    true,
2083                    userId, REASON_LISTENER_CANCEL, info);
2084        }
2085
2086        /**
2087         * Allow an INotificationListener to snooze a single notification until a context.
2088         *
2089         * @param token The binder for the listener, to check that the caller is allowed
2090         */
2091        @Override
2092        public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2093                String key, String snoozeCriterionId) {
2094            long identity = Binder.clearCallingIdentity();
2095            try {
2096                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2097                snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2098            } finally {
2099                Binder.restoreCallingIdentity(identity);
2100            }
2101        }
2102
2103        /**
2104         * Allow an INotificationListener to snooze a single notification until a time.
2105         *
2106         * @param token The binder for the listener, to check that the caller is allowed
2107         */
2108        @Override
2109        public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2110                long duration) {
2111            long identity = Binder.clearCallingIdentity();
2112            try {
2113                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2114                snoozeNotificationInt(key, duration, null, info);
2115            } finally {
2116                Binder.restoreCallingIdentity(identity);
2117            }
2118        }
2119
2120        /**
2121         * Allows the notification assistant to un-snooze a single notification.
2122         *
2123         * @param token The binder for the assistant, to check that the caller is allowed
2124         */
2125        @Override
2126        public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2127            long identity = Binder.clearCallingIdentity();
2128            try {
2129                final ManagedServiceInfo info =
2130                        mNotificationAssistants.checkServiceTokenLocked(token);
2131                unsnoozeNotificationInt(key, info);
2132            } finally {
2133                Binder.restoreCallingIdentity(identity);
2134            }
2135        }
2136
2137        /**
2138         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2139         *
2140         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2141         *
2142         * @param token The binder for the listener, to check that the caller is allowed
2143         */
2144        @Override
2145        public void cancelNotificationFromListener(INotificationListener token, String pkg,
2146                String tag, int id) {
2147            final int callingUid = Binder.getCallingUid();
2148            final int callingPid = Binder.getCallingPid();
2149            long identity = Binder.clearCallingIdentity();
2150            try {
2151                synchronized (mNotificationLock) {
2152                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2153                    if (info.supportsProfiles()) {
2154                        Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2155                                + "from " + info.component
2156                                + " use cancelNotification(key) instead.");
2157                    } else {
2158                        cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2159                                pkg, tag, id, info.userid);
2160                    }
2161                }
2162            } finally {
2163                Binder.restoreCallingIdentity(identity);
2164            }
2165        }
2166
2167        /**
2168         * Allow an INotificationListener to request the list of outstanding notifications seen by
2169         * the current user. Useful when starting up, after which point the listener callbacks
2170         * should be used.
2171         *
2172         * @param token The binder for the listener, to check that the caller is allowed
2173         * @param keys An array of notification keys to fetch, or null to fetch everything
2174         * @returns The return value will contain the notifications specified in keys, in that
2175         *      order, or if keys is null, all the notifications, in natural order.
2176         */
2177        @Override
2178        public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2179                INotificationListener token, String[] keys, int trim) {
2180            synchronized (mNotificationLock) {
2181                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2182                final boolean getKeys = keys != null;
2183                final int N = getKeys ? keys.length : mNotificationList.size();
2184                final ArrayList<StatusBarNotification> list
2185                        = new ArrayList<StatusBarNotification>(N);
2186                for (int i=0; i<N; i++) {
2187                    final NotificationRecord r = getKeys
2188                            ? mNotificationsByKey.get(keys[i])
2189                            : mNotificationList.get(i);
2190                    if (r == null) continue;
2191                    StatusBarNotification sbn = r.sbn;
2192                    if (!isVisibleToListener(sbn, info)) continue;
2193                    StatusBarNotification sbnToSend =
2194                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2195                    list.add(sbnToSend);
2196                }
2197                return new ParceledListSlice<StatusBarNotification>(list);
2198            }
2199        }
2200
2201        /**
2202         * Allow an INotificationListener to request the list of outstanding snoozed notifications
2203         * seen by the current user. Useful when starting up, after which point the listener
2204         * callbacks should be used.
2205         *
2206         * @param token The binder for the listener, to check that the caller is allowed
2207         * @returns The return value will contain the notifications specified in keys, in that
2208         *      order, or if keys is null, all the notifications, in natural order.
2209         */
2210        @Override
2211        public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2212                INotificationListener token, int trim) {
2213            synchronized (mNotificationLock) {
2214                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2215                List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2216                final int N = snoozedRecords.size();
2217                final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2218                for (int i=0; i < N; i++) {
2219                    final NotificationRecord r = snoozedRecords.get(i);
2220                    if (r == null) continue;
2221                    StatusBarNotification sbn = r.sbn;
2222                    if (!isVisibleToListener(sbn, info)) continue;
2223                    StatusBarNotification sbnToSend =
2224                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2225                    list.add(sbnToSend);
2226                }
2227                return new ParceledListSlice<>(list);
2228            }
2229        }
2230
2231        @Override
2232        public void requestHintsFromListener(INotificationListener token, int hints) {
2233            final long identity = Binder.clearCallingIdentity();
2234            try {
2235                synchronized (mNotificationLock) {
2236                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2237                    final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2238                            | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2239                            | HINT_HOST_DISABLE_CALL_EFFECTS;
2240                    final boolean disableEffects = (hints & disableEffectsMask) != 0;
2241                    if (disableEffects) {
2242                        addDisabledHints(info, hints);
2243                    } else {
2244                        removeDisabledHints(info, hints);
2245                    }
2246                    updateListenerHintsLocked();
2247                    updateEffectsSuppressorLocked();
2248                }
2249            } finally {
2250                Binder.restoreCallingIdentity(identity);
2251            }
2252        }
2253
2254        @Override
2255        public int getHintsFromListener(INotificationListener token) {
2256            synchronized (mNotificationLock) {
2257                return mListenerHints;
2258            }
2259        }
2260
2261        @Override
2262        public void requestInterruptionFilterFromListener(INotificationListener token,
2263                int interruptionFilter) throws RemoteException {
2264            final long identity = Binder.clearCallingIdentity();
2265            try {
2266                synchronized (mNotificationLock) {
2267                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2268                    mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2269                    updateInterruptionFilterLocked();
2270                }
2271            } finally {
2272                Binder.restoreCallingIdentity(identity);
2273            }
2274        }
2275
2276        @Override
2277        public int getInterruptionFilterFromListener(INotificationListener token)
2278                throws RemoteException {
2279            synchronized (mNotificationLight) {
2280                return mInterruptionFilter;
2281            }
2282        }
2283
2284        @Override
2285        public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2286                throws RemoteException {
2287            synchronized (mNotificationLock) {
2288                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2289                if (info == null) return;
2290                mListeners.setOnNotificationPostedTrimLocked(info, trim);
2291            }
2292        }
2293
2294        @Override
2295        public int getZenMode() {
2296            return mZenModeHelper.getZenMode();
2297        }
2298
2299        @Override
2300        public ZenModeConfig getZenModeConfig() {
2301            enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2302            return mZenModeHelper.getConfig();
2303        }
2304
2305        @Override
2306        public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2307            enforceSystemOrSystemUI("INotificationManager.setZenMode");
2308            final long identity = Binder.clearCallingIdentity();
2309            try {
2310                mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2311            } finally {
2312                Binder.restoreCallingIdentity(identity);
2313            }
2314        }
2315
2316        @Override
2317        public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2318            enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2319            return mZenModeHelper.getZenRules();
2320        }
2321
2322        @Override
2323        public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2324            Preconditions.checkNotNull(id, "Id is null");
2325            enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2326            return mZenModeHelper.getAutomaticZenRule(id);
2327        }
2328
2329        @Override
2330        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2331                throws RemoteException {
2332            Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2333            Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2334            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2335            Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2336            enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2337
2338            return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2339                    "addAutomaticZenRule");
2340        }
2341
2342        @Override
2343        public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2344                throws RemoteException {
2345            Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2346            Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2347            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2348            Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2349            enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2350
2351            return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2352                    "updateAutomaticZenRule");
2353        }
2354
2355        @Override
2356        public boolean removeAutomaticZenRule(String id) throws RemoteException {
2357            Preconditions.checkNotNull(id, "Id is null");
2358            // Verify that they can modify zen rules.
2359            enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2360
2361            return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2362        }
2363
2364        @Override
2365        public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2366            Preconditions.checkNotNull(packageName, "Package name is null");
2367            enforceSystemOrSystemUI("removeAutomaticZenRules");
2368
2369            return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2370        }
2371
2372        @Override
2373        public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2374            Preconditions.checkNotNull(owner, "Owner is null");
2375            enforceSystemOrSystemUI("getRuleInstanceCount");
2376
2377            return mZenModeHelper.getCurrentInstanceCount(owner);
2378        }
2379
2380        @Override
2381        public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2382            enforcePolicyAccess(pkg, "setInterruptionFilter");
2383            final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2384            if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2385            final long identity = Binder.clearCallingIdentity();
2386            try {
2387                mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2388            } finally {
2389                Binder.restoreCallingIdentity(identity);
2390            }
2391        }
2392
2393        @Override
2394        public void notifyConditions(final String pkg, IConditionProvider provider,
2395                final Condition[] conditions) {
2396            final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2397            checkCallerIsSystemOrSameApp(pkg);
2398            mHandler.post(new Runnable() {
2399                @Override
2400                public void run() {
2401                    mConditionProviders.notifyConditions(pkg, info, conditions);
2402                }
2403            });
2404        }
2405
2406        @Override
2407        public void requestUnbindProvider(IConditionProvider provider) {
2408            long identity = Binder.clearCallingIdentity();
2409            try {
2410                // allow bound services to disable themselves
2411                final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2412                info.getOwner().setComponentState(info.component, false);
2413            } finally {
2414                Binder.restoreCallingIdentity(identity);
2415            }
2416        }
2417
2418        @Override
2419        public void requestBindProvider(ComponentName component) {
2420            checkCallerIsSystemOrSameApp(component.getPackageName());
2421            long identity = Binder.clearCallingIdentity();
2422            try {
2423                mConditionProviders.setComponentState(component, true);
2424            } finally {
2425                Binder.restoreCallingIdentity(identity);
2426            }
2427        }
2428
2429        private void enforceSystemOrSystemUI(String message) {
2430            if (isCallerSystem()) return;
2431            getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2432                    message);
2433        }
2434
2435        private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2436            try {
2437                checkCallerIsSystemOrSameApp(pkg);
2438            } catch (SecurityException e) {
2439                getContext().enforceCallingPermission(
2440                        android.Manifest.permission.STATUS_BAR_SERVICE,
2441                        message);
2442            }
2443        }
2444
2445        private void enforcePolicyAccess(int uid, String method) {
2446            if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2447                    android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2448                return;
2449            }
2450            boolean accessAllowed = false;
2451            String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2452            final int packageCount = packages.length;
2453            for (int i = 0; i < packageCount; i++) {
2454                if (checkPolicyAccess(packages[i])) {
2455                    accessAllowed = true;
2456                }
2457            }
2458            if (!accessAllowed) {
2459                Slog.w(TAG, "Notification policy access denied calling " + method);
2460                throw new SecurityException("Notification policy access denied");
2461            }
2462        }
2463
2464        private void enforcePolicyAccess(String pkg, String method) {
2465            if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2466                    android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2467                return;
2468            }
2469            checkCallerIsSameApp(pkg);
2470            if (!checkPolicyAccess(pkg)) {
2471                Slog.w(TAG, "Notification policy access denied calling " + method);
2472                throw new SecurityException("Notification policy access denied");
2473            }
2474        }
2475
2476        private boolean checkPackagePolicyAccess(String pkg) {
2477            return mPolicyAccess.isPackageGranted(pkg);
2478        }
2479
2480        private boolean checkPolicyAccess(String pkg) {
2481            try {
2482                int uid = getContext().getPackageManager().getPackageUidAsUser(
2483                        pkg, UserHandle.getCallingUserId());
2484                if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2485                        android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2486                        -1, true)) {
2487                    return true;
2488                }
2489            } catch (NameNotFoundException e) {
2490                return false;
2491            }
2492            return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2493        }
2494
2495        @Override
2496        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2497            if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2498            final DumpFilter filter = DumpFilter.parseFromArguments(args);
2499            if (filter != null && filter.stats) {
2500                dumpJson(pw, filter);
2501            } else if (filter != null && filter.proto) {
2502                dumpProto(fd, filter);
2503            } else {
2504                dumpImpl(pw, filter);
2505            }
2506        }
2507
2508        @Override
2509        public ComponentName getEffectsSuppressor() {
2510            return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2511        }
2512
2513        @Override
2514        public boolean matchesCallFilter(Bundle extras) {
2515            enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2516            return mZenModeHelper.matchesCallFilter(
2517                    Binder.getCallingUserHandle(),
2518                    extras,
2519                    mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2520                    MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2521                    MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2522        }
2523
2524        @Override
2525        public boolean isSystemConditionProviderEnabled(String path) {
2526            enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2527            return mConditionProviders.isSystemProviderEnabled(path);
2528        }
2529
2530        // Backup/restore interface
2531        @Override
2532        public byte[] getBackupPayload(int user) {
2533            if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2534            //TODO: http://b/22388012
2535            if (user != UserHandle.USER_SYSTEM) {
2536                Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2537                return null;
2538            }
2539            synchronized(mPolicyFile) {
2540                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2541                try {
2542                    writePolicyXml(baos, true /*forBackup*/);
2543                    return baos.toByteArray();
2544                } catch (IOException e) {
2545                    Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2546                }
2547            }
2548            return null;
2549        }
2550
2551        @Override
2552        public void applyRestore(byte[] payload, int user) {
2553            if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2554                    + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2555            if (payload == null) {
2556                Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2557                return;
2558            }
2559            //TODO: http://b/22388012
2560            if (user != UserHandle.USER_SYSTEM) {
2561                Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2562                return;
2563            }
2564            synchronized(mPolicyFile) {
2565                final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2566                try {
2567                    readPolicyXml(bais, true /*forRestore*/);
2568                    savePolicyFile();
2569                } catch (NumberFormatException | XmlPullParserException | IOException e) {
2570                    Slog.w(TAG, "applyRestore: error reading payload", e);
2571                }
2572            }
2573        }
2574
2575        @Override
2576        public boolean isNotificationPolicyAccessGranted(String pkg) {
2577            return checkPolicyAccess(pkg);
2578        }
2579
2580        @Override
2581        public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2582            enforceSystemOrSystemUIOrSamePackage(pkg,
2583                    "request policy access status for another package");
2584            return checkPolicyAccess(pkg);
2585        }
2586
2587        @Override
2588        public String[] getPackagesRequestingNotificationPolicyAccess()
2589                throws RemoteException {
2590            enforceSystemOrSystemUI("request policy access packages");
2591            final long identity = Binder.clearCallingIdentity();
2592            try {
2593                return mPolicyAccess.getRequestingPackages();
2594            } finally {
2595                Binder.restoreCallingIdentity(identity);
2596            }
2597        }
2598
2599        @Override
2600        public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2601                throws RemoteException {
2602            enforceSystemOrSystemUI("grant notification policy access");
2603            final long identity = Binder.clearCallingIdentity();
2604            try {
2605                synchronized (mNotificationLock) {
2606                    mPolicyAccess.put(pkg, granted);
2607                }
2608            } finally {
2609                Binder.restoreCallingIdentity(identity);
2610            }
2611        }
2612
2613        @Override
2614        public Policy getNotificationPolicy(String pkg) {
2615            enforcePolicyAccess(pkg, "getNotificationPolicy");
2616            final long identity = Binder.clearCallingIdentity();
2617            try {
2618                return mZenModeHelper.getNotificationPolicy();
2619            } finally {
2620                Binder.restoreCallingIdentity(identity);
2621            }
2622        }
2623
2624        @Override
2625        public void setNotificationPolicy(String pkg, Policy policy) {
2626            enforcePolicyAccess(pkg, "setNotificationPolicy");
2627            final long identity = Binder.clearCallingIdentity();
2628            try {
2629                mZenModeHelper.setNotificationPolicy(policy);
2630            } finally {
2631                Binder.restoreCallingIdentity(identity);
2632            }
2633        }
2634
2635        @Override
2636        public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2637                Adjustment adjustment) throws RemoteException {
2638            final long identity = Binder.clearCallingIdentity();
2639            try {
2640                synchronized (mNotificationLock) {
2641                    mNotificationAssistants.checkServiceTokenLocked(token);
2642                    int N = mEnqueuedNotifications.size();
2643                    for (int i = 0; i < N; i++) {
2644                        final NotificationRecord n = mEnqueuedNotifications.get(i);
2645                        if (Objects.equals(adjustment.getKey(), n.getKey())
2646                                && Objects.equals(adjustment.getUser(), n.getUserId())) {
2647                            applyAdjustment(n, adjustment);
2648                            break;
2649                        }
2650                    }
2651                }
2652            } finally {
2653                Binder.restoreCallingIdentity(identity);
2654            }
2655        }
2656
2657        @Override
2658        public void applyAdjustmentFromAssistant(INotificationListener token,
2659                Adjustment adjustment) throws RemoteException {
2660            final long identity = Binder.clearCallingIdentity();
2661            try {
2662                synchronized (mNotificationLock) {
2663                    mNotificationAssistants.checkServiceTokenLocked(token);
2664                    NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2665                    applyAdjustment(n, adjustment);
2666                }
2667                mRankingHandler.requestSort(true);
2668            } finally {
2669                Binder.restoreCallingIdentity(identity);
2670            }
2671        }
2672
2673        @Override
2674        public void applyAdjustmentsFromAssistant(INotificationListener token,
2675                List<Adjustment> adjustments) throws RemoteException {
2676
2677            final long identity = Binder.clearCallingIdentity();
2678            try {
2679                synchronized (mNotificationLock) {
2680                    mNotificationAssistants.checkServiceTokenLocked(token);
2681                    for (Adjustment adjustment : adjustments) {
2682                        NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2683                        applyAdjustment(n, adjustment);
2684                    }
2685                }
2686                mRankingHandler.requestSort(true);
2687            } finally {
2688                Binder.restoreCallingIdentity(identity);
2689            }
2690        }
2691
2692        @Override
2693        public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2694                String pkg, NotificationChannel channel) throws RemoteException {
2695            Preconditions.checkNotNull(channel);
2696
2697            ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2698            if (!hasCompanionDevice(info)) {
2699                throw new SecurityException(info + " does not have access");
2700            }
2701
2702            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
2703            updateNotificationChannelInt(pkg, uid, channel, true);
2704        }
2705
2706        @Override
2707        public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2708                INotificationListener token, String pkg) throws RemoteException {
2709            ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2710            if (!hasCompanionDevice(info)) {
2711                throw new SecurityException(info + " does not have access");
2712            }
2713
2714            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
2715            return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */);
2716        }
2717
2718        @Override
2719        public ParceledListSlice<NotificationChannelGroup>
2720                getNotificationChannelGroupsFromPrivilegedListener(
2721                INotificationListener token, String pkg) throws RemoteException {
2722            ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2723            if (!hasCompanionDevice(info)) {
2724                throw new SecurityException(info + " does not have access");
2725            }
2726
2727            List<NotificationChannelGroup> groups = new ArrayList<>();
2728            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
2729            groups.addAll(mRankingHelper.getNotificationChannelGroups(pkg, uid));
2730            return new ParceledListSlice<>(groups);
2731        }
2732    };
2733
2734    private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
2735        if (n == null) {
2736            return;
2737        }
2738        if (adjustment.getSignals() != null) {
2739            Bundle.setDefusable(adjustment.getSignals(), true);
2740            final ArrayList<String> people =
2741                    adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
2742            final ArrayList<SnoozeCriterion> snoozeCriterionList =
2743                    adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
2744            n.setPeopleOverride(people);
2745            n.setSnoozeCriteria(snoozeCriterionList);
2746        }
2747    }
2748
2749    private void addAutogroupKeyLocked(String key) {
2750        NotificationRecord n = mNotificationsByKey.get(key);
2751        if (n == null) {
2752            return;
2753        }
2754        n.sbn.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
2755        EventLogTags.writeNotificationAutogrouped(key);
2756    }
2757
2758    private void removeAutogroupKeyLocked(String key) {
2759        NotificationRecord n = mNotificationsByKey.get(key);
2760        if (n == null) {
2761            return;
2762        }
2763        n.sbn.setOverrideGroupKey(null);
2764        EventLogTags.writeNotificationUnautogrouped(key);
2765    }
2766
2767    // Clears the 'fake' auto-group summary.
2768    private void clearAutogroupSummaryLocked(int userId, String pkg) {
2769        ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2770        if (summaries != null && summaries.containsKey(pkg)) {
2771            // Clear summary.
2772            final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
2773            if (removed != null) {
2774                cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2775            }
2776        }
2777    }
2778
2779    // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2780    private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
2781        NotificationRecord summaryRecord = null;
2782        synchronized (mNotificationLock) {
2783            NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
2784            if (notificationRecord == null) {
2785                // The notification could have been cancelled again already. A successive
2786                // adjustment will post a summary if needed.
2787                return;
2788            }
2789            final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2790            userId = adjustedSbn.getUser().getIdentifier();
2791            ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2792            if (summaries == null) {
2793                summaries = new ArrayMap<>();
2794            }
2795            mAutobundledSummaries.put(userId, summaries);
2796            if (!summaries.containsKey(pkg)) {
2797                // Add summary
2798                final ApplicationInfo appInfo =
2799                       adjustedSbn.getNotification().extras.getParcelable(
2800                               Notification.EXTRA_BUILDER_APPLICATION_INFO);
2801                final Bundle extras = new Bundle();
2802                extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2803                final String channelId = notificationRecord.getChannel().getId();
2804                final Notification summaryNotification =
2805                        new Notification.Builder(getContext(), channelId)
2806                                .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
2807                                .setGroupSummary(true)
2808                                .setGroup(GroupHelper.AUTOGROUP_KEY)
2809                                .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2810                                .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2811                                .setColor(adjustedSbn.getNotification().color)
2812                                .setLocalOnly(true)
2813                                .build();
2814                summaryNotification.extras.putAll(extras);
2815                Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
2816                if (appIntent != null) {
2817                    summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2818                            getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
2819                }
2820                final StatusBarNotification summarySbn =
2821                        new StatusBarNotification(adjustedSbn.getPackageName(),
2822                                adjustedSbn.getOpPkg(),
2823                                Integer.MAX_VALUE,
2824                                GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
2825                                adjustedSbn.getInitialPid(), summaryNotification,
2826                                adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
2827                                System.currentTimeMillis());
2828                summaryRecord = new NotificationRecord(getContext(), summarySbn,
2829                        notificationRecord.getChannel());
2830                summaries.put(pkg, summarySbn.getKey());
2831            }
2832        }
2833        if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
2834                summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
2835            mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2836        }
2837    }
2838
2839    private String disableNotificationEffects(NotificationRecord record) {
2840        if (mDisableNotificationEffects) {
2841            return "booleanState";
2842        }
2843        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2844            return "listenerHints";
2845        }
2846        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2847            return "callState";
2848        }
2849        return null;
2850    };
2851
2852    private void dumpJson(PrintWriter pw, DumpFilter filter) {
2853        JSONObject dump = new JSONObject();
2854        try {
2855            dump.put("service", "Notification Manager");
2856            dump.put("bans", mRankingHelper.dumpBansJson(filter));
2857            dump.put("ranking", mRankingHelper.dumpJson(filter));
2858            dump.put("stats", mUsageStats.dumpJson(filter));
2859            dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
2860        } catch (JSONException e) {
2861            e.printStackTrace();
2862        }
2863        pw.println(dump);
2864    }
2865
2866    private void dumpProto(FileDescriptor fd, DumpFilter filter) {
2867        final ProtoOutputStream proto = new ProtoOutputStream(fd);
2868        synchronized (mNotificationLock) {
2869            long records = proto.start(NotificationServiceDumpProto.RECORDS);
2870            int N = mNotificationList.size();
2871            if (N > 0) {
2872                for (int i = 0; i < N; i++) {
2873                    final NotificationRecord nr = mNotificationList.get(i);
2874                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
2875                    nr.dump(proto, filter.redact);
2876                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
2877                }
2878            }
2879            N = mEnqueuedNotifications.size();
2880            if (N > 0) {
2881                for (int i = 0; i < N; i++) {
2882                    final NotificationRecord nr = mEnqueuedNotifications.get(i);
2883                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
2884                    nr.dump(proto, filter.redact);
2885                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
2886                }
2887            }
2888            List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
2889            N = snoozed.size();
2890            if (N > 0) {
2891                for (int i = 0; i < N; i++) {
2892                    final NotificationRecord nr = snoozed.get(i);
2893                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
2894                    nr.dump(proto, filter.redact);
2895                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
2896                }
2897            }
2898            proto.end(records);
2899        }
2900
2901        long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
2902        mZenModeHelper.dump(proto);
2903        for (ComponentName suppressor : mEffectsSuppressors) {
2904            proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
2905        }
2906        proto.end(zenLog);
2907
2908        proto.flush();
2909    }
2910
2911    void dumpImpl(PrintWriter pw, DumpFilter filter) {
2912        pw.print("Current Notification Manager state");
2913        if (filter.filtered) {
2914            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2915        }
2916        pw.println(':');
2917        int N;
2918        final boolean zenOnly = filter.filtered && filter.zen;
2919
2920        if (!zenOnly) {
2921            synchronized (mToastQueue) {
2922                N = mToastQueue.size();
2923                if (N > 0) {
2924                    pw.println("  Toast Queue:");
2925                    for (int i=0; i<N; i++) {
2926                        mToastQueue.get(i).dump(pw, "    ", filter);
2927                    }
2928                    pw.println("  ");
2929                }
2930            }
2931        }
2932
2933        synchronized (mNotificationLock) {
2934            if (!zenOnly) {
2935                N = mNotificationList.size();
2936                if (N > 0) {
2937                    pw.println("  Notification List:");
2938                    for (int i=0; i<N; i++) {
2939                        final NotificationRecord nr = mNotificationList.get(i);
2940                        if (filter.filtered && !filter.matches(nr.sbn)) continue;
2941                        nr.dump(pw, "    ", getContext(), filter.redact);
2942                    }
2943                    pw.println("  ");
2944                }
2945
2946                if (!filter.filtered) {
2947                    N = mLights.size();
2948                    if (N > 0) {
2949                        pw.println("  Lights List:");
2950                        for (int i=0; i<N; i++) {
2951                            if (i == N - 1) {
2952                                pw.print("  > ");
2953                            } else {
2954                                pw.print("    ");
2955                            }
2956                            pw.println(mLights.get(i));
2957                        }
2958                        pw.println("  ");
2959                    }
2960                    pw.println("  mUseAttentionLight=" + mUseAttentionLight);
2961                    pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2962                    pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
2963                    pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
2964                    pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
2965                    pw.println("  mCallState=" + callStateToString(mCallState));
2966                    pw.println("  mSystemReady=" + mSystemReady);
2967                    pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
2968                }
2969                pw.println("  mArchive=" + mArchive.toString());
2970                Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2971                int j=0;
2972                while (iter.hasNext()) {
2973                    final StatusBarNotification sbn = iter.next();
2974                    if (filter != null && !filter.matches(sbn)) continue;
2975                    pw.println("    " + sbn);
2976                    if (++j >= 5) {
2977                        if (iter.hasNext()) pw.println("    ...");
2978                        break;
2979                    }
2980                }
2981
2982                if (!zenOnly) {
2983                    N = mEnqueuedNotifications.size();
2984                    if (N > 0) {
2985                        pw.println("  Enqueued Notification List:");
2986                        for (int i = 0; i < N; i++) {
2987                            final NotificationRecord nr = mEnqueuedNotifications.get(i);
2988                            if (filter.filtered && !filter.matches(nr.sbn)) continue;
2989                            nr.dump(pw, "    ", getContext(), filter.redact);
2990                        }
2991                        pw.println("  ");
2992                    }
2993
2994                    mSnoozeHelper.dump(pw, filter);
2995                }
2996            }
2997
2998            if (!zenOnly) {
2999                pw.println("\n  Ranking Config:");
3000                mRankingHelper.dump(pw, "    ", filter);
3001
3002                pw.println("\n  Notification listeners:");
3003                mListeners.dump(pw, filter);
3004                pw.print("    mListenerHints: "); pw.println(mListenerHints);
3005                pw.print("    mListenersDisablingEffects: (");
3006                N = mListenersDisablingEffects.size();
3007                for (int i = 0; i < N; i++) {
3008                    final int hint = mListenersDisablingEffects.keyAt(i);
3009                    if (i > 0) pw.print(';');
3010                    pw.print("hint[" + hint + "]:");
3011
3012                    final ArraySet<ManagedServiceInfo> listeners =
3013                            mListenersDisablingEffects.valueAt(i);
3014                    final int listenerSize = listeners.size();
3015
3016                    for (int j = 0; j < listenerSize; j++) {
3017                        if (i > 0) pw.print(',');
3018                        final ManagedServiceInfo listener = listeners.valueAt(i);
3019                        pw.print(listener.component);
3020                    }
3021                }
3022                pw.println(')');
3023                pw.println("\n  Notification assistant services:");
3024                mNotificationAssistants.dump(pw, filter);
3025            }
3026
3027            if (!filter.filtered || zenOnly) {
3028                pw.println("\n  Zen Mode:");
3029                pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3030                mZenModeHelper.dump(pw, "    ");
3031
3032                pw.println("\n  Zen Log:");
3033                ZenLog.dump(pw, "    ");
3034            }
3035
3036            pw.println("\n  Policy access:");
3037            pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
3038
3039            pw.println("\n  Condition providers:");
3040            mConditionProviders.dump(pw, filter);
3041
3042            pw.println("\n  Group summaries:");
3043            for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3044                NotificationRecord r = entry.getValue();
3045                pw.println("    " + entry.getKey() + " -> " + r.getKey());
3046                if (mNotificationsByKey.get(r.getKey()) != r) {
3047                    pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3048                    r.dump(pw, "      ", getContext(), filter.redact);
3049                }
3050            }
3051
3052            if (!zenOnly) {
3053                pw.println("\n  Usage Stats:");
3054                mUsageStats.dump(pw, "    ", filter);
3055            }
3056        }
3057    }
3058
3059    /**
3060     * The private API only accessible to the system process.
3061     */
3062    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3063        @Override
3064        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3065                String tag, int id, Notification notification, int[] idReceived, int userId) {
3066            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3067                    idReceived, userId);
3068        }
3069
3070        @Override
3071        public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3072                int userId) {
3073            checkCallerIsSystem();
3074            mHandler.post(new Runnable() {
3075                @Override
3076                public void run() {
3077                    synchronized (mNotificationLock) {
3078                        removeForegroundServiceFlagByListLocked(mEnqueuedNotifications, pkg, notificationId, userId);
3079                        removeForegroundServiceFlagByListLocked(mNotificationList, pkg, notificationId, userId);
3080                    }
3081                }
3082            });
3083        }
3084
3085        private void removeForegroundServiceFlagByListLocked(
3086                ArrayList<NotificationRecord> notificationList, String pkg, int notificationId, int userId) {
3087            NotificationRecord r =
3088                    findNotificationByListLocked(notificationList, pkg, null, notificationId, userId);
3089            if (r == null) {
3090                return;
3091            }
3092            StatusBarNotification sbn = r.sbn;
3093            // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3094            // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3095            // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3096            // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3097            sbn.getNotification().flags =
3098                    (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3099            mRankingHelper.sort(mNotificationList);
3100            mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3101            mGroupHelper.onNotificationPosted(sbn);
3102        }
3103    };
3104
3105    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3106            final int callingPid, final String tag, final int id, final Notification notification,
3107            int[] idOut, int incomingUserId) {
3108        if (DBG) {
3109            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3110                    + " notification=" + notification);
3111        }
3112        checkCallerIsSystemOrSameApp(pkg);
3113
3114        final int userId = ActivityManager.handleIncomingUser(callingPid,
3115                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3116        final UserHandle user = new UserHandle(userId);
3117
3118        if (pkg == null || notification == null) {
3119            throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3120                    + " id=" + id + " notification=" + notification);
3121        }
3122
3123        // The system can post notifications for any package, let us resolve that.
3124        final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3125
3126        // Fix the notification as best we can.
3127        try {
3128            final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3129                    pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3130                    (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3131            Notification.addFieldsFromContext(ai, notification);
3132        } catch (NameNotFoundException e) {
3133            Slog.e(TAG, "Cannot create a context for sending app", e);
3134            return;
3135        }
3136
3137        mUsageStats.registerEnqueuedByApp(pkg);
3138
3139        // setup local book-keeping
3140        String channelId = notification.getChannel();
3141        if (mIsTelevision && (new Notification.TvExtender(notification)).getChannel() != null) {
3142            channelId = (new Notification.TvExtender(notification)).getChannel();
3143        }
3144        final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3145                notificationUid, channelId, false /* includeDeleted */);
3146        if (channel == null) {
3147            // STOPSHIP TODO: remove before release - should always throw without a valid channel.
3148            if (channelId == null) {
3149                Log.e(TAG, "Cannot post notification without channel ID when targeting O "
3150                        + " - notification=" + notification);
3151                return;
3152            }
3153            final String noChannelStr = "No Channel found for "
3154                    + "pkg=" + pkg
3155                    + ", channelId=" + channelId
3156                    + ", opPkg=" + opPkg
3157                    + ", callingUid=" + callingUid
3158                    + ", userId=" + userId
3159                    + ", incomingUserId=" + incomingUserId
3160                    + ", notificationUid=" + notificationUid
3161                    + ", notification=" + notification;
3162            // STOPSHIP TODO: should throw instead of logging or toasting.
3163            // throw new IllegalArgumentException(noChannelStr);
3164            Log.e(TAG, noChannelStr);
3165
3166            final String noChannelToastStr =
3167                    "Developer warning for package \"" + pkg + "\"\n" +
3168                    "Failed to post notification on channel \"" + channelId + "\"\n" +
3169                    "See log for more details";
3170            Toast noChannelToast =
3171                    Toast.makeText(getContext(), noChannelToastStr, Toast.LENGTH_LONG);
3172            noChannelToast.show();
3173            return;
3174        }
3175        final StatusBarNotification n = new StatusBarNotification(
3176                pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3177                user, null, System.currentTimeMillis());
3178        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3179
3180        if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
3181            return;
3182        }
3183
3184        // Whitelist pending intents.
3185        if (notification.allPendingIntents != null) {
3186            final int intentCount = notification.allPendingIntents.size();
3187            if (intentCount > 0) {
3188                final ActivityManagerInternal am = LocalServices
3189                        .getService(ActivityManagerInternal.class);
3190                final long duration = LocalServices.getService(
3191                        DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3192                for (int i = 0; i < intentCount; i++) {
3193                    PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3194                    if (pendingIntent != null) {
3195                        am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
3196                    }
3197                }
3198            }
3199        }
3200
3201        mHandler.post(new EnqueueNotificationRunnable(userId, r));
3202
3203        idOut[0] = id;
3204    }
3205
3206    private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3207        // The system can post notifications on behalf of any package it wants
3208        if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) {
3209            try {
3210                return getContext().getPackageManager()
3211                        .getPackageUidAsUser(opPackageName, userId);
3212            } catch (NameNotFoundException e) {
3213                /* ignore */
3214            }
3215        }
3216        return callingUid;
3217    }
3218
3219    /**
3220     * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3221     *
3222     * Has side effects.
3223     */
3224    private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3225            NotificationRecord r) {
3226        final String pkg = r.sbn.getPackageName();
3227        final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
3228        final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3229
3230        // Limit the number of notifications that any given package except the android
3231        // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3232        if (!isSystemNotification && !isNotificationFromListener) {
3233            synchronized (mNotificationLock) {
3234                if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
3235                    // this is an update, rate limit updates only
3236                    final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3237                    if (appEnqueueRate > mMaxPackageEnqueueRate) {
3238                        mUsageStats.registerOverRateQuota(pkg);
3239                        final long now = SystemClock.elapsedRealtime();
3240                        if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3241                            Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3242                                    + ". Shedding events. package=" + pkg);
3243                            mLastOverRateLogTime = now;
3244                        }
3245                        return false;
3246                    }
3247                } else if (isCallerInstantApp(pkg)) {
3248                    // Ephemeral apps have some special contraints for notifications.
3249                    // They are not allowed to create new notifications however they are allowed to
3250                    // update notifications created by the system (e.g. a foreground service
3251                    // notification).
3252                    throw new SecurityException("Instant app " + pkg
3253                            + " cannot create notifications");
3254                }
3255
3256                int count = 0;
3257                final int N = mNotificationList.size();
3258                for (int i=0; i<N; i++) {
3259                    final NotificationRecord existing = mNotificationList.get(i);
3260                    if (existing.sbn.getPackageName().equals(pkg)
3261                            && existing.sbn.getUserId() == userId) {
3262                        if (existing.sbn.getId() == id
3263                                && TextUtils.equals(existing.sbn.getTag(), tag)) {
3264                            break;  // Allow updating existing notification
3265                        }
3266                        count++;
3267                        if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3268                            mUsageStats.registerOverCountQuota(pkg);
3269                            Slog.e(TAG, "Package has already posted " + count
3270                                    + " notifications.  Not showing more.  package=" + pkg);
3271                            return false;
3272                        }
3273                    }
3274                }
3275            }
3276        }
3277
3278        // snoozed apps
3279        if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3280            MetricsLogger.action(r.getLogMaker()
3281                    .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3282                    .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3283            if (DBG) {
3284                Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3285            }
3286            mSnoozeHelper.update(userId, r);
3287            savePolicyFile();
3288            return false;
3289        }
3290
3291
3292        // blocked apps
3293        if (isBlocked(r, mUsageStats)) {
3294            return false;
3295        }
3296
3297        return true;
3298    }
3299
3300    protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3301        final String pkg = r.sbn.getPackageName();
3302        final int callingUid = r.sbn.getUid();
3303
3304        final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3305        if (isPackageSuspended) {
3306            Slog.e(TAG, "Suppressing notification from package due to package "
3307                    + "suspended by administrator.");
3308            usageStats.registerSuspendedByAdmin(r);
3309            return isPackageSuspended;
3310        }
3311
3312        final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
3313                || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
3314                || !noteNotificationOp(pkg, callingUid);
3315        if (isBlocked) {
3316            Slog.e(TAG, "Suppressing notification from package by user request.");
3317            usageStats.registerBlocked(r);
3318        }
3319        return isBlocked;
3320    }
3321
3322    protected class EnqueueNotificationRunnable implements Runnable {
3323        private final NotificationRecord r;
3324        private final int userId;
3325
3326        EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3327            this.userId = userId;
3328            this.r = r;
3329        };
3330
3331        @Override
3332        public void run() {
3333            synchronized (mNotificationLock) {
3334                mEnqueuedNotifications.add(r);
3335                scheduleTimeoutLocked(r);
3336
3337                final StatusBarNotification n = r.sbn;
3338                if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3339                NotificationRecord old = mNotificationsByKey.get(n.getKey());
3340                if (old != null) {
3341                    // Retain ranking information from previous record
3342                    r.copyRankingInformation(old);
3343                }
3344
3345                final int callingUid = n.getUid();
3346                final int callingPid = n.getInitialPid();
3347                final Notification notification = n.getNotification();
3348                final String pkg = n.getPackageName();
3349                final int id = n.getId();
3350                final String tag = n.getTag();
3351
3352                // Handle grouped notifications and bail out early if we
3353                // can to avoid extracting signals.
3354                handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3355
3356                // This conditional is a dirty hack to limit the logging done on
3357                //     behalf of the download manager without affecting other apps.
3358                if (!pkg.equals("com.android.providers.downloads")
3359                        || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3360                    int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3361                    if (old != null) {
3362                        enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3363                    }
3364                    EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3365                            pkg, id, tag, userId, notification.toString(),
3366                            enqueueStatus);
3367                }
3368
3369                mRankingHelper.extractSignals(r);
3370
3371                // tell the assistant service about the notification
3372                if (mNotificationAssistants.isEnabled()) {
3373                    mNotificationAssistants.onNotificationEnqueued(r);
3374                    mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3375                            DELAY_FOR_ASSISTANT_TIME);
3376                } else {
3377                    mHandler.post(new PostNotificationRunnable(r.getKey()));
3378                }
3379            }
3380        }
3381    }
3382
3383    protected class PostNotificationRunnable implements Runnable {
3384        private final String key;
3385
3386        PostNotificationRunnable(String key) {
3387            this.key = key;
3388        }
3389
3390        @Override
3391        public void run() {
3392            synchronized (mNotificationLock) {
3393                try {
3394                    NotificationRecord r = null;
3395                    int N = mEnqueuedNotifications.size();
3396                    for (int i = 0; i < N; i++) {
3397                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3398                        if (Objects.equals(key, enqueued.getKey())) {
3399                            r = enqueued;
3400                            break;
3401                        }
3402                    }
3403                    if (r == null) {
3404                        Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3405                        return;
3406                    }
3407                    NotificationRecord old = mNotificationsByKey.get(key);
3408                    final StatusBarNotification n = r.sbn;
3409                    final Notification notification = n.getNotification();
3410                    int index = indexOfNotificationLocked(n.getKey());
3411                    if (index < 0) {
3412                        mNotificationList.add(r);
3413                        mUsageStats.registerPostedByApp(r);
3414                    } else {
3415                        old = mNotificationList.get(index);
3416                        mNotificationList.set(index, r);
3417                        mUsageStats.registerUpdatedByApp(r, old);
3418                        // Make sure we don't lose the foreground service state.
3419                        notification.flags |=
3420                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3421                        r.isUpdate = true;
3422                    }
3423
3424                    mNotificationsByKey.put(n.getKey(), r);
3425
3426                    // Ensure if this is a foreground service that the proper additional
3427                    // flags are set.
3428                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3429                        notification.flags |= Notification.FLAG_ONGOING_EVENT
3430                                | Notification.FLAG_NO_CLEAR;
3431                    }
3432
3433                    applyZenModeLocked(r);
3434                    mRankingHelper.sort(mNotificationList);
3435
3436                    if (notification.getSmallIcon() != null) {
3437                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3438                        mListeners.notifyPostedLocked(n, oldSbn);
3439                        mHandler.post(new Runnable() {
3440                            @Override
3441                            public void run() {
3442                                mGroupHelper.onNotificationPosted(n);
3443                            }
3444                        });
3445                    } else {
3446                        Slog.e(TAG, "Not posting notification without small icon: " + notification);
3447                        if (old != null && !old.isCanceled) {
3448                            mListeners.notifyRemovedLocked(n,
3449                                    NotificationListenerService.REASON_ERROR);
3450                            mHandler.post(new Runnable() {
3451                                @Override
3452                                public void run() {
3453                                    mGroupHelper.onNotificationRemoved(n);
3454                                }
3455                            });
3456                        }
3457                        // ATTENTION: in a future release we will bail out here
3458                        // so that we do not play sounds, show lights, etc. for invalid
3459                        // notifications
3460                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3461                                + n.getPackageName());
3462                    }
3463
3464                    buzzBeepBlinkLocked(r);
3465                } finally {
3466                    int N = mEnqueuedNotifications.size();
3467                    for (int i = 0; i < N; i++) {
3468                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3469                        if (Objects.equals(key, enqueued.getKey())) {
3470                            mEnqueuedNotifications.remove(i);
3471                            break;
3472                        }
3473                    }
3474                }
3475            }
3476        }
3477    }
3478
3479    /**
3480     * Ensures that grouped notification receive their special treatment.
3481     *
3482     * <p>Cancels group children if the new notification causes a group to lose
3483     * its summary.</p>
3484     *
3485     * <p>Updates mSummaryByGroupKey.</p>
3486     */
3487    private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3488            int callingUid, int callingPid) {
3489        StatusBarNotification sbn = r.sbn;
3490        Notification n = sbn.getNotification();
3491        if (n.isGroupSummary() && !sbn.isAppGroup())  {
3492            // notifications without a group shouldn't be a summary, otherwise autobundling can
3493            // lead to bugs
3494            n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3495        }
3496
3497        String group = sbn.getGroupKey();
3498        boolean isSummary = n.isGroupSummary();
3499
3500        Notification oldN = old != null ? old.sbn.getNotification() : null;
3501        String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3502        boolean oldIsSummary = old != null && oldN.isGroupSummary();
3503
3504        if (oldIsSummary) {
3505            NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3506            if (removedSummary != old) {
3507                String removedKey =
3508                        removedSummary != null ? removedSummary.getKey() : "<null>";
3509                Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3510                        ", removed=" + removedKey);
3511            }
3512        }
3513        if (isSummary) {
3514            mSummaryByGroupKey.put(group, r);
3515        }
3516
3517        // Clear out group children of the old notification if the update
3518        // causes the group summary to go away. This happens when the old
3519        // notification was a summary and the new one isn't, or when the old
3520        // notification was a summary and its group key changed.
3521        if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3522            cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
3523        }
3524    }
3525
3526    @VisibleForTesting
3527    void scheduleTimeoutLocked(NotificationRecord record) {
3528        if (record.getNotification().getTimeout() > 0) {
3529            final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3530                    REQUEST_CODE_TIMEOUT,
3531                    new Intent(ACTION_NOTIFICATION_TIMEOUT)
3532                            .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3533                                    .appendPath(record.getKey()).build())
3534                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3535                            .putExtra(EXTRA_KEY, record.getKey()),
3536                    PendingIntent.FLAG_UPDATE_CURRENT);
3537            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3538                    SystemClock.elapsedRealtime() + record.getNotification().getTimeout(), pi);
3539        }
3540    }
3541
3542    @VisibleForTesting
3543    void buzzBeepBlinkLocked(NotificationRecord record) {
3544        boolean buzz = false;
3545        boolean beep = false;
3546        boolean blink = false;
3547
3548        final Notification notification = record.sbn.getNotification();
3549        final String key = record.getKey();
3550
3551        // Should this notification make noise, vibe, or use the LED?
3552        final boolean aboveThreshold =
3553                record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
3554        final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
3555        if (DBG || record.isIntercepted())
3556            Slog.v(TAG,
3557                    "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
3558                            " intercept=" + record.isIntercepted()
3559            );
3560
3561        final int currentUser;
3562        final long token = Binder.clearCallingIdentity();
3563        try {
3564            currentUser = ActivityManager.getCurrentUser();
3565        } finally {
3566            Binder.restoreCallingIdentity(token);
3567        }
3568
3569        // If we're not supposed to beep, vibrate, etc. then don't.
3570        final String disableEffects = disableNotificationEffects(record);
3571        if (disableEffects != null) {
3572            ZenLog.traceDisableEffects(record, disableEffects);
3573        }
3574
3575        // Remember if this notification already owns the notification channels.
3576        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3577        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
3578
3579        // These are set inside the conditional if the notification is allowed to make noise.
3580        boolean hasValidVibrate = false;
3581        boolean hasValidSound = false;
3582        if (disableEffects == null
3583                && (record.getUserId() == UserHandle.USER_ALL ||
3584                    record.getUserId() == currentUser ||
3585                    mUserProfiles.isCurrentProfile(record.getUserId()))
3586                && canInterrupt
3587                && mSystemReady
3588                && mAudioManager != null) {
3589            if (DBG) Slog.v(TAG, "Interrupting!");
3590
3591            Uri soundUri = record.getSound();
3592            hasValidSound = (soundUri != null);
3593            long[] vibration = record.getVibration();
3594            // Demote sound to vibration if vibration missing & phone in vibration mode.
3595            if (vibration == null
3596                    && hasValidSound
3597                    && (mAudioManager.getRingerModeInternal()
3598                            == AudioManager.RINGER_MODE_VIBRATE)) {
3599                vibration = mFallbackVibrationPattern;
3600            }
3601            hasValidVibrate = vibration != null;
3602
3603            // We can alert, and we're allowed to alert, but if the developer asked us to only do
3604            // it once, and we already have, then don't.
3605            if (!(record.isUpdate
3606                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
3607
3608                sendAccessibilityEvent(notification, record.sbn.getPackageName());
3609                if (hasValidSound) {
3610                    mSoundNotificationKey = key;
3611                    beep = playSound(record, soundUri);
3612                }
3613                if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
3614                        == AudioManager.RINGER_MODE_SILENT)) {
3615                    mVibrateNotificationKey = key;
3616
3617                    buzz = playVibration(record, vibration);
3618                }
3619            }
3620        }
3621        // If a notification is updated to remove the actively playing sound or vibrate,
3622        // cancel that feedback now
3623        if (wasBeep && !hasValidSound) {
3624            clearSoundLocked();
3625        }
3626        if (wasBuzz && !hasValidVibrate) {
3627            clearVibrateLocked();
3628        }
3629
3630        // light
3631        // release the light
3632        boolean wasShowLights = mLights.remove(key);
3633        if (record.getLight() != null && aboveThreshold
3634                && ((record.getSuppressedVisualEffects()
3635                & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3636            mLights.add(key);
3637            updateLightsLocked();
3638            if (mUseAttentionLight) {
3639                mAttentionLight.pulse();
3640            }
3641            blink = true;
3642        } else if (wasShowLights) {
3643            updateLightsLocked();
3644        }
3645        if (buzz || beep || blink) {
3646            if (((record.getSuppressedVisualEffects()
3647                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
3648                if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
3649            } else {
3650                MetricsLogger.action(record.getLogMaker()
3651                        .setCategory(MetricsEvent.NOTIFICATION_ALERT)
3652                        .setType(MetricsEvent.TYPE_OPEN)
3653                        .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
3654                EventLogTags.writeNotificationAlert(key,
3655                        buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3656            }
3657        }
3658    }
3659
3660    private boolean playSound(final NotificationRecord record, Uri soundUri) {
3661        boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3662        // do not play notifications if there is a user of exclusive audio focus
3663        // or the device is in vibrate mode
3664        if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
3665                != AudioManager.RINGER_MODE_VIBRATE) {
3666            final long identity = Binder.clearCallingIdentity();
3667            try {
3668                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3669                if (player != null) {
3670                    if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3671                            + " with attributes " + record.getAudioAttributes());
3672                    player.playAsync(soundUri, record.sbn.getUser(), looping,
3673                            record.getAudioAttributes());
3674                    return true;
3675                }
3676            } catch (RemoteException e) {
3677            } finally {
3678                Binder.restoreCallingIdentity(identity);
3679            }
3680        }
3681        return false;
3682    }
3683
3684    private boolean playVibration(final NotificationRecord record, long[] vibration) {
3685        // Escalate privileges so we can use the vibrator even if the
3686        // notifying app does not have the VIBRATE permission.
3687        long identity = Binder.clearCallingIdentity();
3688        try {
3689            final boolean insistent =
3690                (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3691            final VibrationEffect effect = VibrationEffect.createWaveform(
3692                    vibration, insistent ? 0 : -1 /*repeatIndex*/);
3693            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3694                    effect, record.getAudioAttributes());
3695            return true;
3696        } catch (IllegalArgumentException e) {
3697            Slog.e(TAG, "Error creating vibration waveform with pattern: " +
3698                    Arrays.toString(vibration));
3699            return false;
3700        } finally{
3701            Binder.restoreCallingIdentity(identity);
3702        }
3703    }
3704
3705    void showNextToastLocked() {
3706        ToastRecord record = mToastQueue.get(0);
3707        while (record != null) {
3708            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3709            try {
3710                record.callback.show(record.token);
3711                scheduleTimeoutLocked(record);
3712                return;
3713            } catch (RemoteException e) {
3714                Slog.w(TAG, "Object died trying to show notification " + record.callback
3715                        + " in package " + record.pkg);
3716                // remove it from the list and let the process die
3717                int index = mToastQueue.indexOf(record);
3718                if (index >= 0) {
3719                    mToastQueue.remove(index);
3720                }
3721                keepProcessAliveIfNeededLocked(record.pid);
3722                if (mToastQueue.size() > 0) {
3723                    record = mToastQueue.get(0);
3724                } else {
3725                    record = null;
3726                }
3727            }
3728        }
3729    }
3730
3731    void cancelToastLocked(int index) {
3732        ToastRecord record = mToastQueue.get(index);
3733        try {
3734            record.callback.hide();
3735        } catch (RemoteException e) {
3736            Slog.w(TAG, "Object died trying to hide notification " + record.callback
3737                    + " in package " + record.pkg);
3738            // don't worry about this, we're about to remove it from
3739            // the list anyway
3740        }
3741
3742        ToastRecord lastToast = mToastQueue.remove(index);
3743        mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
3744
3745        keepProcessAliveIfNeededLocked(record.pid);
3746        if (mToastQueue.size() > 0) {
3747            // Show the next one. If the callback fails, this will remove
3748            // it from the list, so don't assume that the list hasn't changed
3749            // after this point.
3750            showNextToastLocked();
3751        }
3752    }
3753
3754    private void scheduleTimeoutLocked(ToastRecord r)
3755    {
3756        mHandler.removeCallbacksAndMessages(r);
3757        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3758        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3759        mHandler.sendMessageDelayed(m, delay);
3760    }
3761
3762    private void handleTimeout(ToastRecord record)
3763    {
3764        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3765        synchronized (mToastQueue) {
3766            int index = indexOfToastLocked(record.pkg, record.callback);
3767            if (index >= 0) {
3768                cancelToastLocked(index);
3769            }
3770        }
3771    }
3772
3773    // lock on mToastQueue
3774    int indexOfToastLocked(String pkg, ITransientNotification callback)
3775    {
3776        IBinder cbak = callback.asBinder();
3777        ArrayList<ToastRecord> list = mToastQueue;
3778        int len = list.size();
3779        for (int i=0; i<len; i++) {
3780            ToastRecord r = list.get(i);
3781            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3782                return i;
3783            }
3784        }
3785        return -1;
3786    }
3787
3788    // lock on mToastQueue
3789    void keepProcessAliveIfNeededLocked(int pid)
3790    {
3791        int toastCount = 0; // toasts from this pid
3792        ArrayList<ToastRecord> list = mToastQueue;
3793        int N = list.size();
3794        for (int i=0; i<N; i++) {
3795            ToastRecord r = list.get(i);
3796            if (r.pid == pid) {
3797                toastCount++;
3798            }
3799        }
3800        try {
3801            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3802        } catch (RemoteException e) {
3803            // Shouldn't happen.
3804        }
3805    }
3806
3807    private void handleRankingReconsideration(Message message) {
3808        if (!(message.obj instanceof RankingReconsideration)) return;
3809        RankingReconsideration recon = (RankingReconsideration) message.obj;
3810        recon.run();
3811        boolean changed;
3812        synchronized (mNotificationLock) {
3813            final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3814            if (record == null) {
3815                return;
3816            }
3817            int indexBefore = findNotificationRecordIndexLocked(record);
3818            boolean interceptBefore = record.isIntercepted();
3819            int visibilityBefore = record.getPackageVisibilityOverride();
3820            recon.applyChangesLocked(record);
3821            applyZenModeLocked(record);
3822            mRankingHelper.sort(mNotificationList);
3823            int indexAfter = findNotificationRecordIndexLocked(record);
3824            boolean interceptAfter = record.isIntercepted();
3825            int visibilityAfter = record.getPackageVisibilityOverride();
3826            changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3827                    || visibilityBefore != visibilityAfter;
3828            if (interceptBefore && !interceptAfter) {
3829                buzzBeepBlinkLocked(record);
3830            }
3831        }
3832        if (changed) {
3833            scheduleSendRankingUpdate();
3834        }
3835    }
3836
3837    private void handleRankingSort(Message msg) {
3838        if (!(msg.obj instanceof Boolean)) return;
3839        boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
3840        synchronized (mNotificationLock) {
3841            final int N = mNotificationList.size();
3842            // Any field that can change via one of the extractors or by the assistant
3843            // needs to be added here.
3844            ArrayList<String> orderBefore = new ArrayList<String>(N);
3845            ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3846            int[] visibilities = new int[N];
3847            boolean[] showBadges = new boolean[N];
3848            for (int i = 0; i < N; i++) {
3849                final NotificationRecord r = mNotificationList.get(i);
3850                orderBefore.add(r.getKey());
3851                groupOverrideBefore.add(r.sbn.getGroupKey());
3852                visibilities[i] = r.getPackageVisibilityOverride();
3853                showBadges[i] = r.canShowBadge();
3854                mRankingHelper.extractSignals(r);
3855            }
3856            mRankingHelper.sort(mNotificationList);
3857            for (int i = 0; i < N; i++) {
3858                final NotificationRecord r = mNotificationList.get(i);
3859                if (forceUpdate
3860                        || !orderBefore.get(i).equals(r.getKey())
3861                        || visibilities[i] != r.getPackageVisibilityOverride()
3862                        || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
3863                        || showBadges[i] != r.canShowBadge()) {
3864                    scheduleSendRankingUpdate();
3865                    return;
3866                }
3867            }
3868        }
3869    }
3870
3871    private void recordCallerLocked(NotificationRecord record) {
3872        if (mZenModeHelper.isCall(record)) {
3873            mZenModeHelper.recordCaller(record);
3874        }
3875    }
3876
3877    // let zen mode evaluate this record
3878    private void applyZenModeLocked(NotificationRecord record) {
3879        record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3880        if (record.isIntercepted()) {
3881            int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3882                    ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3883                    | (mZenModeHelper.shouldSuppressWhenScreenOn()
3884                    ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3885            record.setSuppressedVisualEffects(suppressed);
3886        }
3887    }
3888
3889    // lock on mNotificationList
3890    private int findNotificationRecordIndexLocked(NotificationRecord target) {
3891        return mRankingHelper.indexOf(mNotificationList, target);
3892    }
3893
3894    private void scheduleSendRankingUpdate() {
3895        if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3896            Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3897            mHandler.sendMessage(m);
3898        }
3899    }
3900
3901    private void handleSendRankingUpdate() {
3902        synchronized (mNotificationLock) {
3903            mListeners.notifyRankingUpdateLocked();
3904        }
3905    }
3906
3907    private void scheduleListenerHintsChanged(int state) {
3908        mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3909        mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3910    }
3911
3912    private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3913        mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3914        mHandler.obtainMessage(
3915                MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3916                listenerInterruptionFilter,
3917                0).sendToTarget();
3918    }
3919
3920    private void handleListenerHintsChanged(int hints) {
3921        synchronized (mNotificationLock) {
3922            mListeners.notifyListenerHintsChangedLocked(hints);
3923        }
3924    }
3925
3926    private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3927        synchronized (mNotificationLock) {
3928            mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3929        }
3930    }
3931
3932    private final class WorkerHandler extends Handler
3933    {
3934        public WorkerHandler(Looper looper) {
3935            super(looper);
3936        }
3937
3938        @Override
3939        public void handleMessage(Message msg)
3940        {
3941            switch (msg.what)
3942            {
3943                case MESSAGE_TIMEOUT:
3944                    handleTimeout((ToastRecord)msg.obj);
3945                    break;
3946                case MESSAGE_SAVE_POLICY_FILE:
3947                    handleSavePolicyFile();
3948                    break;
3949                case MESSAGE_SEND_RANKING_UPDATE:
3950                    handleSendRankingUpdate();
3951                    break;
3952                case MESSAGE_LISTENER_HINTS_CHANGED:
3953                    handleListenerHintsChanged(msg.arg1);
3954                    break;
3955                case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3956                    handleListenerInterruptionFilterChanged(msg.arg1);
3957                    break;
3958            }
3959        }
3960
3961    }
3962
3963    private final class RankingHandlerWorker extends Handler implements RankingHandler
3964    {
3965        public RankingHandlerWorker(Looper looper) {
3966            super(looper);
3967        }
3968
3969        @Override
3970        public void handleMessage(Message msg) {
3971            switch (msg.what) {
3972                case MESSAGE_RECONSIDER_RANKING:
3973                    handleRankingReconsideration(msg);
3974                    break;
3975                case MESSAGE_RANKING_SORT:
3976                    handleRankingSort(msg);
3977                    break;
3978            }
3979        }
3980
3981        public void requestSort(boolean forceUpdate) {
3982            removeMessages(MESSAGE_RANKING_SORT);
3983            Message msg = Message.obtain();
3984            msg.what = MESSAGE_RANKING_SORT;
3985            msg.obj = forceUpdate;
3986            sendMessage(msg);
3987        }
3988
3989        public void requestReconsideration(RankingReconsideration recon) {
3990            Message m = Message.obtain(this,
3991                    NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3992            long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3993            sendMessageDelayed(m, delay);
3994        }
3995    }
3996
3997    // Notifications
3998    // ============================================================================
3999    static int clamp(int x, int low, int high) {
4000        return (x < low) ? low : ((x > high) ? high : x);
4001    }
4002
4003    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4004        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
4005        if (!manager.isEnabled()) {
4006            return;
4007        }
4008
4009        AccessibilityEvent event =
4010            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4011        event.setPackageName(packageName);
4012        event.setClassName(Notification.class.getName());
4013        event.setParcelableData(notification);
4014        CharSequence tickerText = notification.tickerText;
4015        if (!TextUtils.isEmpty(tickerText)) {
4016            event.getText().add(tickerText);
4017        }
4018
4019        manager.sendAccessibilityEvent(event);
4020    }
4021
4022    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
4023        final String canceledKey = r.getKey();
4024
4025        // Remove from both lists, either list could have a separate Record for what is effectively
4026        // the same notification.
4027        boolean wasPosted = false;
4028        NotificationRecord recordInList = null;
4029        if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) != null) {
4030            mNotificationList.remove(recordInList);
4031            mNotificationsByKey.remove(recordInList.sbn.getKey());
4032            wasPosted = true;
4033        }
4034        if ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4035                != null) {
4036            mEnqueuedNotifications.remove(recordInList);
4037        }
4038
4039        // Record caller.
4040        recordCallerLocked(r);
4041
4042        // tell the app
4043        if (sendDelete) {
4044            if (r.getNotification().deleteIntent != null) {
4045                try {
4046                    r.getNotification().deleteIntent.send();
4047                } catch (PendingIntent.CanceledException ex) {
4048                    // do nothing - there's no relevant way to recover, and
4049                    //     no reason to let this propagate
4050                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4051                }
4052            }
4053        }
4054
4055        // Only cancel these if this notification actually got to be posted.
4056        if (wasPosted) {
4057            // status bar
4058            if (r.getNotification().getSmallIcon() != null) {
4059                r.isCanceled = true;
4060                mListeners.notifyRemovedLocked(r.sbn, reason);
4061                mHandler.post(new Runnable() {
4062                    @Override
4063                    public void run() {
4064                        mGroupHelper.onNotificationRemoved(r.sbn);
4065                    }
4066                });
4067            }
4068
4069            // sound
4070            if (canceledKey.equals(mSoundNotificationKey)) {
4071                mSoundNotificationKey = null;
4072                final long identity = Binder.clearCallingIdentity();
4073                try {
4074                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4075                    if (player != null) {
4076                        player.stopAsync();
4077                    }
4078                } catch (RemoteException e) {
4079                } finally {
4080                    Binder.restoreCallingIdentity(identity);
4081                }
4082            }
4083
4084            // vibrate
4085            if (canceledKey.equals(mVibrateNotificationKey)) {
4086                mVibrateNotificationKey = null;
4087                long identity = Binder.clearCallingIdentity();
4088                try {
4089                    mVibrator.cancel();
4090                }
4091                finally {
4092                    Binder.restoreCallingIdentity(identity);
4093                }
4094            }
4095
4096            // light
4097            mLights.remove(canceledKey);
4098        }
4099
4100        // Record usage stats
4101        // TODO: add unbundling stats?
4102        switch (reason) {
4103            case REASON_CANCEL:
4104            case REASON_CANCEL_ALL:
4105            case REASON_LISTENER_CANCEL:
4106            case REASON_LISTENER_CANCEL_ALL:
4107                mUsageStats.registerDismissedByUser(r);
4108                break;
4109            case REASON_APP_CANCEL:
4110            case REASON_APP_CANCEL_ALL:
4111                mUsageStats.registerRemovedByApp(r);
4112                break;
4113        }
4114
4115        String groupKey = r.getGroupKey();
4116        NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4117        if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4118            mSummaryByGroupKey.remove(groupKey);
4119        }
4120        final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4121        if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4122            summaries.remove(r.sbn.getPackageName());
4123        }
4124
4125        // Save it for users of getHistoricalNotifications()
4126        mArchive.record(r.sbn);
4127
4128        final long now = System.currentTimeMillis();
4129        MetricsLogger.action(r.getLogMaker(now)
4130                .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4131                .setType(MetricsEvent.TYPE_DISMISS)
4132                .setSubtype(reason));
4133        EventLogTags.writeNotificationCanceled(canceledKey, reason,
4134                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
4135    }
4136
4137    /**
4138     * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4139     * and none of the {@code mustNotHaveFlags}.
4140     */
4141    void cancelNotification(final int callingUid, final int callingPid,
4142            final String pkg, final String tag, final int id,
4143            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4144            final int userId, final int reason, final ManagedServiceInfo listener) {
4145        // In enqueueNotificationInternal notifications are added by scheduling the
4146        // work on the worker handler. Hence, we also schedule the cancel on this
4147        // handler to avoid a scenario where an add notification call followed by a
4148        // remove notification call ends up in not removing the notification.
4149        mHandler.post(new Runnable() {
4150            @Override
4151            public void run() {
4152                String listenerName = listener == null ? null : listener.component.toShortString();
4153                if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4154                        userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4155
4156                synchronized (mNotificationLock) {
4157                    // Look for the notification, searching both the posted and enqueued lists.
4158                    NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4159                    if (r != null) {
4160                        // The notification was found, check if it should be removed.
4161
4162                        // Ideally we'd do this in the caller of this method. However, that would
4163                        // require the caller to also find the notification.
4164                        if (reason == REASON_CLICK) {
4165                            mUsageStats.registerClickedByUser(r);
4166                        }
4167
4168                        if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4169                            return;
4170                        }
4171                        if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4172                            return;
4173                        }
4174
4175                        // Cancel the notification.
4176                        cancelNotificationLocked(r, sendDelete, reason);
4177                        cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4178                                sendDelete);
4179                        updateLightsLocked();
4180                    } else {
4181                        // No notification was found, assume that it is snoozed and cancel it.
4182                        final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4183                        if (wasSnoozed) {
4184                            savePolicyFile();
4185                        }
4186                    }
4187                }
4188            }
4189        });
4190    }
4191
4192    /**
4193     * Determine whether the userId applies to the notification in question, either because
4194     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4195     */
4196    private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4197        return
4198                // looking for USER_ALL notifications? match everything
4199                   userId == UserHandle.USER_ALL
4200                // a notification sent to USER_ALL matches any query
4201                || r.getUserId() == UserHandle.USER_ALL
4202                // an exact user match
4203                || r.getUserId() == userId;
4204    }
4205
4206    /**
4207     * Determine whether the userId applies to the notification in question, either because
4208     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4209     * because it matches one of the users profiles.
4210     */
4211    private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4212        return notificationMatchesUserId(r, userId)
4213                || mUserProfiles.isCurrentProfile(r.getUserId());
4214    }
4215
4216    /**
4217     * Cancels all notifications from a given package that have all of the
4218     * {@code mustHaveFlags}.
4219     */
4220    void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4221            int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4222            ManagedServiceInfo listener) {
4223        mHandler.post(new Runnable() {
4224            @Override
4225            public void run() {
4226                String listenerName = listener == null ? null : listener.component.toShortString();
4227                EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4228                        pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4229                        listenerName);
4230
4231                // Why does this parameter exist? Do we actually want to execute the above if doit
4232                // is false?
4233                if (!doit) {
4234                    return;
4235                }
4236
4237                synchronized (mNotificationLock) {
4238                    FlagChecker flagChecker = (int flags) -> {
4239                        if ((flags & mustHaveFlags) != mustHaveFlags) {
4240                            return false;
4241                        }
4242                        if ((flags & mustNotHaveFlags) != 0) {
4243                            return false;
4244                        }
4245                        return true;
4246                    };
4247
4248                    cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4249                            pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4250                            false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4251                            listenerName);
4252                    cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4253                            callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4254                            flagChecker, false /*includeCurrentProfiles*/, userId,
4255                            false /*sendDelete*/, reason, listenerName);
4256                    mSnoozeHelper.cancel(userId, pkg);
4257                }
4258            }
4259        });
4260    }
4261
4262    private interface FlagChecker {
4263        // Returns false if these flags do not pass the defined flag test.
4264        public boolean apply(int flags);
4265    }
4266
4267    private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4268            int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4269            String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4270            boolean sendDelete, int reason, String listenerName) {
4271        ArrayList<NotificationRecord> canceledNotifications = null;
4272        for (int i = notificationList.size() - 1; i >= 0; --i) {
4273            NotificationRecord r = notificationList.get(i);
4274            if (includeCurrentProfiles) {
4275                if (!notificationMatchesCurrentProfiles(r, userId)) {
4276                    continue;
4277                }
4278            } else if (!notificationMatchesUserId(r, userId)) {
4279                continue;
4280            }
4281            // Don't remove notifications to all, if there's no package name specified
4282            if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4283                continue;
4284            }
4285            if (!flagChecker.apply(r.getFlags())) {
4286                continue;
4287            }
4288            if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4289                continue;
4290            }
4291            if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4292                continue;
4293            }
4294
4295            if (canceledNotifications == null) {
4296                canceledNotifications = new ArrayList<>();
4297            }
4298            canceledNotifications.add(r);
4299            cancelNotificationLocked(r, sendDelete, reason);
4300        }
4301        if (canceledNotifications != null) {
4302            final int M = canceledNotifications.size();
4303            for (int i = 0; i < M; i++) {
4304                cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4305                        listenerName, false /* sendDelete */);
4306            }
4307            updateLightsLocked();
4308        }
4309    }
4310
4311    void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4312            ManagedServiceInfo listener) {
4313        String listenerName = listener == null ? null : listener.component.toShortString();
4314        if (duration <= 0 && snoozeCriterionId == null) {
4315            return;
4316        }
4317
4318        if (DBG) {
4319            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4320                    snoozeCriterionId, listenerName));
4321        }
4322        // Needs to post so that it can cancel notifications not yet enqueued.
4323        mHandler.post(new Runnable() {
4324            @Override
4325            public void run() {
4326                synchronized (mNotificationLock) {
4327                    final NotificationRecord r = findNotificationByKeyLocked(key);
4328                    if (r != null) {
4329                        MetricsLogger.action(r.getLogMaker()
4330                                .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4331                                .setType(MetricsEvent.TYPE_CLOSE)
4332                                .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4333                                        snoozeCriterionId == null ? 0 : 1));
4334                        cancelNotificationLocked(r, false, REASON_SNOOZED);
4335                        updateLightsLocked();
4336                        if (snoozeCriterionId != null) {
4337                            mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn,
4338                                    snoozeCriterionId);
4339                            mSnoozeHelper.snooze(r);
4340                        } else {
4341                            mSnoozeHelper.snooze(r, duration);
4342                        }
4343                        savePolicyFile();
4344                    }
4345                }
4346            }
4347        });
4348    }
4349
4350    void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4351        String listenerName = listener == null ? null : listener.component.toShortString();
4352        if (DBG) {
4353            Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4354        }
4355        mSnoozeHelper.repost(key);
4356        savePolicyFile();
4357    }
4358
4359    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4360            ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4361        mHandler.post(new Runnable() {
4362            @Override
4363            public void run() {
4364                synchronized (mNotificationLock) {
4365                    String listenerName =
4366                            listener == null ? null : listener.component.toShortString();
4367                    EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4368                            null, userId, 0, 0, reason, listenerName);
4369
4370                    FlagChecker flagChecker = (int flags) -> {
4371                        if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4372                                != 0) {
4373                            return false;
4374                        }
4375                        return true;
4376                    };
4377
4378                    cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4379                            null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4380                            includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4381                            listenerName);
4382                    cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4383                            callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4384                            flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4385                            reason, listenerName);
4386                    mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4387                }
4388            }
4389        });
4390    }
4391
4392    // Warning: The caller is responsible for invoking updateLightsLocked().
4393    private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4394            String listenerName, boolean sendDelete) {
4395        Notification n = r.getNotification();
4396        if (!n.isGroupSummary()) {
4397            return;
4398        }
4399
4400        String pkg = r.sbn.getPackageName();
4401        int userId = r.getUserId();
4402
4403        if (pkg == null) {
4404            if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4405            return;
4406        }
4407
4408        cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4409                sendDelete);
4410        cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4411                listenerName, sendDelete);
4412    }
4413
4414    private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4415            NotificationRecord parentNotification, int callingUid, int callingPid,
4416            String listenerName, boolean sendDelete) {
4417        final String pkg = parentNotification.sbn.getPackageName();
4418        final int userId = parentNotification.getUserId();
4419        final int reason = REASON_GROUP_SUMMARY_CANCELED;
4420        for (int i = notificationList.size() - 1; i >= 0; i--) {
4421            final NotificationRecord childR = notificationList.get(i);
4422            final StatusBarNotification childSbn = childR.sbn;
4423            if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4424                    childR.getGroupKey().equals(parentNotification.getGroupKey())
4425                    && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
4426                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4427                        childSbn.getTag(), userId, 0, 0, reason, listenerName);
4428                cancelNotificationLocked(childR, sendDelete, reason);
4429            }
4430        }
4431    }
4432
4433    // lock on mNotificationList
4434    void updateLightsLocked()
4435    {
4436        // handle notification lights
4437        NotificationRecord ledNotification = null;
4438        while (ledNotification == null && !mLights.isEmpty()) {
4439            final String owner = mLights.get(mLights.size() - 1);
4440            ledNotification = mNotificationsByKey.get(owner);
4441            if (ledNotification == null) {
4442                Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4443                mLights.remove(owner);
4444            }
4445        }
4446
4447        // Don't flash while we are in a call or screen is on
4448        if (ledNotification == null || mInCall || mScreenOn) {
4449            mNotificationLight.turnOff();
4450        } else {
4451            NotificationRecord.Light light = ledNotification.getLight();
4452            if (light != null && mNotificationPulseEnabled) {
4453                // pulse repeatedly
4454                mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4455                        light.onMs, light.offMs);
4456            }
4457        }
4458    }
4459
4460    // Searches both enqueued and posted notifications by key.
4461    // TODO: need to combine a bunch of these getters with slightly different behavior.
4462    // TODO: Should enqueuing just add to mNotificationsByKey instead?
4463    private NotificationRecord findNotificationByKeyLocked(String key) {
4464        NotificationRecord r;
4465        if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4466            return r;
4467        }
4468        if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4469            return r;
4470        }
4471        return null;
4472    }
4473
4474    private NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
4475        NotificationRecord r;
4476        if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4477            return r;
4478        }
4479        if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4480                != null) {
4481            return r;
4482        }
4483        return null;
4484    }
4485
4486    private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4487            String pkg, String tag, int id, int userId) {
4488        final int len = list.size();
4489        for (int i = 0; i < len; i++) {
4490            NotificationRecord r = list.get(i);
4491            if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
4492                    TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
4493                return r;
4494            }
4495        }
4496        return null;
4497    }
4498
4499    private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4500            String key)
4501    {
4502        final int N = list.size();
4503        for (int i = 0; i < N; i++) {
4504            if (key.equals(list.get(i).getKey())) {
4505                return list.get(i);
4506            }
4507        }
4508        return null;
4509    }
4510
4511    // lock on mNotificationList
4512    int indexOfNotificationLocked(String key) {
4513        final int N = mNotificationList.size();
4514        for (int i = 0; i < N; i++) {
4515            if (key.equals(mNotificationList.get(i).getKey())) {
4516                return i;
4517            }
4518        }
4519        return -1;
4520    }
4521
4522    private void updateNotificationPulse() {
4523        synchronized (mNotificationLock) {
4524            updateLightsLocked();
4525        }
4526    }
4527
4528    protected boolean isUidSystem(int uid) {
4529        final int appid = UserHandle.getAppId(uid);
4530        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
4531    }
4532
4533    protected boolean isCallerSystem() {
4534        return isUidSystem(Binder.getCallingUid());
4535    }
4536
4537    private void checkCallerIsSystem() {
4538        if (isCallerSystem()) {
4539            return;
4540        }
4541        throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
4542    }
4543
4544    private void checkCallerIsSystemOrSameApp(String pkg) {
4545        if (isCallerSystem()) {
4546            return;
4547        }
4548        checkCallerIsSameApp(pkg);
4549    }
4550
4551    private boolean isCallerInstantApp(String pkg) {
4552        // System is always allowed to act for ephemeral apps.
4553        if (isCallerSystem()) {
4554            return false;
4555        }
4556
4557        mAppOps.checkPackage(Binder.getCallingUid(), pkg);
4558
4559        try {
4560            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
4561                    UserHandle.getCallingUserId());
4562            if (ai == null) {
4563                throw new SecurityException("Unknown package " + pkg);
4564            }
4565            return ai.isInstantApp();
4566        } catch (RemoteException re) {
4567            throw new SecurityException("Unknown package " + pkg, re);
4568        }
4569
4570    }
4571
4572    private void checkCallerIsSameApp(String pkg) {
4573        final int uid = Binder.getCallingUid();
4574        try {
4575            ApplicationInfo ai = mPackageManager.getApplicationInfo(
4576                    pkg, 0, UserHandle.getCallingUserId());
4577            if (ai == null) {
4578                throw new SecurityException("Unknown package " + pkg);
4579            }
4580            if (!UserHandle.isSameApp(ai.uid, uid)) {
4581                throw new SecurityException("Calling uid " + uid + " gave package "
4582                        + pkg + " which is owned by uid " + ai.uid);
4583            }
4584        } catch (RemoteException re) {
4585            throw new SecurityException("Unknown package " + pkg + "\n" + re);
4586        }
4587    }
4588
4589    private static String callStateToString(int state) {
4590        switch (state) {
4591            case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
4592            case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
4593            case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
4594            default: return "CALL_STATE_UNKNOWN_" + state;
4595        }
4596    }
4597
4598    private void listenForCallState() {
4599        TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
4600            @Override
4601            public void onCallStateChanged(int state, String incomingNumber) {
4602                if (mCallState == state) return;
4603                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
4604                mCallState = state;
4605            }
4606        }, PhoneStateListener.LISTEN_CALL_STATE);
4607    }
4608
4609    /**
4610     * Generates a NotificationRankingUpdate from 'sbns', considering only
4611     * notifications visible to the given listener.
4612     *
4613     * <p>Caller must hold a lock on mNotificationList.</p>
4614     */
4615    private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
4616        final int N = mNotificationList.size();
4617        ArrayList<String> keys = new ArrayList<String>(N);
4618        ArrayList<String> interceptedKeys = new ArrayList<String>(N);
4619        ArrayList<Integer> importance = new ArrayList<>(N);
4620        Bundle overrideGroupKeys = new Bundle();
4621        Bundle visibilityOverrides = new Bundle();
4622        Bundle suppressedVisualEffects = new Bundle();
4623        Bundle explanation = new Bundle();
4624        Bundle channels = new Bundle();
4625        Bundle overridePeople = new Bundle();
4626        Bundle snoozeCriteria = new Bundle();
4627        Bundle showBadge = new Bundle();
4628        for (int i = 0; i < N; i++) {
4629            NotificationRecord record = mNotificationList.get(i);
4630            if (!isVisibleToListener(record.sbn, info)) {
4631                continue;
4632            }
4633            final String key = record.sbn.getKey();
4634            keys.add(key);
4635            importance.add(record.getImportance());
4636            if (record.getImportanceExplanation() != null) {
4637                explanation.putCharSequence(key, record.getImportanceExplanation());
4638            }
4639            if (record.isIntercepted()) {
4640                interceptedKeys.add(key);
4641
4642            }
4643            suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
4644            if (record.getPackageVisibilityOverride()
4645                    != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
4646                visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
4647            }
4648            overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
4649            channels.putParcelable(key, record.getChannel());
4650            overridePeople.putStringArrayList(key, record.getPeopleOverride());
4651            snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
4652            showBadge.putBoolean(key, record.canShowBadge());
4653        }
4654        final int M = keys.size();
4655        String[] keysAr = keys.toArray(new String[M]);
4656        String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4657        int[] importanceAr = new int[M];
4658        for (int i = 0; i < M; i++) {
4659            importanceAr[i] = importance.get(i);
4660        }
4661        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4662                suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
4663                channels, overridePeople, snoozeCriteria, showBadge);
4664    }
4665
4666    boolean hasCompanionDevice(ManagedServiceInfo info) {
4667        if (mCompanionManager == null) {
4668            mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
4669                    ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
4670        }
4671        long identity = Binder.clearCallingIdentity();
4672        try {
4673            List<String> associations = mCompanionManager.getAssociations(
4674                    info.component.getPackageName(), info.userid);
4675            if (!ArrayUtils.isEmpty(associations)) {
4676                return true;
4677            }
4678        } catch (SecurityException se) {
4679            // Not a privileged listener
4680        } catch (RemoteException re) {
4681            Slog.e(TAG, "Cannot reach companion device service", re);
4682        } catch (Exception e) {
4683            Slog.e(TAG, "Cannot verify listener " + info, e);
4684        } finally {
4685            Binder.restoreCallingIdentity(identity);
4686        }
4687        return false;
4688    }
4689
4690    private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
4691        if (!listener.enabledAndUserMatches(sbn.getUserId())) {
4692            return false;
4693        }
4694        // TODO: remove this for older listeners.
4695        return true;
4696    }
4697
4698    private boolean isPackageSuspendedForUser(String pkg, int uid) {
4699        int userId = UserHandle.getUserId(uid);
4700        try {
4701            return mPackageManager.isPackageSuspendedForUser(pkg, userId);
4702        } catch (RemoteException re) {
4703            throw new SecurityException("Could not talk to package manager service");
4704        } catch (IllegalArgumentException ex) {
4705            // Package not found.
4706            return false;
4707        }
4708    }
4709
4710    private class TrimCache {
4711        StatusBarNotification heavy;
4712        StatusBarNotification sbnClone;
4713        StatusBarNotification sbnCloneLight;
4714
4715        TrimCache(StatusBarNotification sbn) {
4716            heavy = sbn;
4717        }
4718
4719        StatusBarNotification ForListener(ManagedServiceInfo info) {
4720            if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
4721                if (sbnCloneLight == null) {
4722                    sbnCloneLight = heavy.cloneLight();
4723                }
4724                return sbnCloneLight;
4725            } else {
4726                if (sbnClone == null) {
4727                    sbnClone = heavy.clone();
4728                }
4729                return sbnClone;
4730            }
4731        }
4732    }
4733
4734    public class NotificationAssistants extends ManagedServices {
4735
4736        public NotificationAssistants() {
4737            super(getContext(), mHandler, mNotificationList, mUserProfiles);
4738        }
4739
4740        @Override
4741        protected Config getConfig() {
4742            Config c = new Config();
4743            c.caption = "notification assistant service";
4744            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
4745            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
4746            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
4747            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
4748            c.clientLabel = R.string.notification_ranker_binding_label;
4749            return c;
4750        }
4751
4752        @Override
4753        protected IInterface asInterface(IBinder binder) {
4754            return INotificationListener.Stub.asInterface(binder);
4755        }
4756
4757        @Override
4758        protected boolean checkType(IInterface service) {
4759            return service instanceof INotificationListener;
4760        }
4761
4762        @Override
4763        protected void onServiceAdded(ManagedServiceInfo info) {
4764            mListeners.registerGuestService(info);
4765        }
4766
4767        @Override
4768        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4769            mListeners.unregisterService(removed.service, removed.userid);
4770        }
4771
4772        public void onNotificationEnqueued(final NotificationRecord r) {
4773            final StatusBarNotification sbn = r.sbn;
4774            TrimCache trimCache = new TrimCache(sbn);
4775
4776            // There should be only one, but it's a list, so while we enforce
4777            // singularity elsewhere, we keep it general here, to avoid surprises.
4778            for (final ManagedServiceInfo info : NotificationAssistants.this.mServices) {
4779                boolean sbnVisible = isVisibleToListener(sbn, info);
4780                if (!sbnVisible) {
4781                    continue;
4782                }
4783
4784                final int importance = r.getImportance();
4785                final boolean fromUser = r.isImportanceFromUser();
4786                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4787                mHandler.post(new Runnable() {
4788                    @Override
4789                    public void run() {
4790                        notifyEnqueued(info, sbnToPost);
4791                    }
4792                });
4793            }
4794        }
4795
4796        private void notifyEnqueued(final ManagedServiceInfo info,
4797                final StatusBarNotification sbn) {
4798            final INotificationListener assistant = (INotificationListener) info.service;
4799            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4800            try {
4801                assistant.onNotificationEnqueued(sbnHolder);
4802            } catch (RemoteException ex) {
4803                Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
4804            }
4805        }
4806
4807        /**
4808         * asynchronously notify the assistant that a notification has been snoozed until a
4809         * context
4810         */
4811        public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
4812                final String snoozeCriterionId) {
4813            TrimCache trimCache = new TrimCache(sbn);
4814            for (final ManagedServiceInfo info : mServices) {
4815                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4816                mHandler.post(new Runnable() {
4817                    @Override
4818                    public void run() {
4819                        final INotificationListener assistant =
4820                                (INotificationListener) info.service;
4821                        StatusBarNotificationHolder sbnHolder
4822                                = new StatusBarNotificationHolder(sbnToPost);
4823                        try {
4824                            assistant.onNotificationSnoozedUntilContext(
4825                                    sbnHolder, snoozeCriterionId);
4826                        } catch (RemoteException ex) {
4827                            Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
4828                        }
4829                    }
4830                });
4831            }
4832        }
4833
4834        public boolean isEnabled() {
4835            return !mServices.isEmpty();
4836        }
4837    }
4838
4839    public class NotificationListeners extends ManagedServices {
4840
4841        private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
4842
4843        public NotificationListeners() {
4844            super(getContext(), mHandler, mNotificationList, mUserProfiles);
4845        }
4846
4847        @Override
4848        protected Config getConfig() {
4849            Config c = new Config();
4850            c.caption = "notification listener";
4851            c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
4852            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
4853            c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
4854            c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
4855            c.clientLabel = R.string.notification_listener_binding_label;
4856            return c;
4857        }
4858
4859        @Override
4860        protected IInterface asInterface(IBinder binder) {
4861            return INotificationListener.Stub.asInterface(binder);
4862        }
4863
4864        @Override
4865        protected boolean checkType(IInterface service) {
4866            return service instanceof INotificationListener;
4867        }
4868
4869        @Override
4870        public void onServiceAdded(ManagedServiceInfo info) {
4871            final INotificationListener listener = (INotificationListener) info.service;
4872            final NotificationRankingUpdate update;
4873            synchronized (mNotificationLock) {
4874                update = makeRankingUpdateLocked(info);
4875            }
4876            try {
4877                listener.onListenerConnected(update);
4878            } catch (RemoteException e) {
4879                // we tried
4880            }
4881        }
4882
4883        @Override
4884        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4885            if (removeDisabledHints(removed)) {
4886                updateListenerHintsLocked();
4887                updateEffectsSuppressorLocked();
4888            }
4889            mLightTrimListeners.remove(removed);
4890        }
4891
4892        public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
4893            if (trim == TRIM_LIGHT) {
4894                mLightTrimListeners.add(info);
4895            } else {
4896                mLightTrimListeners.remove(info);
4897            }
4898        }
4899
4900        public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4901            return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
4902        }
4903
4904        /**
4905         * asynchronously notify all listeners about a new notification
4906         *
4907         * <p>
4908         * Also takes care of removing a notification that has been visible to a listener before,
4909         * but isn't anymore.
4910         */
4911        public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
4912            // Lazily initialized snapshots of the notification.
4913            TrimCache trimCache = new TrimCache(sbn);
4914
4915            for (final ManagedServiceInfo info : mServices) {
4916                boolean sbnVisible = isVisibleToListener(sbn, info);
4917                boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4918                // This notification hasn't been and still isn't visible -> ignore.
4919                if (!oldSbnVisible && !sbnVisible) {
4920                    continue;
4921                }
4922                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4923
4924                // This notification became invisible -> remove the old one.
4925                if (oldSbnVisible && !sbnVisible) {
4926                    final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4927                    mHandler.post(new Runnable() {
4928                        @Override
4929                        public void run() {
4930                            notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
4931                        }
4932                    });
4933                    continue;
4934                }
4935
4936                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4937                mHandler.post(new Runnable() {
4938                    @Override
4939                    public void run() {
4940                        notifyPosted(info, sbnToPost, update);
4941                    }
4942                });
4943            }
4944        }
4945
4946        /**
4947         * asynchronously notify all listeners about a removed notification
4948         */
4949        public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
4950            // make a copy in case changes are made to the underlying Notification object
4951            // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4952            // notification
4953            final StatusBarNotification sbnLight = sbn.cloneLight();
4954            for (final ManagedServiceInfo info : mServices) {
4955                if (!isVisibleToListener(sbn, info)) {
4956                    continue;
4957                }
4958                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4959                mHandler.post(new Runnable() {
4960                    @Override
4961                    public void run() {
4962                        notifyRemoved(info, sbnLight, update, reason);
4963                    }
4964                });
4965            }
4966        }
4967
4968        /**
4969         * asynchronously notify all listeners about a reordering of notifications
4970         */
4971        public void notifyRankingUpdateLocked() {
4972            for (final ManagedServiceInfo serviceInfo : mServices) {
4973                if (!serviceInfo.isEnabledForCurrentProfiles()) {
4974                    continue;
4975                }
4976                final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
4977                mHandler.post(new Runnable() {
4978                    @Override
4979                    public void run() {
4980                        notifyRankingUpdate(serviceInfo, update);
4981                    }
4982                });
4983            }
4984        }
4985
4986        public void notifyListenerHintsChangedLocked(final int hints) {
4987            for (final ManagedServiceInfo serviceInfo : mServices) {
4988                if (!serviceInfo.isEnabledForCurrentProfiles()) {
4989                    continue;
4990                }
4991                mHandler.post(new Runnable() {
4992                    @Override
4993                    public void run() {
4994                        notifyListenerHintsChanged(serviceInfo, hints);
4995                    }
4996                });
4997            }
4998        }
4999
5000        public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5001            for (final ManagedServiceInfo serviceInfo : mServices) {
5002                if (!serviceInfo.isEnabledForCurrentProfiles()) {
5003                    continue;
5004                }
5005                mHandler.post(new Runnable() {
5006                    @Override
5007                    public void run() {
5008                        notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5009                    }
5010                });
5011            }
5012        }
5013
5014        protected void notifyNotificationChannelChanged(final String pkg,
5015                final NotificationChannel channel, final int modificationType) {
5016            if (channel == null) {
5017                return;
5018            }
5019            for (final ManagedServiceInfo serviceInfo : getServices()) {
5020                if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5021                    continue;
5022                }
5023                if (!hasCompanionDevice(serviceInfo)) {
5024                    continue;
5025                }
5026                mHandler.post(new Runnable() {
5027                    @Override
5028                    public void run() {
5029                        notifyNotificationChannelChanged(serviceInfo, pkg, channel,
5030                                modificationType);
5031                    }
5032                });
5033            }
5034        }
5035
5036        protected void notifyNotificationChannelGroupChanged(final String pkg,
5037                final NotificationChannelGroup group, final int modificationType) {
5038            if (group == null) {
5039                return;
5040            }
5041            for (final ManagedServiceInfo serviceInfo : getServices()) {
5042                if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5043                    continue;
5044                }
5045                if (!hasCompanionDevice(serviceInfo)) {
5046                    continue;
5047                }
5048                mHandler.post(new Runnable() {
5049                    @Override
5050                    public void run() {
5051                        notifyNotificationChannelGroupChanged(serviceInfo, pkg, group,
5052                                modificationType);
5053                    }
5054                });
5055            }
5056        }
5057
5058        private void notifyPosted(final ManagedServiceInfo info,
5059                final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5060            final INotificationListener listener = (INotificationListener) info.service;
5061            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5062            try {
5063                listener.onNotificationPosted(sbnHolder, rankingUpdate);
5064            } catch (RemoteException ex) {
5065                Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5066            }
5067        }
5068
5069        private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5070                NotificationRankingUpdate rankingUpdate, int reason) {
5071            if (!info.enabledAndUserMatches(sbn.getUserId())) {
5072                return;
5073            }
5074            final INotificationListener listener = (INotificationListener) info.service;
5075            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5076            try {
5077                listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5078            } catch (RemoteException ex) {
5079                Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5080            }
5081        }
5082
5083        private void notifyRankingUpdate(ManagedServiceInfo info,
5084                                         NotificationRankingUpdate rankingUpdate) {
5085            final INotificationListener listener = (INotificationListener) info.service;
5086            try {
5087                listener.onNotificationRankingUpdate(rankingUpdate);
5088            } catch (RemoteException ex) {
5089                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5090            }
5091        }
5092
5093        private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5094            final INotificationListener listener = (INotificationListener) info.service;
5095            try {
5096                listener.onListenerHintsChanged(hints);
5097            } catch (RemoteException ex) {
5098                Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5099            }
5100        }
5101
5102        private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5103                int interruptionFilter) {
5104            final INotificationListener listener = (INotificationListener) info.service;
5105            try {
5106                listener.onInterruptionFilterChanged(interruptionFilter);
5107            } catch (RemoteException ex) {
5108                Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5109            }
5110        }
5111
5112        void notifyNotificationChannelChanged(ManagedServiceInfo info,
5113                final String pkg, final NotificationChannel channel,
5114                final int modificationType) {
5115            final INotificationListener listener = (INotificationListener) info.service;
5116            try {
5117                listener.onNotificationChannelModification(pkg, channel, modificationType);
5118            } catch (RemoteException ex) {
5119                Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5120            }
5121        }
5122
5123        private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5124                final String pkg, final NotificationChannelGroup group,
5125                final int modificationType) {
5126            final INotificationListener listener = (INotificationListener) info.service;
5127            try {
5128                listener.onNotificationChannelGroupModification(pkg, group, modificationType);
5129            } catch (RemoteException ex) {
5130                Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5131            }
5132        }
5133
5134        public boolean isListenerPackage(String packageName) {
5135            if (packageName == null) {
5136                return false;
5137            }
5138            // TODO: clean up locking object later
5139            synchronized (mNotificationLock) {
5140                for (final ManagedServiceInfo serviceInfo : mServices) {
5141                    if (packageName.equals(serviceInfo.component.getPackageName())) {
5142                        return true;
5143                    }
5144                }
5145            }
5146            return false;
5147        }
5148    }
5149
5150    public static final class DumpFilter {
5151        public boolean filtered = false;
5152        public String pkgFilter;
5153        public boolean zen;
5154        public long since;
5155        public boolean stats;
5156        public boolean redact = true;
5157        public boolean proto = false;
5158
5159        public static DumpFilter parseFromArguments(String[] args) {
5160            final DumpFilter filter = new DumpFilter();
5161            for (int ai = 0; ai < args.length; ai++) {
5162                final String a = args[ai];
5163                if ("--proto".equals(args[0])) {
5164                    filter.proto = true;
5165                }
5166                if ("--noredact".equals(a) || "--reveal".equals(a)) {
5167                    filter.redact = false;
5168                } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5169                    if (ai < args.length-1) {
5170                        ai++;
5171                        filter.pkgFilter = args[ai].trim().toLowerCase();
5172                        if (filter.pkgFilter.isEmpty()) {
5173                            filter.pkgFilter = null;
5174                        } else {
5175                            filter.filtered = true;
5176                        }
5177                    }
5178                } else if ("--zen".equals(a) || "zen".equals(a)) {
5179                    filter.filtered = true;
5180                    filter.zen = true;
5181                } else if ("--stats".equals(a)) {
5182                    filter.stats = true;
5183                    if (ai < args.length-1) {
5184                        ai++;
5185                        filter.since = Long.parseLong(args[ai]);
5186                    } else {
5187                        filter.since = 0;
5188                    }
5189                }
5190            }
5191            return filter;
5192        }
5193
5194        public boolean matches(StatusBarNotification sbn) {
5195            if (!filtered) return true;
5196            return zen ? true : sbn != null
5197                    && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5198        }
5199
5200        public boolean matches(ComponentName component) {
5201            if (!filtered) return true;
5202            return zen ? true : component != null && matches(component.getPackageName());
5203        }
5204
5205        public boolean matches(String pkg) {
5206            if (!filtered) return true;
5207            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5208        }
5209
5210        @Override
5211        public String toString() {
5212            return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5213        }
5214    }
5215
5216    /**
5217     * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5218     * binder without sending large amounts of data over a oneway transaction.
5219     */
5220    private static final class StatusBarNotificationHolder
5221            extends IStatusBarNotificationHolder.Stub {
5222        private StatusBarNotification mValue;
5223
5224        public StatusBarNotificationHolder(StatusBarNotification value) {
5225            mValue = value;
5226        }
5227
5228        /** Get the held value and clear it. This function should only be called once per holder */
5229        @Override
5230        public StatusBarNotification get() {
5231            StatusBarNotification value = mValue;
5232            mValue = null;
5233            return value;
5234        }
5235    }
5236
5237    private final class PolicyAccess {
5238        private static final String SEPARATOR = ":";
5239        private final String[] PERM = {
5240            android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
5241        };
5242
5243        public boolean isPackageGranted(String pkg) {
5244            return pkg != null && getGrantedPackages().contains(pkg);
5245        }
5246
5247        public void put(String pkg, boolean granted) {
5248            if (pkg == null) return;
5249            final ArraySet<String> pkgs = getGrantedPackages();
5250            boolean changed;
5251            if (granted) {
5252                changed = pkgs.add(pkg);
5253            } else {
5254                changed = pkgs.remove(pkg);
5255            }
5256            if (!changed) return;
5257            final String setting = TextUtils.join(SEPARATOR, pkgs);
5258            final int currentUser = ActivityManager.getCurrentUser();
5259            Settings.Secure.putStringForUser(getContext().getContentResolver(),
5260                    Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5261                    setting,
5262                    currentUser);
5263            getContext().sendBroadcastAsUser(new Intent(NotificationManager
5264                    .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5265                .setPackage(pkg)
5266                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
5267        }
5268
5269        public ArraySet<String> getGrantedPackages() {
5270            final ArraySet<String> pkgs = new ArraySet<>();
5271
5272            long identity = Binder.clearCallingIdentity();
5273            try {
5274                final String setting = Settings.Secure.getStringForUser(
5275                        getContext().getContentResolver(),
5276                        Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5277                        ActivityManager.getCurrentUser());
5278                if (setting != null) {
5279                    final String[] tokens = setting.split(SEPARATOR);
5280                    for (int i = 0; i < tokens.length; i++) {
5281                        String token = tokens[i];
5282                        if (token != null) {
5283                            token = token.trim();
5284                        }
5285                        if (TextUtils.isEmpty(token)) {
5286                            continue;
5287                        }
5288                        pkgs.add(token);
5289                    }
5290                }
5291            } finally {
5292                Binder.restoreCallingIdentity(identity);
5293            }
5294            return pkgs;
5295        }
5296
5297        public String[] getRequestingPackages() throws RemoteException {
5298            final ParceledListSlice list = mPackageManager
5299                    .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
5300                            ActivityManager.getCurrentUser());
5301            final List<PackageInfo> pkgs = list.getList();
5302            if (pkgs == null || pkgs.isEmpty()) return new String[0];
5303            final int N = pkgs.size();
5304            final String[] rt = new String[N];
5305            for (int i = 0; i < N; i++) {
5306                rt[i] = pkgs.get(i).packageName;
5307            }
5308            return rt;
5309        }
5310    }
5311}
5312