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