NotificationManagerService.java revision ea6c4489598fce95ac0e22ff13290a9fb264db5a
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.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
20import static android.service.notification.NotificationListenerService.TRIM_FULL;
21import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
22import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
23import static org.xmlpull.v1.XmlPullParser.END_TAG;
24import static org.xmlpull.v1.XmlPullParser.START_TAG;
25
26import android.app.ActivityManager;
27import android.app.ActivityManagerNative;
28import android.app.AppGlobals;
29import android.app.AppOpsManager;
30import android.app.IActivityManager;
31import android.app.INotificationManager;
32import android.app.ITransientNotification;
33import android.app.Notification;
34import android.app.NotificationManager;
35import android.app.NotificationManager.Policy;
36import android.app.PendingIntent;
37import android.app.StatusBarManager;
38import android.app.backup.BackupManager;
39import android.app.usage.UsageEvents;
40import android.app.usage.UsageStatsManagerInternal;
41import android.content.BroadcastReceiver;
42import android.content.ComponentName;
43import android.content.ContentResolver;
44import android.content.Context;
45import android.content.Intent;
46import android.content.IntentFilter;
47import android.content.pm.ApplicationInfo;
48import android.content.pm.IPackageManager;
49import android.content.pm.PackageInfo;
50import android.content.pm.PackageManager;
51import android.content.pm.PackageManager.NameNotFoundException;
52import android.content.pm.ParceledListSlice;
53import android.content.pm.UserInfo;
54import android.content.res.Resources;
55import android.database.ContentObserver;
56import android.media.AudioAttributes;
57import android.media.AudioManager;
58import android.media.AudioManagerInternal;
59import android.media.AudioSystem;
60import android.media.IRingtonePlayer;
61import android.net.Uri;
62import android.os.Binder;
63import android.os.Build;
64import android.os.Bundle;
65import android.os.Environment;
66import android.os.Handler;
67import android.os.HandlerThread;
68import android.os.IBinder;
69import android.os.IInterface;
70import android.os.Looper;
71import android.os.Message;
72import android.os.Process;
73import android.os.RemoteException;
74import android.os.SystemProperties;
75import android.os.UserHandle;
76import android.os.UserManager;
77import android.os.Vibrator;
78import android.provider.Settings;
79import android.service.notification.Condition;
80import android.service.notification.IConditionListener;
81import android.service.notification.IConditionProvider;
82import android.service.notification.INotificationListener;
83import android.service.notification.IStatusBarNotificationHolder;
84import android.service.notification.NotificationListenerService;
85import android.service.notification.NotificationRankingUpdate;
86import android.service.notification.StatusBarNotification;
87import android.service.notification.ZenModeConfig;
88import android.telephony.PhoneStateListener;
89import android.telephony.TelephonyManager;
90import android.text.TextUtils;
91import android.util.ArrayMap;
92import android.util.ArraySet;
93import android.util.AtomicFile;
94import android.util.Log;
95import android.util.Slog;
96import android.util.Xml;
97import android.view.accessibility.AccessibilityEvent;
98import android.view.accessibility.AccessibilityManager;
99import android.widget.Toast;
100
101import com.android.internal.R;
102import com.android.internal.statusbar.NotificationVisibility;
103import com.android.internal.util.FastXmlSerializer;
104import com.android.server.EventLogTags;
105import com.android.server.LocalServices;
106import com.android.server.SystemService;
107import com.android.server.lights.Light;
108import com.android.server.lights.LightsManager;
109import com.android.server.notification.ManagedServices.ManagedServiceInfo;
110import com.android.server.notification.ManagedServices.UserProfiles;
111import com.android.server.statusbar.StatusBarManagerInternal;
112
113import libcore.io.IoUtils;
114
115import org.json.JSONArray;
116import org.json.JSONException;
117import org.json.JSONObject;
118import org.xmlpull.v1.XmlPullParser;
119import org.xmlpull.v1.XmlPullParserException;
120import org.xmlpull.v1.XmlSerializer;
121
122import java.io.ByteArrayInputStream;
123import java.io.ByteArrayOutputStream;
124import java.io.File;
125import java.io.FileDescriptor;
126import java.io.FileInputStream;
127import java.io.FileNotFoundException;
128import java.io.FileOutputStream;
129import java.io.IOException;
130import java.io.InputStream;
131import java.io.OutputStream;
132import java.io.PrintWriter;
133import java.nio.charset.StandardCharsets;
134import java.util.ArrayDeque;
135import java.util.ArrayList;
136import java.util.HashSet;
137import java.util.Iterator;
138import java.util.List;
139import java.util.Map.Entry;
140import java.util.Objects;
141
142/** {@hide} */
143public class NotificationManagerService extends SystemService {
144    static final String TAG = "NotificationService";
145    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
146    public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
147            && SystemProperties.getBoolean("debug.child_notifs", false);
148
149    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
150
151    // message codes
152    static final int MESSAGE_TIMEOUT = 2;
153    static final int MESSAGE_SAVE_POLICY_FILE = 3;
154    static final int MESSAGE_RECONSIDER_RANKING = 4;
155    static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
156    static final int MESSAGE_SEND_RANKING_UPDATE = 6;
157    static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
158    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
159
160    static final int LONG_DELAY = 3500; // 3.5 seconds
161    static final int SHORT_DELAY = 2000; // 2 seconds
162
163    static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
164
165    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
166
167    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
168    static final boolean SCORE_ONGOING_HIGHER = false;
169
170    static final int JUNK_SCORE = -1000;
171    static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
172    static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
173
174    // Notifications with scores below this will not interrupt the user, either via LED or
175    // sound or vibration
176    static final int SCORE_INTERRUPTION_THRESHOLD =
177            Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
178
179    static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
180    static final boolean ENABLE_BLOCKED_TOASTS = true;
181
182    // When #matchesCallFilter is called from the ringer, wait at most
183    // 3s to resolve the contacts. This timeout is required since
184    // ContactsProvider might take a long time to start up.
185    //
186    // Return STARRED_CONTACT when the timeout is hit in order to avoid
187    // missed calls in ZEN mode "Important".
188    static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
189    static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
190            ValidateNotificationPeople.STARRED_CONTACT;
191
192    /** notification_enqueue status value for a newly enqueued notification. */
193    private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
194
195    /** notification_enqueue status value for an existing notification. */
196    private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
197
198    /** notification_enqueue status value for an ignored notification. */
199    private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
200
201    private IActivityManager mAm;
202    AudioManager mAudioManager;
203    AudioManagerInternal mAudioManagerInternal;
204    StatusBarManagerInternal mStatusBar;
205    Vibrator mVibrator;
206
207    final IBinder mForegroundToken = new Binder();
208    private WorkerHandler mHandler;
209    private final HandlerThread mRankingThread = new HandlerThread("ranker",
210            Process.THREAD_PRIORITY_BACKGROUND);
211
212    private Light mNotificationLight;
213    Light mAttentionLight;
214    private int mDefaultNotificationColor;
215    private int mDefaultNotificationLedOn;
216
217    private int mDefaultNotificationLedOff;
218    private long[] mDefaultVibrationPattern;
219
220    private long[] mFallbackVibrationPattern;
221    private boolean mUseAttentionLight;
222    boolean mSystemReady;
223
224    private boolean mDisableNotificationEffects;
225    private int mCallState;
226    private String mSoundNotificationKey;
227    private String mVibrateNotificationKey;
228
229    private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
230    private ComponentName mEffectsSuppressor;
231    private int mListenerHints;  // right now, all hints are global
232    private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
233
234    // for enabling and disabling notification pulse behavior
235    private boolean mScreenOn = true;
236    private boolean mInCall = false;
237    private boolean mNotificationPulseEnabled;
238
239    // used as a mutex for access to all active notifications & listeners
240    final ArrayList<NotificationRecord> mNotificationList =
241            new ArrayList<NotificationRecord>();
242    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
243            new ArrayMap<String, NotificationRecord>();
244    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
245    final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
246    final PolicyAccess mPolicyAccess = new PolicyAccess();
247
248    // The last key in this list owns the hardware.
249    ArrayList<String> mLights = new ArrayList<>();
250
251    private AppOpsManager mAppOps;
252    private UsageStatsManagerInternal mAppUsageStats;
253
254    private Archive mArchive;
255
256    // Persistent storage for notification policy
257    private AtomicFile mPolicyFile;
258
259    // Temporary holder for <blocked-packages> config coming from old policy files.
260    private HashSet<String> mBlockedPackages = new HashSet<String>();
261
262    private static final int DB_VERSION = 1;
263
264    private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
265    private static final String ATTR_VERSION = "version";
266
267    // Obsolete:  converted if present, but not resaved to disk.
268    private static final String TAG_BLOCKED_PKGS = "blocked-packages";
269    private static final String TAG_PACKAGE = "package";
270    private static final String ATTR_NAME = "name";
271
272    private RankingHelper mRankingHelper;
273
274    private final UserProfiles mUserProfiles = new UserProfiles();
275    private NotificationListeners mListeners;
276    private ConditionProviders mConditionProviders;
277    private NotificationUsageStats mUsageStats;
278
279    private static final int MY_UID = Process.myUid();
280    private static final int MY_PID = Process.myPid();
281    private static final int REASON_DELEGATE_CLICK = 1;
282    private static final int REASON_DELEGATE_CANCEL = 2;
283    private static final int REASON_DELEGATE_CANCEL_ALL = 3;
284    private static final int REASON_DELEGATE_ERROR = 4;
285    private static final int REASON_PACKAGE_CHANGED = 5;
286    private static final int REASON_USER_STOPPED = 6;
287    private static final int REASON_PACKAGE_BANNED = 7;
288    private static final int REASON_NOMAN_CANCEL = 8;
289    private static final int REASON_NOMAN_CANCEL_ALL = 9;
290    private static final int REASON_LISTENER_CANCEL = 10;
291    private static final int REASON_LISTENER_CANCEL_ALL = 11;
292    private static final int REASON_GROUP_SUMMARY_CANCELED = 12;
293    private static final int REASON_GROUP_OPTIMIZATION = 13;
294
295    private static class Archive {
296        final int mBufferSize;
297        final ArrayDeque<StatusBarNotification> mBuffer;
298
299        public Archive(int size) {
300            mBufferSize = size;
301            mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
302        }
303
304        public String toString() {
305            final StringBuilder sb = new StringBuilder();
306            final int N = mBuffer.size();
307            sb.append("Archive (");
308            sb.append(N);
309            sb.append(" notification");
310            sb.append((N==1)?")":"s)");
311            return sb.toString();
312        }
313
314        public void record(StatusBarNotification nr) {
315            if (mBuffer.size() == mBufferSize) {
316                mBuffer.removeFirst();
317            }
318
319            // We don't want to store the heavy bits of the notification in the archive,
320            // but other clients in the system process might be using the object, so we
321            // store a (lightened) copy.
322            mBuffer.addLast(nr.cloneLight());
323        }
324
325        public Iterator<StatusBarNotification> descendingIterator() {
326            return mBuffer.descendingIterator();
327        }
328
329        public StatusBarNotification[] getArray(int count) {
330            if (count == 0) count = mBufferSize;
331            final StatusBarNotification[] a
332                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
333            Iterator<StatusBarNotification> iter = descendingIterator();
334            int i=0;
335            while (iter.hasNext() && i < count) {
336                a[i++] = iter.next();
337            }
338            return a;
339        }
340
341    }
342
343    private void readPolicyXml(InputStream stream, boolean forRestore)
344            throws XmlPullParserException, NumberFormatException, IOException {
345        final XmlPullParser parser = Xml.newPullParser();
346        parser.setInput(stream, StandardCharsets.UTF_8.name());
347
348        int type;
349        String tag;
350        int version = DB_VERSION;
351        while ((type = parser.next()) != END_DOCUMENT) {
352            tag = parser.getName();
353            if (type == START_TAG) {
354                if (TAG_NOTIFICATION_POLICY.equals(tag)) {
355                    version = Integer.parseInt(
356                            parser.getAttributeValue(null, ATTR_VERSION));
357                } else if (TAG_BLOCKED_PKGS.equals(tag)) {
358                    while ((type = parser.next()) != END_DOCUMENT) {
359                        tag = parser.getName();
360                        if (TAG_PACKAGE.equals(tag)) {
361                            mBlockedPackages.add(
362                                    parser.getAttributeValue(null, ATTR_NAME));
363                        } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
364                            break;
365                        }
366                    }
367                }
368            }
369            mZenModeHelper.readXml(parser, forRestore);
370            mRankingHelper.readXml(parser, forRestore);
371        }
372    }
373
374    private void loadPolicyFile() {
375        if (DBG) Slog.d(TAG, "loadPolicyFile");
376        synchronized(mPolicyFile) {
377            mBlockedPackages.clear();
378
379            FileInputStream infile = null;
380            try {
381                infile = mPolicyFile.openRead();
382                readPolicyXml(infile, false /*forRestore*/);
383            } catch (FileNotFoundException e) {
384                // No data yet
385            } catch (IOException e) {
386                Log.wtf(TAG, "Unable to read notification policy", e);
387            } catch (NumberFormatException e) {
388                Log.wtf(TAG, "Unable to parse notification policy", e);
389            } catch (XmlPullParserException e) {
390                Log.wtf(TAG, "Unable to parse notification policy", e);
391            } finally {
392                IoUtils.closeQuietly(infile);
393            }
394        }
395    }
396
397    public void savePolicyFile() {
398        mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
399        mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
400    }
401
402    private void handleSavePolicyFile() {
403        if (DBG) Slog.d(TAG, "handleSavePolicyFile");
404        synchronized (mPolicyFile) {
405            final FileOutputStream stream;
406            try {
407                stream = mPolicyFile.startWrite();
408            } catch (IOException e) {
409                Slog.w(TAG, "Failed to save policy file", e);
410                return;
411            }
412
413            try {
414                writePolicyXml(stream, false /*forBackup*/);
415                mPolicyFile.finishWrite(stream);
416            } catch (IOException e) {
417                Slog.w(TAG, "Failed to save policy file, restoring backup", e);
418                mPolicyFile.failWrite(stream);
419            }
420        }
421        BackupManager.dataChanged(getContext().getPackageName());
422    }
423
424    private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
425        final XmlSerializer out = new FastXmlSerializer();
426        out.setOutput(stream, StandardCharsets.UTF_8.name());
427        out.startDocument(null, true);
428        out.startTag(null, TAG_NOTIFICATION_POLICY);
429        out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
430        mZenModeHelper.writeXml(out, forBackup);
431        mRankingHelper.writeXml(out, forBackup);
432        out.endTag(null, TAG_NOTIFICATION_POLICY);
433        out.endDocument();
434    }
435
436    /** Use this when you actually want to post a notification or toast.
437     *
438     * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
439     */
440    private boolean noteNotificationOp(String pkg, int uid) {
441        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
442                != AppOpsManager.MODE_ALLOWED) {
443            Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
444            return false;
445        }
446        return true;
447    }
448
449    /** Use this to check if a package can post a notification or toast. */
450    private boolean checkNotificationOp(String pkg, int uid) {
451        return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
452                == AppOpsManager.MODE_ALLOWED;
453    }
454
455    private static final class ToastRecord
456    {
457        final int pid;
458        final String pkg;
459        final ITransientNotification callback;
460        int duration;
461
462        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
463        {
464            this.pid = pid;
465            this.pkg = pkg;
466            this.callback = callback;
467            this.duration = duration;
468        }
469
470        void update(int duration) {
471            this.duration = duration;
472        }
473
474        void dump(PrintWriter pw, String prefix, DumpFilter filter) {
475            if (filter != null && !filter.matches(pkg)) return;
476            pw.println(prefix + this);
477        }
478
479        @Override
480        public final String toString()
481        {
482            return "ToastRecord{"
483                + Integer.toHexString(System.identityHashCode(this))
484                + " pkg=" + pkg
485                + " callback=" + callback
486                + " duration=" + duration;
487        }
488    }
489
490    private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
491
492        @Override
493        public void onSetDisabled(int status) {
494            synchronized (mNotificationList) {
495                mDisableNotificationEffects =
496                        (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
497                if (disableNotificationEffects(null) != null) {
498                    // cancel whatever's going on
499                    long identity = Binder.clearCallingIdentity();
500                    try {
501                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
502                        if (player != null) {
503                            player.stopAsync();
504                        }
505                    } catch (RemoteException e) {
506                    } finally {
507                        Binder.restoreCallingIdentity(identity);
508                    }
509
510                    identity = Binder.clearCallingIdentity();
511                    try {
512                        mVibrator.cancel();
513                    } finally {
514                        Binder.restoreCallingIdentity(identity);
515                    }
516                }
517            }
518        }
519
520        @Override
521        public void onClearAll(int callingUid, int callingPid, int userId) {
522            synchronized (mNotificationList) {
523                cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
524                        /*includeCurrentProfiles*/ true);
525            }
526        }
527
528        @Override
529        public void onNotificationClick(int callingUid, int callingPid, String key) {
530            synchronized (mNotificationList) {
531                NotificationRecord r = mNotificationsByKey.get(key);
532                if (r == null) {
533                    Log.w(TAG, "No notification with key: " + key);
534                    return;
535                }
536                final long now = System.currentTimeMillis();
537                EventLogTags.writeNotificationClicked(key,
538                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
539
540                StatusBarNotification sbn = r.sbn;
541                cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
542                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
543                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
544                        REASON_DELEGATE_CLICK, null);
545            }
546        }
547
548        @Override
549        public void onNotificationActionClick(int callingUid, int callingPid, String key,
550                int actionIndex) {
551            synchronized (mNotificationList) {
552                NotificationRecord r = mNotificationsByKey.get(key);
553                if (r == null) {
554                    Log.w(TAG, "No notification with key: " + key);
555                    return;
556                }
557                final long now = System.currentTimeMillis();
558                EventLogTags.writeNotificationActionClicked(key, actionIndex,
559                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
560                // TODO: Log action click via UsageStats.
561            }
562        }
563
564        @Override
565        public void onNotificationClear(int callingUid, int callingPid,
566                String pkg, String tag, int id, int userId) {
567            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
568                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
569                    true, userId, REASON_DELEGATE_CANCEL, null);
570        }
571
572        @Override
573        public void onPanelRevealed(boolean clearEffects, int items) {
574            EventLogTags.writeNotificationPanelRevealed(items);
575            if (clearEffects) {
576                clearEffects();
577            }
578        }
579
580        @Override
581        public void onPanelHidden() {
582            EventLogTags.writeNotificationPanelHidden();
583        }
584
585        @Override
586        public void clearEffects() {
587            synchronized (mNotificationList) {
588                if (DBG) Slog.d(TAG, "clearEffects");
589
590                // sound
591                mSoundNotificationKey = null;
592
593                long identity = Binder.clearCallingIdentity();
594                try {
595                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
596                    if (player != null) {
597                        player.stopAsync();
598                    }
599                } catch (RemoteException e) {
600                } finally {
601                    Binder.restoreCallingIdentity(identity);
602                }
603
604                // vibrate
605                mVibrateNotificationKey = null;
606                identity = Binder.clearCallingIdentity();
607                try {
608                    mVibrator.cancel();
609                } finally {
610                    Binder.restoreCallingIdentity(identity);
611                }
612
613                // light
614                mLights.clear();
615                updateLightsLocked();
616            }
617        }
618
619        @Override
620        public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
621                int uid, int initialPid, String message, int userId) {
622            Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
623                    + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
624            cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
625                    REASON_DELEGATE_ERROR, null);
626            long ident = Binder.clearCallingIdentity();
627            try {
628                ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
629                        "Bad notification posted from package " + pkg
630                        + ": " + message);
631            } catch (RemoteException e) {
632            }
633            Binder.restoreCallingIdentity(ident);
634        }
635
636        @Override
637        public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
638                NotificationVisibility[] noLongerVisibleKeys) {
639            synchronized (mNotificationList) {
640                for (NotificationVisibility nv : newlyVisibleKeys) {
641                    NotificationRecord r = mNotificationsByKey.get(nv.key);
642                    if (r == null) continue;
643                    r.setVisibility(true, nv.rank);
644                    nv.recycle();
645                }
646                // Note that we might receive this event after notifications
647                // have already left the system, e.g. after dismissing from the
648                // shade. Hence not finding notifications in
649                // mNotificationsByKey is not an exceptional condition.
650                for (NotificationVisibility nv : noLongerVisibleKeys) {
651                    NotificationRecord r = mNotificationsByKey.get(nv.key);
652                    if (r == null) continue;
653                    r.setVisibility(false, nv.rank);
654                    nv.recycle();
655                }
656            }
657        }
658
659        @Override
660        public void onNotificationExpansionChanged(String key,
661                boolean userAction, boolean expanded) {
662            synchronized (mNotificationList) {
663                NotificationRecord r = mNotificationsByKey.get(key);
664                if (r != null) {
665                    r.stats.onExpansionChanged(userAction, expanded);
666                    final long now = System.currentTimeMillis();
667                    EventLogTags.writeNotificationExpansion(key,
668                            userAction ? 1 : 0, expanded ? 1 : 0,
669                            r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
670                }
671            }
672        }
673    };
674
675    private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
676        @Override
677        public void onReceive(Context context, Intent intent) {
678            String action = intent.getAction();
679            if (action == null) {
680                return;
681            }
682
683            boolean queryRestart = false;
684            boolean queryRemove = false;
685            boolean packageChanged = false;
686            boolean cancelNotifications = true;
687
688            if (action.equals(Intent.ACTION_PACKAGE_ADDED)
689                    || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
690                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
691                    || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
692                    || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
693                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
694                int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
695                        UserHandle.USER_ALL);
696                String pkgList[] = null;
697                boolean queryReplace = queryRemove &&
698                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
699                if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
700                if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
701                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
702                } else if (queryRestart) {
703                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
704                } else {
705                    Uri uri = intent.getData();
706                    if (uri == null) {
707                        return;
708                    }
709                    String pkgName = uri.getSchemeSpecificPart();
710                    if (pkgName == null) {
711                        return;
712                    }
713                    if (packageChanged) {
714                        // We cancel notifications for packages which have just been disabled
715                        try {
716                            final IPackageManager pm = AppGlobals.getPackageManager();
717                            final int enabled = pm.getApplicationEnabledSetting(pkgName,
718                                    changeUserId != UserHandle.USER_ALL ? changeUserId :
719                                    UserHandle.USER_OWNER);
720                            if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
721                                    || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
722                                cancelNotifications = false;
723                            }
724                        } catch (IllegalArgumentException e) {
725                            // Package doesn't exist; probably racing with uninstall.
726                            // cancelNotifications is already true, so nothing to do here.
727                            if (DBG) {
728                                Slog.i(TAG, "Exception trying to look up app enabled setting", e);
729                            }
730                        } catch (RemoteException e) {
731                            // Failed to talk to PackageManagerService Should never happen!
732                        }
733                    }
734                    pkgList = new String[]{pkgName};
735                }
736
737                if (pkgList != null && (pkgList.length > 0)) {
738                    for (String pkgName : pkgList) {
739                        if (cancelNotifications) {
740                            cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
741                                    changeUserId, REASON_PACKAGE_CHANGED, null);
742                        }
743                    }
744                }
745                mListeners.onPackagesChanged(queryReplace, pkgList);
746                mConditionProviders.onPackagesChanged(queryReplace, pkgList);
747                mRankingHelper.onPackagesChanged(queryReplace, pkgList);
748            }
749        }
750    };
751
752    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
753        @Override
754        public void onReceive(Context context, Intent intent) {
755            String action = intent.getAction();
756
757            if (action.equals(Intent.ACTION_SCREEN_ON)) {
758                // Keep track of screen on/off state, but do not turn off the notification light
759                // until user passes through the lock screen or views the notification.
760                mScreenOn = true;
761                updateNotificationPulse();
762            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
763                mScreenOn = false;
764                updateNotificationPulse();
765            } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
766                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
767                        .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
768                updateNotificationPulse();
769            } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
770                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
771                if (userHandle >= 0) {
772                    cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
773                            REASON_USER_STOPPED, null);
774                }
775            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
776                // turn off LED when user passes through lock screen
777                mNotificationLight.turnOff();
778                mStatusBar.notificationLightOff();
779            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
780                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
781                // reload per-user settings
782                mSettingsObserver.update(null);
783                mUserProfiles.updateCache(context);
784                // Refresh managed services
785                mConditionProviders.onUserSwitched(user);
786                mListeners.onUserSwitched(user);
787                mZenModeHelper.onUserSwitched(user);
788            } else if (action.equals(Intent.ACTION_USER_ADDED)) {
789                mUserProfiles.updateCache(context);
790            } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
791                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
792                mZenModeHelper.onUserRemoved(user);
793            }
794        }
795    };
796
797    private final class SettingsObserver extends ContentObserver {
798        private final Uri NOTIFICATION_LIGHT_PULSE_URI
799                = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
800
801        SettingsObserver(Handler handler) {
802            super(handler);
803        }
804
805        void observe() {
806            ContentResolver resolver = getContext().getContentResolver();
807            resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
808                    false, this, UserHandle.USER_ALL);
809            update(null);
810        }
811
812        @Override public void onChange(boolean selfChange, Uri uri) {
813            update(uri);
814        }
815
816        public void update(Uri uri) {
817            ContentResolver resolver = getContext().getContentResolver();
818            if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
819                boolean pulseEnabled = Settings.System.getInt(resolver,
820                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
821                if (mNotificationPulseEnabled != pulseEnabled) {
822                    mNotificationPulseEnabled = pulseEnabled;
823                    updateNotificationPulse();
824                }
825            }
826        }
827    }
828
829    private SettingsObserver mSettingsObserver;
830    private ZenModeHelper mZenModeHelper;
831
832    private final Runnable mBuzzBeepBlinked = new Runnable() {
833        @Override
834        public void run() {
835            mStatusBar.buzzBeepBlinked();
836        }
837    };
838
839    static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
840        int[] ar = r.getIntArray(resid);
841        if (ar == null) {
842            return def;
843        }
844        final int len = ar.length > maxlen ? maxlen : ar.length;
845        long[] out = new long[len];
846        for (int i=0; i<len; i++) {
847            out[i] = ar[i];
848        }
849        return out;
850    }
851
852    public NotificationManagerService(Context context) {
853        super(context);
854    }
855
856    @Override
857    public void onStart() {
858        Resources resources = getContext().getResources();
859
860        mAm = ActivityManagerNative.getDefault();
861        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
862        mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
863        mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
864
865        mHandler = new WorkerHandler();
866        mRankingThread.start();
867        String[] extractorNames;
868        try {
869            extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
870        } catch (Resources.NotFoundException e) {
871            extractorNames = new String[0];
872        }
873        mUsageStats = new NotificationUsageStats(getContext());
874        mRankingHelper = new RankingHelper(getContext(),
875                new RankingWorkerHandler(mRankingThread.getLooper()),
876                mUsageStats,
877                extractorNames);
878        mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
879        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
880        mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
881            @Override
882            public void onConfigChanged() {
883                savePolicyFile();
884            }
885
886            @Override
887            void onZenModeChanged() {
888                sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
889                synchronized(mNotificationList) {
890                    updateInterruptionFilterLocked();
891                }
892            }
893
894            @Override
895            void onPolicyChanged() {
896                sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
897            }
898        });
899        final File systemDir = new File(Environment.getDataDirectory(), "system");
900        mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
901
902        importOldBlockDb();
903
904        mListeners = new NotificationListeners();
905        mStatusBar = getLocalService(StatusBarManagerInternal.class);
906        mStatusBar.setNotificationDelegate(mNotificationDelegate);
907
908        final LightsManager lights = getLocalService(LightsManager.class);
909        mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
910        mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
911
912        mDefaultNotificationColor = resources.getColor(
913                R.color.config_defaultNotificationColor);
914        mDefaultNotificationLedOn = resources.getInteger(
915                R.integer.config_defaultNotificationLedOn);
916        mDefaultNotificationLedOff = resources.getInteger(
917                R.integer.config_defaultNotificationLedOff);
918
919        mDefaultVibrationPattern = getLongArray(resources,
920                R.array.config_defaultNotificationVibePattern,
921                VIBRATE_PATTERN_MAXLEN,
922                DEFAULT_VIBRATE_PATTERN);
923
924        mFallbackVibrationPattern = getLongArray(resources,
925                R.array.config_notificationFallbackVibePattern,
926                VIBRATE_PATTERN_MAXLEN,
927                DEFAULT_VIBRATE_PATTERN);
928
929        mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
930
931        // Don't start allowing notifications until the setup wizard has run once.
932        // After that, including subsequent boots, init with notifications turned on.
933        // This works on the first boot because the setup wizard will toggle this
934        // flag at least once and we'll go back to 0 after that.
935        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
936                    Settings.Global.DEVICE_PROVISIONED, 0)) {
937            mDisableNotificationEffects = true;
938        }
939        mZenModeHelper.initZenMode();
940        mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
941
942        mUserProfiles.updateCache(getContext());
943        listenForCallState();
944
945        // register for various Intents
946        IntentFilter filter = new IntentFilter();
947        filter.addAction(Intent.ACTION_SCREEN_ON);
948        filter.addAction(Intent.ACTION_SCREEN_OFF);
949        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
950        filter.addAction(Intent.ACTION_USER_PRESENT);
951        filter.addAction(Intent.ACTION_USER_STOPPED);
952        filter.addAction(Intent.ACTION_USER_SWITCHED);
953        filter.addAction(Intent.ACTION_USER_ADDED);
954        filter.addAction(Intent.ACTION_USER_REMOVED);
955        getContext().registerReceiver(mIntentReceiver, filter);
956
957        IntentFilter pkgFilter = new IntentFilter();
958        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
959        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
960        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
961        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
962        pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
963        pkgFilter.addDataScheme("package");
964        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
965                null);
966
967        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
968        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
969                null);
970
971        mSettingsObserver = new SettingsObserver(mHandler);
972
973        mArchive = new Archive(resources.getInteger(
974                R.integer.config_notificationServiceArchiveSize));
975
976        publishBinderService(Context.NOTIFICATION_SERVICE, mService);
977        publishLocalService(NotificationManagerInternal.class, mInternalService);
978    }
979
980    private void sendRegisteredOnlyBroadcast(String action) {
981        getContext().sendBroadcastAsUser(new Intent(action)
982                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
983    }
984
985    /**
986     * Read the old XML-based app block database and import those blockages into the AppOps system.
987     */
988    private void importOldBlockDb() {
989        loadPolicyFile();
990
991        PackageManager pm = getContext().getPackageManager();
992        for (String pkg : mBlockedPackages) {
993            PackageInfo info = null;
994            try {
995                info = pm.getPackageInfo(pkg, 0);
996                setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
997            } catch (NameNotFoundException e) {
998                // forget you
999            }
1000        }
1001        mBlockedPackages.clear();
1002    }
1003
1004    @Override
1005    public void onBootPhase(int phase) {
1006        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1007            // no beeping until we're basically done booting
1008            mSystemReady = true;
1009
1010            // Grab our optional AudioService
1011            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1012            mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1013            mZenModeHelper.onSystemReady();
1014        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1015            // This observer will force an update when observe is called, causing us to
1016            // bind to listener services.
1017            mSettingsObserver.observe();
1018            mListeners.onBootPhaseAppsCanStart();
1019            mConditionProviders.onBootPhaseAppsCanStart();
1020        }
1021    }
1022
1023    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1024        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1025
1026        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1027                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1028
1029        // Now, cancel any outstanding notifications that are part of a just-disabled app
1030        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1031            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1032                    REASON_PACKAGE_BANNED, null);
1033        }
1034    }
1035
1036    private void updateListenerHintsLocked() {
1037        final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
1038        if (hints == mListenerHints) return;
1039        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
1040        mListenerHints = hints;
1041        scheduleListenerHintsChanged(hints);
1042    }
1043
1044    private void updateEffectsSuppressorLocked() {
1045        final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
1046                ? mListenersDisablingEffects.valueAt(0).component : null;
1047        if (Objects.equals(suppressor, mEffectsSuppressor)) return;
1048        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
1049        mEffectsSuppressor = suppressor;
1050        mZenModeHelper.setEffectsSuppressed(suppressor != null);
1051        sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1052    }
1053
1054    private void updateInterruptionFilterLocked() {
1055        int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1056        if (interruptionFilter == mInterruptionFilter) return;
1057        mInterruptionFilter = interruptionFilter;
1058        scheduleInterruptionFilterChanged(interruptionFilter);
1059    }
1060
1061    private final IBinder mService = new INotificationManager.Stub() {
1062        // Toasts
1063        // ============================================================================
1064
1065        @Override
1066        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1067        {
1068            if (DBG) {
1069                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1070                        + " duration=" + duration);
1071            }
1072
1073            if (pkg == null || callback == null) {
1074                Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1075                return ;
1076            }
1077
1078            final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1079
1080            if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
1081                if (!isSystemToast) {
1082                    Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
1083                    return;
1084                }
1085            }
1086
1087            synchronized (mToastQueue) {
1088                int callingPid = Binder.getCallingPid();
1089                long callingId = Binder.clearCallingIdentity();
1090                try {
1091                    ToastRecord record;
1092                    int index = indexOfToastLocked(pkg, callback);
1093                    // If it's already in the queue, we update it in place, we don't
1094                    // move it to the end of the queue.
1095                    if (index >= 0) {
1096                        record = mToastQueue.get(index);
1097                        record.update(duration);
1098                    } else {
1099                        // Limit the number of toasts that any given package except the android
1100                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
1101                        if (!isSystemToast) {
1102                            int count = 0;
1103                            final int N = mToastQueue.size();
1104                            for (int i=0; i<N; i++) {
1105                                 final ToastRecord r = mToastQueue.get(i);
1106                                 if (r.pkg.equals(pkg)) {
1107                                     count++;
1108                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1109                                         Slog.e(TAG, "Package has already posted " + count
1110                                                + " toasts. Not showing more. Package=" + pkg);
1111                                         return;
1112                                     }
1113                                 }
1114                            }
1115                        }
1116
1117                        record = new ToastRecord(callingPid, pkg, callback, duration);
1118                        mToastQueue.add(record);
1119                        index = mToastQueue.size() - 1;
1120                        keepProcessAliveLocked(callingPid);
1121                    }
1122                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
1123                    // new or just been updated.  Call back and tell it to show itself.
1124                    // If the callback fails, this will remove it from the list, so don't
1125                    // assume that it's valid after this.
1126                    if (index == 0) {
1127                        showNextToastLocked();
1128                    }
1129                } finally {
1130                    Binder.restoreCallingIdentity(callingId);
1131                }
1132            }
1133        }
1134
1135        @Override
1136        public void cancelToast(String pkg, ITransientNotification callback) {
1137            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1138
1139            if (pkg == null || callback == null) {
1140                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1141                return ;
1142            }
1143
1144            synchronized (mToastQueue) {
1145                long callingId = Binder.clearCallingIdentity();
1146                try {
1147                    int index = indexOfToastLocked(pkg, callback);
1148                    if (index >= 0) {
1149                        cancelToastLocked(index);
1150                    } else {
1151                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1152                                + " callback=" + callback);
1153                    }
1154                } finally {
1155                    Binder.restoreCallingIdentity(callingId);
1156                }
1157            }
1158        }
1159
1160        @Override
1161        public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1162                Notification notification, int[] idOut, int userId) throws RemoteException {
1163            enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1164                    Binder.getCallingPid(), tag, id, notification, idOut, userId);
1165        }
1166
1167        @Override
1168        public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1169            checkCallerIsSystemOrSameApp(pkg);
1170            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1171                    Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1172            // Don't allow client applications to cancel foreground service notis.
1173            cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1174                    Binder.getCallingUid() == Process.SYSTEM_UID
1175                    ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL,
1176                    null);
1177        }
1178
1179        @Override
1180        public void cancelAllNotifications(String pkg, int userId) {
1181            checkCallerIsSystemOrSameApp(pkg);
1182
1183            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1184                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1185
1186            // Calling from user space, don't allow the canceling of actively
1187            // running foreground services.
1188            cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1189                    pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1190                    REASON_NOMAN_CANCEL_ALL, null);
1191        }
1192
1193        @Override
1194        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1195            checkCallerIsSystem();
1196
1197            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1198        }
1199
1200        /**
1201         * Use this when you just want to know if notifications are OK for this package.
1202         */
1203        @Override
1204        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1205            checkCallerIsSystem();
1206            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1207                    == AppOpsManager.MODE_ALLOWED);
1208        }
1209
1210        @Override
1211        public void setPackagePriority(String pkg, int uid, int priority) {
1212            checkCallerIsSystem();
1213            mRankingHelper.setPackagePriority(pkg, uid, priority);
1214            savePolicyFile();
1215        }
1216
1217        @Override
1218        public int getPackagePriority(String pkg, int uid) {
1219            checkCallerIsSystem();
1220            return mRankingHelper.getPackagePriority(pkg, uid);
1221        }
1222
1223        @Override
1224        public void setPackagePeekable(String pkg, int uid, boolean peekable) {
1225            checkCallerIsSystem();
1226
1227            mRankingHelper.setPackagePeekable(pkg, uid, peekable);
1228        }
1229
1230        @Override
1231        public boolean getPackagePeekable(String pkg, int uid) {
1232            checkCallerIsSystem();
1233            return mRankingHelper.getPackagePeekable(pkg, uid);
1234        }
1235
1236        @Override
1237        public void setPackageVisibilityOverride(String pkg, int uid, int visibility) {
1238            checkCallerIsSystem();
1239            mRankingHelper.setPackageVisibilityOverride(pkg, uid, visibility);
1240            savePolicyFile();
1241        }
1242
1243        @Override
1244        public int getPackageVisibilityOverride(String pkg, int uid) {
1245            checkCallerIsSystem();
1246            return mRankingHelper.getPackageVisibilityOverride(pkg, uid);
1247        }
1248
1249        /**
1250         * System-only API for getting a list of current (i.e. not cleared) notifications.
1251         *
1252         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1253         * @returns A list of all the notifications, in natural order.
1254         */
1255        @Override
1256        public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1257            // enforce() will ensure the calling uid has the correct permission
1258            getContext().enforceCallingOrSelfPermission(
1259                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1260                    "NotificationManagerService.getActiveNotifications");
1261
1262            StatusBarNotification[] tmp = null;
1263            int uid = Binder.getCallingUid();
1264
1265            // noteOp will check to make sure the callingPkg matches the uid
1266            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1267                    == AppOpsManager.MODE_ALLOWED) {
1268                synchronized (mNotificationList) {
1269                    tmp = new StatusBarNotification[mNotificationList.size()];
1270                    final int N = mNotificationList.size();
1271                    for (int i=0; i<N; i++) {
1272                        tmp[i] = mNotificationList.get(i).sbn;
1273                    }
1274                }
1275            }
1276            return tmp;
1277        }
1278
1279        /**
1280         * Public API for getting a list of current notifications for the calling package/uid.
1281         *
1282         * @returns A list of all the package's notifications, in natural order.
1283         */
1284        @Override
1285        public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1286                int incomingUserId) {
1287            checkCallerIsSystemOrSameApp(pkg);
1288            int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1289                    Binder.getCallingUid(), incomingUserId, true, false,
1290                    "getAppActiveNotifications", pkg);
1291
1292            final int N = mNotificationList.size();
1293            final ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>(N);
1294
1295            synchronized (mNotificationList) {
1296                for (int i = 0; i < N; i++) {
1297                    final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1298                    if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
1299                        // We could pass back a cloneLight() but clients might get confused and
1300                        // try to send this thing back to notify() again, which would not work
1301                        // very well.
1302                        final StatusBarNotification sbnOut = new StatusBarNotification(
1303                                sbn.getPackageName(),
1304                                sbn.getOpPkg(),
1305                                sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1306                                0, // hide score from apps
1307                                sbn.getNotification().clone(),
1308                                sbn.getUser(), sbn.getPostTime());
1309                        list.add(sbnOut);
1310                    }
1311                }
1312            }
1313
1314            return new ParceledListSlice<StatusBarNotification>(list);
1315        }
1316
1317        /**
1318         * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1319         *
1320         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1321         */
1322        @Override
1323        public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1324            // enforce() will ensure the calling uid has the correct permission
1325            getContext().enforceCallingOrSelfPermission(
1326                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1327                    "NotificationManagerService.getHistoricalNotifications");
1328
1329            StatusBarNotification[] tmp = null;
1330            int uid = Binder.getCallingUid();
1331
1332            // noteOp will check to make sure the callingPkg matches the uid
1333            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1334                    == AppOpsManager.MODE_ALLOWED) {
1335                synchronized (mArchive) {
1336                    tmp = mArchive.getArray(count);
1337                }
1338            }
1339            return tmp;
1340        }
1341
1342        /**
1343         * Register a listener binder directly with the notification manager.
1344         *
1345         * Only works with system callers. Apps should extend
1346         * {@link android.service.notification.NotificationListenerService}.
1347         */
1348        @Override
1349        public void registerListener(final INotificationListener listener,
1350                final ComponentName component, final int userid) {
1351            enforceSystemOrSystemUI("INotificationManager.registerListener");
1352            mListeners.registerService(listener, component, userid);
1353        }
1354
1355        /**
1356         * Remove a listener binder directly
1357         */
1358        @Override
1359        public void unregisterListener(INotificationListener listener, int userid) {
1360            mListeners.unregisterService(listener, userid);
1361        }
1362
1363        /**
1364         * Allow an INotificationListener to simulate a "clear all" operation.
1365         *
1366         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1367         *
1368         * @param token The binder for the listener, to check that the caller is allowed
1369         */
1370        @Override
1371        public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1372            final int callingUid = Binder.getCallingUid();
1373            final int callingPid = Binder.getCallingPid();
1374            long identity = Binder.clearCallingIdentity();
1375            try {
1376                synchronized (mNotificationList) {
1377                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1378                    if (keys != null) {
1379                        final int N = keys.length;
1380                        for (int i = 0; i < N; i++) {
1381                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
1382                            if (r == null) continue;
1383                            final int userId = r.sbn.getUserId();
1384                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
1385                                    !mUserProfiles.isCurrentProfile(userId)) {
1386                                throw new SecurityException("Disallowed call from listener: "
1387                                        + info.service);
1388                            }
1389                            cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1390                                    r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1391                                    userId);
1392                        }
1393                    } else {
1394                        cancelAllLocked(callingUid, callingPid, info.userid,
1395                                REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1396                    }
1397                }
1398            } finally {
1399                Binder.restoreCallingIdentity(identity);
1400            }
1401        }
1402
1403        @Override
1404        public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1405            long identity = Binder.clearCallingIdentity();
1406            try {
1407                synchronized (mNotificationList) {
1408                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1409                    if (keys != null) {
1410                        final int N = keys.length;
1411                        for (int i = 0; i < N; i++) {
1412                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
1413                            if (r == null) continue;
1414                            final int userId = r.sbn.getUserId();
1415                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
1416                                    !mUserProfiles.isCurrentProfile(userId)) {
1417                                throw new SecurityException("Disallowed call from listener: "
1418                                        + info.service);
1419                            }
1420                            if (!r.isSeen()) {
1421                                if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1422                                mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1423                                        userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER
1424                                                : userId,
1425                                        UsageEvents.Event.USER_INTERACTION);
1426                                r.setSeen();
1427                            }
1428                        }
1429                    }
1430                }
1431            } finally {
1432                Binder.restoreCallingIdentity(identity);
1433            }
1434        }
1435
1436        private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1437                int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1438            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1439                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1440                    true,
1441                    userId, REASON_LISTENER_CANCEL, info);
1442        }
1443
1444        /**
1445         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1446         *
1447         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1448         *
1449         * @param token The binder for the listener, to check that the caller is allowed
1450         */
1451        @Override
1452        public void cancelNotificationFromListener(INotificationListener token, String pkg,
1453                String tag, int id) {
1454            final int callingUid = Binder.getCallingUid();
1455            final int callingPid = Binder.getCallingPid();
1456            long identity = Binder.clearCallingIdentity();
1457            try {
1458                synchronized (mNotificationList) {
1459                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1460                    if (info.supportsProfiles()) {
1461                        Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1462                                + "from " + info.component
1463                                + " use cancelNotification(key) instead.");
1464                    } else {
1465                        cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1466                                pkg, tag, id, info.userid);
1467                    }
1468                }
1469            } finally {
1470                Binder.restoreCallingIdentity(identity);
1471            }
1472        }
1473
1474        /**
1475         * Allow an INotificationListener to request the list of outstanding notifications seen by
1476         * the current user. Useful when starting up, after which point the listener callbacks
1477         * should be used.
1478         *
1479         * @param token The binder for the listener, to check that the caller is allowed
1480         * @param keys An array of notification keys to fetch, or null to fetch everything
1481         * @returns The return value will contain the notifications specified in keys, in that
1482         *      order, or if keys is null, all the notifications, in natural order.
1483         */
1484        @Override
1485        public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1486                INotificationListener token, String[] keys, int trim) {
1487            synchronized (mNotificationList) {
1488                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1489                final boolean getKeys = keys != null;
1490                final int N = getKeys ? keys.length : mNotificationList.size();
1491                final ArrayList<StatusBarNotification> list
1492                        = new ArrayList<StatusBarNotification>(N);
1493                for (int i=0; i<N; i++) {
1494                    final NotificationRecord r = getKeys
1495                            ? mNotificationsByKey.get(keys[i])
1496                            : mNotificationList.get(i);
1497                    if (r == null) continue;
1498                    StatusBarNotification sbn = r.sbn;
1499                    if (!isVisibleToListener(sbn, info)) continue;
1500                    StatusBarNotification sbnToSend =
1501                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1502                    list.add(sbnToSend);
1503                }
1504                return new ParceledListSlice<StatusBarNotification>(list);
1505            }
1506        }
1507
1508        @Override
1509        public void requestHintsFromListener(INotificationListener token, int hints) {
1510            final long identity = Binder.clearCallingIdentity();
1511            try {
1512                synchronized (mNotificationList) {
1513                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1514                    final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
1515                    if (disableEffects) {
1516                        mListenersDisablingEffects.add(info);
1517                    } else {
1518                        mListenersDisablingEffects.remove(info);
1519                    }
1520                    updateListenerHintsLocked();
1521                    updateEffectsSuppressorLocked();
1522                }
1523            } finally {
1524                Binder.restoreCallingIdentity(identity);
1525            }
1526        }
1527
1528        @Override
1529        public int getHintsFromListener(INotificationListener token) {
1530            synchronized (mNotificationList) {
1531                return mListenerHints;
1532            }
1533        }
1534
1535        @Override
1536        public void requestInterruptionFilterFromListener(INotificationListener token,
1537                int interruptionFilter) throws RemoteException {
1538            final long identity = Binder.clearCallingIdentity();
1539            try {
1540                synchronized (mNotificationList) {
1541                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1542                    mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1543                    updateInterruptionFilterLocked();
1544                }
1545            } finally {
1546                Binder.restoreCallingIdentity(identity);
1547            }
1548        }
1549
1550        @Override
1551        public int getInterruptionFilterFromListener(INotificationListener token)
1552                throws RemoteException {
1553            synchronized (mNotificationLight) {
1554                return mInterruptionFilter;
1555            }
1556        }
1557
1558        @Override
1559        public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1560                throws RemoteException {
1561            synchronized (mNotificationList) {
1562                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1563                if (info == null) return;
1564                mListeners.setOnNotificationPostedTrimLocked(info, trim);
1565            }
1566        }
1567
1568        @Override
1569        public int getZenMode() {
1570            return mZenModeHelper.getZenMode();
1571        }
1572
1573        @Override
1574        public ZenModeConfig getZenModeConfig() {
1575            enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1576            return mZenModeHelper.getConfig();
1577        }
1578
1579        @Override
1580        public boolean setZenModeConfig(ZenModeConfig config, String reason) {
1581            checkCallerIsSystem();
1582            return mZenModeHelper.setConfig(config, reason);
1583        }
1584
1585        @Override
1586        public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1587            enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1588            final long identity = Binder.clearCallingIdentity();
1589            try {
1590                mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1591            } finally {
1592                Binder.restoreCallingIdentity(identity);
1593            }
1594        }
1595
1596        @Override
1597        public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1598            enforcePolicyAccess(pkg, "setInterruptionFilter");
1599            final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1600            if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1601            final long identity = Binder.clearCallingIdentity();
1602            try {
1603                mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1604            } finally {
1605                Binder.restoreCallingIdentity(identity);
1606            }
1607        }
1608
1609        @Override
1610        public void notifyConditions(final String pkg, IConditionProvider provider,
1611                final Condition[] conditions) {
1612            final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1613            checkCallerIsSystemOrSameApp(pkg);
1614            mHandler.post(new Runnable() {
1615                @Override
1616                public void run() {
1617                    mConditionProviders.notifyConditions(pkg, info, conditions);
1618                }
1619            });
1620        }
1621
1622        @Override
1623        public void requestZenModeConditions(IConditionListener callback, int relevance) {
1624            enforceSystemOrSystemUIOrVolume("INotificationManager.requestZenModeConditions");
1625            mZenModeHelper.requestZenModeConditions(callback, relevance);
1626        }
1627
1628        private void enforceSystemOrSystemUIOrVolume(String message) {
1629            if (mAudioManagerInternal != null) {
1630                final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1631                if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1632                    return;
1633                }
1634            }
1635            enforceSystemOrSystemUI(message);
1636        }
1637
1638        private void enforceSystemOrSystemUI(String message) {
1639            if (isCallerSystem()) return;
1640            getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1641                    message);
1642        }
1643
1644        private void enforcePolicyAccess(String pkg, String method) {
1645            if (!checkPolicyAccess(pkg)) {
1646                Slog.w(TAG, "Notification policy access denied calling " + method);
1647                throw new SecurityException("Notification policy access denied");
1648            }
1649        }
1650
1651        private boolean checkPackagePolicyAccess(String pkg) {
1652            return mPolicyAccess.isPackageGranted(pkg);
1653        }
1654
1655        private boolean checkPolicyAccess(String pkg) {
1656            return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
1657        }
1658
1659        @Override
1660        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1661            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1662                    != PackageManager.PERMISSION_GRANTED) {
1663                pw.println("Permission Denial: can't dump NotificationManager from pid="
1664                        + Binder.getCallingPid()
1665                        + ", uid=" + Binder.getCallingUid());
1666                return;
1667            }
1668
1669            final DumpFilter filter = DumpFilter.parseFromArguments(args);
1670            if (filter != null && filter.stats) {
1671                dumpJson(pw, filter);
1672            } else {
1673                dumpImpl(pw, filter);
1674            }
1675        }
1676
1677        @Override
1678        public ComponentName getEffectsSuppressor() {
1679            enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
1680            return mEffectsSuppressor;
1681        }
1682
1683        @Override
1684        public boolean matchesCallFilter(Bundle extras) {
1685            enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
1686            return mZenModeHelper.matchesCallFilter(
1687                    UserHandle.getCallingUserHandle(),
1688                    extras,
1689                    mRankingHelper.findExtractor(ValidateNotificationPeople.class),
1690                    MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
1691                    MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
1692        }
1693
1694        @Override
1695        public boolean isSystemConditionProviderEnabled(String path) {
1696            enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
1697            return mConditionProviders.isSystemProviderEnabled(path);
1698        }
1699
1700        // Backup/restore interface
1701        @Override
1702        public byte[] getBackupPayload(int user) {
1703            if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
1704            if (user != UserHandle.USER_OWNER) {
1705                Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
1706                return null;
1707            }
1708            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1709            try {
1710                writePolicyXml(baos, true /*forBackup*/);
1711                return baos.toByteArray();
1712            } catch (IOException e) {
1713                Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
1714            }
1715            return null;
1716        }
1717
1718        @Override
1719        public void applyRestore(byte[] payload, int user) {
1720            if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
1721                    + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
1722            if (payload == null) {
1723                Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
1724                return;
1725            }
1726            if (user != UserHandle.USER_OWNER) {
1727                Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
1728                return;
1729            }
1730            final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
1731            try {
1732                readPolicyXml(bais, true /*forRestore*/);
1733                savePolicyFile();
1734            } catch (NumberFormatException | XmlPullParserException | IOException e) {
1735                Slog.w(TAG, "applyRestore: error reading payload", e);
1736            }
1737        }
1738
1739        @Override
1740        public boolean isNotificationPolicyAccessGranted(String pkg) {
1741            return checkPolicyAccess(pkg);
1742        }
1743
1744        @Override
1745        public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
1746            enforceSystemOrSystemUI("request policy access status for another package");
1747            return checkPackagePolicyAccess(pkg);
1748        }
1749
1750        @Override
1751        public String[] getPackagesRequestingNotificationPolicyAccess()
1752                throws RemoteException {
1753            enforceSystemOrSystemUI("request policy access packages");
1754            final long identity = Binder.clearCallingIdentity();
1755            try {
1756                return mPolicyAccess.getRequestingPackages();
1757            } finally {
1758                Binder.restoreCallingIdentity(identity);
1759            }
1760        }
1761
1762        @Override
1763        public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
1764                throws RemoteException {
1765            enforceSystemOrSystemUI("grant notification policy access");
1766            final long identity = Binder.clearCallingIdentity();
1767            try {
1768                synchronized (mNotificationList) {
1769                    mPolicyAccess.put(pkg, granted);
1770                }
1771            } finally {
1772                Binder.restoreCallingIdentity(identity);
1773            }
1774        }
1775
1776        @Override
1777        public Policy getNotificationPolicy(String pkg) {
1778            enforcePolicyAccess(pkg, "getNotificationPolicy");
1779            final long identity = Binder.clearCallingIdentity();
1780            try {
1781                return mZenModeHelper.getNotificationPolicy();
1782            } finally {
1783                Binder.restoreCallingIdentity(identity);
1784            }
1785        }
1786
1787        @Override
1788        public void setNotificationPolicy(String pkg, Policy policy) {
1789            enforcePolicyAccess(pkg, "setNotificationPolicy");
1790            final long identity = Binder.clearCallingIdentity();
1791            try {
1792                mZenModeHelper.setNotificationPolicy(policy);
1793            } finally {
1794                Binder.restoreCallingIdentity(identity);
1795            }
1796        }
1797    };
1798
1799    private String disableNotificationEffects(NotificationRecord record) {
1800        if (mDisableNotificationEffects) {
1801            return "booleanState";
1802        }
1803        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1804            return "listenerHints";
1805        }
1806        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
1807            return "callState";
1808        }
1809        return null;
1810    };
1811
1812    private void dumpJson(PrintWriter pw, DumpFilter filter) {
1813        JSONObject dump = new JSONObject();
1814        try {
1815            dump.put("service", "Notification Manager");
1816            JSONArray bans = new JSONArray();
1817            try {
1818                ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
1819                for (Integer userId : packageBans.keySet()) {
1820                    for (String packageName : packageBans.get(userId)) {
1821                        JSONObject ban = new JSONObject();
1822                        ban.put("userId", userId);
1823                        ban.put("packageName", packageName);
1824                        bans.put(ban);
1825                    }
1826                }
1827            } catch (NameNotFoundException e) {
1828                // pass
1829            }
1830            dump.put("bans", bans);
1831            dump.put("stats", mUsageStats.dumpJson(filter));
1832        } catch (JSONException e) {
1833            e.printStackTrace();
1834        }
1835        pw.println(dump);
1836    }
1837
1838    void dumpImpl(PrintWriter pw, DumpFilter filter) {
1839        pw.print("Current Notification Manager state");
1840        if (filter.filtered) {
1841            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
1842        }
1843        pw.println(':');
1844        int N;
1845        final boolean zenOnly = filter.filtered && filter.zen;
1846
1847        if (!zenOnly) {
1848            synchronized (mToastQueue) {
1849                N = mToastQueue.size();
1850                if (N > 0) {
1851                    pw.println("  Toast Queue:");
1852                    for (int i=0; i<N; i++) {
1853                        mToastQueue.get(i).dump(pw, "    ", filter);
1854                    }
1855                    pw.println("  ");
1856                }
1857            }
1858        }
1859
1860        synchronized (mNotificationList) {
1861            if (!zenOnly) {
1862                N = mNotificationList.size();
1863                if (N > 0) {
1864                    pw.println("  Notification List:");
1865                    for (int i=0; i<N; i++) {
1866                        final NotificationRecord nr = mNotificationList.get(i);
1867                        if (filter.filtered && !filter.matches(nr.sbn)) continue;
1868                        nr.dump(pw, "    ", getContext(), filter.redact);
1869                    }
1870                    pw.println("  ");
1871                }
1872
1873                if (!filter.filtered) {
1874                    N = mLights.size();
1875                    if (N > 0) {
1876                        pw.println("  Lights List:");
1877                        for (int i=0; i<N; i++) {
1878                            if (i == N - 1) {
1879                                pw.print("  > ");
1880                            } else {
1881                                pw.print("    ");
1882                            }
1883                            pw.println(mLights.get(i));
1884                        }
1885                        pw.println("  ");
1886                    }
1887                    pw.println("  mUseAttentionLight=" + mUseAttentionLight);
1888                    pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
1889                    pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
1890                    pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
1891                    pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
1892                    pw.println("  mCallState=" + callStateToString(mCallState));
1893                    pw.println("  mSystemReady=" + mSystemReady);
1894                }
1895                pw.println("  mArchive=" + mArchive.toString());
1896                Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
1897                int i=0;
1898                while (iter.hasNext()) {
1899                    final StatusBarNotification sbn = iter.next();
1900                    if (filter != null && !filter.matches(sbn)) continue;
1901                    pw.println("    " + sbn);
1902                    if (++i >= 5) {
1903                        if (iter.hasNext()) pw.println("    ...");
1904                        break;
1905                    }
1906                }
1907            }
1908
1909            if (!zenOnly) {
1910                pw.println("\n  Usage Stats:");
1911                mUsageStats.dump(pw, "    ", filter);
1912            }
1913
1914            if (!filter.filtered || zenOnly) {
1915                pw.println("\n  Zen Mode:");
1916                pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
1917                mZenModeHelper.dump(pw, "    ");
1918
1919                pw.println("\n  Zen Log:");
1920                ZenLog.dump(pw, "    ");
1921            }
1922
1923            if (!zenOnly) {
1924                pw.println("\n  Ranking Config:");
1925                mRankingHelper.dump(pw, "    ", filter);
1926
1927                pw.println("\n  Notification listeners:");
1928                mListeners.dump(pw, filter);
1929                pw.print("    mListenerHints: "); pw.println(mListenerHints);
1930                pw.print("    mListenersDisablingEffects: (");
1931                N = mListenersDisablingEffects.size();
1932                for (int i = 0; i < N; i++) {
1933                    final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
1934                    if (i > 0) pw.print(',');
1935                    pw.print(listener.component);
1936                }
1937                pw.println(')');
1938            }
1939            pw.println("\n  Policy access:");
1940            pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
1941
1942            pw.println("\n  Condition providers:");
1943            mConditionProviders.dump(pw, filter);
1944
1945            pw.println("\n  Group summaries:");
1946            for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
1947                NotificationRecord r = entry.getValue();
1948                pw.println("    " + entry.getKey() + " -> " + r.getKey());
1949                if (mNotificationsByKey.get(r.getKey()) != r) {
1950                    pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
1951                    r.dump(pw, "      ", getContext(), filter.redact);
1952                }
1953            }
1954
1955            try {
1956                pw.println("\n  Banned Packages:");
1957                ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
1958                for (Integer userId : packageBans.keySet()) {
1959                    for (String packageName : packageBans.get(userId)) {
1960                        pw.println("    " + userId + ": " + packageName);
1961                    }
1962                }
1963            } catch (NameNotFoundException e) {
1964                // pass
1965            }
1966        }
1967    }
1968
1969    private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter)
1970            throws NameNotFoundException {
1971        ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>();
1972        ArrayList<String> packageNames = new ArrayList<>();
1973        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1974            final int userId = user.getUserHandle().getIdentifier();
1975            final PackageManager packageManager = getContext().getPackageManager();
1976            List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId);
1977            final int packageCount = packages.size();
1978            for (int p = 0; p < packageCount; p++) {
1979                final String packageName = packages.get(p).packageName;
1980                if (filter == null || filter.matches(packageName)) {
1981                    final int uid = packageManager.getPackageUid(packageName, userId);
1982                    if (!checkNotificationOp(packageName, uid)) {
1983                        packageNames.add(packageName);
1984                    }
1985                }
1986            }
1987            if (!packageNames.isEmpty()) {
1988                packageBans.put(userId, packageNames);
1989                packageNames = new ArrayList<>();
1990            }
1991        }
1992        return packageBans;
1993    }
1994
1995    /**
1996     * The private API only accessible to the system process.
1997     */
1998    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
1999        @Override
2000        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2001                String tag, int id, Notification notification, int[] idReceived, int userId) {
2002            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2003                    idReceived, userId);
2004        }
2005
2006        @Override
2007        public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2008                int userId) {
2009            checkCallerIsSystem();
2010            synchronized (mNotificationList) {
2011                int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2012                if (i < 0) {
2013                    Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2014                            + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2015                    return;
2016                }
2017                NotificationRecord r = mNotificationList.get(i);
2018                StatusBarNotification sbn = r.sbn;
2019                // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2020                // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2021                // we have to revert to the flags we received initially *and* force remove
2022                // FLAG_FOREGROUND_SERVICE.
2023                sbn.getNotification().flags =
2024                        (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2025                mRankingHelper.sort(mNotificationList);
2026                mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2027            }
2028        }
2029    };
2030
2031    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2032            final int callingPid, final String tag, final int id, final Notification notification,
2033            int[] idOut, int incomingUserId) {
2034        if (DBG) {
2035            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2036                    + " notification=" + notification);
2037        }
2038        checkCallerIsSystemOrSameApp(pkg);
2039        final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2040        final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2041
2042        final int userId = ActivityManager.handleIncomingUser(callingPid,
2043                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2044        final UserHandle user = new UserHandle(userId);
2045
2046        // Limit the number of notifications that any given package except the android
2047        // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
2048        if (!isSystemNotification && !isNotificationFromListener) {
2049            synchronized (mNotificationList) {
2050                int count = 0;
2051                final int N = mNotificationList.size();
2052                for (int i=0; i<N; i++) {
2053                    final NotificationRecord r = mNotificationList.get(i);
2054                    if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2055                        if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2056                            break;  // Allow updating existing notification
2057                        }
2058                        count++;
2059                        if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2060                            Slog.e(TAG, "Package has already posted " + count
2061                                    + " notifications.  Not showing more.  package=" + pkg);
2062                            return;
2063                        }
2064                    }
2065                }
2066            }
2067        }
2068
2069        if (pkg == null || notification == null) {
2070            throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2071                    + " id=" + id + " notification=" + notification);
2072        }
2073
2074        if (notification.getSmallIcon() != null) {
2075            if (!notification.isValid()) {
2076                throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
2077                        + " id=" + id + " notification=" + notification);
2078            }
2079        }
2080
2081        mHandler.post(new Runnable() {
2082            @Override
2083            public void run() {
2084
2085                synchronized (mNotificationList) {
2086
2087                    // === Scoring ===
2088
2089                    // 0. Sanitize inputs
2090                    notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2091                            Notification.PRIORITY_MAX);
2092                    // Migrate notification flags to scores
2093                    if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
2094                        if (notification.priority < Notification.PRIORITY_MAX) {
2095                            notification.priority = Notification.PRIORITY_MAX;
2096                        }
2097                    } else if (SCORE_ONGOING_HIGHER &&
2098                            0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
2099                        if (notification.priority < Notification.PRIORITY_HIGH) {
2100                            notification.priority = Notification.PRIORITY_HIGH;
2101                        }
2102                    }
2103                    // force no heads up per package config
2104                    if (!mRankingHelper.getPackagePeekable(pkg, callingUid)) {
2105                        if (notification.extras == null) {
2106                            notification.extras = new Bundle();
2107                        }
2108                        notification.extras.putInt(Notification.EXTRA_AS_HEADS_UP,
2109                                Notification.HEADS_UP_NEVER);
2110                    }
2111
2112                    // 1. initial score: buckets of 10, around the app [-20..20]
2113                    final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;
2114
2115                    // 2. extract ranking signals from the notification data
2116                    final StatusBarNotification n = new StatusBarNotification(
2117                            pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
2118                            user);
2119                    NotificationRecord r = new NotificationRecord(n, score);
2120                    NotificationRecord old = mNotificationsByKey.get(n.getKey());
2121                    if (old != null) {
2122                        // Retain ranking information from previous record
2123                        r.copyRankingInformation(old);
2124                    }
2125
2126                    // Handle grouped notifications and bail out early if we
2127                    // can to avoid extracting signals.
2128                    handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2129                    boolean ignoreNotification =
2130                            removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
2131
2132                    // This conditional is a dirty hack to limit the logging done on
2133                    //     behalf of the download manager without affecting other apps.
2134                    if (!pkg.equals("com.android.providers.downloads")
2135                            || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2136                        int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2137                        if (ignoreNotification) {
2138                            enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED;
2139                        } else if (old != null) {
2140                            enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2141                        }
2142                        EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2143                                pkg, id, tag, userId, notification.toString(),
2144                                enqueueStatus);
2145                    }
2146
2147                    if (ignoreNotification) {
2148                        return;
2149                    }
2150
2151                    mRankingHelper.extractSignals(r);
2152
2153                    // 3. Apply local rules
2154
2155                    // blocked apps
2156                    if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
2157                        if (!isSystemNotification) {
2158                            r.score = JUNK_SCORE;
2159                            Slog.e(TAG, "Suppressing notification from package " + pkg
2160                                    + " by user request.");
2161                            mUsageStats.registerBlocked(r);
2162                        }
2163                    }
2164
2165                    if (r.score < SCORE_DISPLAY_THRESHOLD) {
2166                        // Notification will be blocked because the score is too low.
2167                        return;
2168                    }
2169
2170                    int index = indexOfNotificationLocked(n.getKey());
2171                    if (index < 0) {
2172                        mNotificationList.add(r);
2173                        mUsageStats.registerPostedByApp(r);
2174                    } else {
2175                        old = mNotificationList.get(index);
2176                        mNotificationList.set(index, r);
2177                        mUsageStats.registerUpdatedByApp(r, old);
2178                        // Make sure we don't lose the foreground service state.
2179                        notification.flags |=
2180                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2181                        r.isUpdate = true;
2182                    }
2183
2184                    mNotificationsByKey.put(n.getKey(), r);
2185
2186                    // Ensure if this is a foreground service that the proper additional
2187                    // flags are set.
2188                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2189                        notification.flags |= Notification.FLAG_ONGOING_EVENT
2190                                | Notification.FLAG_NO_CLEAR;
2191                    }
2192
2193                    applyZenModeLocked(r);
2194                    mRankingHelper.sort(mNotificationList);
2195
2196                    if (notification.getSmallIcon() != null) {
2197                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2198                        mListeners.notifyPostedLocked(n, oldSbn);
2199                    } else {
2200                        Slog.e(TAG, "Not posting notification without small icon: " + notification);
2201                        if (old != null && !old.isCanceled) {
2202                            mListeners.notifyRemovedLocked(n);
2203                        }
2204                        // ATTENTION: in a future release we will bail out here
2205                        // so that we do not play sounds, show lights, etc. for invalid
2206                        // notifications
2207                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2208                                + n.getPackageName());
2209                    }
2210
2211                    buzzBeepBlinkLocked(r);
2212                }
2213            }
2214        });
2215
2216        idOut[0] = id;
2217    }
2218
2219    /**
2220     * Ensures that grouped notification receive their special treatment.
2221     *
2222     * <p>Cancels group children if the new notification causes a group to lose
2223     * its summary.</p>
2224     *
2225     * <p>Updates mSummaryByGroupKey.</p>
2226     */
2227    private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2228            int callingUid, int callingPid) {
2229        StatusBarNotification sbn = r.sbn;
2230        Notification n = sbn.getNotification();
2231        String group = sbn.getGroupKey();
2232        boolean isSummary = n.isGroupSummary();
2233
2234        Notification oldN = old != null ? old.sbn.getNotification() : null;
2235        String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2236        boolean oldIsSummary = old != null && oldN.isGroupSummary();
2237
2238        if (oldIsSummary) {
2239            NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2240            if (removedSummary != old) {
2241                String removedKey =
2242                        removedSummary != null ? removedSummary.getKey() : "<null>";
2243                Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2244                        ", removed=" + removedKey);
2245            }
2246        }
2247        if (isSummary) {
2248            mSummaryByGroupKey.put(group, r);
2249        }
2250
2251        // Clear out group children of the old notification if the update
2252        // causes the group summary to go away. This happens when the old
2253        // notification was a summary and the new one isn't, or when the old
2254        // notification was a summary and its group key changed.
2255        if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2256            cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2257                    REASON_GROUP_SUMMARY_CANCELED);
2258        }
2259    }
2260
2261    /**
2262     * Performs group notification optimizations if SysUI is the only active
2263     * notification listener and returns whether the given notification should
2264     * be ignored.
2265     *
2266     * <p>Returns true if the given notification is a child of a group with a
2267     * summary, which means that SysUI will never show it, and hence the new
2268     * notification can be safely ignored. Also cancels any previous instance
2269     * of the ignored notification.</p>
2270     *
2271     * <p>For summaries, cancels all children of that group, as SysUI will
2272     * never show them anymore.</p>
2273     *
2274     * @return true if the given notification can be ignored as an optimization
2275     */
2276    private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
2277            NotificationRecord old, int callingUid, int callingPid) {
2278        if (!ENABLE_CHILD_NOTIFICATIONS) {
2279            // No optimizations are possible if listeners want groups.
2280            if (mListeners.notificationGroupsDesired()) {
2281                return false;
2282            }
2283
2284            StatusBarNotification sbn = r.sbn;
2285            String group = sbn.getGroupKey();
2286            boolean isSummary = sbn.getNotification().isGroupSummary();
2287            boolean isChild = sbn.getNotification().isGroupChild();
2288
2289            NotificationRecord summary = mSummaryByGroupKey.get(group);
2290            if (isChild && summary != null) {
2291                // Child with an active summary -> ignore
2292                if (DBG) {
2293                    Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
2294                            + summary.getKey());
2295                }
2296                // Make sure we don't leave an old version of the notification around.
2297                if (old != null) {
2298                    if (DBG) {
2299                        Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
2300                    }
2301                    cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
2302                }
2303                return true;
2304            } else if (isSummary) {
2305                // Summary -> cancel children
2306                cancelGroupChildrenLocked(r, callingUid, callingPid, null,
2307                        REASON_GROUP_OPTIMIZATION);
2308            }
2309        }
2310        return false;
2311    }
2312
2313    private void buzzBeepBlinkLocked(NotificationRecord record) {
2314        boolean buzz = false;
2315        boolean beep = false;
2316        boolean blink = false;
2317
2318        final Notification notification = record.sbn.getNotification();
2319
2320        // Should this notification make noise, vibe, or use the LED?
2321        final boolean aboveThreshold = record.score >= SCORE_INTERRUPTION_THRESHOLD;
2322        final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2323        if (DBG || record.isIntercepted())
2324            Slog.v(TAG,
2325                    "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2326                            " intercept=" + record.isIntercepted()
2327            );
2328
2329        final int currentUser;
2330        final long token = Binder.clearCallingIdentity();
2331        try {
2332            currentUser = ActivityManager.getCurrentUser();
2333        } finally {
2334            Binder.restoreCallingIdentity(token);
2335        }
2336
2337        // If we're not supposed to beep, vibrate, etc. then don't.
2338        final String disableEffects = disableNotificationEffects(record);
2339        if (disableEffects != null) {
2340            ZenLog.traceDisableEffects(record, disableEffects);
2341        }
2342        if (disableEffects == null
2343                && (!(record.isUpdate
2344                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
2345                && (record.getUserId() == UserHandle.USER_ALL ||
2346                    record.getUserId() == currentUser ||
2347                    mUserProfiles.isCurrentProfile(record.getUserId()))
2348                && canInterrupt
2349                && mSystemReady
2350                && mAudioManager != null) {
2351            if (DBG) Slog.v(TAG, "Interrupting!");
2352
2353            sendAccessibilityEvent(notification, record.sbn.getPackageName());
2354
2355            // sound
2356
2357            // should we use the default notification sound? (indicated either by
2358            // DEFAULT_SOUND or because notification.sound is pointing at
2359            // Settings.System.NOTIFICATION_SOUND)
2360            final boolean useDefaultSound =
2361                   (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2362                           Settings.System.DEFAULT_NOTIFICATION_URI
2363                                   .equals(notification.sound);
2364
2365            Uri soundUri = null;
2366            boolean hasValidSound = false;
2367
2368            if (useDefaultSound) {
2369                soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2370
2371                // check to see if the default notification sound is silent
2372                ContentResolver resolver = getContext().getContentResolver();
2373                hasValidSound = Settings.System.getString(resolver,
2374                       Settings.System.NOTIFICATION_SOUND) != null;
2375            } else if (notification.sound != null) {
2376                soundUri = notification.sound;
2377                hasValidSound = (soundUri != null);
2378            }
2379
2380            if (hasValidSound) {
2381                boolean looping =
2382                        (notification.flags & Notification.FLAG_INSISTENT) != 0;
2383                AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2384                mSoundNotificationKey = record.getKey();
2385                // do not play notifications if stream volume is 0 (typically because
2386                // ringer mode is silent) or if there is a user of exclusive audio focus
2387                if ((mAudioManager.getStreamVolume(
2388                        AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2389                            && !mAudioManager.isAudioFocusExclusive()) {
2390                    final long identity = Binder.clearCallingIdentity();
2391                    try {
2392                        final IRingtonePlayer player =
2393                                mAudioManager.getRingtonePlayer();
2394                        if (player != null) {
2395                            if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2396                                    + " with attributes " + audioAttributes);
2397                            player.playAsync(soundUri, record.sbn.getUser(), looping,
2398                                    audioAttributes);
2399                            beep = true;
2400                        }
2401                    } catch (RemoteException e) {
2402                    } finally {
2403                        Binder.restoreCallingIdentity(identity);
2404                    }
2405                }
2406            }
2407
2408            // vibrate
2409            // Does the notification want to specify its own vibration?
2410            final boolean hasCustomVibrate = notification.vibrate != null;
2411
2412            // new in 4.2: if there was supposed to be a sound and we're in vibrate
2413            // mode, and no other vibration is specified, we fall back to vibration
2414            final boolean convertSoundToVibration =
2415                       !hasCustomVibrate
2416                    && hasValidSound
2417                    && (mAudioManager.getRingerModeInternal()
2418                               == AudioManager.RINGER_MODE_VIBRATE);
2419
2420            // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2421            final boolean useDefaultVibrate =
2422                    (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2423
2424            if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
2425                    && !(mAudioManager.getRingerModeInternal()
2426                            == AudioManager.RINGER_MODE_SILENT)) {
2427                mVibrateNotificationKey = record.getKey();
2428
2429                if (useDefaultVibrate || convertSoundToVibration) {
2430                    // Escalate privileges so we can use the vibrator even if the
2431                    // notifying app does not have the VIBRATE permission.
2432                    long identity = Binder.clearCallingIdentity();
2433                    try {
2434                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2435                            useDefaultVibrate ? mDefaultVibrationPattern
2436                                : mFallbackVibrationPattern,
2437                            ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2438                                ? 0: -1, audioAttributesForNotification(notification));
2439                        buzz = true;
2440                    } finally {
2441                        Binder.restoreCallingIdentity(identity);
2442                    }
2443                } else if (notification.vibrate.length > 1) {
2444                    // If you want your own vibration pattern, you need the VIBRATE
2445                    // permission
2446                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2447                            notification.vibrate,
2448                        ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2449                                ? 0: -1, audioAttributesForNotification(notification));
2450                    buzz = true;
2451                }
2452            }
2453        }
2454
2455        // light
2456        // release the light
2457        boolean wasShowLights = mLights.remove(record.getKey());
2458        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) {
2459            mLights.add(record.getKey());
2460            updateLightsLocked();
2461            if (mUseAttentionLight) {
2462                mAttentionLight.pulse();
2463            }
2464            blink = true;
2465        } else if (wasShowLights) {
2466            updateLightsLocked();
2467        }
2468        if (buzz || beep || blink) {
2469            EventLogTags.writeNotificationAlert(record.getKey(),
2470                    buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2471            mHandler.post(mBuzzBeepBlinked);
2472        }
2473    }
2474
2475    private static AudioAttributes audioAttributesForNotification(Notification n) {
2476        if (n.audioAttributes != null
2477                && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2478            // the audio attributes are set and different from the default, use them
2479            return n.audioAttributes;
2480        } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2481            // the stream type is valid, use it
2482            return new AudioAttributes.Builder()
2483                    .setInternalLegacyStreamType(n.audioStreamType)
2484                    .build();
2485        } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2486            return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2487        } else {
2488            Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2489            return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2490        }
2491    }
2492
2493    void showNextToastLocked() {
2494        ToastRecord record = mToastQueue.get(0);
2495        while (record != null) {
2496            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2497            try {
2498                record.callback.show();
2499                scheduleTimeoutLocked(record);
2500                return;
2501            } catch (RemoteException e) {
2502                Slog.w(TAG, "Object died trying to show notification " + record.callback
2503                        + " in package " + record.pkg);
2504                // remove it from the list and let the process die
2505                int index = mToastQueue.indexOf(record);
2506                if (index >= 0) {
2507                    mToastQueue.remove(index);
2508                }
2509                keepProcessAliveLocked(record.pid);
2510                if (mToastQueue.size() > 0) {
2511                    record = mToastQueue.get(0);
2512                } else {
2513                    record = null;
2514                }
2515            }
2516        }
2517    }
2518
2519    void cancelToastLocked(int index) {
2520        ToastRecord record = mToastQueue.get(index);
2521        try {
2522            record.callback.hide();
2523        } catch (RemoteException e) {
2524            Slog.w(TAG, "Object died trying to hide notification " + record.callback
2525                    + " in package " + record.pkg);
2526            // don't worry about this, we're about to remove it from
2527            // the list anyway
2528        }
2529        mToastQueue.remove(index);
2530        keepProcessAliveLocked(record.pid);
2531        if (mToastQueue.size() > 0) {
2532            // Show the next one. If the callback fails, this will remove
2533            // it from the list, so don't assume that the list hasn't changed
2534            // after this point.
2535            showNextToastLocked();
2536        }
2537    }
2538
2539    private void scheduleTimeoutLocked(ToastRecord r)
2540    {
2541        mHandler.removeCallbacksAndMessages(r);
2542        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2543        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2544        mHandler.sendMessageDelayed(m, delay);
2545    }
2546
2547    private void handleTimeout(ToastRecord record)
2548    {
2549        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2550        synchronized (mToastQueue) {
2551            int index = indexOfToastLocked(record.pkg, record.callback);
2552            if (index >= 0) {
2553                cancelToastLocked(index);
2554            }
2555        }
2556    }
2557
2558    // lock on mToastQueue
2559    int indexOfToastLocked(String pkg, ITransientNotification callback)
2560    {
2561        IBinder cbak = callback.asBinder();
2562        ArrayList<ToastRecord> list = mToastQueue;
2563        int len = list.size();
2564        for (int i=0; i<len; i++) {
2565            ToastRecord r = list.get(i);
2566            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
2567                return i;
2568            }
2569        }
2570        return -1;
2571    }
2572
2573    // lock on mToastQueue
2574    void keepProcessAliveLocked(int pid)
2575    {
2576        int toastCount = 0; // toasts from this pid
2577        ArrayList<ToastRecord> list = mToastQueue;
2578        int N = list.size();
2579        for (int i=0; i<N; i++) {
2580            ToastRecord r = list.get(i);
2581            if (r.pid == pid) {
2582                toastCount++;
2583            }
2584        }
2585        try {
2586            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
2587        } catch (RemoteException e) {
2588            // Shouldn't happen.
2589        }
2590    }
2591
2592    private void handleRankingReconsideration(Message message) {
2593        if (!(message.obj instanceof RankingReconsideration)) return;
2594        RankingReconsideration recon = (RankingReconsideration) message.obj;
2595        recon.run();
2596        boolean changed;
2597        synchronized (mNotificationList) {
2598            final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
2599            if (record == null) {
2600                return;
2601            }
2602            int indexBefore = findNotificationRecordIndexLocked(record);
2603            boolean interceptBefore = record.isIntercepted();
2604            int visibilityBefore = record.getPackageVisibilityOverride();
2605            recon.applyChangesLocked(record);
2606            applyZenModeLocked(record);
2607            mRankingHelper.sort(mNotificationList);
2608            int indexAfter = findNotificationRecordIndexLocked(record);
2609            boolean interceptAfter = record.isIntercepted();
2610            int visibilityAfter = record.getPackageVisibilityOverride();
2611            changed = indexBefore != indexAfter || interceptBefore != interceptAfter
2612                    || visibilityBefore != visibilityAfter;
2613            if (interceptBefore && !interceptAfter) {
2614                buzzBeepBlinkLocked(record);
2615            }
2616        }
2617        if (changed) {
2618            scheduleSendRankingUpdate();
2619        }
2620    }
2621
2622    private void handleRankingConfigChange() {
2623        synchronized (mNotificationList) {
2624            final int N = mNotificationList.size();
2625            ArrayList<String> orderBefore = new ArrayList<String>(N);
2626            int[] visibilities = new int[N];
2627            for (int i = 0; i < N; i++) {
2628                final NotificationRecord r = mNotificationList.get(i);
2629                orderBefore.add(r.getKey());
2630                visibilities[i] = r.getPackageVisibilityOverride();
2631                mRankingHelper.extractSignals(r);
2632            }
2633            for (int i = 0; i < N; i++) {
2634                mRankingHelper.sort(mNotificationList);
2635                final NotificationRecord r = mNotificationList.get(i);
2636                if (!orderBefore.get(i).equals(r.getKey())
2637                        || visibilities[i] != r.getPackageVisibilityOverride()) {
2638                    scheduleSendRankingUpdate();
2639                    return;
2640                }
2641            }
2642        }
2643    }
2644
2645    // let zen mode evaluate this record
2646    private void applyZenModeLocked(NotificationRecord record) {
2647        record.setIntercepted(mZenModeHelper.shouldIntercept(record));
2648    }
2649
2650    // lock on mNotificationList
2651    private int findNotificationRecordIndexLocked(NotificationRecord target) {
2652        return mRankingHelper.indexOf(mNotificationList, target);
2653    }
2654
2655    private void scheduleSendRankingUpdate() {
2656        mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
2657        Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
2658        mHandler.sendMessage(m);
2659    }
2660
2661    private void handleSendRankingUpdate() {
2662        synchronized (mNotificationList) {
2663            mListeners.notifyRankingUpdateLocked();
2664        }
2665    }
2666
2667    private void scheduleListenerHintsChanged(int state) {
2668        mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
2669        mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
2670    }
2671
2672    private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
2673        mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
2674        mHandler.obtainMessage(
2675                MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
2676                listenerInterruptionFilter,
2677                0).sendToTarget();
2678    }
2679
2680    private void handleListenerHintsChanged(int hints) {
2681        synchronized (mNotificationList) {
2682            mListeners.notifyListenerHintsChangedLocked(hints);
2683        }
2684    }
2685
2686    private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
2687        synchronized (mNotificationList) {
2688            mListeners.notifyInterruptionFilterChanged(interruptionFilter);
2689        }
2690    }
2691
2692    private final class WorkerHandler extends Handler
2693    {
2694        @Override
2695        public void handleMessage(Message msg)
2696        {
2697            switch (msg.what)
2698            {
2699                case MESSAGE_TIMEOUT:
2700                    handleTimeout((ToastRecord)msg.obj);
2701                    break;
2702                case MESSAGE_SAVE_POLICY_FILE:
2703                    handleSavePolicyFile();
2704                    break;
2705                case MESSAGE_SEND_RANKING_UPDATE:
2706                    handleSendRankingUpdate();
2707                    break;
2708                case MESSAGE_LISTENER_HINTS_CHANGED:
2709                    handleListenerHintsChanged(msg.arg1);
2710                    break;
2711                case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
2712                    handleListenerInterruptionFilterChanged(msg.arg1);
2713                    break;
2714            }
2715        }
2716
2717    }
2718
2719    private final class RankingWorkerHandler extends Handler
2720    {
2721        public RankingWorkerHandler(Looper looper) {
2722            super(looper);
2723        }
2724
2725        @Override
2726        public void handleMessage(Message msg) {
2727            switch (msg.what) {
2728                case MESSAGE_RECONSIDER_RANKING:
2729                    handleRankingReconsideration(msg);
2730                    break;
2731                case MESSAGE_RANKING_CONFIG_CHANGE:
2732                    handleRankingConfigChange();
2733                    break;
2734            }
2735        }
2736    }
2737
2738    // Notifications
2739    // ============================================================================
2740    static int clamp(int x, int low, int high) {
2741        return (x < low) ? low : ((x > high) ? high : x);
2742    }
2743
2744    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
2745        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
2746        if (!manager.isEnabled()) {
2747            return;
2748        }
2749
2750        AccessibilityEvent event =
2751            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
2752        event.setPackageName(packageName);
2753        event.setClassName(Notification.class.getName());
2754        event.setParcelableData(notification);
2755        CharSequence tickerText = notification.tickerText;
2756        if (!TextUtils.isEmpty(tickerText)) {
2757            event.getText().add(tickerText);
2758        }
2759
2760        manager.sendAccessibilityEvent(event);
2761    }
2762
2763    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
2764        // tell the app
2765        if (sendDelete) {
2766            if (r.getNotification().deleteIntent != null) {
2767                try {
2768                    r.getNotification().deleteIntent.send();
2769                } catch (PendingIntent.CanceledException ex) {
2770                    // do nothing - there's no relevant way to recover, and
2771                    //     no reason to let this propagate
2772                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
2773                }
2774            }
2775        }
2776
2777        // status bar
2778        if (r.getNotification().getSmallIcon() != null) {
2779            r.isCanceled = true;
2780            mListeners.notifyRemovedLocked(r.sbn);
2781        }
2782
2783        final String canceledKey = r.getKey();
2784
2785        // sound
2786        if (canceledKey.equals(mSoundNotificationKey)) {
2787            mSoundNotificationKey = null;
2788            final long identity = Binder.clearCallingIdentity();
2789            try {
2790                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
2791                if (player != null) {
2792                    player.stopAsync();
2793                }
2794            } catch (RemoteException e) {
2795            } finally {
2796                Binder.restoreCallingIdentity(identity);
2797            }
2798        }
2799
2800        // vibrate
2801        if (canceledKey.equals(mVibrateNotificationKey)) {
2802            mVibrateNotificationKey = null;
2803            long identity = Binder.clearCallingIdentity();
2804            try {
2805                mVibrator.cancel();
2806            }
2807            finally {
2808                Binder.restoreCallingIdentity(identity);
2809            }
2810        }
2811
2812        // light
2813        mLights.remove(canceledKey);
2814
2815        // Record usage stats
2816        switch (reason) {
2817            case REASON_DELEGATE_CANCEL:
2818            case REASON_DELEGATE_CANCEL_ALL:
2819            case REASON_LISTENER_CANCEL:
2820            case REASON_LISTENER_CANCEL_ALL:
2821                mUsageStats.registerDismissedByUser(r);
2822                break;
2823            case REASON_NOMAN_CANCEL:
2824            case REASON_NOMAN_CANCEL_ALL:
2825                mUsageStats.registerRemovedByApp(r);
2826                break;
2827        }
2828
2829        mNotificationsByKey.remove(r.sbn.getKey());
2830        String groupKey = r.getGroupKey();
2831        NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
2832        if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
2833            mSummaryByGroupKey.remove(groupKey);
2834        }
2835
2836        // Save it for users of getHistoricalNotifications()
2837        mArchive.record(r.sbn);
2838
2839        final long now = System.currentTimeMillis();
2840        EventLogTags.writeNotificationCanceled(canceledKey, reason,
2841                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
2842    }
2843
2844    /**
2845     * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
2846     * and none of the {@code mustNotHaveFlags}.
2847     */
2848    void cancelNotification(final int callingUid, final int callingPid,
2849            final String pkg, final String tag, final int id,
2850            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
2851            final int userId, final int reason, final ManagedServiceInfo listener) {
2852        // In enqueueNotificationInternal notifications are added by scheduling the
2853        // work on the worker handler. Hence, we also schedule the cancel on this
2854        // handler to avoid a scenario where an add notification call followed by a
2855        // remove notification call ends up in not removing the notification.
2856        mHandler.post(new Runnable() {
2857            @Override
2858            public void run() {
2859                String listenerName = listener == null ? null : listener.component.toShortString();
2860                if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
2861                        userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
2862
2863                synchronized (mNotificationList) {
2864                    int index = indexOfNotificationLocked(pkg, tag, id, userId);
2865                    if (index >= 0) {
2866                        NotificationRecord r = mNotificationList.get(index);
2867
2868                        // Ideally we'd do this in the caller of this method. However, that would
2869                        // require the caller to also find the notification.
2870                        if (reason == REASON_DELEGATE_CLICK) {
2871                            mUsageStats.registerClickedByUser(r);
2872                        }
2873
2874                        if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
2875                            return;
2876                        }
2877                        if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
2878                            return;
2879                        }
2880
2881                        mNotificationList.remove(index);
2882
2883                        cancelNotificationLocked(r, sendDelete, reason);
2884                        cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
2885                                REASON_GROUP_SUMMARY_CANCELED);
2886                        updateLightsLocked();
2887                    }
2888                }
2889            }
2890        });
2891    }
2892
2893    /**
2894     * Determine whether the userId applies to the notification in question, either because
2895     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
2896     */
2897    private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
2898        return
2899                // looking for USER_ALL notifications? match everything
2900                   userId == UserHandle.USER_ALL
2901                // a notification sent to USER_ALL matches any query
2902                || r.getUserId() == UserHandle.USER_ALL
2903                // an exact user match
2904                || r.getUserId() == userId;
2905    }
2906
2907    /**
2908     * Determine whether the userId applies to the notification in question, either because
2909     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
2910     * because it matches one of the users profiles.
2911     */
2912    private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
2913        return notificationMatchesUserId(r, userId)
2914                || mUserProfiles.isCurrentProfile(r.getUserId());
2915    }
2916
2917    /**
2918     * Cancels all notifications from a given package that have all of the
2919     * {@code mustHaveFlags}.
2920     */
2921    boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
2922            int mustNotHaveFlags, boolean doit, int userId, int reason,
2923            ManagedServiceInfo listener) {
2924        String listenerName = listener == null ? null : listener.component.toShortString();
2925        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
2926                pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
2927                listenerName);
2928
2929        synchronized (mNotificationList) {
2930            final int N = mNotificationList.size();
2931            ArrayList<NotificationRecord> canceledNotifications = null;
2932            for (int i = N-1; i >= 0; --i) {
2933                NotificationRecord r = mNotificationList.get(i);
2934                if (!notificationMatchesUserId(r, userId)) {
2935                    continue;
2936                }
2937                // Don't remove notifications to all, if there's no package name specified
2938                if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
2939                    continue;
2940                }
2941                if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
2942                    continue;
2943                }
2944                if ((r.getFlags() & mustNotHaveFlags) != 0) {
2945                    continue;
2946                }
2947                if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
2948                    continue;
2949                }
2950                if (canceledNotifications == null) {
2951                    canceledNotifications = new ArrayList<>();
2952                }
2953                canceledNotifications.add(r);
2954                if (!doit) {
2955                    return true;
2956                }
2957                mNotificationList.remove(i);
2958                cancelNotificationLocked(r, false, reason);
2959            }
2960            if (doit && canceledNotifications != null) {
2961                final int M = canceledNotifications.size();
2962                for (int i = 0; i < M; i++) {
2963                    cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
2964                            listenerName, REASON_GROUP_SUMMARY_CANCELED);
2965                }
2966            }
2967            if (canceledNotifications != null) {
2968                updateLightsLocked();
2969            }
2970            return canceledNotifications != null;
2971        }
2972    }
2973
2974    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
2975            ManagedServiceInfo listener, boolean includeCurrentProfiles) {
2976        String listenerName = listener == null ? null : listener.component.toShortString();
2977        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
2978                null, userId, 0, 0, reason, listenerName);
2979
2980        ArrayList<NotificationRecord> canceledNotifications = null;
2981        final int N = mNotificationList.size();
2982        for (int i=N-1; i>=0; i--) {
2983            NotificationRecord r = mNotificationList.get(i);
2984            if (includeCurrentProfiles) {
2985                if (!notificationMatchesCurrentProfiles(r, userId)) {
2986                    continue;
2987                }
2988            } else {
2989                if (!notificationMatchesUserId(r, userId)) {
2990                    continue;
2991                }
2992            }
2993
2994            if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
2995                            | Notification.FLAG_NO_CLEAR)) == 0) {
2996                mNotificationList.remove(i);
2997                cancelNotificationLocked(r, true, reason);
2998                // Make a note so we can cancel children later.
2999                if (canceledNotifications == null) {
3000                    canceledNotifications = new ArrayList<>();
3001                }
3002                canceledNotifications.add(r);
3003            }
3004        }
3005        int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3006        for (int i = 0; i < M; i++) {
3007            cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3008                    listenerName, REASON_GROUP_SUMMARY_CANCELED);
3009        }
3010        updateLightsLocked();
3011    }
3012
3013    // Warning: The caller is responsible for invoking updateLightsLocked().
3014    private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3015            String listenerName, int reason) {
3016        Notification n = r.getNotification();
3017        if (!n.isGroupSummary()) {
3018            return;
3019        }
3020
3021        String pkg = r.sbn.getPackageName();
3022        int userId = r.getUserId();
3023
3024        if (pkg == null) {
3025            if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3026            return;
3027        }
3028
3029        final int N = mNotificationList.size();
3030        for (int i = N - 1; i >= 0; i--) {
3031            NotificationRecord childR = mNotificationList.get(i);
3032            StatusBarNotification childSbn = childR.sbn;
3033            if (childR.getNotification().isGroupChild() &&
3034                    childR.getGroupKey().equals(r.getGroupKey())) {
3035                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3036                        childSbn.getTag(), userId, 0, 0, reason, listenerName);
3037                mNotificationList.remove(i);
3038                cancelNotificationLocked(childR, false, reason);
3039            }
3040        }
3041    }
3042
3043    // lock on mNotificationList
3044    void updateLightsLocked()
3045    {
3046        // handle notification lights
3047        NotificationRecord ledNotification = null;
3048        while (ledNotification == null && !mLights.isEmpty()) {
3049            final String owner = mLights.get(mLights.size() - 1);
3050            ledNotification = mNotificationsByKey.get(owner);
3051            if (ledNotification == null) {
3052                Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3053                mLights.remove(owner);
3054            }
3055        }
3056
3057        // Don't flash while we are in a call or screen is on
3058        if (ledNotification == null || mInCall || mScreenOn) {
3059            mNotificationLight.turnOff();
3060            mStatusBar.notificationLightOff();
3061        } else {
3062            final Notification ledno = ledNotification.sbn.getNotification();
3063            int ledARGB = ledno.ledARGB;
3064            int ledOnMS = ledno.ledOnMS;
3065            int ledOffMS = ledno.ledOffMS;
3066            if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3067                ledARGB = mDefaultNotificationColor;
3068                ledOnMS = mDefaultNotificationLedOn;
3069                ledOffMS = mDefaultNotificationLedOff;
3070            }
3071            if (mNotificationPulseEnabled) {
3072                // pulse repeatedly
3073                mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3074                        ledOnMS, ledOffMS);
3075            }
3076            // let SystemUI make an independent decision
3077            mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3078        }
3079    }
3080
3081    // lock on mNotificationList
3082    int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3083    {
3084        ArrayList<NotificationRecord> list = mNotificationList;
3085        final int len = list.size();
3086        for (int i=0; i<len; i++) {
3087            NotificationRecord r = list.get(i);
3088            if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3089                    TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3090                return i;
3091            }
3092        }
3093        return -1;
3094    }
3095
3096    // lock on mNotificationList
3097    int indexOfNotificationLocked(String key) {
3098        final int N = mNotificationList.size();
3099        for (int i = 0; i < N; i++) {
3100            if (key.equals(mNotificationList.get(i).getKey())) {
3101                return i;
3102            }
3103        }
3104        return -1;
3105    }
3106
3107    private void updateNotificationPulse() {
3108        synchronized (mNotificationList) {
3109            updateLightsLocked();
3110        }
3111    }
3112
3113    private static boolean isUidSystem(int uid) {
3114        final int appid = UserHandle.getAppId(uid);
3115        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3116    }
3117
3118    private static boolean isCallerSystem() {
3119        return isUidSystem(Binder.getCallingUid());
3120    }
3121
3122    private static void checkCallerIsSystem() {
3123        if (isCallerSystem()) {
3124            return;
3125        }
3126        throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3127    }
3128
3129    private static void checkCallerIsSystemOrSameApp(String pkg) {
3130        if (isCallerSystem()) {
3131            return;
3132        }
3133        final int uid = Binder.getCallingUid();
3134        try {
3135            ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3136                    pkg, 0, UserHandle.getCallingUserId());
3137            if (ai == null) {
3138                throw new SecurityException("Unknown package " + pkg);
3139            }
3140            if (!UserHandle.isSameApp(ai.uid, uid)) {
3141                throw new SecurityException("Calling uid " + uid + " gave package"
3142                        + pkg + " which is owned by uid " + ai.uid);
3143            }
3144        } catch (RemoteException re) {
3145            throw new SecurityException("Unknown package " + pkg + "\n" + re);
3146        }
3147    }
3148
3149    private static String callStateToString(int state) {
3150        switch (state) {
3151            case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3152            case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3153            case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3154            default: return "CALL_STATE_UNKNOWN_" + state;
3155        }
3156    }
3157
3158    private void listenForCallState() {
3159        TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3160            @Override
3161            public void onCallStateChanged(int state, String incomingNumber) {
3162                if (mCallState == state) return;
3163                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3164                mCallState = state;
3165            }
3166        }, PhoneStateListener.LISTEN_CALL_STATE);
3167    }
3168
3169    /**
3170     * Generates a NotificationRankingUpdate from 'sbns', considering only
3171     * notifications visible to the given listener.
3172     *
3173     * <p>Caller must hold a lock on mNotificationList.</p>
3174     */
3175    private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3176        int speedBumpIndex = -1;
3177        final int N = mNotificationList.size();
3178        ArrayList<String> keys = new ArrayList<String>(N);
3179        ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3180        Bundle visibilityOverrides = new Bundle();
3181        for (int i = 0; i < N; i++) {
3182            NotificationRecord record = mNotificationList.get(i);
3183            if (!isVisibleToListener(record.sbn, info)) {
3184                continue;
3185            }
3186            keys.add(record.sbn.getKey());
3187            if (record.isIntercepted()) {
3188                interceptedKeys.add(record.sbn.getKey());
3189            }
3190            if (record.getPackageVisibilityOverride()
3191                    != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3192                visibilityOverrides.putInt(record.sbn.getKey(),
3193                        record.getPackageVisibilityOverride());
3194            }
3195            // Find first min-prio notification for speedbump placement.
3196            if (speedBumpIndex == -1 &&
3197                    // Intrusiveness trumps priority, hence ignore intrusives.
3198                    !record.isRecentlyIntrusive() &&
3199                    // Currently, package priority is either PRIORITY_DEFAULT or PRIORITY_MAX, so
3200                    // scanning for PRIORITY_MIN within the package bucket PRIORITY_DEFAULT
3201                    // (or lower as a safeguard) is sufficient to find the speedbump index.
3202                    // We'll have to revisit this when more package priority buckets are introduced.
3203                    record.getPackagePriority() <= Notification.PRIORITY_DEFAULT &&
3204                    record.sbn.getNotification().priority == Notification.PRIORITY_MIN) {
3205                speedBumpIndex = keys.size() - 1;
3206            }
3207        }
3208        String[] keysAr = keys.toArray(new String[keys.size()]);
3209        String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3210        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3211                speedBumpIndex);
3212    }
3213
3214    private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3215        if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3216            return false;
3217        }
3218        // TODO: remove this for older listeners.
3219        return true;
3220    }
3221
3222    public class NotificationListeners extends ManagedServices {
3223
3224        private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3225        private boolean mNotificationGroupsDesired;
3226
3227        public NotificationListeners() {
3228            super(getContext(), mHandler, mNotificationList, mUserProfiles);
3229        }
3230
3231        @Override
3232        protected Config getConfig() {
3233            Config c = new Config();
3234            c.caption = "notification listener";
3235            c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3236            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3237            c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3238            c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3239            c.clientLabel = R.string.notification_listener_binding_label;
3240            return c;
3241        }
3242
3243        @Override
3244        protected IInterface asInterface(IBinder binder) {
3245            return INotificationListener.Stub.asInterface(binder);
3246        }
3247
3248        @Override
3249        public void onServiceAdded(ManagedServiceInfo info) {
3250            final INotificationListener listener = (INotificationListener) info.service;
3251            final NotificationRankingUpdate update;
3252            synchronized (mNotificationList) {
3253                updateNotificationGroupsDesiredLocked();
3254                update = makeRankingUpdateLocked(info);
3255            }
3256            try {
3257                listener.onListenerConnected(update);
3258            } catch (RemoteException e) {
3259                // we tried
3260            }
3261        }
3262
3263        @Override
3264        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3265            if (mListenersDisablingEffects.remove(removed)) {
3266                updateListenerHintsLocked();
3267                updateEffectsSuppressorLocked();
3268            }
3269            mLightTrimListeners.remove(removed);
3270            updateNotificationGroupsDesiredLocked();
3271        }
3272
3273        public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3274            if (trim == TRIM_LIGHT) {
3275                mLightTrimListeners.add(info);
3276            } else {
3277                mLightTrimListeners.remove(info);
3278            }
3279        }
3280
3281        public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3282            return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3283
3284        }
3285
3286        /**
3287         * asynchronously notify all listeners about a new notification
3288         *
3289         * <p>
3290         * Also takes care of removing a notification that has been visible to a listener before,
3291         * but isn't anymore.
3292         */
3293        public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3294            // Lazily initialized snapshots of the notification.
3295            StatusBarNotification sbnClone = null;
3296            StatusBarNotification sbnCloneLight = null;
3297
3298            for (final ManagedServiceInfo info : mServices) {
3299                boolean sbnVisible = isVisibleToListener(sbn, info);
3300                boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3301                // This notification hasn't been and still isn't visible -> ignore.
3302                if (!oldSbnVisible && !sbnVisible) {
3303                    continue;
3304                }
3305                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3306
3307                // This notification became invisible -> remove the old one.
3308                if (oldSbnVisible && !sbnVisible) {
3309                    final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3310                    mHandler.post(new Runnable() {
3311                        @Override
3312                        public void run() {
3313                            notifyRemoved(info, oldSbnLightClone, update);
3314                        }
3315                    });
3316                    continue;
3317                }
3318
3319                final int trim = mListeners.getOnNotificationPostedTrim(info);
3320
3321                if (trim == TRIM_LIGHT && sbnCloneLight == null) {
3322                    sbnCloneLight = sbn.cloneLight();
3323                } else if (trim == TRIM_FULL && sbnClone == null) {
3324                    sbnClone = sbn.clone();
3325                }
3326                final StatusBarNotification sbnToPost =
3327                        (trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
3328
3329                mHandler.post(new Runnable() {
3330                    @Override
3331                    public void run() {
3332                        notifyPosted(info, sbnToPost, update);
3333                    }
3334                });
3335            }
3336        }
3337
3338        /**
3339         * asynchronously notify all listeners about a removed notification
3340         */
3341        public void notifyRemovedLocked(StatusBarNotification sbn) {
3342            // make a copy in case changes are made to the underlying Notification object
3343            // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
3344            // notification
3345            final StatusBarNotification sbnLight = sbn.cloneLight();
3346            for (final ManagedServiceInfo info : mServices) {
3347                if (!isVisibleToListener(sbn, info)) {
3348                    continue;
3349                }
3350                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3351                mHandler.post(new Runnable() {
3352                    @Override
3353                    public void run() {
3354                        notifyRemoved(info, sbnLight, update);
3355                    }
3356                });
3357            }
3358        }
3359
3360        /**
3361         * asynchronously notify all listeners about a reordering of notifications
3362         */
3363        public void notifyRankingUpdateLocked() {
3364            for (final ManagedServiceInfo serviceInfo : mServices) {
3365                if (!serviceInfo.isEnabledForCurrentProfiles()) {
3366                    continue;
3367                }
3368                final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
3369                mHandler.post(new Runnable() {
3370                    @Override
3371                    public void run() {
3372                        notifyRankingUpdate(serviceInfo, update);
3373                    }
3374                });
3375            }
3376        }
3377
3378        public void notifyListenerHintsChangedLocked(final int hints) {
3379            for (final ManagedServiceInfo serviceInfo : mServices) {
3380                if (!serviceInfo.isEnabledForCurrentProfiles()) {
3381                    continue;
3382                }
3383                mHandler.post(new Runnable() {
3384                    @Override
3385                    public void run() {
3386                        notifyListenerHintsChanged(serviceInfo, hints);
3387                    }
3388                });
3389            }
3390        }
3391
3392        public void notifyInterruptionFilterChanged(final int interruptionFilter) {
3393            for (final ManagedServiceInfo serviceInfo : mServices) {
3394                if (!serviceInfo.isEnabledForCurrentProfiles()) {
3395                    continue;
3396                }
3397                mHandler.post(new Runnable() {
3398                    @Override
3399                    public void run() {
3400                        notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
3401                    }
3402                });
3403            }
3404        }
3405
3406        private void notifyPosted(final ManagedServiceInfo info,
3407                final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
3408            final INotificationListener listener = (INotificationListener)info.service;
3409            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3410            try {
3411                listener.onNotificationPosted(sbnHolder, rankingUpdate);
3412            } catch (RemoteException ex) {
3413                Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
3414            }
3415        }
3416
3417        private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
3418                NotificationRankingUpdate rankingUpdate) {
3419            if (!info.enabledAndUserMatches(sbn.getUserId())) {
3420                return;
3421            }
3422            final INotificationListener listener = (INotificationListener) info.service;
3423            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3424            try {
3425                listener.onNotificationRemoved(sbnHolder, rankingUpdate);
3426            } catch (RemoteException ex) {
3427                Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
3428            }
3429        }
3430
3431        private void notifyRankingUpdate(ManagedServiceInfo info,
3432                                         NotificationRankingUpdate rankingUpdate) {
3433            final INotificationListener listener = (INotificationListener) info.service;
3434            try {
3435                listener.onNotificationRankingUpdate(rankingUpdate);
3436            } catch (RemoteException ex) {
3437                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
3438            }
3439        }
3440
3441        private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
3442            final INotificationListener listener = (INotificationListener) info.service;
3443            try {
3444                listener.onListenerHintsChanged(hints);
3445            } catch (RemoteException ex) {
3446                Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
3447            }
3448        }
3449
3450        private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
3451                int interruptionFilter) {
3452            final INotificationListener listener = (INotificationListener) info.service;
3453            try {
3454                listener.onInterruptionFilterChanged(interruptionFilter);
3455            } catch (RemoteException ex) {
3456                Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
3457            }
3458        }
3459
3460        private boolean isListenerPackage(String packageName) {
3461            if (packageName == null) {
3462                return false;
3463            }
3464            // TODO: clean up locking object later
3465            synchronized (mNotificationList) {
3466                for (final ManagedServiceInfo serviceInfo : mServices) {
3467                    if (packageName.equals(serviceInfo.component.getPackageName())) {
3468                        return true;
3469                    }
3470                }
3471            }
3472            return false;
3473        }
3474
3475        /**
3476         * Returns whether any of the currently registered listeners wants to receive notification
3477         * groups.
3478         *
3479         * <p>Currently we assume groups are desired by non-SystemUI listeners.</p>
3480         */
3481        public boolean notificationGroupsDesired() {
3482            return mNotificationGroupsDesired;
3483        }
3484
3485        private void updateNotificationGroupsDesiredLocked() {
3486            mNotificationGroupsDesired = true;
3487            // No listeners, no groups.
3488            if (mServices.isEmpty()) {
3489                mNotificationGroupsDesired = false;
3490                return;
3491            }
3492            // One listener: Check whether it's SysUI.
3493            if (mServices.size() == 1 &&
3494                    mServices.get(0).component.getPackageName().equals("com.android.systemui")) {
3495                mNotificationGroupsDesired = false;
3496                return;
3497            }
3498        }
3499    }
3500
3501    public static final class DumpFilter {
3502        public boolean filtered = false;
3503        public String pkgFilter;
3504        public boolean zen;
3505        public long since;
3506        public boolean stats;
3507        public boolean redact = true;
3508
3509        public static DumpFilter parseFromArguments(String[] args) {
3510            final DumpFilter filter = new DumpFilter();
3511            for (int ai = 0; ai < args.length; ai++) {
3512                final String a = args[ai];
3513                if ("--noredact".equals(a) || "--reveal".equals(a)) {
3514                    filter.redact = false;
3515                } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
3516                    if (ai < args.length-1) {
3517                        ai++;
3518                        filter.pkgFilter = args[ai].trim().toLowerCase();
3519                        if (filter.pkgFilter.isEmpty()) {
3520                            filter.pkgFilter = null;
3521                        } else {
3522                            filter.filtered = true;
3523                        }
3524                    }
3525                } else if ("--zen".equals(a) || "zen".equals(a)) {
3526                    filter.filtered = true;
3527                    filter.zen = true;
3528                } else if ("--stats".equals(a)) {
3529                    filter.stats = true;
3530                    if (ai < args.length-1) {
3531                        ai++;
3532                        filter.since = Long.valueOf(args[ai]);
3533                    } else {
3534                        filter.since = 0;
3535                    }
3536                }
3537            }
3538            return filter;
3539        }
3540
3541        public boolean matches(StatusBarNotification sbn) {
3542            if (!filtered) return true;
3543            return zen ? true : sbn != null
3544                    && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
3545        }
3546
3547        public boolean matches(ComponentName component) {
3548            if (!filtered) return true;
3549            return zen ? true : component != null && matches(component.getPackageName());
3550        }
3551
3552        public boolean matches(String pkg) {
3553            if (!filtered) return true;
3554            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
3555        }
3556
3557        @Override
3558        public String toString() {
3559            return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
3560        }
3561    }
3562
3563    /**
3564     * Wrapper for a StatusBarNotification object that allows transfer across a oneway
3565     * binder without sending large amounts of data over a oneway transaction.
3566     */
3567    private static final class StatusBarNotificationHolder
3568            extends IStatusBarNotificationHolder.Stub {
3569        private StatusBarNotification mValue;
3570
3571        public StatusBarNotificationHolder(StatusBarNotification value) {
3572            mValue = value;
3573        }
3574
3575        /** Get the held value and clear it. This function should only be called once per holder */
3576        @Override
3577        public StatusBarNotification get() {
3578            StatusBarNotification value = mValue;
3579            mValue = null;
3580            return value;
3581        }
3582    }
3583
3584    private final class PolicyAccess {
3585        private static final String SEPARATOR = ":";
3586        private final String[] PERM = {
3587            android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
3588        };
3589
3590        public boolean isPackageGranted(String pkg) {
3591            return pkg != null && getGrantedPackages().contains(pkg);
3592        }
3593
3594        public void put(String pkg, boolean granted) {
3595            if (pkg == null) return;
3596            final ArraySet<String> pkgs = getGrantedPackages();
3597            boolean changed;
3598            if (granted) {
3599                changed = pkgs.add(pkg);
3600            } else {
3601                changed = pkgs.remove(pkg);
3602            }
3603            if (!changed) return;
3604            final String setting = TextUtils.join(SEPARATOR, pkgs);
3605            final int currentUser = ActivityManager.getCurrentUser();
3606            Settings.Secure.putStringForUser(getContext().getContentResolver(),
3607                    Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
3608                    setting,
3609                    currentUser);
3610            getContext().sendBroadcastAsUser(new Intent(NotificationManager
3611                    .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3612                .setPackage(pkg)
3613                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
3614        }
3615
3616        public ArraySet<String> getGrantedPackages() {
3617            final ArraySet<String> pkgs = new ArraySet<>();
3618
3619            long identity = Binder.clearCallingIdentity();
3620            try {
3621                final String setting = Settings.Secure.getStringForUser(
3622                        getContext().getContentResolver(),
3623                        Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
3624                        ActivityManager.getCurrentUser());
3625                if (setting != null) {
3626                    final String[] tokens = setting.split(SEPARATOR);
3627                    for (int i = 0; i < tokens.length; i++) {
3628                        String token = tokens[i];
3629                        if (token != null) {
3630                            token.trim();
3631                        }
3632                        if (TextUtils.isEmpty(token)) {
3633                            continue;
3634                        }
3635                        pkgs.add(token);
3636                    }
3637                }
3638            } finally {
3639                Binder.restoreCallingIdentity(identity);
3640            }
3641            return pkgs;
3642        }
3643
3644        public String[] getRequestingPackages() throws RemoteException {
3645            final ParceledListSlice list = AppGlobals.getPackageManager()
3646                    .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
3647                            ActivityManager.getCurrentUser());
3648            final List<PackageInfo> pkgs = list.getList();
3649            if (pkgs == null || pkgs.isEmpty()) return new String[0];
3650            final int N = pkgs.size();
3651            final String[] rt = new String[N];
3652            for (int i = 0; i < N; i++) {
3653                rt[i] = pkgs.get(i).packageName;
3654            }
3655            return rt;
3656        }
3657    }
3658}
3659