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