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