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.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 20 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; 21 import static android.app.Notification.FLAG_BUBBLE; 22 import static android.app.Notification.FLAG_FOREGROUND_SERVICE; 23 import static android.app.Notification.FLAG_INSISTENT; 24 import static android.app.Notification.FLAG_NO_CLEAR; 25 import static android.app.Notification.FLAG_ONGOING_EVENT; 26 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; 27 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; 28 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED; 29 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; 30 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; 31 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL; 32 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED; 33 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED; 34 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED; 35 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 36 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; 37 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; 38 import static android.app.NotificationManager.IMPORTANCE_LOW; 39 import static android.app.NotificationManager.IMPORTANCE_MIN; 40 import static android.app.NotificationManager.IMPORTANCE_NONE; 41 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 42 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET; 43 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 44 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 45 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 46 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 47 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 48 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 49 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 50 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 51 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 52 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; 53 import static android.content.Context.BIND_AUTO_CREATE; 54 import static android.content.Context.BIND_FOREGROUND_SERVICE; 55 import static android.content.Context.BIND_NOT_PERCEPTIBLE; 56 import static android.content.pm.PackageManager.FEATURE_LEANBACK; 57 import static android.content.pm.PackageManager.FEATURE_TELEVISION; 58 import static android.content.pm.PackageManager.MATCH_ALL; 59 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; 60 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 61 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 62 import static android.media.AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; 63 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 64 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; 65 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; 66 import static android.os.UserHandle.USER_NULL; 67 import static android.os.UserHandle.USER_SYSTEM; 68 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 69 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 70 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 71 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; 72 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; 73 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; 74 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 75 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; 76 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 77 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; 78 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; 79 import static android.service.notification.NotificationListenerService.REASON_CLICK; 80 import static android.service.notification.NotificationListenerService.REASON_ERROR; 81 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; 82 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; 83 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; 84 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; 85 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; 86 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; 87 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF; 88 import static android.service.notification.NotificationListenerService.REASON_SNOOZED; 89 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; 90 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; 91 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; 92 import static android.service.notification.NotificationListenerService.TRIM_FULL; 93 import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 94 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 95 96 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; 97 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES; 98 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES; 99 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES; 100 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 101 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 102 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 103 import static com.android.server.utils.PriorityDump.PRIORITY_ARG; 104 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; 105 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; 106 107 import android.Manifest; 108 import android.Manifest.permission; 109 import android.annotation.CallbackExecutor; 110 import android.annotation.NonNull; 111 import android.annotation.Nullable; 112 import android.annotation.RequiresPermission; 113 import android.annotation.UserIdInt; 114 import android.annotation.WorkerThread; 115 import android.app.ActivityManager; 116 import android.app.ActivityManagerInternal; 117 import android.app.AlarmManager; 118 import android.app.AppGlobals; 119 import android.app.AppOpsManager; 120 import android.app.AutomaticZenRule; 121 import android.app.IActivityManager; 122 import android.app.INotificationManager; 123 import android.app.ITransientNotification; 124 import android.app.ITransientNotificationCallback; 125 import android.app.IUriGrantsManager; 126 import android.app.KeyguardManager; 127 import android.app.Notification; 128 import android.app.NotificationChannel; 129 import android.app.NotificationChannelGroup; 130 import android.app.NotificationHistory; 131 import android.app.NotificationHistory.HistoricalNotification; 132 import android.app.NotificationManager; 133 import android.app.NotificationManager.Policy; 134 import android.app.PendingIntent; 135 import android.app.StatsManager; 136 import android.app.StatusBarManager; 137 import android.app.UriGrantsManager; 138 import android.app.admin.DeviceAdminInfo; 139 import android.app.admin.DevicePolicyManagerInternal; 140 import android.app.backup.BackupManager; 141 import android.app.role.OnRoleHoldersChangedListener; 142 import android.app.role.RoleManager; 143 import android.app.usage.UsageEvents; 144 import android.app.usage.UsageStatsManagerInternal; 145 import android.companion.ICompanionDeviceManager; 146 import android.compat.annotation.ChangeId; 147 import android.compat.annotation.EnabledAfter; 148 import android.content.BroadcastReceiver; 149 import android.content.ComponentName; 150 import android.content.ContentProvider; 151 import android.content.ContentResolver; 152 import android.content.Context; 153 import android.content.Intent; 154 import android.content.IntentFilter; 155 import android.content.pm.ApplicationInfo; 156 import android.content.pm.IPackageManager; 157 import android.content.pm.LauncherApps; 158 import android.content.pm.PackageManager; 159 import android.content.pm.PackageManager.NameNotFoundException; 160 import android.content.pm.PackageManagerInternal; 161 import android.content.pm.ParceledListSlice; 162 import android.content.pm.ShortcutInfo; 163 import android.content.pm.ShortcutServiceInternal; 164 import android.content.pm.UserInfo; 165 import android.content.res.Resources; 166 import android.database.ContentObserver; 167 import android.media.AudioAttributes; 168 import android.media.AudioManager; 169 import android.media.AudioManagerInternal; 170 import android.media.IRingtonePlayer; 171 import android.metrics.LogMaker; 172 import android.net.Uri; 173 import android.os.Binder; 174 import android.os.Build; 175 import android.os.Bundle; 176 import android.os.Environment; 177 import android.os.Handler; 178 import android.os.HandlerExecutor; 179 import android.os.HandlerThread; 180 import android.os.IBinder; 181 import android.os.IDeviceIdleController; 182 import android.os.IInterface; 183 import android.os.Looper; 184 import android.os.Message; 185 import android.os.ParcelFileDescriptor; 186 import android.os.Process; 187 import android.os.RemoteException; 188 import android.os.ResultReceiver; 189 import android.os.ServiceManager; 190 import android.os.ShellCallback; 191 import android.os.SystemProperties; 192 import android.os.Trace; 193 import android.os.UserHandle; 194 import android.os.UserManager; 195 import android.os.VibrationEffect; 196 import android.os.Vibrator; 197 import android.provider.DeviceConfig; 198 import android.provider.Settings; 199 import android.service.notification.Adjustment; 200 import android.service.notification.Condition; 201 import android.service.notification.ConversationChannelWrapper; 202 import android.service.notification.IConditionProvider; 203 import android.service.notification.INotificationListener; 204 import android.service.notification.IStatusBarNotificationHolder; 205 import android.service.notification.ListenersDisablingEffectsProto; 206 import android.service.notification.NotificationAssistantService; 207 import android.service.notification.NotificationListenerService; 208 import android.service.notification.NotificationRankingUpdate; 209 import android.service.notification.NotificationRecordProto; 210 import android.service.notification.NotificationServiceDumpProto; 211 import android.service.notification.NotificationStats; 212 import android.service.notification.SnoozeCriterion; 213 import android.service.notification.StatusBarNotification; 214 import android.service.notification.ZenModeConfig; 215 import android.service.notification.ZenModeProto; 216 import android.telephony.PhoneStateListener; 217 import android.telephony.TelephonyManager; 218 import android.text.TextUtils; 219 import android.util.ArrayMap; 220 import android.util.ArraySet; 221 import android.util.AtomicFile; 222 import android.util.IntArray; 223 import android.util.Log; 224 import android.util.Pair; 225 import android.util.Slog; 226 import android.util.SparseArray; 227 import android.util.StatsEvent; 228 import android.util.Xml; 229 import android.util.proto.ProtoOutputStream; 230 import android.view.accessibility.AccessibilityEvent; 231 import android.view.accessibility.AccessibilityManager; 232 import android.widget.RemoteViews; 233 import android.widget.Toast; 234 235 import com.android.internal.R; 236 import com.android.internal.annotations.GuardedBy; 237 import com.android.internal.annotations.VisibleForTesting; 238 import com.android.internal.compat.IPlatformCompat; 239 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; 240 import com.android.internal.logging.InstanceId; 241 import com.android.internal.logging.InstanceIdSequence; 242 import com.android.internal.logging.MetricsLogger; 243 import com.android.internal.logging.nano.MetricsProto; 244 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 245 import com.android.internal.notification.SystemNotificationChannels; 246 import com.android.internal.os.BackgroundThread; 247 import com.android.internal.os.SomeArgs; 248 import com.android.internal.statusbar.NotificationVisibility; 249 import com.android.internal.util.ArrayUtils; 250 import com.android.internal.util.CollectionUtils; 251 import com.android.internal.util.ConcurrentUtils; 252 import com.android.internal.util.DumpUtils; 253 import com.android.internal.util.FastXmlSerializer; 254 import com.android.internal.util.Preconditions; 255 import com.android.internal.util.XmlUtils; 256 import com.android.internal.util.function.TriPredicate; 257 import com.android.server.DeviceIdleInternal; 258 import com.android.server.EventLogTags; 259 import com.android.server.IoThread; 260 import com.android.server.LocalServices; 261 import com.android.server.SystemService; 262 import com.android.server.UiThread; 263 import com.android.server.lights.LightsManager; 264 import com.android.server.lights.LogicalLight; 265 import com.android.server.notification.ManagedServices.ManagedServiceInfo; 266 import com.android.server.notification.ManagedServices.UserProfiles; 267 import com.android.server.notification.toast.CustomToastRecord; 268 import com.android.server.notification.toast.TextToastRecord; 269 import com.android.server.notification.toast.ToastRecord; 270 import com.android.server.pm.PackageManagerService; 271 import com.android.server.policy.PhoneWindowManager; 272 import com.android.server.statusbar.StatusBarManagerInternal; 273 import com.android.server.uri.UriGrantsManagerInternal; 274 import com.android.server.wm.ActivityTaskManagerInternal; 275 import com.android.server.wm.WindowManagerInternal; 276 277 import libcore.io.IoUtils; 278 279 import org.json.JSONException; 280 import org.json.JSONObject; 281 import org.xmlpull.v1.XmlPullParser; 282 import org.xmlpull.v1.XmlPullParserException; 283 import org.xmlpull.v1.XmlSerializer; 284 285 import java.io.ByteArrayInputStream; 286 import java.io.ByteArrayOutputStream; 287 import java.io.File; 288 import java.io.FileDescriptor; 289 import java.io.FileNotFoundException; 290 import java.io.FileOutputStream; 291 import java.io.IOException; 292 import java.io.InputStream; 293 import java.io.OutputStream; 294 import java.io.PrintWriter; 295 import java.nio.charset.StandardCharsets; 296 import java.util.ArrayList; 297 import java.util.Arrays; 298 import java.util.HashSet; 299 import java.util.Iterator; 300 import java.util.LinkedList; 301 import java.util.List; 302 import java.util.Map.Entry; 303 import java.util.Objects; 304 import java.util.Set; 305 import java.util.concurrent.Executor; 306 import java.util.concurrent.TimeUnit; 307 import java.util.function.BiConsumer; 308 309 /** {@hide} */ 310 public class NotificationManagerService extends SystemService { 311 public static final String TAG = "NotificationService"; 312 public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 313 public static final boolean ENABLE_CHILD_NOTIFICATIONS 314 = SystemProperties.getBoolean("debug.child_notifs", true); 315 316 // pullStats report request: undecorated remote view stats 317 public static final int REPORT_REMOTE_VIEWS = 0x01; 318 319 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean( 320 "debug.notification.interruptiveness", false); 321 322 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 323 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f; 324 325 // message codes 326 static final int MESSAGE_DURATION_REACHED = 2; 327 // 3: removed to a different handler 328 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 329 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 330 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 331 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7; 332 static final int MESSAGE_ON_PACKAGE_CHANGED = 8; 333 334 // ranking thread messages 335 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 336 private static final int MESSAGE_RANKING_SORT = 1001; 337 338 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 339 static final int SHORT_DELAY = 2000; // 2 seconds 340 341 // 1 second past the ANR timeout. 342 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000; 343 344 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 345 346 static final long SNOOZE_UNTIL_UNSPECIFIED = -1; 347 348 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 349 350 static final int INVALID_UID = -1; 351 static final String ROOT_PKG = "root"; 352 353 static final boolean ENABLE_BLOCKED_TOASTS = true; 354 355 static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] { 356 Adjustment.KEY_CONTEXTUAL_ACTIONS, 357 Adjustment.KEY_TEXT_REPLIES}; 358 359 static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] { 360 RoleManager.ROLE_DIALER, 361 RoleManager.ROLE_EMERGENCY 362 }; 363 364 // When #matchesCallFilter is called from the ringer, wait at most 365 // 3s to resolve the contacts. This timeout is required since 366 // ContactsProvider might take a long time to start up. 367 // 368 // Return STARRED_CONTACT when the timeout is hit in order to avoid 369 // missed calls in ZEN mode "Important". 370 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 371 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 372 ValidateNotificationPeople.STARRED_CONTACT; 373 374 /** notification_enqueue status value for a newly enqueued notification. */ 375 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 376 377 /** notification_enqueue status value for an existing notification. */ 378 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 379 380 /** notification_enqueue status value for an ignored notification. */ 381 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 382 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds 383 384 private static final long DELAY_FOR_ASSISTANT_TIME = 200; 385 386 private static final String ACTION_NOTIFICATION_TIMEOUT = 387 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 388 private static final int REQUEST_CODE_TIMEOUT = 1; 389 private static final String SCHEME_TIMEOUT = "timeout"; 390 private static final String EXTRA_KEY = "key"; 391 392 private static final int NOTIFICATION_INSTANCE_ID_MAX = (1 << 13); 393 394 /** 395 * Apps that post custom toasts in the background will have those blocked. Apps can 396 * still post toasts created with 397 * {@link android.widget.Toast#makeText(Context, CharSequence, int)} and its variants while 398 * in the background. 399 */ 400 @ChangeId 401 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) 402 private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; 403 404 private IActivityManager mAm; 405 private ActivityTaskManagerInternal mAtm; 406 private ActivityManager mActivityManager; 407 private ActivityManagerInternal mAmi; 408 private IPackageManager mPackageManager; 409 private PackageManager mPackageManagerClient; 410 AudioManager mAudioManager; 411 AudioManagerInternal mAudioManagerInternal; 412 // Can be null for wear 413 @Nullable StatusBarManagerInternal mStatusBar; 414 Vibrator mVibrator; 415 private WindowManagerInternal mWindowManagerInternal; 416 private AlarmManager mAlarmManager; 417 private ICompanionDeviceManager mCompanionManager; 418 private AccessibilityManager mAccessibilityManager; 419 private IDeviceIdleController mDeviceIdleController; 420 private IUriGrantsManager mUgm; 421 private UriGrantsManagerInternal mUgmInternal; 422 private RoleObserver mRoleObserver; 423 private UserManager mUm; 424 private IPlatformCompat mPlatformCompat; 425 private ShortcutHelper mShortcutHelper; 426 427 final IBinder mForegroundToken = new Binder(); 428 private WorkerHandler mHandler; 429 private Handler mUiHandler; 430 private final HandlerThread mRankingThread = new HandlerThread("ranker", 431 Process.THREAD_PRIORITY_BACKGROUND); 432 433 private LogicalLight mNotificationLight; 434 LogicalLight mAttentionLight; 435 436 private long[] mFallbackVibrationPattern; 437 private boolean mUseAttentionLight; 438 boolean mHasLight = true; 439 boolean mLightEnabled; 440 boolean mSystemReady; 441 442 private boolean mDisableNotificationEffects; 443 private int mCallState; 444 private String mSoundNotificationKey; 445 private String mVibrateNotificationKey; 446 447 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects = 448 new SparseArray<>(); 449 private List<ComponentName> mEffectsSuppressors = new ArrayList<>(); 450 private int mListenerHints; // right now, all hints are global 451 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 452 453 // for enabling and disabling notification pulse behavior 454 boolean mScreenOn = true; 455 protected boolean mInCallStateOffHook = false; 456 boolean mNotificationPulseEnabled; 457 458 private Uri mInCallNotificationUri; 459 private AudioAttributes mInCallNotificationAudioAttributes; 460 private float mInCallNotificationVolume; 461 private Binder mCallNotificationToken = null; 462 463 // used as a mutex for access to all active notifications & listeners 464 final Object mNotificationLock = new Object(); 465 @GuardedBy("mNotificationLock") 466 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>(); 467 @GuardedBy("mNotificationLock") 468 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>(); 469 @GuardedBy("mNotificationLock") 470 final ArrayMap<String, InlineReplyUriRecord> mInlineReplyRecordsByKey = new ArrayMap<>(); 471 @GuardedBy("mNotificationLock") 472 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>(); 473 @GuardedBy("mNotificationLock") 474 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); 475 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>(); 476 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 477 // Keep track of `CancelNotificationRunnable`s which have been delayed due to awaiting 478 // enqueued notifications to post 479 @GuardedBy("mNotificationLock") 480 final ArrayMap<NotificationRecord, ArrayList<CancelNotificationRunnable>> mDelayedCancelations = 481 new ArrayMap<>(); 482 483 private KeyguardManager mKeyguardManager; 484 485 // The last key in this list owns the hardware. 486 ArrayList<String> mLights = new ArrayList<>(); 487 488 private AppOpsManager mAppOps; 489 private UsageStatsManagerInternal mAppUsageStats; 490 private DevicePolicyManagerInternal mDpm; 491 private StatsManager mStatsManager; 492 private StatsPullAtomCallbackImpl mPullAtomCallback; 493 494 private Archive mArchive; 495 496 // Persistent storage for notification policy 497 private AtomicFile mPolicyFile; 498 499 private static final int DB_VERSION = 1; 500 501 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 502 private static final String ATTR_VERSION = "version"; 503 504 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG = 505 "allow-secure-notifications-on-lockscreen"; 506 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value"; 507 508 @VisibleForTesting 509 RankingHelper mRankingHelper; 510 @VisibleForTesting 511 PreferencesHelper mPreferencesHelper; 512 513 private final UserProfiles mUserProfiles = new UserProfiles(); 514 private NotificationListeners mListeners; 515 private NotificationAssistants mAssistants; 516 private ConditionProviders mConditionProviders; 517 private NotificationUsageStats mUsageStats; 518 private boolean mLockScreenAllowSecureNotifications = true; 519 520 private static final int MY_UID = Process.myUid(); 521 private static final int MY_PID = Process.myPid(); 522 private static final IBinder WHITELIST_TOKEN = new Binder(); 523 protected RankingHandler mRankingHandler; 524 private long mLastOverRateLogTime; 525 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 526 527 private NotificationHistoryManager mHistoryManager; 528 protected SnoozeHelper mSnoozeHelper; 529 private GroupHelper mGroupHelper; 530 private int mAutoGroupAtCount; 531 private boolean mIsTelevision; 532 private boolean mIsAutomotive; 533 private boolean mNotificationEffectsEnabledForAutomotive; 534 private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener; 535 536 private int mWarnRemoteViewsSizeBytes; 537 private int mStripRemoteViewsSizeBytes; 538 539 private MetricsLogger mMetricsLogger; 540 private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; 541 542 private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); 543 private NotificationRecordLogger mNotificationRecordLogger; 544 private InstanceIdSequence mNotificationInstanceIdSequence; 545 private Set<String> mMsgPkgsAllowedAsConvos = new HashSet(); 546 private final InjectableSystemClock mSystemClock; 547 548 static class Archive { 549 final SparseArray<Boolean> mEnabled; 550 final int mBufferSize; 551 final LinkedList<Pair<StatusBarNotification, Integer>> mBuffer; 552 Archive(int size)553 public Archive(int size) { 554 mBufferSize = size; 555 mBuffer = new LinkedList<>(); 556 mEnabled = new SparseArray<>(); 557 } 558 toString()559 public String toString() { 560 final StringBuilder sb = new StringBuilder(); 561 final int N = mBuffer.size(); 562 sb.append("Archive ("); 563 sb.append(N); 564 sb.append(" notification"); 565 sb.append((N==1)?")":"s)"); 566 return sb.toString(); 567 } 568 record(StatusBarNotification sbn, int reason)569 public void record(StatusBarNotification sbn, int reason) { 570 if (!mEnabled.get(sbn.getNormalizedUserId(), false)) { 571 return; 572 } 573 if (mBuffer.size() == mBufferSize) { 574 mBuffer.removeFirst(); 575 } 576 577 // We don't want to store the heavy bits of the notification in the archive, 578 // but other clients in the system process might be using the object, so we 579 // store a (lightened) copy. 580 mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason)); 581 } 582 descendingIterator()583 public Iterator<Pair<StatusBarNotification, Integer>> descendingIterator() { 584 return mBuffer.descendingIterator(); 585 } 586 getArray(int count, boolean includeSnoozed)587 public StatusBarNotification[] getArray(int count, boolean includeSnoozed) { 588 if (count == 0) count = mBufferSize; 589 List<StatusBarNotification> a = new ArrayList(); 590 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); 591 int i=0; 592 while (iter.hasNext() && i < count) { 593 Pair<StatusBarNotification, Integer> pair = iter.next(); 594 if (pair.second != REASON_SNOOZED || includeSnoozed) { 595 i++; 596 a.add(pair.first); 597 } 598 } 599 return a.toArray(new StatusBarNotification[a.size()]); 600 } 601 updateHistoryEnabled(@serIdInt int userId, boolean enabled)602 public void updateHistoryEnabled(@UserIdInt int userId, boolean enabled) { 603 mEnabled.put(userId, enabled); 604 605 if (!enabled) { 606 for (int i = mBuffer.size() - 1; i >= 0; i--) { 607 if (userId == mBuffer.get(i).first.getNormalizedUserId()) { 608 mBuffer.remove(i); 609 } 610 } 611 } 612 } 613 } 614 loadDefaultApprovedServices(int userId)615 void loadDefaultApprovedServices(int userId) { 616 mListeners.loadDefaultsFromConfig(); 617 618 mConditionProviders.loadDefaultsFromConfig(); 619 620 mAssistants.loadDefaultsFromConfig(); 621 } 622 allowDefaultApprovedServices(int userId)623 protected void allowDefaultApprovedServices(int userId) { 624 ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents(); 625 for (int i = 0; i < defaultListeners.size(); i++) { 626 ComponentName cn = defaultListeners.valueAt(i); 627 allowNotificationListener(userId, cn); 628 } 629 630 ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages(); 631 for (int i = 0; i < defaultDnds.size(); i++) { 632 allowDndPackage(defaultDnds.valueAt(i)); 633 } 634 635 setDefaultAssistantForUser(userId); 636 } 637 setDefaultAssistantForUser(int userId)638 protected void setDefaultAssistantForUser(int userId) { 639 String overrideDefaultAssistantString = DeviceConfig.getProperty( 640 DeviceConfig.NAMESPACE_SYSTEMUI, 641 SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE); 642 if (overrideDefaultAssistantString != null) { 643 ArraySet<ComponentName> approved = mAssistants.queryPackageForServices( 644 overrideDefaultAssistantString, 645 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 646 userId); 647 for (int i = 0; i < approved.size(); i++) { 648 if (allowAssistant(userId, approved.valueAt(i))) return; 649 } 650 } 651 ArraySet<ComponentName> defaults = mAssistants.getDefaultComponents(); 652 // We should have only one default assistant by default 653 // allowAssistant should execute once in practice 654 for (int i = 0; i < defaults.size(); i++) { 655 ComponentName cn = defaults.valueAt(i); 656 if (allowAssistant(userId, cn)) return; 657 } 658 } 659 660 /** 661 * This method will update the flags of the summary. 662 * It will set it to FLAG_ONGOING_EVENT if any of its group members 663 * has the same flag. It will delete the flag otherwise 664 * @param userId user id of the autogroup summary 665 * @param pkg package of the autogroup summary 666 * @param needsOngoingFlag true if the group has at least one ongoing notification 667 * @param isAppForeground true if the app is currently in the foreground. 668 */ 669 @GuardedBy("mNotificationLock") updateAutobundledSummaryFlags(int userId, String pkg, boolean needsOngoingFlag, boolean isAppForeground)670 protected void updateAutobundledSummaryFlags(int userId, String pkg, boolean needsOngoingFlag, 671 boolean isAppForeground) { 672 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 673 if (summaries == null) { 674 return; 675 } 676 String summaryKey = summaries.get(pkg); 677 if (summaryKey == null) { 678 return; 679 } 680 NotificationRecord summary = mNotificationsByKey.get(summaryKey); 681 if (summary == null) { 682 return; 683 } 684 int oldFlags = summary.getSbn().getNotification().flags; 685 if (needsOngoingFlag) { 686 summary.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; 687 } else { 688 summary.getSbn().getNotification().flags &= ~FLAG_ONGOING_EVENT; 689 } 690 691 if (summary.getSbn().getNotification().flags != oldFlags) { 692 mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground)); 693 } 694 } 695 allowDndPackage(String packageName)696 private void allowDndPackage(String packageName) { 697 try { 698 getBinderService().setNotificationPolicyAccessGranted(packageName, true); 699 } catch (RemoteException e) { 700 e.printStackTrace(); 701 } 702 } 703 allowNotificationListener(int userId, ComponentName cn)704 private void allowNotificationListener(int userId, ComponentName cn) { 705 706 try { 707 getBinderService().setNotificationListenerAccessGrantedForUser(cn, 708 userId, true); 709 } catch (RemoteException e) { 710 e.printStackTrace(); 711 } 712 } 713 allowAssistant(int userId, ComponentName candidate)714 private boolean allowAssistant(int userId, ComponentName candidate) { 715 Set<ComponentName> validAssistants = 716 mAssistants.queryPackageForServices( 717 null, 718 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); 719 if (candidate != null && validAssistants.contains(candidate)) { 720 setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true); 721 return true; 722 } 723 return false; 724 } 725 readPolicyXml(InputStream stream, boolean forRestore, int userId)726 void readPolicyXml(InputStream stream, boolean forRestore, int userId) 727 throws XmlPullParserException, NumberFormatException, IOException { 728 final XmlPullParser parser = Xml.newPullParser(); 729 parser.setInput(stream, StandardCharsets.UTF_8.name()); 730 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY); 731 boolean migratedManagedServices = false; 732 boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId); 733 int outerDepth = parser.getDepth(); 734 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 735 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) { 736 mZenModeHelper.readXml(parser, forRestore, userId); 737 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){ 738 mPreferencesHelper.readXml(parser, forRestore, userId); 739 } 740 if (mListeners.getConfig().xmlTag.equals(parser.getName())) { 741 if (ineligibleForManagedServices) { 742 continue; 743 } 744 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 745 migratedManagedServices = true; 746 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) { 747 if (ineligibleForManagedServices) { 748 continue; 749 } 750 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 751 migratedManagedServices = true; 752 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) { 753 if (ineligibleForManagedServices) { 754 continue; 755 } 756 mConditionProviders.readXml( 757 parser, mAllowedManagedServicePackages, forRestore, userId); 758 migratedManagedServices = true; 759 } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) { 760 mSnoozeHelper.readXml(parser, mSystemClock.currentTimeMillis()); 761 } 762 if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) { 763 if (forRestore && userId != UserHandle.USER_SYSTEM) { 764 continue; 765 } 766 mLockScreenAllowSecureNotifications = 767 safeBoolean(parser.getAttributeValue(null, 768 LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true); 769 } 770 } 771 772 if (!migratedManagedServices) { 773 mListeners.migrateToXml(); 774 mAssistants.migrateToXml(); 775 mConditionProviders.migrateToXml(); 776 handleSavePolicyFile(); 777 } 778 779 mAssistants.resetDefaultAssistantsIfNecessary(); 780 } 781 782 @VisibleForTesting loadPolicyFile()783 protected void loadPolicyFile() { 784 if (DBG) Slog.d(TAG, "loadPolicyFile"); 785 synchronized (mPolicyFile) { 786 InputStream infile = null; 787 try { 788 infile = mPolicyFile.openRead(); 789 readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL); 790 } catch (FileNotFoundException e) { 791 // No data yet 792 // Load default managed services approvals 793 loadDefaultApprovedServices(USER_SYSTEM); 794 allowDefaultApprovedServices(USER_SYSTEM); 795 } catch (IOException e) { 796 Log.wtf(TAG, "Unable to read notification policy", e); 797 } catch (NumberFormatException e) { 798 Log.wtf(TAG, "Unable to parse notification policy", e); 799 } catch (XmlPullParserException e) { 800 Log.wtf(TAG, "Unable to parse notification policy", e); 801 } finally { 802 IoUtils.closeQuietly(infile); 803 } 804 } 805 } 806 807 @VisibleForTesting handleSavePolicyFile()808 protected void handleSavePolicyFile() { 809 if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) { 810 IoThread.getHandler().post(mSavePolicyFile); 811 } 812 } 813 814 private final class SavePolicyFileRunnable implements Runnable { 815 @Override run()816 public void run() { 817 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 818 synchronized (mPolicyFile) { 819 final FileOutputStream stream; 820 try { 821 stream = mPolicyFile.startWrite(); 822 } catch (IOException e) { 823 Slog.w(TAG, "Failed to save policy file", e); 824 return; 825 } 826 827 try { 828 writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL); 829 mPolicyFile.finishWrite(stream); 830 } catch (IOException e) { 831 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 832 mPolicyFile.failWrite(stream); 833 } 834 } 835 BackupManager.dataChanged(getContext().getPackageName()); 836 } 837 } 838 writePolicyXml(OutputStream stream, boolean forBackup, int userId)839 private void writePolicyXml(OutputStream stream, boolean forBackup, int userId) 840 throws IOException { 841 final XmlSerializer out = new FastXmlSerializer(); 842 out.setOutput(stream, StandardCharsets.UTF_8.name()); 843 out.startDocument(null, true); 844 out.startTag(null, TAG_NOTIFICATION_POLICY); 845 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 846 mZenModeHelper.writeXml(out, forBackup, null, userId); 847 mPreferencesHelper.writeXml(out, forBackup, userId); 848 mListeners.writeXml(out, forBackup, userId); 849 mAssistants.writeXml(out, forBackup, userId); 850 mSnoozeHelper.writeXml(out); 851 mConditionProviders.writeXml(out, forBackup, userId); 852 if (!forBackup || userId == UserHandle.USER_SYSTEM) { 853 writeSecureNotificationsPolicy(out); 854 } 855 out.endTag(null, TAG_NOTIFICATION_POLICY); 856 out.endDocument(); 857 } 858 859 @VisibleForTesting 860 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 861 862 @Override 863 public void prepareForPossibleShutdown() { 864 mHistoryManager.triggerWriteToDisk(); 865 } 866 867 @Override 868 public void onSetDisabled(int status) { 869 synchronized (mNotificationLock) { 870 mDisableNotificationEffects = 871 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 872 if (disableNotificationEffects(null) != null) { 873 // cancel whatever's going on 874 long identity = Binder.clearCallingIdentity(); 875 try { 876 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 877 if (player != null) { 878 player.stopAsync(); 879 } 880 } catch (RemoteException e) { 881 } finally { 882 Binder.restoreCallingIdentity(identity); 883 } 884 885 identity = Binder.clearCallingIdentity(); 886 try { 887 mVibrator.cancel(); 888 } finally { 889 Binder.restoreCallingIdentity(identity); 890 } 891 } 892 } 893 } 894 895 @Override 896 public void onClearAll(int callingUid, int callingPid, int userId) { 897 synchronized (mNotificationLock) { 898 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null, 899 /*includeCurrentProfiles*/ true); 900 } 901 } 902 903 @Override 904 public void onNotificationClick(int callingUid, int callingPid, String key, 905 NotificationVisibility nv) { 906 exitIdle(); 907 synchronized (mNotificationLock) { 908 NotificationRecord r = mNotificationsByKey.get(key); 909 if (r == null) { 910 Slog.w(TAG, "No notification with key: " + key); 911 return; 912 } 913 final long now = mSystemClock.currentTimeMillis(); 914 MetricsLogger.action(r.getItemLogMaker() 915 .setType(MetricsEvent.TYPE_ACTION) 916 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 917 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); 918 mNotificationRecordLogger.log( 919 NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, r); 920 EventLogTags.writeNotificationClicked(key, 921 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 922 nv.rank, nv.count); 923 924 StatusBarNotification sbn = r.getSbn(); 925 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 926 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 927 FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE, false, r.getUserId(), 928 REASON_CLICK, nv.rank, nv.count, null); 929 nv.recycle(); 930 reportUserInteraction(r); 931 } 932 } 933 934 @Override 935 public void onNotificationActionClick(int callingUid, int callingPid, String key, 936 int actionIndex, Notification.Action action, NotificationVisibility nv, 937 boolean generatedByAssistant) { 938 exitIdle(); 939 synchronized (mNotificationLock) { 940 NotificationRecord r = mNotificationsByKey.get(key); 941 if (r == null) { 942 Slog.w(TAG, "No notification with key: " + key); 943 return; 944 } 945 final long now = mSystemClock.currentTimeMillis(); 946 MetricsLogger.action(r.getLogMaker(now) 947 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) 948 .setType(MetricsEvent.TYPE_ACTION) 949 .setSubtype(actionIndex) 950 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 951 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count) 952 .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART, 953 action.isContextual() ? 1 : 0) 954 .addTaggedData( 955 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 956 generatedByAssistant ? 1 : 0) 957 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 958 nv.location.toMetricsEventEnum())); 959 mNotificationRecordLogger.log( 960 NotificationRecordLogger.NotificationEvent.fromAction(actionIndex, 961 generatedByAssistant, action.isContextual()), r); 962 EventLogTags.writeNotificationActionClicked(key, actionIndex, 963 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 964 nv.rank, nv.count); 965 nv.recycle(); 966 reportUserInteraction(r); 967 mAssistants.notifyAssistantActionClicked( 968 r.getSbn(), actionIndex, action, generatedByAssistant); 969 } 970 } 971 972 @Override 973 public void onNotificationClear(int callingUid, int callingPid, 974 String pkg, String tag, int id, int userId, String key, 975 @NotificationStats.DismissalSurface int dismissalSurface, 976 @NotificationStats.DismissalSentiment int dismissalSentiment, 977 NotificationVisibility nv) { 978 synchronized (mNotificationLock) { 979 NotificationRecord r = mNotificationsByKey.get(key); 980 if (r != null) { 981 r.recordDismissalSurface(dismissalSurface); 982 r.recordDismissalSentiment(dismissalSentiment); 983 } 984 } 985 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 986 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE, 987 true, userId, REASON_CANCEL, nv.rank, nv.count,null); 988 nv.recycle(); 989 } 990 991 @Override 992 public void onPanelRevealed(boolean clearEffects, int items) { 993 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL); 994 MetricsLogger.histogram(getContext(), "note_load", items); 995 mNotificationRecordLogger.log( 996 NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN); 997 EventLogTags.writeNotificationPanelRevealed(items); 998 if (clearEffects) { 999 clearEffects(); 1000 } 1001 mAssistants.onPanelRevealed(items); 1002 } 1003 1004 @Override 1005 public void onPanelHidden() { 1006 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL); 1007 mNotificationRecordLogger.log( 1008 NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE); 1009 EventLogTags.writeNotificationPanelHidden(); 1010 mAssistants.onPanelHidden(); 1011 } 1012 1013 @Override 1014 public void clearEffects() { 1015 synchronized (mNotificationLock) { 1016 if (DBG) Slog.d(TAG, "clearEffects"); 1017 clearSoundLocked(); 1018 clearVibrateLocked(); 1019 clearLightsLocked(); 1020 } 1021 } 1022 1023 @Override 1024 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, 1025 int id, int uid, int initialPid, String message, int userId) { 1026 final boolean fgService; 1027 synchronized (mNotificationLock) { 1028 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 1029 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; 1030 } 1031 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 1032 REASON_ERROR, null); 1033 if (fgService) { 1034 // Still crash for foreground services, preventing the not-crash behaviour abused 1035 // by apps to give us a garbage notification and silently start a fg service. 1036 Binder.withCleanCallingIdentity( 1037 () -> mAm.crashApplication(uid, initialPid, pkg, -1, 1038 "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " 1039 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " 1040 + message, true /* force */)); 1041 } 1042 } 1043 1044 @Override 1045 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 1046 NotificationVisibility[] noLongerVisibleKeys) { 1047 synchronized (mNotificationLock) { 1048 for (NotificationVisibility nv : newlyVisibleKeys) { 1049 NotificationRecord r = mNotificationsByKey.get(nv.key); 1050 if (r == null) continue; 1051 if (!r.isSeen()) { 1052 // Report to usage stats that notification was made visible 1053 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key); 1054 reportSeen(r); 1055 } 1056 r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger); 1057 mAssistants.notifyAssistantVisibilityChangedLocked(r.getSbn(), true); 1058 boolean isHun = (nv.location 1059 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP); 1060 // hasBeenVisiblyExpanded must be called after updating the expansion state of 1061 // the NotificationRecord to ensure the expansion state is up-to-date. 1062 if (isHun || r.hasBeenVisiblyExpanded()) { 1063 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum()); 1064 } 1065 maybeRecordInterruptionLocked(r); 1066 nv.recycle(); 1067 } 1068 // Note that we might receive this event after notifications 1069 // have already left the system, e.g. after dismissing from the 1070 // shade. Hence not finding notifications in 1071 // mNotificationsByKey is not an exceptional condition. 1072 for (NotificationVisibility nv : noLongerVisibleKeys) { 1073 NotificationRecord r = mNotificationsByKey.get(nv.key); 1074 if (r == null) continue; 1075 r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger); 1076 mAssistants.notifyAssistantVisibilityChangedLocked(r.getSbn(), false); 1077 nv.recycle(); 1078 } 1079 } 1080 } 1081 1082 @Override 1083 public void onNotificationExpansionChanged(String key, 1084 boolean userAction, boolean expanded, int notificationLocation) { 1085 synchronized (mNotificationLock) { 1086 NotificationRecord r = mNotificationsByKey.get(key); 1087 if (r != null) { 1088 r.stats.onExpansionChanged(userAction, expanded); 1089 // hasBeenVisiblyExpanded must be called after updating the expansion state of 1090 // the NotificationRecord to ensure the expansion state is up-to-date. 1091 if (r.hasBeenVisiblyExpanded()) { 1092 logSmartSuggestionsVisible(r, notificationLocation); 1093 } 1094 if (userAction) { 1095 MetricsLogger.action(r.getItemLogMaker() 1096 .setType(expanded ? MetricsEvent.TYPE_DETAIL 1097 : MetricsEvent.TYPE_COLLAPSE)); 1098 mNotificationRecordLogger.log( 1099 NotificationRecordLogger.NotificationEvent.fromExpanded(expanded, 1100 userAction), 1101 r); 1102 } 1103 if (expanded && userAction) { 1104 r.recordExpanded(); 1105 reportUserInteraction(r); 1106 } 1107 mAssistants.notifyAssistantExpansionChangedLocked( 1108 r.getSbn(), userAction, expanded); 1109 } 1110 } 1111 } 1112 1113 @Override 1114 public void onNotificationDirectReplied(String key) { 1115 exitIdle(); 1116 synchronized (mNotificationLock) { 1117 NotificationRecord r = mNotificationsByKey.get(key); 1118 if (r != null) { 1119 r.recordDirectReplied(); 1120 mMetricsLogger.write(r.getLogMaker() 1121 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION) 1122 .setType(MetricsEvent.TYPE_ACTION)); 1123 mNotificationRecordLogger.log( 1124 NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED, 1125 r); 1126 reportUserInteraction(r); 1127 mAssistants.notifyAssistantNotificationDirectReplyLocked(r.getSbn()); 1128 } 1129 } 1130 } 1131 1132 @Override 1133 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, 1134 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) { 1135 synchronized (mNotificationLock) { 1136 NotificationRecord r = mNotificationsByKey.get(key); 1137 if (r != null) { 1138 r.setNumSmartRepliesAdded(smartReplyCount); 1139 r.setNumSmartActionsAdded(smartActionCount); 1140 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 1141 r.setEditChoicesBeforeSending(editBeforeSending); 1142 } 1143 } 1144 } 1145 1146 @Override 1147 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply, 1148 int notificationLocation, boolean modifiedBeforeSending) { 1149 1150 synchronized (mNotificationLock) { 1151 NotificationRecord r = mNotificationsByKey.get(key); 1152 if (r != null) { 1153 LogMaker logMaker = r.getLogMaker() 1154 .setCategory(MetricsEvent.SMART_REPLY_ACTION) 1155 .setSubtype(replyIndex) 1156 .addTaggedData( 1157 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1158 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1159 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 1160 notificationLocation) 1161 .addTaggedData( 1162 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1163 r.getEditChoicesBeforeSending() ? 1 : 0) 1164 .addTaggedData( 1165 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING, 1166 modifiedBeforeSending ? 1 : 0); 1167 mMetricsLogger.write(logMaker); 1168 mNotificationRecordLogger.log( 1169 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED, 1170 r); 1171 // Treat clicking on a smart reply as a user interaction. 1172 reportUserInteraction(r); 1173 mAssistants.notifyAssistantSuggestedReplySent( 1174 r.getSbn(), reply, r.getSuggestionsGeneratedByAssistant()); 1175 } 1176 } 1177 } 1178 1179 @Override 1180 public void onNotificationSettingsViewed(String key) { 1181 synchronized (mNotificationLock) { 1182 NotificationRecord r = mNotificationsByKey.get(key); 1183 if (r != null) { 1184 r.recordViewedSettings(); 1185 } 1186 } 1187 } 1188 1189 @Override 1190 public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) { 1191 synchronized (mNotificationLock) { 1192 NotificationRecord r = mNotificationsByKey.get(key); 1193 if (r != null) { 1194 if (!isBubble) { 1195 // This happens if the user has dismissed the bubble but the notification 1196 // is still active in the shade, enqueuing would create a bubble since 1197 // the notification is technically allowed. Flip the flag so that 1198 // apps querying noMan will know that their notification is not showing 1199 // as a bubble. 1200 r.getNotification().flags &= ~FLAG_BUBBLE; 1201 r.setFlagBubbleRemoved(true); 1202 } else { 1203 // Enqueue will trigger resort & if the flag is allowed to be true it'll 1204 // be applied there. 1205 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 1206 r.setFlagBubbleRemoved(false); 1207 if (r.getNotification().getBubbleMetadata() != null) { 1208 r.getNotification().getBubbleMetadata().setFlags(flags); 1209 } 1210 // Force isAppForeground true here, because for sysui's purposes we 1211 // want to adjust the flag behaviour. 1212 mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), 1213 r, true /* isAppForeground*/)); 1214 } 1215 } 1216 } 1217 } 1218 1219 @Override 1220 public void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed) { 1221 synchronized (mNotificationLock) { 1222 NotificationRecord r = mNotificationsByKey.get(key); 1223 if (r != null) { 1224 Notification.BubbleMetadata data = r.getNotification().getBubbleMetadata(); 1225 if (data == null) { 1226 // No data, do nothing 1227 return; 1228 } 1229 boolean currentlySuppressed = data.isNotificationSuppressed(); 1230 if (currentlySuppressed == isSuppressed) { 1231 // No changes, do nothing 1232 return; 1233 } 1234 int flags = data.getFlags(); 1235 if (isSuppressed) { 1236 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 1237 } else { 1238 flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 1239 } 1240 data.setFlags(flags); 1241 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 1242 mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r, 1243 true /* isAppForeground */)); 1244 } 1245 } 1246 } 1247 1248 @Override 1249 /** 1250 * Grant permission to read the specified URI to the package specified in the 1251 * NotificationRecord associated with the given key. The callingUid represents the UID of 1252 * SystemUI from which this method is being called. 1253 * 1254 * For this to work, SystemUI must have permission to read the URI when running under the 1255 * user associated with the NotificationRecord, and this grant will fail when trying 1256 * to grant URI permissions across users. 1257 */ 1258 public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, 1259 String packageName, int callingUid) { 1260 synchronized (mNotificationLock) { 1261 InlineReplyUriRecord r = mInlineReplyRecordsByKey.get(key); 1262 if (r == null) { 1263 InlineReplyUriRecord newRecord = new InlineReplyUriRecord( 1264 mUgmInternal.newUriPermissionOwner("INLINE_REPLY:" + key), 1265 user, 1266 packageName, 1267 key); 1268 r = newRecord; 1269 mInlineReplyRecordsByKey.put(key, r); 1270 } 1271 IBinder owner = r.getPermissionOwner(); 1272 int uid = callingUid; 1273 int userId = r.getUserId(); 1274 if (UserHandle.getUserId(uid) != userId) { 1275 try { 1276 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 1277 if (pkgs == null) { 1278 Log.e(TAG, "Cannot grant uri permission to unknown UID: " 1279 + callingUid); 1280 } 1281 final String pkg = pkgs[0]; // Get the SystemUI package 1282 // Find the UID for SystemUI for the correct user 1283 uid = mPackageManager.getPackageUid(pkg, 0, userId); 1284 } catch (RemoteException re) { 1285 Log.e(TAG, "Cannot talk to package manager", re); 1286 } 1287 } 1288 r.addUri(uri); 1289 grantUriPermission(owner, uri, uid, r.getPackageName(), userId); 1290 } 1291 } 1292 1293 @Override 1294 /** 1295 * Clears inline URI permission grants by destroying the permission owner for the specified 1296 * notification. 1297 */ 1298 public void clearInlineReplyUriPermissions(String key, int callingUid) { 1299 synchronized (mNotificationLock) { 1300 InlineReplyUriRecord uriRecord = mInlineReplyRecordsByKey.get(key); 1301 if (uriRecord != null) { 1302 destroyPermissionOwner(uriRecord.getPermissionOwner(), uriRecord.getUserId(), 1303 "INLINE_REPLY: " + uriRecord.getKey()); 1304 mInlineReplyRecordsByKey.remove(key); 1305 } 1306 } 1307 } 1308 }; 1309 1310 @VisibleForTesting logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)1311 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) { 1312 // If the newly visible notification has smart suggestions 1313 // then log that the user has seen them. 1314 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0) 1315 && !r.hasSeenSmartReplies()) { 1316 r.setSeenSmartReplies(true); 1317 LogMaker logMaker = r.getLogMaker() 1318 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE) 1319 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT, 1320 r.getNumSmartRepliesAdded()) 1321 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT, 1322 r.getNumSmartActionsAdded()) 1323 .addTaggedData( 1324 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1325 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1326 // The fields in the NotificationVisibility.NotificationLocation enum map 1327 // directly to the fields in the MetricsEvent.NotificationLocation enum. 1328 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation) 1329 .addTaggedData( 1330 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1331 r.getEditChoicesBeforeSending() ? 1 : 0); 1332 mMetricsLogger.write(logMaker); 1333 mNotificationRecordLogger.log( 1334 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLY_VISIBLE, 1335 r); 1336 } 1337 } 1338 1339 @GuardedBy("mNotificationLock") clearSoundLocked()1340 void clearSoundLocked() { 1341 mSoundNotificationKey = null; 1342 long identity = Binder.clearCallingIdentity(); 1343 try { 1344 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 1345 if (player != null) { 1346 player.stopAsync(); 1347 } 1348 } catch (RemoteException e) { 1349 } finally { 1350 Binder.restoreCallingIdentity(identity); 1351 } 1352 } 1353 1354 @GuardedBy("mNotificationLock") clearVibrateLocked()1355 void clearVibrateLocked() { 1356 mVibrateNotificationKey = null; 1357 long identity = Binder.clearCallingIdentity(); 1358 try { 1359 mVibrator.cancel(); 1360 } finally { 1361 Binder.restoreCallingIdentity(identity); 1362 } 1363 } 1364 1365 @GuardedBy("mNotificationLock") clearLightsLocked()1366 private void clearLightsLocked() { 1367 // light 1368 mLights.clear(); 1369 updateLightsLocked(); 1370 } 1371 1372 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { 1373 @Override 1374 public void onReceive(Context context, Intent intent) { 1375 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 1376 // update system notification channels 1377 SystemNotificationChannels.createAll(context); 1378 mZenModeHelper.updateDefaultZenRules(); 1379 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser()); 1380 } 1381 } 1382 }; 1383 1384 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() { 1385 @Override 1386 public void onReceive(Context context, Intent intent) { 1387 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) { 1388 try { 1389 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); 1390 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); 1391 int restoredFromSdkInt = intent.getIntExtra( 1392 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0); 1393 mListeners.onSettingRestored( 1394 element, newValue, restoredFromSdkInt, getSendingUserId()); 1395 mConditionProviders.onSettingRestored( 1396 element, newValue, restoredFromSdkInt, getSendingUserId()); 1397 } catch (Exception e) { 1398 Slog.wtf(TAG, "Cannot restore managed services from settings", e); 1399 } 1400 } 1401 } 1402 }; 1403 1404 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() { 1405 @Override 1406 public void onReceive(Context context, Intent intent) { 1407 String action = intent.getAction(); 1408 if (action == null) { 1409 return; 1410 } 1411 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) { 1412 final NotificationRecord record; 1413 synchronized (mNotificationLock) { 1414 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY)); 1415 } 1416 if (record != null) { 1417 cancelNotification(record.getSbn().getUid(), record.getSbn().getInitialPid(), 1418 record.getSbn().getPackageName(), record.getSbn().getTag(), 1419 record.getSbn().getId(), 0, 1420 FLAG_FOREGROUND_SERVICE, true, record.getUserId(), 1421 REASON_TIMEOUT, null); 1422 } 1423 } 1424 } 1425 }; 1426 1427 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 1428 @Override 1429 public void onReceive(Context context, Intent intent) { 1430 String action = intent.getAction(); 1431 if (action == null) { 1432 return; 1433 } 1434 1435 boolean queryRestart = false; 1436 boolean queryRemove = false; 1437 boolean packageChanged = false; 1438 boolean cancelNotifications = true; 1439 boolean hideNotifications = false; 1440 boolean unhideNotifications = false; 1441 int reason = REASON_PACKAGE_CHANGED; 1442 1443 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1444 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 1445 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1446 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 1447 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 1448 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) 1449 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED) 1450 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED) 1451 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 1452 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1453 UserHandle.USER_ALL); 1454 String pkgList[] = null; 1455 int uidList[] = null; 1456 boolean removingPackage = queryRemove && 1457 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 1458 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage); 1459 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1460 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1461 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1462 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 1463 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1464 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1465 cancelNotifications = false; 1466 hideNotifications = true; 1467 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { 1468 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1469 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1470 cancelNotifications = false; 1471 unhideNotifications = true; 1472 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 1473 final int distractionRestrictions = 1474 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS, 1475 PackageManager.RESTRICTION_NONE); 1476 if ((distractionRestrictions 1477 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) { 1478 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1479 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1480 cancelNotifications = false; 1481 hideNotifications = true; 1482 } else { 1483 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1484 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1485 cancelNotifications = false; 1486 unhideNotifications = true; 1487 } 1488 1489 } else if (queryRestart) { 1490 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 1491 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 1492 } else { 1493 Uri uri = intent.getData(); 1494 if (uri == null) { 1495 return; 1496 } 1497 String pkgName = uri.getSchemeSpecificPart(); 1498 if (pkgName == null) { 1499 return; 1500 } 1501 if (packageChanged) { 1502 // We cancel notifications for packages which have just been disabled 1503 try { 1504 final int enabled = mPackageManager.getApplicationEnabledSetting( 1505 pkgName, 1506 changeUserId != UserHandle.USER_ALL ? changeUserId : 1507 USER_SYSTEM); 1508 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 1509 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 1510 cancelNotifications = false; 1511 } 1512 } catch (IllegalArgumentException e) { 1513 // Package doesn't exist; probably racing with uninstall. 1514 // cancelNotifications is already true, so nothing to do here. 1515 if (DBG) { 1516 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 1517 } 1518 } catch (RemoteException e) { 1519 // Failed to talk to PackageManagerService Should never happen! 1520 } 1521 } 1522 pkgList = new String[]{pkgName}; 1523 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 1524 } 1525 if (pkgList != null && (pkgList.length > 0)) { 1526 if (cancelNotifications) { 1527 for (String pkgName : pkgList) { 1528 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, 1529 !queryRestart, changeUserId, reason, null); 1530 } 1531 } else if (hideNotifications) { 1532 hideNotificationsForPackages(pkgList); 1533 } else if (unhideNotifications) { 1534 unhideNotificationsForPackages(pkgList); 1535 } 1536 } 1537 1538 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList); 1539 } 1540 } 1541 }; 1542 1543 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 1544 @Override 1545 public void onReceive(Context context, Intent intent) { 1546 String action = intent.getAction(); 1547 1548 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1549 // Keep track of screen on/off state, but do not turn off the notification light 1550 // until user passes through the lock screen or views the notification. 1551 mScreenOn = true; 1552 updateNotificationPulse(); 1553 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1554 mScreenOn = false; 1555 updateNotificationPulse(); 1556 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 1557 mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK 1558 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 1559 updateNotificationPulse(); 1560 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 1561 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1562 if (userHandle >= 0) { 1563 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle, 1564 REASON_USER_STOPPED, null); 1565 } 1566 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 1567 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1568 if (userHandle >= 0) { 1569 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle, 1570 REASON_PROFILE_TURNED_OFF, null); 1571 } 1572 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1573 // turn off LED when user passes through lock screen 1574 if (mNotificationLight != null) { 1575 mNotificationLight.turnOff(); 1576 } 1577 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 1578 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1579 mUserProfiles.updateCache(context); 1580 if (!mUserProfiles.isManagedProfile(userId)) { 1581 // reload per-user settings 1582 mSettingsObserver.update(null); 1583 // Refresh managed services 1584 mConditionProviders.onUserSwitched(userId); 1585 mListeners.onUserSwitched(userId); 1586 mZenModeHelper.onUserSwitched(userId); 1587 mPreferencesHelper.onUserSwitched(userId); 1588 } 1589 // assistant is the only thing that cares about managed profiles specifically 1590 mAssistants.onUserSwitched(userId); 1591 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 1592 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1593 if (userId != USER_NULL) { 1594 mUserProfiles.updateCache(context); 1595 if (!mUserProfiles.isManagedProfile(userId)) { 1596 allowDefaultApprovedServices(userId); 1597 } 1598 } 1599 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 1600 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1601 mUserProfiles.updateCache(context); 1602 mZenModeHelper.onUserRemoved(userId); 1603 mPreferencesHelper.onUserRemoved(userId); 1604 mListeners.onUserRemoved(userId); 1605 mConditionProviders.onUserRemoved(userId); 1606 mAssistants.onUserRemoved(userId); 1607 mHistoryManager.onUserRemoved(userId); 1608 handleSavePolicyFile(); 1609 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { 1610 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1611 mUserProfiles.updateCache(context); 1612 mAssistants.onUserUnlocked(userId); 1613 if (!mUserProfiles.isManagedProfile(userId)) { 1614 mConditionProviders.onUserUnlocked(userId); 1615 mListeners.onUserUnlocked(userId); 1616 mZenModeHelper.onUserUnlocked(userId); 1617 mPreferencesHelper.onUserUnlocked(userId); 1618 } 1619 } 1620 } 1621 }; 1622 1623 private final class SettingsObserver extends ContentObserver { 1624 private final Uri NOTIFICATION_BADGING_URI 1625 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING); 1626 private final Uri NOTIFICATION_BUBBLES_URI 1627 = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_BUBBLES); 1628 private final Uri NOTIFICATION_LIGHT_PULSE_URI 1629 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 1630 private final Uri NOTIFICATION_RATE_LIMIT_URI 1631 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); 1632 private final Uri NOTIFICATION_HISTORY_ENABLED 1633 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED); 1634 SettingsObserver(Handler handler)1635 SettingsObserver(Handler handler) { 1636 super(handler); 1637 } 1638 observe()1639 void observe() { 1640 ContentResolver resolver = getContext().getContentResolver(); 1641 resolver.registerContentObserver(NOTIFICATION_BADGING_URI, 1642 false, this, UserHandle.USER_ALL); 1643 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 1644 false, this, UserHandle.USER_ALL); 1645 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, 1646 false, this, UserHandle.USER_ALL); 1647 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI, 1648 false, this, UserHandle.USER_ALL); 1649 resolver.registerContentObserver(NOTIFICATION_HISTORY_ENABLED, 1650 false, this, UserHandle.USER_ALL); 1651 update(null); 1652 } 1653 onChange(boolean selfChange, Uri uri, int userId)1654 @Override public void onChange(boolean selfChange, Uri uri, int userId) { 1655 update(uri); 1656 } 1657 update(Uri uri)1658 public void update(Uri uri) { 1659 ContentResolver resolver = getContext().getContentResolver(); 1660 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 1661 boolean pulseEnabled = Settings.System.getIntForUser(resolver, 1662 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) 1663 != 0; 1664 if (mNotificationPulseEnabled != pulseEnabled) { 1665 mNotificationPulseEnabled = pulseEnabled; 1666 updateNotificationPulse(); 1667 } 1668 } 1669 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) { 1670 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver, 1671 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate); 1672 } 1673 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { 1674 mPreferencesHelper.updateBadgingEnabled(); 1675 } 1676 if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) { 1677 mPreferencesHelper.updateBubblesEnabled(); 1678 } 1679 if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) { 1680 final IntArray userIds = mUserProfiles.getCurrentProfileIds(); 1681 1682 for (int i = 0; i < userIds.size(); i++) { 1683 mArchive.updateHistoryEnabled(userIds.get(i), Settings.Secure.getInt(resolver, 1684 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) == 1); 1685 } 1686 } 1687 } 1688 } 1689 1690 private SettingsObserver mSettingsObserver; 1691 protected ZenModeHelper mZenModeHelper; 1692 getLongArray(Resources r, int resid, int maxlen, long[] def)1693 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 1694 int[] ar = r.getIntArray(resid); 1695 if (ar == null) { 1696 return def; 1697 } 1698 final int len = ar.length > maxlen ? maxlen : ar.length; 1699 long[] out = new long[len]; 1700 for (int i=0; i<len; i++) { 1701 out[i] = ar[i]; 1702 } 1703 return out; 1704 } 1705 NotificationManagerService(Context context)1706 public NotificationManagerService(Context context) { 1707 this(context, 1708 new NotificationRecordLoggerImpl(), 1709 new InjectableSystemClockImpl(), 1710 new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX)); 1711 } 1712 1713 @VisibleForTesting NotificationManagerService(Context context, NotificationRecordLogger notificationRecordLogger, InjectableSystemClock systemClock, InstanceIdSequence notificationInstanceIdSequence)1714 public NotificationManagerService(Context context, 1715 NotificationRecordLogger notificationRecordLogger, 1716 InjectableSystemClock systemClock, 1717 InstanceIdSequence notificationInstanceIdSequence) { 1718 super(context); 1719 mNotificationRecordLogger = notificationRecordLogger; 1720 mSystemClock = systemClock; 1721 mNotificationInstanceIdSequence = notificationInstanceIdSequence; 1722 Notification.processWhitelistToken = WHITELIST_TOKEN; 1723 } 1724 1725 // TODO - replace these methods with new fields in the VisibleForTesting constructor 1726 @VisibleForTesting setAudioManager(AudioManager audioMananger)1727 void setAudioManager(AudioManager audioMananger) { 1728 mAudioManager = audioMananger; 1729 } 1730 1731 @VisibleForTesting setKeyguardManager(KeyguardManager keyguardManager)1732 void setKeyguardManager(KeyguardManager keyguardManager) { 1733 mKeyguardManager = keyguardManager; 1734 } 1735 1736 @VisibleForTesting getShortcutHelper()1737 ShortcutHelper getShortcutHelper() { 1738 return mShortcutHelper; 1739 } 1740 1741 @VisibleForTesting setShortcutHelper(ShortcutHelper helper)1742 void setShortcutHelper(ShortcutHelper helper) { 1743 mShortcutHelper = helper; 1744 } 1745 1746 @VisibleForTesting setHints(int hints)1747 void setHints(int hints) { 1748 mListenerHints = hints; 1749 } 1750 1751 @VisibleForTesting setVibrator(Vibrator vibrator)1752 void setVibrator(Vibrator vibrator) { 1753 mVibrator = vibrator; 1754 } 1755 1756 @VisibleForTesting setLights(LogicalLight light)1757 void setLights(LogicalLight light) { 1758 mNotificationLight = light; 1759 mAttentionLight = light; 1760 mNotificationPulseEnabled = true; 1761 } 1762 1763 @VisibleForTesting setScreenOn(boolean on)1764 void setScreenOn(boolean on) { 1765 mScreenOn = on; 1766 } 1767 1768 @VisibleForTesting getNotificationRecordCount()1769 int getNotificationRecordCount() { 1770 synchronized (mNotificationLock) { 1771 int count = mNotificationList.size() + mNotificationsByKey.size() 1772 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size(); 1773 // subtract duplicates 1774 for (NotificationRecord posted : mNotificationList) { 1775 if (mNotificationsByKey.containsKey(posted.getKey())) { 1776 count--; 1777 } 1778 if (posted.getSbn().isGroup() && posted.getNotification().isGroupSummary()) { 1779 count--; 1780 } 1781 } 1782 1783 return count; 1784 } 1785 } 1786 1787 @VisibleForTesting clearNotifications()1788 void clearNotifications() { 1789 synchronized (mNotificationList) { 1790 mEnqueuedNotifications.clear(); 1791 mNotificationList.clear(); 1792 mNotificationsByKey.clear(); 1793 mSummaryByGroupKey.clear(); 1794 } 1795 } 1796 1797 @VisibleForTesting addNotification(NotificationRecord r)1798 void addNotification(NotificationRecord r) { 1799 mNotificationList.add(r); 1800 mNotificationsByKey.put(r.getSbn().getKey(), r); 1801 if (r.getSbn().isGroup()) { 1802 mSummaryByGroupKey.put(r.getGroupKey(), r); 1803 } 1804 } 1805 1806 @VisibleForTesting addEnqueuedNotification(NotificationRecord r)1807 void addEnqueuedNotification(NotificationRecord r) { 1808 mEnqueuedNotifications.add(r); 1809 } 1810 1811 @VisibleForTesting getNotificationRecord(String key)1812 NotificationRecord getNotificationRecord(String key) { 1813 return mNotificationsByKey.get(key); 1814 } 1815 1816 1817 @VisibleForTesting setSystemReady(boolean systemReady)1818 void setSystemReady(boolean systemReady) { 1819 mSystemReady = systemReady; 1820 } 1821 1822 @VisibleForTesting setHandler(WorkerHandler handler)1823 void setHandler(WorkerHandler handler) { 1824 mHandler = handler; 1825 } 1826 1827 @VisibleForTesting setFallbackVibrationPattern(long[] vibrationPattern)1828 void setFallbackVibrationPattern(long[] vibrationPattern) { 1829 mFallbackVibrationPattern = vibrationPattern; 1830 } 1831 1832 @VisibleForTesting setPackageManager(IPackageManager packageManager)1833 void setPackageManager(IPackageManager packageManager) { 1834 mPackageManager = packageManager; 1835 } 1836 1837 @VisibleForTesting setRankingHelper(RankingHelper rankingHelper)1838 void setRankingHelper(RankingHelper rankingHelper) { 1839 mRankingHelper = rankingHelper; 1840 } 1841 1842 @VisibleForTesting setPreferencesHelper(PreferencesHelper prefHelper)1843 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; } 1844 1845 @VisibleForTesting setZenHelper(ZenModeHelper zenHelper)1846 void setZenHelper(ZenModeHelper zenHelper) { 1847 mZenModeHelper = zenHelper; 1848 } 1849 1850 @VisibleForTesting setIsAutomotive(boolean isAutomotive)1851 void setIsAutomotive(boolean isAutomotive) { 1852 mIsAutomotive = isAutomotive; 1853 } 1854 1855 @VisibleForTesting setNotificationEffectsEnabledForAutomotive(boolean isEnabled)1856 void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) { 1857 mNotificationEffectsEnabledForAutomotive = isEnabled; 1858 } 1859 1860 @VisibleForTesting setIsTelevision(boolean isTelevision)1861 void setIsTelevision(boolean isTelevision) { 1862 mIsTelevision = isTelevision; 1863 } 1864 1865 @VisibleForTesting setUsageStats(NotificationUsageStats us)1866 void setUsageStats(NotificationUsageStats us) { 1867 mUsageStats = us; 1868 } 1869 1870 @VisibleForTesting setAccessibilityManager(AccessibilityManager am)1871 void setAccessibilityManager(AccessibilityManager am) { 1872 mAccessibilityManager = am; 1873 } 1874 1875 // TODO: All tests should use this init instead of the one-off setters above. 1876 @VisibleForTesting init(WorkerHandler handler, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, LightsManager lightsManager, NotificationListeners notificationListeners, NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, NotificationUsageStats usageStats, AtomicFile policyFile, ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, NotificationHistoryManager historyManager, StatsManager statsManager, TelephonyManager telephonyManager, ActivityManagerInternal ami)1877 void init(WorkerHandler handler, RankingHandler rankingHandler, 1878 IPackageManager packageManager, PackageManager packageManagerClient, 1879 LightsManager lightsManager, NotificationListeners notificationListeners, 1880 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, 1881 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, 1882 NotificationUsageStats usageStats, AtomicFile policyFile, 1883 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, 1884 ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats, 1885 DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, 1886 UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, 1887 NotificationHistoryManager historyManager, StatsManager statsManager, 1888 TelephonyManager telephonyManager, ActivityManagerInternal ami) { 1889 mHandler = handler; 1890 Resources resources = getContext().getResources(); 1891 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), 1892 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, 1893 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); 1894 1895 mAccessibilityManager = 1896 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 1897 mAm = am; 1898 mAtm = atm; 1899 mUgm = ugm; 1900 mUgmInternal = ugmInternal; 1901 mPackageManager = packageManager; 1902 mPackageManagerClient = packageManagerClient; 1903 mAppOps = appOps; 1904 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 1905 mAppUsageStats = appUsageStats; 1906 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 1907 mCompanionManager = companionManager; 1908 mActivityManager = activityManager; 1909 mAmi = ami; 1910 mDeviceIdleController = IDeviceIdleController.Stub.asInterface( 1911 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); 1912 mDpm = dpm; 1913 mUm = userManager; 1914 mPlatformCompat = IPlatformCompat.Stub.asInterface( 1915 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); 1916 1917 mUiHandler = new Handler(UiThread.get().getLooper()); 1918 String[] extractorNames; 1919 try { 1920 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 1921 } catch (Resources.NotFoundException e) { 1922 extractorNames = new String[0]; 1923 } 1924 mUsageStats = usageStats; 1925 mMetricsLogger = new MetricsLogger(); 1926 mRankingHandler = rankingHandler; 1927 mConditionProviders = conditionProviders; 1928 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders, 1929 new SysUiStatsEvent.BuilderFactory()); 1930 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 1931 @Override 1932 public void onConfigChanged() { 1933 handleSavePolicyFile(); 1934 } 1935 1936 @Override 1937 void onZenModeChanged() { 1938 Binder.withCleanCallingIdentity(() -> { 1939 sendRegisteredOnlyBroadcast(ACTION_INTERRUPTION_FILTER_CHANGED); 1940 getContext().sendBroadcastAsUser( 1941 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 1942 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 1943 UserHandle.ALL, permission.MANAGE_NOTIFICATIONS); 1944 synchronized (mNotificationLock) { 1945 updateInterruptionFilterLocked(); 1946 } 1947 mRankingHandler.requestSort(); 1948 }); 1949 } 1950 1951 @Override 1952 void onPolicyChanged() { 1953 Binder.withCleanCallingIdentity(() -> { 1954 sendRegisteredOnlyBroadcast( 1955 NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 1956 mRankingHandler.requestSort(); 1957 }); 1958 } 1959 1960 @Override 1961 void onConsolidatedPolicyChanged() { 1962 Binder.withCleanCallingIdentity(() -> { 1963 mRankingHandler.requestSort(); 1964 }); 1965 } 1966 1967 @Override 1968 void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) { 1969 Binder.withCleanCallingIdentity(() -> { 1970 Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED); 1971 intent.setPackage(pkg); 1972 intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id); 1973 intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status); 1974 getContext().sendBroadcastAsUser(intent, UserHandle.of(userId)); 1975 }); 1976 } 1977 }); 1978 mPreferencesHelper = new PreferencesHelper(getContext(), 1979 mPackageManagerClient, 1980 mRankingHandler, 1981 mZenModeHelper, 1982 new NotificationChannelLoggerImpl(), 1983 mAppOps, 1984 new SysUiStatsEvent.BuilderFactory()); 1985 mRankingHelper = new RankingHelper(getContext(), 1986 mRankingHandler, 1987 mPreferencesHelper, 1988 mZenModeHelper, 1989 mUsageStats, 1990 extractorNames); 1991 mSnoozeHelper = snoozeHelper; 1992 mGroupHelper = groupHelper; 1993 mHistoryManager = historyManager; 1994 1995 // This is a ManagedServices object that keeps track of the listeners. 1996 mListeners = notificationListeners; 1997 1998 // This is a MangedServices object that keeps track of the assistant. 1999 mAssistants = notificationAssistants; 2000 2001 // Needs to be set before loadPolicyFile 2002 mAllowedManagedServicePackages = this::canUseManagedServices; 2003 2004 mPolicyFile = policyFile; 2005 loadPolicyFile(); 2006 mStatusBar = getLocalService(StatusBarManagerInternal.class); 2007 if (mStatusBar != null) { 2008 mStatusBar.setNotificationDelegate(mNotificationDelegate); 2009 } 2010 2011 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 2012 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION); 2013 2014 mFallbackVibrationPattern = getLongArray(resources, 2015 R.array.config_notificationFallbackVibePattern, 2016 VIBRATE_PATTERN_MAXLEN, 2017 DEFAULT_VIBRATE_PATTERN); 2018 mInCallNotificationUri = Uri.parse("file://" + 2019 resources.getString(R.string.config_inCallNotificationSound)); 2020 mInCallNotificationAudioAttributes = new AudioAttributes.Builder() 2021 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 2022 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) 2023 .build(); 2024 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume); 2025 2026 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); 2027 mHasLight = 2028 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed); 2029 2030 // Don't start allowing notifications until the setup wizard has run once. 2031 // After that, including subsequent boots, init with notifications turned on. 2032 // This works on the first boot because the setup wizard will toggle this 2033 // flag at least once and we'll go back to 0 after that. 2034 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 2035 Settings.Global.DEVICE_PROVISIONED, 0)) { 2036 mDisableNotificationEffects = true; 2037 } 2038 mZenModeHelper.initZenMode(); 2039 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 2040 2041 mUserProfiles.updateCache(getContext()); 2042 2043 telephonyManager.listen(new PhoneStateListener() { 2044 @Override 2045 public void onCallStateChanged(int state, String incomingNumber) { 2046 if (mCallState == state) return; 2047 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 2048 mCallState = state; 2049 } 2050 }, PhoneStateListener.LISTEN_CALL_STATE); 2051 2052 mSettingsObserver = new SettingsObserver(mHandler); 2053 2054 mArchive = new Archive(resources.getInteger( 2055 R.integer.config_notificationServiceArchiveSize)); 2056 2057 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK) 2058 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION); 2059 2060 mIsAutomotive = 2061 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0); 2062 mNotificationEffectsEnabledForAutomotive = 2063 resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive); 2064 2065 mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray( 2066 com.android.internal.R.array.config_nonBlockableNotificationPackages)); 2067 2068 mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( 2069 com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); 2070 2071 mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger( 2072 com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes); 2073 mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( 2074 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); 2075 2076 mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource( 2077 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos)); 2078 mStatsManager = statsManager; 2079 } 2080 getStringArrayResource(int key)2081 protected String[] getStringArrayResource(int key) { 2082 return getContext().getResources().getStringArray(key); 2083 } 2084 2085 @VisibleForTesting getWorkHandler()2086 protected Handler getWorkHandler() { 2087 return mHandler; 2088 } 2089 2090 @Override onStart()2091 public void onStart() { 2092 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> { 2093 try { 2094 if (DBG) { 2095 Slog.d(TAG, "Reposting " + r.getKey()); 2096 } 2097 enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), 2098 r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), 2099 r.getSbn().getId(), r.getSbn().getNotification(), userId, true); 2100 } catch (Exception e) { 2101 Slog.e(TAG, "Cannot un-snooze notification", e); 2102 } 2103 }, mUserProfiles); 2104 2105 final File systemDir = new File(Environment.getDataDirectory(), "system"); 2106 mRankingThread.start(); 2107 2108 WorkerHandler handler = new WorkerHandler(Looper.myLooper()); 2109 2110 init(handler, new RankingHandlerWorker(mRankingThread.getLooper()), 2111 AppGlobals.getPackageManager(), getContext().getPackageManager(), 2112 getLocalService(LightsManager.class), 2113 new NotificationListeners(AppGlobals.getPackageManager()), 2114 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles, 2115 AppGlobals.getPackageManager()), 2116 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()), 2117 null, snoozeHelper, new NotificationUsageStats(getContext()), 2118 new AtomicFile(new File( 2119 systemDir, "notification_policy.xml"), "notification-policy"), 2120 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE), 2121 getGroupHelper(), ActivityManager.getService(), 2122 LocalServices.getService(ActivityTaskManagerInternal.class), 2123 LocalServices.getService(UsageStatsManagerInternal.class), 2124 LocalServices.getService(DevicePolicyManagerInternal.class), 2125 UriGrantsManager.getService(), 2126 LocalServices.getService(UriGrantsManagerInternal.class), 2127 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE), 2128 getContext().getSystemService(UserManager.class), 2129 new NotificationHistoryManager(getContext(), handler), 2130 mStatsManager = (StatsManager) getContext().getSystemService( 2131 Context.STATS_MANAGER), 2132 getContext().getSystemService(TelephonyManager.class), 2133 LocalServices.getService(ActivityManagerInternal.class)); 2134 2135 // register for various Intents 2136 IntentFilter filter = new IntentFilter(); 2137 filter.addAction(Intent.ACTION_SCREEN_ON); 2138 filter.addAction(Intent.ACTION_SCREEN_OFF); 2139 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 2140 filter.addAction(Intent.ACTION_USER_PRESENT); 2141 filter.addAction(Intent.ACTION_USER_STOPPED); 2142 filter.addAction(Intent.ACTION_USER_SWITCHED); 2143 filter.addAction(Intent.ACTION_USER_ADDED); 2144 filter.addAction(Intent.ACTION_USER_REMOVED); 2145 filter.addAction(Intent.ACTION_USER_UNLOCKED); 2146 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 2147 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null); 2148 2149 IntentFilter pkgFilter = new IntentFilter(); 2150 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 2151 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 2152 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 2153 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 2154 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 2155 pkgFilter.addDataScheme("package"); 2156 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 2157 null); 2158 2159 IntentFilter suspendedPkgFilter = new IntentFilter(); 2160 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 2161 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); 2162 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 2163 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, 2164 suspendedPkgFilter, null, null); 2165 2166 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 2167 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 2168 null); 2169 2170 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT); 2171 timeoutFilter.addDataScheme(SCHEME_TIMEOUT); 2172 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter); 2173 2174 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED); 2175 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter); 2176 2177 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED); 2178 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter); 2179 2180 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, 2181 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); 2182 publishLocalService(NotificationManagerInternal.class, mInternalService); 2183 } 2184 registerDeviceConfigChange()2185 private void registerDeviceConfigChange() { 2186 mDeviceConfigChangedListener = properties -> { 2187 if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) { 2188 return; 2189 } 2190 if (properties.getKeyset() 2191 .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) { 2192 mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE); 2193 mAssistants.resetDefaultAssistantsIfNecessary(); 2194 } 2195 }; 2196 DeviceConfig.addOnPropertiesChangedListener( 2197 DeviceConfig.NAMESPACE_SYSTEMUI, 2198 new HandlerExecutor(mHandler), 2199 mDeviceConfigChangedListener); 2200 } 2201 unregisterDeviceConfigChange()2202 void unregisterDeviceConfigChange() { 2203 if (mDeviceConfigChangedListener != null) { 2204 DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener); 2205 } 2206 } 2207 registerNotificationPreferencesPullers()2208 private void registerNotificationPreferencesPullers() { 2209 mPullAtomCallback = new StatsPullAtomCallbackImpl(); 2210 mStatsManager.setPullAtomCallback( 2211 PACKAGE_NOTIFICATION_PREFERENCES, 2212 null, // use default PullAtomMetadata values 2213 ConcurrentUtils.DIRECT_EXECUTOR, 2214 mPullAtomCallback 2215 ); 2216 mStatsManager.setPullAtomCallback( 2217 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES, 2218 null, // use default PullAtomMetadata values 2219 ConcurrentUtils.DIRECT_EXECUTOR, 2220 mPullAtomCallback 2221 ); 2222 mStatsManager.setPullAtomCallback( 2223 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES, 2224 null, // use default PullAtomMetadata values 2225 ConcurrentUtils.DIRECT_EXECUTOR, 2226 mPullAtomCallback 2227 ); 2228 mStatsManager.setPullAtomCallback( 2229 DND_MODE_RULE, 2230 null, // use default PullAtomMetadata values 2231 BackgroundThread.getExecutor(), 2232 mPullAtomCallback 2233 ); 2234 } 2235 2236 private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { 2237 @Override onPullAtom(int atomTag, List<StatsEvent> data)2238 public int onPullAtom(int atomTag, List<StatsEvent> data) { 2239 switch (atomTag) { 2240 case PACKAGE_NOTIFICATION_PREFERENCES: 2241 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: 2242 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: 2243 case DND_MODE_RULE: 2244 return pullNotificationStates(atomTag, data); 2245 default: 2246 throw new UnsupportedOperationException("Unknown tagId=" + atomTag); 2247 } 2248 } 2249 } 2250 pullNotificationStates(int atomTag, List<StatsEvent> data)2251 private int pullNotificationStates(int atomTag, List<StatsEvent> data) { 2252 switch(atomTag) { 2253 case PACKAGE_NOTIFICATION_PREFERENCES: 2254 mPreferencesHelper.pullPackagePreferencesStats(data); 2255 break; 2256 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: 2257 mPreferencesHelper.pullPackageChannelPreferencesStats(data); 2258 break; 2259 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: 2260 mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data); 2261 break; 2262 case DND_MODE_RULE: 2263 mZenModeHelper.pullRules(data); 2264 break; 2265 } 2266 return StatsManager.PULL_SUCCESS; 2267 } 2268 getGroupHelper()2269 private GroupHelper getGroupHelper() { 2270 mAutoGroupAtCount = 2271 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount); 2272 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() { 2273 @Override 2274 public void addAutoGroup(String key) { 2275 synchronized (mNotificationLock) { 2276 addAutogroupKeyLocked(key); 2277 } 2278 } 2279 2280 @Override 2281 public void removeAutoGroup(String key) { 2282 synchronized (mNotificationLock) { 2283 removeAutogroupKeyLocked(key); 2284 } 2285 } 2286 2287 @Override 2288 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) { 2289 createAutoGroupSummary(userId, pkg, triggeringKey); 2290 } 2291 2292 @Override 2293 public void removeAutoGroupSummary(int userId, String pkg) { 2294 synchronized (mNotificationLock) { 2295 clearAutogroupSummaryLocked(userId, pkg); 2296 } 2297 } 2298 2299 @Override 2300 public void updateAutogroupSummary(String key, boolean needsOngoingFlag) { 2301 String pkg; 2302 synchronized (mNotificationLock) { 2303 NotificationRecord r = mNotificationsByKey.get(key); 2304 pkg = r != null && r.getSbn() != null ? r.getSbn().getPackageName() : null; 2305 } 2306 boolean isAppForeground = pkg != null 2307 && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 2308 synchronized (mNotificationLock) { 2309 NotificationRecord r = mNotificationsByKey.get(key); 2310 if (r == null) return; 2311 updateAutobundledSummaryFlags(r.getUser().getIdentifier(), 2312 r.getSbn().getPackageName(), needsOngoingFlag, isAppForeground); 2313 } 2314 } 2315 }); 2316 } 2317 2318 private void sendRegisteredOnlyBroadcast(String action) { 2319 Intent intent = new Intent(action); 2320 getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 2321 UserHandle.ALL, null); 2322 // explicitly send the broadcast to all DND packages, even if they aren't currently running 2323 intent.setFlags(0); 2324 final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages(); 2325 for (String pkg : dndApprovedPackages) { 2326 intent.setPackage(pkg); 2327 getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 2328 } 2329 } 2330 2331 @Override 2332 public void onBootPhase(int phase) { 2333 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 2334 // no beeping until we're basically done booting 2335 mSystemReady = true; 2336 2337 // Grab our optional AudioService 2338 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 2339 mAudioManagerInternal = getLocalService(AudioManagerInternal.class); 2340 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 2341 mKeyguardManager = getContext().getSystemService(KeyguardManager.class); 2342 mZenModeHelper.onSystemReady(); 2343 mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class), 2344 mPackageManager, getContext().getMainExecutor()); 2345 mRoleObserver.init(); 2346 LauncherApps launcherApps = 2347 (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE); 2348 mShortcutHelper = new ShortcutHelper(launcherApps, mShortcutListener, getLocalService( 2349 ShortcutServiceInternal.class)); 2350 BubbleExtractor bubbsExtractor = mRankingHelper.findExtractor(BubbleExtractor.class); 2351 if (bubbsExtractor != null) { 2352 bubbsExtractor.setShortcutHelper(mShortcutHelper); 2353 } 2354 registerNotificationPreferencesPullers(); 2355 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 2356 // This observer will force an update when observe is called, causing us to 2357 // bind to listener services. 2358 mSettingsObserver.observe(); 2359 mListeners.onBootPhaseAppsCanStart(); 2360 mAssistants.onBootPhaseAppsCanStart(); 2361 mConditionProviders.onBootPhaseAppsCanStart(); 2362 mHistoryManager.onBootPhaseAppsCanStart(); 2363 registerDeviceConfigChange(); 2364 } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 2365 mSnoozeHelper.scheduleRepostsForPersistedNotifications( 2366 mSystemClock.currentTimeMillis()); 2367 } 2368 } 2369 2370 @Override 2371 public void onUnlockUser(@NonNull UserInfo userInfo) { 2372 mHandler.post(() -> { 2373 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser"); 2374 try { 2375 mHistoryManager.onUserUnlocked(userInfo.id); 2376 } finally { 2377 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 2378 } 2379 }); 2380 } 2381 2382 @Override 2383 public void onStopUser(@NonNull UserInfo userInfo) { 2384 mHandler.post(() -> { 2385 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser"); 2386 try { 2387 mHistoryManager.onUserStopped(userInfo.id); 2388 } finally { 2389 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 2390 } 2391 }); 2392 } 2393 2394 @GuardedBy("mNotificationLock") 2395 private void updateListenerHintsLocked() { 2396 final int hints = calculateHints(); 2397 if (hints == mListenerHints) return; 2398 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size()); 2399 mListenerHints = hints; 2400 scheduleListenerHintsChanged(hints); 2401 } 2402 2403 @GuardedBy("mNotificationLock") 2404 private void updateEffectsSuppressorLocked() { 2405 final long updatedSuppressedEffects = calculateSuppressedEffects(); 2406 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; 2407 final List<ComponentName> suppressors = getSuppressors(); 2408 ZenLog.traceEffectsSuppressorChanged( 2409 mEffectsSuppressors, suppressors, updatedSuppressedEffects); 2410 mEffectsSuppressors = suppressors; 2411 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); 2412 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 2413 } 2414 2415 private void exitIdle() { 2416 try { 2417 if (mDeviceIdleController != null) { 2418 mDeviceIdleController.exitIdle("notification interaction"); 2419 } 2420 } catch (RemoteException e) { 2421 } 2422 } 2423 2424 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel, 2425 boolean fromListener) { 2426 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) { 2427 // cancel 2428 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, 2429 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED, 2430 null); 2431 if (isUidSystemOrPhone(uid)) { 2432 IntArray profileIds = mUserProfiles.getCurrentProfileIds(); 2433 int N = profileIds.size(); 2434 for (int i = 0; i < N; i++) { 2435 int profileId = profileIds.get(i); 2436 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, 2437 profileId, REASON_CHANNEL_BANNED, 2438 null); 2439 } 2440 } 2441 } 2442 final NotificationChannel preUpdate = 2443 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true); 2444 2445 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true); 2446 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel); 2447 2448 if (!fromListener) { 2449 final NotificationChannel modifiedChannel = mPreferencesHelper.getNotificationChannel( 2450 pkg, uid, channel.getId(), false); 2451 mListeners.notifyNotificationChannelChanged( 2452 pkg, UserHandle.getUserHandleForUid(uid), 2453 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); 2454 } 2455 2456 handleSavePolicyFile(); 2457 } 2458 2459 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate, 2460 NotificationChannel update) { 2461 try { 2462 if ((preUpdate.getImportance() == IMPORTANCE_NONE 2463 && update.getImportance() != IMPORTANCE_NONE) 2464 || (preUpdate.getImportance() != IMPORTANCE_NONE 2465 && update.getImportance() == IMPORTANCE_NONE)) { 2466 getContext().sendBroadcastAsUser( 2467 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED) 2468 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID, 2469 update.getId()) 2470 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 2471 update.getImportance() == IMPORTANCE_NONE) 2472 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 2473 .setPackage(pkg), 2474 UserHandle.of(UserHandle.getUserId(uid)), null); 2475 } 2476 } catch (SecurityException e) { 2477 Slog.w(TAG, "Can't notify app about channel change", e); 2478 } 2479 } 2480 2481 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, 2482 boolean fromApp, boolean fromListener) { 2483 Objects.requireNonNull(group); 2484 Objects.requireNonNull(pkg); 2485 2486 final NotificationChannelGroup preUpdate = 2487 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid); 2488 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group, 2489 fromApp); 2490 if (!fromApp) { 2491 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group); 2492 } 2493 if (!fromListener) { 2494 mListeners.notifyNotificationChannelGroupChanged(pkg, 2495 UserHandle.of(UserHandle.getCallingUserId()), group, 2496 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 2497 } 2498 } 2499 2500 private void maybeNotifyChannelGroupOwner(String pkg, int uid, 2501 NotificationChannelGroup preUpdate, NotificationChannelGroup update) { 2502 try { 2503 if (preUpdate.isBlocked() != update.isBlocked()) { 2504 getContext().sendBroadcastAsUser( 2505 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED) 2506 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID, 2507 update.getId()) 2508 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 2509 update.isBlocked()) 2510 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 2511 .setPackage(pkg), 2512 UserHandle.of(UserHandle.getUserId(uid)), null); 2513 } 2514 } catch (SecurityException e) { 2515 Slog.w(TAG, "Can't notify app about group change", e); 2516 } 2517 } 2518 2519 private ArrayList<ComponentName> getSuppressors() { 2520 ArrayList<ComponentName> names = new ArrayList<ComponentName>(); 2521 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 2522 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 2523 2524 for (ComponentName info : serviceInfoList) { 2525 names.add(info); 2526 } 2527 } 2528 2529 return names; 2530 } 2531 2532 private boolean removeDisabledHints(ManagedServiceInfo info) { 2533 return removeDisabledHints(info, 0); 2534 } 2535 2536 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) { 2537 boolean removed = false; 2538 2539 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 2540 final int hint = mListenersDisablingEffects.keyAt(i); 2541 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 2542 2543 if (hints == 0 || (hint & hints) == hint) { 2544 removed |= listeners.remove(info.component); 2545 } 2546 } 2547 2548 return removed; 2549 } 2550 2551 private void addDisabledHints(ManagedServiceInfo info, int hints) { 2552 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2553 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS); 2554 } 2555 2556 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 2557 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 2558 } 2559 2560 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 2561 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS); 2562 } 2563 } 2564 2565 private void addDisabledHint(ManagedServiceInfo info, int hint) { 2566 if (mListenersDisablingEffects.indexOfKey(hint) < 0) { 2567 mListenersDisablingEffects.put(hint, new ArraySet<>()); 2568 } 2569 2570 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint); 2571 hintListeners.add(info.component); 2572 } 2573 2574 private int calculateHints() { 2575 int hints = 0; 2576 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 2577 int hint = mListenersDisablingEffects.keyAt(i); 2578 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 2579 2580 if (!serviceInfoList.isEmpty()) { 2581 hints |= hint; 2582 } 2583 } 2584 2585 return hints; 2586 } 2587 2588 private long calculateSuppressedEffects() { 2589 int hints = calculateHints(); 2590 long suppressedEffects = 0; 2591 2592 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2593 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL; 2594 } 2595 2596 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 2597 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS; 2598 } 2599 2600 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 2601 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS; 2602 } 2603 2604 return suppressedEffects; 2605 } 2606 2607 @GuardedBy("mNotificationLock") 2608 private void updateInterruptionFilterLocked() { 2609 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 2610 if (interruptionFilter == mInterruptionFilter) return; 2611 mInterruptionFilter = interruptionFilter; 2612 scheduleInterruptionFilterChanged(interruptionFilter); 2613 } 2614 2615 int correctCategory(int requestedCategoryList, int categoryType, 2616 int currentCategoryList) { 2617 if ((requestedCategoryList & categoryType) != 0 2618 && (currentCategoryList & categoryType) == 0) { 2619 requestedCategoryList &= ~categoryType; 2620 } else if ((requestedCategoryList & categoryType) == 0 2621 && (currentCategoryList & categoryType) != 0){ 2622 requestedCategoryList |= categoryType; 2623 } 2624 return requestedCategoryList; 2625 } 2626 2627 @VisibleForTesting 2628 INotificationManager getBinderService() { 2629 return INotificationManager.Stub.asInterface(mService); 2630 } 2631 2632 /** 2633 * Report to usage stats that the notification was seen. 2634 * @param r notification record 2635 */ 2636 @GuardedBy("mNotificationLock") 2637 protected void reportSeen(NotificationRecord r) { 2638 if (!r.isProxied()) { 2639 mAppUsageStats.reportEvent(r.getSbn().getPackageName(), 2640 getRealUserId(r.getSbn().getUserId()), 2641 UsageEvents.Event.NOTIFICATION_SEEN); 2642 } 2643 } 2644 2645 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy, 2646 int targetSdkVersion) { 2647 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) { 2648 return incomingPolicy.suppressedVisualEffects; 2649 } 2650 final int[] effectsIntroducedInP = { 2651 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT, 2652 SUPPRESSED_EFFECT_LIGHTS, 2653 SUPPRESSED_EFFECT_PEEK, 2654 SUPPRESSED_EFFECT_STATUS_BAR, 2655 SUPPRESSED_EFFECT_BADGE, 2656 SUPPRESSED_EFFECT_AMBIENT, 2657 SUPPRESSED_EFFECT_NOTIFICATION_LIST 2658 }; 2659 2660 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects; 2661 if (targetSdkVersion < Build.VERSION_CODES.P) { 2662 // unset higher order bits introduced in P, maintain the user's higher order bits 2663 for (int i = 0; i < effectsIntroducedInP.length ; i++) { 2664 newSuppressedVisualEffects &= ~effectsIntroducedInP[i]; 2665 newSuppressedVisualEffects |= 2666 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]); 2667 } 2668 // set higher order bits according to lower order bits 2669 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 2670 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 2671 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 2672 } 2673 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 2674 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 2675 } 2676 } else { 2677 boolean hasNewEffects = (newSuppressedVisualEffects 2678 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0; 2679 // if any of the new effects introduced in P are set 2680 if (hasNewEffects) { 2681 // clear out the deprecated effects 2682 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON 2683 | SUPPRESSED_EFFECT_SCREEN_OFF); 2684 2685 // set the deprecated effects according to the new more specific effects 2686 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) { 2687 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON; 2688 } 2689 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0 2690 && (newSuppressedVisualEffects 2691 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0 2692 && (newSuppressedVisualEffects 2693 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) { 2694 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF; 2695 } 2696 } else { 2697 // set higher order bits according to lower order bits 2698 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 2699 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 2700 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 2701 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT; 2702 } 2703 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 2704 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 2705 } 2706 } 2707 } 2708 2709 return newSuppressedVisualEffects; 2710 } 2711 2712 @GuardedBy("mNotificationLock") 2713 protected void maybeRecordInterruptionLocked(NotificationRecord r) { 2714 if (r.isInterruptive() && !r.hasRecordedInterruption()) { 2715 mAppUsageStats.reportInterruptiveNotification(r.getSbn().getPackageName(), 2716 r.getChannel().getId(), 2717 getRealUserId(r.getSbn().getUserId())); 2718 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryAddItem"); 2719 try { 2720 mHistoryManager.addNotification(new HistoricalNotification.Builder() 2721 .setPackage(r.getSbn().getPackageName()) 2722 .setUid(r.getSbn().getUid()) 2723 .setUserId(r.getSbn().getNormalizedUserId()) 2724 .setChannelId(r.getChannel().getId()) 2725 .setChannelName(r.getChannel().getName().toString()) 2726 .setPostedTimeMs(mSystemClock.currentTimeMillis()) 2727 .setTitle(getHistoryTitle(r.getNotification())) 2728 .setText(getHistoryText( 2729 r.getSbn().getPackageContext(getContext()), r.getNotification())) 2730 .setIcon(r.getNotification().getSmallIcon()) 2731 .build()); 2732 } finally { 2733 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 2734 } 2735 r.setRecordedInterruption(true); 2736 } 2737 } 2738 2739 private String getHistoryTitle(Notification n) { 2740 CharSequence title = null; 2741 if (n.extras != null) { 2742 title = n.extras.getCharSequence(Notification.EXTRA_TITLE); 2743 if (title == null) { 2744 title = n.extras.getCharSequence(Notification.EXTRA_TITLE_BIG); 2745 } 2746 } 2747 return title == null ? getContext().getResources().getString( 2748 com.android.internal.R.string.notification_history_title_placeholder) 2749 : String.valueOf(title); 2750 } 2751 2752 /** 2753 * Returns the appropriate substring for this notification based on the style of notification. 2754 */ 2755 private String getHistoryText(Context appContext, Notification n) { 2756 CharSequence text = null; 2757 if (n.extras != null) { 2758 text = n.extras.getCharSequence(Notification.EXTRA_TEXT); 2759 2760 Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n); 2761 2762 if (nb.getStyle() instanceof Notification.BigTextStyle) { 2763 text = ((Notification.BigTextStyle) nb.getStyle()).getBigText(); 2764 } else if (nb.getStyle() instanceof Notification.MessagingStyle) { 2765 Notification.MessagingStyle ms = (Notification.MessagingStyle) nb.getStyle(); 2766 final List<Notification.MessagingStyle.Message> messages = ms.getMessages(); 2767 if (messages != null && messages.size() > 0) { 2768 text = messages.get(messages.size() - 1).getText(); 2769 } 2770 } 2771 2772 if (TextUtils.isEmpty(text)) { 2773 text = n.extras.getCharSequence(Notification.EXTRA_TEXT); 2774 } 2775 } 2776 return text == null ? null : String.valueOf(text); 2777 } 2778 2779 protected void maybeRegisterMessageSent(NotificationRecord r) { 2780 if (r.isConversation()) { 2781 if (r.getShortcutInfo() != null) { 2782 if (mPreferencesHelper.setValidMessageSent( 2783 r.getSbn().getPackageName(), r.getUid())) { 2784 handleSavePolicyFile(); 2785 } 2786 } else { 2787 if (mPreferencesHelper.setInvalidMessageSent( 2788 r.getSbn().getPackageName(), r.getUid())) { 2789 handleSavePolicyFile(); 2790 } 2791 } 2792 } 2793 } 2794 2795 /** 2796 * Report to usage stats that the user interacted with the notification. 2797 * @param r notification record 2798 */ 2799 protected void reportUserInteraction(NotificationRecord r) { 2800 mAppUsageStats.reportEvent(r.getSbn().getPackageName(), 2801 getRealUserId(r.getSbn().getUserId()), 2802 UsageEvents.Event.USER_INTERACTION); 2803 } 2804 2805 private int getRealUserId(int userId) { 2806 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId; 2807 } 2808 2809 private ToastRecord getToastRecord(int uid, int pid, String packageName, IBinder token, 2810 @Nullable CharSequence text, @Nullable ITransientNotification callback, int duration, 2811 Binder windowToken, int displayId, 2812 @Nullable ITransientNotificationCallback textCallback) { 2813 if (callback == null) { 2814 return new TextToastRecord(this, mStatusBar, uid, pid, packageName, token, text, 2815 duration, windowToken, displayId, textCallback); 2816 } else { 2817 return new CustomToastRecord(this, uid, pid, packageName, token, callback, duration, 2818 windowToken, displayId); 2819 } 2820 } 2821 2822 @VisibleForTesting 2823 NotificationManagerInternal getInternalService() { 2824 return mInternalService; 2825 } 2826 2827 @VisibleForTesting 2828 final IBinder mService = new INotificationManager.Stub() { 2829 // Toasts 2830 // ============================================================================ 2831 2832 @Override 2833 public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, 2834 int displayId, @Nullable ITransientNotificationCallback callback) { 2835 enqueueToast(pkg, token, text, null, duration, displayId, callback); 2836 } 2837 2838 @Override 2839 public void enqueueToast(String pkg, IBinder token, ITransientNotification callback, 2840 int duration, int displayId) { 2841 enqueueToast(pkg, token, null, callback, duration, displayId, null); 2842 } 2843 2844 private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, 2845 @Nullable ITransientNotification callback, int duration, int displayId, 2846 @Nullable ITransientNotificationCallback textCallback) { 2847 if (DBG) { 2848 Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token 2849 + " duration=" + duration + " displayId=" + displayId); 2850 } 2851 2852 if (pkg == null || (text == null && callback == null) 2853 || (text != null && callback != null) || token == null) { 2854 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback=" 2855 + " token=" + token); 2856 return; 2857 } 2858 2859 final int callingUid = Binder.getCallingUid(); 2860 final UserHandle callingUser = Binder.getCallingUserHandle(); 2861 final boolean isSystemToast = isCallerSystemOrPhone() 2862 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); 2863 final boolean isPackageSuspended = isPackagePaused(pkg); 2864 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, 2865 callingUid); 2866 2867 final boolean appIsForeground; 2868 long callingIdentity = Binder.clearCallingIdentity(); 2869 try { 2870 appIsForeground = mActivityManager.getUidImportance(callingUid) 2871 == IMPORTANCE_FOREGROUND; 2872 } finally { 2873 Binder.restoreCallingIdentity(callingIdentity); 2874 } 2875 2876 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage 2877 && !appIsForeground) || isPackageSuspended)) { 2878 Slog.e(TAG, "Suppressing toast from package " + pkg 2879 + (isPackageSuspended ? " due to package suspended." 2880 : " by user request.")); 2881 return; 2882 } 2883 2884 boolean isAppRenderedToast = (callback != null); 2885 if (isAppRenderedToast && !isSystemToast && !isPackageInForegroundForToast(pkg, 2886 callingUid)) { 2887 boolean block; 2888 long id = Binder.clearCallingIdentity(); 2889 try { 2890 // CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so block will be 2891 // false for apps with targetSdk < R. For apps with targetSdk R+, text toasts 2892 // are not app-rendered, so isAppRenderedToast == true means it's a custom 2893 // toast. 2894 block = mPlatformCompat.isChangeEnabledByPackageName( 2895 CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, pkg, 2896 callingUser.getIdentifier()); 2897 } catch (RemoteException e) { 2898 // Shouldn't happen have since it's a local local 2899 Slog.e(TAG, "Unexpected exception while checking block background custom toasts" 2900 + " change", e); 2901 block = false; 2902 } finally { 2903 Binder.restoreCallingIdentity(id); 2904 } 2905 if (block) { 2906 Slog.w(TAG, "Blocking custom toast from package " + pkg 2907 + " due to package not in the foreground"); 2908 return; 2909 } 2910 } 2911 2912 synchronized (mToastQueue) { 2913 int callingPid = Binder.getCallingPid(); 2914 long callingId = Binder.clearCallingIdentity(); 2915 try { 2916 ToastRecord record; 2917 int index = indexOfToastLocked(pkg, token); 2918 // If it's already in the queue, we update it in place, we don't 2919 // move it to the end of the queue. 2920 if (index >= 0) { 2921 record = mToastQueue.get(index); 2922 record.update(duration); 2923 } else { 2924 // Limit the number of toasts that any given package can enqueue. 2925 // Prevents DOS attacks and deals with leaks. 2926 int count = 0; 2927 final int N = mToastQueue.size(); 2928 for (int i = 0; i < N; i++) { 2929 final ToastRecord r = mToastQueue.get(i); 2930 if (r.pkg.equals(pkg)) { 2931 count++; 2932 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2933 Slog.e(TAG, "Package has already posted " + count 2934 + " toasts. Not showing more. Package=" + pkg); 2935 return; 2936 } 2937 } 2938 } 2939 2940 Binder windowToken = new Binder(); 2941 mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId); 2942 record = getToastRecord(callingUid, callingPid, pkg, token, text, callback, 2943 duration, windowToken, displayId, textCallback); 2944 mToastQueue.add(record); 2945 index = mToastQueue.size() - 1; 2946 keepProcessAliveForToastIfNeededLocked(callingPid); 2947 } 2948 // If it's at index 0, it's the current toast. It doesn't matter if it's 2949 // new or just been updated, show it. 2950 // If the callback fails, this will remove it from the list, so don't 2951 // assume that it's valid after this. 2952 if (index == 0) { 2953 showNextToastLocked(); 2954 } 2955 } finally { 2956 Binder.restoreCallingIdentity(callingId); 2957 } 2958 } 2959 } 2960 2961 /** 2962 * Implementation note: Our definition of foreground for toasts is an implementation matter 2963 * and should strike a balance between functionality and anti-abuse effectiveness. We 2964 * currently worry about the following cases: 2965 * <ol> 2966 * <li>App with fullscreen activity: Allow toasts 2967 * <li>App behind translucent activity from other app: Block toasts 2968 * <li>App in multi-window: Allow toasts 2969 * <li>App with expanded bubble: Allow toasts 2970 * <li>App posting toasts on onCreate(), onStart(), onResume(): Allow toasts 2971 * <li>App posting toasts on onPause(), onStop(), onDestroy(): Block toasts 2972 * </ol> 2973 * Checking if the UID has any resumed activities satisfy use-cases above. 2974 * 2975 * <p>Checking if {@code mActivityManager.getUidImportance(callingUid) == 2976 * IMPORTANCE_FOREGROUND} does not work because it considers the app in foreground if it has 2977 * any visible activities, failing case 2 in list above. 2978 */ 2979 private boolean isPackageInForegroundForToast(String pkg, int callingUid) { 2980 return mAtm.hasResumedActivity(callingUid); 2981 } 2982 2983 @Override 2984 public void cancelToast(String pkg, IBinder token) { 2985 Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token); 2986 2987 if (pkg == null || token == null) { 2988 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token); 2989 return; 2990 } 2991 2992 synchronized (mToastQueue) { 2993 long callingId = Binder.clearCallingIdentity(); 2994 try { 2995 int index = indexOfToastLocked(pkg, token); 2996 if (index >= 0) { 2997 cancelToastLocked(index); 2998 } else { 2999 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 3000 + " token=" + token); 3001 } 3002 } finally { 3003 Binder.restoreCallingIdentity(callingId); 3004 } 3005 } 3006 } 3007 3008 @Override 3009 public void finishToken(String pkg, IBinder token) { 3010 synchronized (mToastQueue) { 3011 long callingId = Binder.clearCallingIdentity(); 3012 try { 3013 int index = indexOfToastLocked(pkg, token); 3014 if (index >= 0) { 3015 ToastRecord record = mToastQueue.get(index); 3016 finishWindowTokenLocked(record.windowToken, record.displayId); 3017 } else { 3018 Slog.w(TAG, "Toast already killed. pkg=" + pkg 3019 + " token=" + token); 3020 } 3021 } finally { 3022 Binder.restoreCallingIdentity(callingId); 3023 } 3024 } 3025 } 3026 3027 @Override 3028 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 3029 Notification notification, int userId) throws RemoteException { 3030 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 3031 Binder.getCallingPid(), tag, id, notification, userId); 3032 } 3033 3034 @Override 3035 public void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id, 3036 int userId) { 3037 cancelNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), 3038 tag, id, userId); 3039 } 3040 3041 @Override 3042 public void cancelAllNotifications(String pkg, int userId) { 3043 checkCallerIsSystemOrSameApp(pkg); 3044 3045 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 3046 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 3047 3048 // Calling from user space, don't allow the canceling of actively 3049 // running foreground services. 3050 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 3051 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId, 3052 REASON_APP_CANCEL_ALL, null); 3053 } 3054 3055 @Override 3056 public void silenceNotificationSound() { 3057 checkCallerIsSystem(); 3058 3059 mNotificationDelegate.clearEffects(); 3060 } 3061 3062 @Override 3063 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 3064 enforceSystemOrSystemUI("setNotificationsEnabledForPackage"); 3065 3066 synchronized (mNotificationLock) { 3067 boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid) 3068 != NotificationManager.IMPORTANCE_NONE; 3069 3070 if (wasEnabled == enabled) { 3071 return; 3072 } 3073 } 3074 3075 mPreferencesHelper.setEnabled(pkg, uid, enabled); 3076 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) 3077 .setType(MetricsEvent.TYPE_ACTION) 3078 .setPackageName(pkg) 3079 .setSubtype(enabled ? 1 : 0)); 3080 // Now, cancel any outstanding notifications that are part of a just-disabled app 3081 if (!enabled) { 3082 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true, 3083 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null); 3084 } 3085 3086 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 3087 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 3088 try { 3089 getContext().sendBroadcastAsUser( 3090 new Intent(ACTION_APP_BLOCK_STATE_CHANGED) 3091 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled) 3092 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3093 .setPackage(pkg), 3094 UserHandle.of(UserHandle.getUserId(uid)), null); 3095 } catch (SecurityException e) { 3096 Slog.w(TAG, "Can't notify app about app block change", e); 3097 } 3098 3099 handleSavePolicyFile(); 3100 } 3101 3102 /** 3103 * Updates the enabled state for notifications for the given package (and uid). 3104 * Additionally, this method marks the app importance as locked by the user, which 3105 * means 3106 * that notifications from the app will <b>not</b> be considered for showing a 3107 * blocking helper. 3108 * 3109 * @param pkg package that owns the notifications to update 3110 * @param uid uid of the app providing notifications 3111 * @param enabled whether notifications should be enabled for the app 3112 * @see #setNotificationsEnabledForPackage(String, int, boolean) 3113 */ 3114 @Override 3115 public void setNotificationsEnabledWithImportanceLockForPackage( 3116 String pkg, int uid, boolean enabled) { 3117 setNotificationsEnabledForPackage(pkg, uid, enabled); 3118 3119 mPreferencesHelper.setAppImportanceLocked(pkg, uid); 3120 } 3121 3122 /** 3123 * Use this when you just want to know if notifications are OK for this package. 3124 */ 3125 @Override 3126 public boolean areNotificationsEnabled(String pkg) { 3127 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()); 3128 } 3129 3130 /** 3131 * Use this when you just want to know if notifications are OK for this package. 3132 */ 3133 @Override 3134 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 3135 enforceSystemOrSystemUIOrSamePackage(pkg, 3136 "Caller not system or systemui or same package"); 3137 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 3138 getContext().enforceCallingPermission( 3139 android.Manifest.permission.INTERACT_ACROSS_USERS, 3140 "canNotifyAsPackage for uid " + uid); 3141 } 3142 3143 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; 3144 } 3145 3146 /** 3147 * @return true if and only if "all" bubbles are allowed from the provided package. 3148 */ 3149 @Override 3150 public boolean areBubblesAllowed(String pkg) { 3151 return getBubblePreferenceForPackage(pkg, Binder.getCallingUid()) 3152 == BUBBLE_PREFERENCE_ALL; 3153 } 3154 3155 @Override 3156 public int getBubblePreferenceForPackage(String pkg, int uid) { 3157 enforceSystemOrSystemUIOrSamePackage(pkg, 3158 "Caller not system or systemui or same package"); 3159 3160 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 3161 getContext().enforceCallingPermission( 3162 android.Manifest.permission.INTERACT_ACROSS_USERS, 3163 "getBubblePreferenceForPackage for uid " + uid); 3164 } 3165 3166 return mPreferencesHelper.getBubblePreference(pkg, uid); 3167 } 3168 3169 @Override 3170 public void setBubblesAllowed(String pkg, int uid, int bubblePreference) { 3171 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 3172 mPreferencesHelper.setBubblesAllowed(pkg, uid, bubblePreference); 3173 handleSavePolicyFile(); 3174 } 3175 3176 @Override 3177 public boolean shouldHideSilentStatusIcons(String callingPkg) { 3178 checkCallerIsSameApp(callingPkg); 3179 3180 if (isCallerSystemOrPhone() 3181 || mListeners.isListenerPackage(callingPkg)) { 3182 return mPreferencesHelper.shouldHideSilentStatusIcons(); 3183 } else { 3184 throw new SecurityException("Only available for notification listeners"); 3185 } 3186 } 3187 3188 @Override 3189 public void setHideSilentStatusIcons(boolean hide) { 3190 checkCallerIsSystem(); 3191 3192 mPreferencesHelper.setHideSilentStatusIcons(hide); 3193 handleSavePolicyFile(); 3194 3195 mListeners.onStatusBarIconsBehaviorChanged(hide); 3196 } 3197 3198 @Override 3199 public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) { 3200 checkCallerIsSystem(); 3201 mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime); 3202 } 3203 3204 @Override 3205 public int getPackageImportance(String pkg) { 3206 checkCallerIsSystemOrSameApp(pkg); 3207 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid()); 3208 } 3209 3210 @Override 3211 public boolean canShowBadge(String pkg, int uid) { 3212 checkCallerIsSystem(); 3213 return mPreferencesHelper.canShowBadge(pkg, uid); 3214 } 3215 3216 @Override 3217 public void setShowBadge(String pkg, int uid, boolean showBadge) { 3218 checkCallerIsSystem(); 3219 mPreferencesHelper.setShowBadge(pkg, uid, showBadge); 3220 handleSavePolicyFile(); 3221 } 3222 3223 @Override 3224 public boolean hasSentValidMsg(String pkg, int uid) { 3225 checkCallerIsSystem(); 3226 return mPreferencesHelper.hasSentValidMsg(pkg, uid); 3227 } 3228 3229 @Override 3230 public boolean isInInvalidMsgState(String pkg, int uid) { 3231 checkCallerIsSystem(); 3232 return mPreferencesHelper.isInInvalidMsgState(pkg, uid); 3233 } 3234 3235 @Override 3236 public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) { 3237 checkCallerIsSystem(); 3238 return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid); 3239 } 3240 3241 @Override 3242 public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) { 3243 checkCallerIsSystem(); 3244 mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted); 3245 handleSavePolicyFile(); 3246 } 3247 3248 @Override 3249 public void setNotificationDelegate(String callingPkg, String delegate) { 3250 checkCallerIsSameApp(callingPkg); 3251 final int callingUid = Binder.getCallingUid(); 3252 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 3253 if (delegate == null) { 3254 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid()); 3255 handleSavePolicyFile(); 3256 } else { 3257 try { 3258 ApplicationInfo info = 3259 mPackageManager.getApplicationInfo(delegate, 3260 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 3261 user.getIdentifier()); 3262 if (info != null) { 3263 mPreferencesHelper.setNotificationDelegate( 3264 callingPkg, callingUid, delegate, info.uid); 3265 handleSavePolicyFile(); 3266 } 3267 } catch (RemoteException e) { 3268 e.rethrowFromSystemServer(); 3269 } 3270 } 3271 } 3272 3273 @Override 3274 public String getNotificationDelegate(String callingPkg) { 3275 // callable by Settings also 3276 checkCallerIsSystemOrSameApp(callingPkg); 3277 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid()); 3278 } 3279 3280 @Override 3281 public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) { 3282 checkCallerIsSameApp(callingPkg); 3283 final int callingUid = Binder.getCallingUid(); 3284 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 3285 if (user.getIdentifier() != userId) { 3286 getContext().enforceCallingPermission( 3287 android.Manifest.permission.INTERACT_ACROSS_USERS, 3288 "canNotifyAsPackage for user " + userId); 3289 } 3290 if (callingPkg.equals(targetPkg)) { 3291 return true; 3292 } 3293 try { 3294 ApplicationInfo info = 3295 mPackageManager.getApplicationInfo(targetPkg, 3296 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 3297 userId); 3298 if (info != null) { 3299 return mPreferencesHelper.isDelegateAllowed( 3300 targetPkg, info.uid, callingPkg, callingUid); 3301 } 3302 } catch (RemoteException e) { 3303 // :( 3304 } 3305 return false; 3306 } 3307 3308 @Override 3309 public void updateNotificationChannelGroupForPackage(String pkg, int uid, 3310 NotificationChannelGroup group) throws RemoteException { 3311 enforceSystemOrSystemUI("Caller not system or systemui"); 3312 createNotificationChannelGroup(pkg, uid, group, false, false); 3313 handleSavePolicyFile(); 3314 } 3315 3316 @Override 3317 public void createNotificationChannelGroups(String pkg, 3318 ParceledListSlice channelGroupList) throws RemoteException { 3319 checkCallerIsSystemOrSameApp(pkg); 3320 List<NotificationChannelGroup> groups = channelGroupList.getList(); 3321 final int groupSize = groups.size(); 3322 for (int i = 0; i < groupSize; i++) { 3323 final NotificationChannelGroup group = groups.get(i); 3324 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false); 3325 } 3326 handleSavePolicyFile(); 3327 } 3328 3329 private void createNotificationChannelsImpl(String pkg, int uid, 3330 ParceledListSlice channelsList) { 3331 List<NotificationChannel> channels = channelsList.getList(); 3332 final int channelsSize = channels.size(); 3333 boolean needsPolicyFileChange = false; 3334 for (int i = 0; i < channelsSize; i++) { 3335 final NotificationChannel channel = channels.get(i); 3336 Objects.requireNonNull(channel, "channel in list is null"); 3337 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid, 3338 channel, true /* fromTargetApp */, 3339 mConditionProviders.isPackageOrComponentAllowed( 3340 pkg, UserHandle.getUserId(uid))); 3341 if (needsPolicyFileChange) { 3342 mListeners.notifyNotificationChannelChanged(pkg, 3343 UserHandle.getUserHandleForUid(uid), 3344 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), 3345 false), 3346 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 3347 } 3348 } 3349 if (needsPolicyFileChange) { 3350 handleSavePolicyFile(); 3351 } 3352 } 3353 3354 @Override 3355 public void createNotificationChannels(String pkg, 3356 ParceledListSlice channelsList) { 3357 checkCallerIsSystemOrSameApp(pkg); 3358 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList); 3359 } 3360 3361 @Override 3362 public void createNotificationChannelsForPackage(String pkg, int uid, 3363 ParceledListSlice channelsList) { 3364 enforceSystemOrSystemUI("only system can call this"); 3365 createNotificationChannelsImpl(pkg, uid, channelsList); 3366 } 3367 3368 @Override 3369 public void createConversationNotificationChannelForPackage(String pkg, int uid, 3370 String triggeringKey, NotificationChannel parentChannel, String conversationId) { 3371 enforceSystemOrSystemUI("only system can call this"); 3372 Preconditions.checkNotNull(parentChannel); 3373 Preconditions.checkNotNull(conversationId); 3374 String parentId = parentChannel.getId(); 3375 NotificationChannel conversationChannel = parentChannel; 3376 conversationChannel.setId(String.format( 3377 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId)); 3378 conversationChannel.setConversationId(parentId, conversationId); 3379 createNotificationChannelsImpl( 3380 pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel))); 3381 mRankingHandler.requestSort(); 3382 handleSavePolicyFile(); 3383 } 3384 3385 @Override 3386 public NotificationChannel getNotificationChannel(String callingPkg, int userId, 3387 String targetPkg, String channelId) { 3388 return getConversationNotificationChannel( 3389 callingPkg, userId, targetPkg, channelId, true, null); 3390 } 3391 3392 @Override 3393 public NotificationChannel getConversationNotificationChannel(String callingPkg, int userId, 3394 String targetPkg, String channelId, boolean returnParentIfNoConversationChannel, 3395 String conversationId) { 3396 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 3397 || isCallerIsSystemOrSysemUiOrShell()) { 3398 int targetUid = -1; 3399 try { 3400 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 3401 } catch (NameNotFoundException e) { 3402 /* ignore */ 3403 } 3404 return mPreferencesHelper.getConversationNotificationChannel( 3405 targetPkg, targetUid, channelId, conversationId, 3406 returnParentIfNoConversationChannel, false /* includeDeleted */); 3407 } 3408 throw new SecurityException("Pkg " + callingPkg 3409 + " cannot read channels for " + targetPkg + " in " + userId); 3410 } 3411 3412 @Override 3413 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, 3414 String channelId, String conversationId, boolean includeDeleted) { 3415 checkCallerIsSystem(); 3416 return mPreferencesHelper.getConversationNotificationChannel( 3417 pkg, uid, channelId, conversationId, true, includeDeleted); 3418 } 3419 3420 // Returns 'true' if the given channel has a notification associated 3421 // with an active foreground service. 3422 private void enforceDeletingChannelHasNoFgService(String pkg, int userId, 3423 String channelId) { 3424 if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { 3425 Slog.w(TAG, "Package u" + userId + "/" + pkg 3426 + " may not delete notification channel '" 3427 + channelId + "' with fg service"); 3428 throw new SecurityException("Not allowed to delete channel " + channelId 3429 + " with a foreground service"); 3430 } 3431 } 3432 3433 @Override 3434 public void deleteNotificationChannel(String pkg, String channelId) { 3435 checkCallerIsSystemOrSameApp(pkg); 3436 final int callingUid = Binder.getCallingUid(); 3437 final int callingUser = UserHandle.getUserId(callingUid); 3438 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 3439 throw new IllegalArgumentException("Cannot delete default channel"); 3440 } 3441 enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); 3442 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, 3443 callingUser, REASON_CHANNEL_BANNED, null); 3444 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId); 3445 mListeners.notifyNotificationChannelChanged(pkg, 3446 UserHandle.getUserHandleForUid(callingUid), 3447 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true), 3448 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 3449 handleSavePolicyFile(); 3450 } 3451 3452 @Override 3453 public void deleteConversationNotificationChannels(String pkg, int uid, 3454 String conversationId) { 3455 checkCallerIsSystem(); 3456 List<NotificationChannel> channels = 3457 mPreferencesHelper.getNotificationChannelsByConversationId( 3458 pkg, uid, conversationId); 3459 if (!channels.isEmpty()) { 3460 // Preflight for fg service notifications in these channels: do nothing 3461 // unless they're all eligible 3462 final int appUserId = UserHandle.getUserId(uid); 3463 for (NotificationChannel nc : channels) { 3464 final String channelId = nc.getId(); 3465 mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId); 3466 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true, 3467 appUserId, REASON_CHANNEL_BANNED, null); 3468 mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId); 3469 mListeners.notifyNotificationChannelChanged(pkg, 3470 UserHandle.getUserHandleForUid(uid), 3471 mPreferencesHelper.getNotificationChannel( 3472 pkg, uid, channelId, true), 3473 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 3474 } 3475 handleSavePolicyFile(); 3476 } 3477 } 3478 3479 3480 @Override 3481 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) { 3482 checkCallerIsSystemOrSameApp(pkg); 3483 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 3484 pkg, Binder.getCallingUid(), groupId, false); 3485 } 3486 3487 @Override 3488 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups( 3489 String pkg) { 3490 checkCallerIsSystemOrSameApp(pkg); 3491 return mPreferencesHelper.getNotificationChannelGroups( 3492 pkg, Binder.getCallingUid(), false, false, true); 3493 } 3494 3495 @Override 3496 public void deleteNotificationChannelGroup(String pkg, String groupId) { 3497 checkCallerIsSystemOrSameApp(pkg); 3498 3499 final int callingUid = Binder.getCallingUid(); 3500 NotificationChannelGroup groupToDelete = 3501 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid); 3502 if (groupToDelete != null) { 3503 // Preflight for allowability 3504 final int userId = UserHandle.getUserId(callingUid); 3505 List<NotificationChannel> groupChannels = groupToDelete.getChannels(); 3506 for (int i = 0; i < groupChannels.size(); i++) { 3507 enforceDeletingChannelHasNoFgService(pkg, userId, 3508 groupChannels.get(i).getId()); 3509 } 3510 List<NotificationChannel> deletedChannels = 3511 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); 3512 for (int i = 0; i < deletedChannels.size(); i++) { 3513 final NotificationChannel deletedChannel = deletedChannels.get(i); 3514 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, 3515 true, 3516 userId, REASON_CHANNEL_BANNED, 3517 null); 3518 mListeners.notifyNotificationChannelChanged(pkg, 3519 UserHandle.getUserHandleForUid(callingUid), 3520 deletedChannel, 3521 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 3522 } 3523 mListeners.notifyNotificationChannelGroupChanged( 3524 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, 3525 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 3526 handleSavePolicyFile(); 3527 } 3528 } 3529 3530 @Override 3531 public void updateNotificationChannelForPackage(String pkg, int uid, 3532 NotificationChannel channel) { 3533 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 3534 Objects.requireNonNull(channel); 3535 updateNotificationChannelInt(pkg, uid, channel, false); 3536 } 3537 3538 @Override 3539 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg, 3540 int uid, boolean includeDeleted) { 3541 enforceSystemOrSystemUI("getNotificationChannelsForPackage"); 3542 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted); 3543 } 3544 3545 @Override 3546 public int getNumNotificationChannelsForPackage(String pkg, int uid, 3547 boolean includeDeleted) { 3548 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage"); 3549 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted) 3550 .getList().size(); 3551 } 3552 3553 @Override 3554 public boolean onlyHasDefaultChannel(String pkg, int uid) { 3555 enforceSystemOrSystemUI("onlyHasDefaultChannel"); 3556 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid); 3557 } 3558 3559 @Override 3560 public int getDeletedChannelCount(String pkg, int uid) { 3561 enforceSystemOrSystemUI("getDeletedChannelCount"); 3562 return mPreferencesHelper.getDeletedChannelCount(pkg, uid); 3563 } 3564 3565 @Override 3566 public int getBlockedChannelCount(String pkg, int uid) { 3567 enforceSystemOrSystemUI("getBlockedChannelCount"); 3568 return mPreferencesHelper.getBlockedChannelCount(pkg, uid); 3569 } 3570 3571 @Override 3572 public ParceledListSlice<ConversationChannelWrapper> getConversations( 3573 boolean onlyImportant) { 3574 enforceSystemOrSystemUI("getConversations"); 3575 IntArray userIds = mUserProfiles.getCurrentProfileIds(); 3576 ArrayList<ConversationChannelWrapper> conversations = 3577 mPreferencesHelper.getConversations(userIds, onlyImportant); 3578 for (ConversationChannelWrapper conversation : conversations) { 3579 if (mShortcutHelper == null) { 3580 conversation.setShortcutInfo(null); 3581 } else { 3582 conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo( 3583 conversation.getNotificationChannel().getConversationId(), 3584 conversation.getPkg(), 3585 UserHandle.of(UserHandle.getUserId(conversation.getUid())))); 3586 } 3587 } 3588 return new ParceledListSlice<>(conversations); 3589 } 3590 3591 @Override 3592 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage( 3593 String pkg, int uid, boolean includeDeleted) { 3594 enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage"); 3595 return mPreferencesHelper.getNotificationChannelGroups( 3596 pkg, uid, includeDeleted, true, false); 3597 } 3598 3599 @Override 3600 public ParceledListSlice<ConversationChannelWrapper> getConversationsForPackage(String pkg, 3601 int uid) { 3602 enforceSystemOrSystemUI("getConversationsForPackage"); 3603 ArrayList<ConversationChannelWrapper> conversations = 3604 mPreferencesHelper.getConversations(pkg, uid); 3605 for (ConversationChannelWrapper conversation : conversations) { 3606 if (mShortcutHelper == null) { 3607 conversation.setShortcutInfo(null); 3608 } else { 3609 conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo( 3610 conversation.getNotificationChannel().getConversationId(), 3611 pkg, 3612 UserHandle.of(UserHandle.getUserId(uid)))); 3613 } 3614 } 3615 return new ParceledListSlice<>(conversations); 3616 } 3617 3618 @Override 3619 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage( 3620 String pkg, int uid, String groupId, boolean includeDeleted) { 3621 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage"); 3622 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 3623 pkg, uid, groupId, includeDeleted); 3624 } 3625 3626 @Override 3627 public NotificationChannelGroup getNotificationChannelGroupForPackage( 3628 String groupId, String pkg, int uid) { 3629 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage"); 3630 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid); 3631 } 3632 3633 @Override 3634 public ParceledListSlice<NotificationChannel> getNotificationChannels( 3635 String callingPkg, String targetPkg, int userId) { 3636 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 3637 || isCallingUidSystem()) { 3638 int targetUid = -1; 3639 try { 3640 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 3641 } catch (NameNotFoundException e) { 3642 /* ignore */ 3643 } 3644 return mPreferencesHelper.getNotificationChannels( 3645 targetPkg, targetUid, false /* includeDeleted */); 3646 } 3647 throw new SecurityException("Pkg " + callingPkg 3648 + " cannot read channels for " + targetPkg + " in " + userId); 3649 } 3650 3651 @Override 3652 public int getBlockedAppCount(int userId) { 3653 checkCallerIsSystem(); 3654 return mPreferencesHelper.getBlockedAppCount(userId); 3655 } 3656 3657 @Override 3658 public int getAppsBypassingDndCount(int userId) { 3659 checkCallerIsSystem(); 3660 return mPreferencesHelper.getAppsBypassingDndCount(userId); 3661 } 3662 3663 @Override 3664 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( 3665 String pkg, int userId) { 3666 checkCallerIsSystem(); 3667 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId); 3668 } 3669 3670 @Override 3671 public boolean areChannelsBypassingDnd() { 3672 return mPreferencesHelper.areChannelsBypassingDnd(); 3673 } 3674 3675 @Override 3676 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException { 3677 boolean packagesChanged = false; 3678 checkCallerIsSystem(); 3679 // Cancel posted notifications 3680 final int userId = UserHandle.getUserId(uid); 3681 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true, 3682 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); 3683 3684 // Zen 3685 packagesChanged |= 3686 mConditionProviders.resetPackage(packageName, userId); 3687 3688 // Listener 3689 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 3690 mListeners.resetComponents(packageName, userId); 3691 packagesChanged |= changedListeners.get(true).size() > 0 3692 || changedListeners.get(false).size() > 0; 3693 3694 // When a listener is enabled, we enable the dnd package as a secondary 3695 for (int i = 0; i < changedListeners.get(true).size(); i++) { 3696 mConditionProviders.setPackageOrComponentEnabled( 3697 changedListeners.get(true).get(i).getPackageName(), 3698 userId, false, true); 3699 } 3700 3701 // Assistant 3702 ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants = 3703 mAssistants.resetComponents(packageName, userId); 3704 packagesChanged |= changedAssistants.get(true).size() > 0 3705 || changedAssistants.get(false).size() > 0; 3706 3707 // we want only one assistant enabled 3708 for (int i = 1; i < changedAssistants.get(true).size(); i++) { 3709 mAssistants.setPackageOrComponentEnabled( 3710 changedAssistants.get(true).get(i).flattenToString(), 3711 userId, true, false); 3712 } 3713 3714 // When the default assistant is enabled, we enable the dnd package as a secondary 3715 if (changedAssistants.get(true).size() > 0) { 3716 //we want only one assistant active 3717 mConditionProviders 3718 .setPackageOrComponentEnabled( 3719 changedAssistants.get(true).get(0).getPackageName(), 3720 userId, false, true); 3721 3722 } 3723 3724 // Snoozing 3725 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName); 3726 3727 // Reset notification preferences 3728 if (!fromApp) { 3729 mPreferencesHelper.clearData(packageName, uid); 3730 } 3731 3732 if (packagesChanged) { 3733 getContext().sendBroadcastAsUser(new Intent( 3734 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 3735 .setPackage(packageName) 3736 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 3737 UserHandle.of(userId), null); 3738 } 3739 3740 handleSavePolicyFile(); 3741 } 3742 3743 @Override 3744 public List<String> getAllowedAssistantAdjustments(String pkg) { 3745 checkCallerIsSystemOrSameApp(pkg); 3746 3747 if (!isCallerSystemOrPhone() 3748 && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) { 3749 throw new SecurityException("Not currently an assistant"); 3750 } 3751 3752 return mAssistants.getAllowedAssistantAdjustments(); 3753 } 3754 3755 @Override 3756 public void allowAssistantAdjustment(String adjustmentType) { 3757 checkCallerIsSystemOrSystemUiOrShell(); 3758 mAssistants.allowAdjustmentType(adjustmentType); 3759 3760 handleSavePolicyFile(); 3761 } 3762 3763 @Override 3764 public void disallowAssistantAdjustment(String adjustmentType) { 3765 checkCallerIsSystemOrSystemUiOrShell(); 3766 mAssistants.disallowAdjustmentType(adjustmentType); 3767 3768 handleSavePolicyFile(); 3769 } 3770 3771 /** 3772 * @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead. 3773 */ 3774 @Deprecated 3775 @Override 3776 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 3777 return getActiveNotificationsWithAttribution(callingPkg, null); 3778 } 3779 3780 /** 3781 * System-only API for getting a list of current (i.e. not cleared) notifications. 3782 * 3783 * Requires ACCESS_NOTIFICATIONS which is signature|system. 3784 * @returns A list of all the notifications, in natural order. 3785 */ 3786 @Override 3787 public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg, 3788 String callingAttributionTag) { 3789 // enforce() will ensure the calling uid has the correct permission 3790 getContext().enforceCallingOrSelfPermission( 3791 android.Manifest.permission.ACCESS_NOTIFICATIONS, 3792 "NotificationManagerService.getActiveNotifications"); 3793 3794 StatusBarNotification[] tmp = null; 3795 int uid = Binder.getCallingUid(); 3796 3797 // noteOp will check to make sure the callingPkg matches the uid 3798 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 3799 callingAttributionTag, null) 3800 == AppOpsManager.MODE_ALLOWED) { 3801 synchronized (mNotificationLock) { 3802 tmp = new StatusBarNotification[mNotificationList.size()]; 3803 final int N = mNotificationList.size(); 3804 for (int i=0; i<N; i++) { 3805 tmp[i] = mNotificationList.get(i).getSbn(); 3806 } 3807 } 3808 } 3809 return tmp; 3810 } 3811 3812 /** 3813 * Public API for getting a list of current notifications for the calling package/uid. 3814 * 3815 * Note that since notification posting is done asynchronously, this will not return 3816 * notifications that are in the process of being posted. 3817 * 3818 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as 3819 * an app's notification delegate via 3820 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}. 3821 * 3822 * @returns A list of all the package's notifications, in natural order. 3823 */ 3824 @Override 3825 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 3826 int incomingUserId) { 3827 checkCallerIsSystemOrSameApp(pkg); 3828 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 3829 Binder.getCallingUid(), incomingUserId, true, false, 3830 "getAppActiveNotifications", pkg); 3831 synchronized (mNotificationLock) { 3832 final ArrayMap<String, StatusBarNotification> map 3833 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); 3834 final int N = mNotificationList.size(); 3835 for (int i = 0; i < N; i++) { 3836 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 3837 mNotificationList.get(i).getSbn()); 3838 if (sbn != null) { 3839 map.put(sbn.getKey(), sbn); 3840 } 3841 } 3842 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) { 3843 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.getSbn()); 3844 if (sbn != null) { 3845 map.put(sbn.getKey(), sbn); 3846 } 3847 } 3848 final int M = mEnqueuedNotifications.size(); 3849 for (int i = 0; i < M; i++) { 3850 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 3851 mEnqueuedNotifications.get(i).getSbn()); 3852 if (sbn != null) { 3853 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here 3854 } 3855 } 3856 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); 3857 list.addAll(map.values()); 3858 return new ParceledListSlice<StatusBarNotification>(list); 3859 } 3860 } 3861 3862 /** Notifications returned here will have allowlistToken stripped from them. */ 3863 private StatusBarNotification sanitizeSbn(String pkg, int userId, 3864 StatusBarNotification sbn) { 3865 if (sbn.getUserId() == userId) { 3866 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) { 3867 // We could pass back a cloneLight() but clients might get confused and 3868 // try to send this thing back to notify() again, which would not work 3869 // very well. 3870 Notification notification = sbn.getNotification().clone(); 3871 // Remove background token before returning notification to untrusted app, this 3872 // ensures the app isn't able to perform background operations that are 3873 // associated with notification interactions. 3874 notification.setAllowlistToken(null); 3875 return new StatusBarNotification( 3876 sbn.getPackageName(), 3877 sbn.getOpPkg(), 3878 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 3879 notification, 3880 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); 3881 } 3882 } 3883 return null; 3884 } 3885 3886 /** 3887 * @deprecated Use {@link #getHistoricalNotificationsWithAttribution} instead. 3888 */ 3889 @Deprecated 3890 @Override 3891 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 3892 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count, 3893 boolean includeSnoozed) { 3894 return getHistoricalNotificationsWithAttribution(callingPkg, null, count, 3895 includeSnoozed); 3896 } 3897 3898 /** 3899 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 3900 */ 3901 @Override 3902 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 3903 public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg, 3904 String callingAttributionTag, int count, boolean includeSnoozed) { 3905 // enforce() will ensure the calling uid has the correct permission 3906 getContext().enforceCallingOrSelfPermission( 3907 android.Manifest.permission.ACCESS_NOTIFICATIONS, 3908 "NotificationManagerService.getHistoricalNotifications"); 3909 3910 StatusBarNotification[] tmp = null; 3911 int uid = Binder.getCallingUid(); 3912 3913 // noteOp will check to make sure the callingPkg matches the uid 3914 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 3915 callingAttributionTag, null) 3916 == AppOpsManager.MODE_ALLOWED) { 3917 synchronized (mArchive) { 3918 tmp = mArchive.getArray(count, includeSnoozed); 3919 } 3920 } 3921 return tmp; 3922 } 3923 3924 /** 3925 * System-only API for getting a list of historical notifications. May contain multiple days 3926 * of notifications. 3927 */ 3928 @Override 3929 @WorkerThread 3930 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 3931 public NotificationHistory getNotificationHistory(String callingPkg, 3932 String callingAttributionTag) { 3933 // enforce() will ensure the calling uid has the correct permission 3934 getContext().enforceCallingOrSelfPermission( 3935 android.Manifest.permission.ACCESS_NOTIFICATIONS, 3936 "NotificationManagerService.getNotificationHistory"); 3937 int uid = Binder.getCallingUid(); 3938 3939 // noteOp will check to make sure the callingPkg matches the uid 3940 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 3941 callingAttributionTag, null) 3942 == AppOpsManager.MODE_ALLOWED) { 3943 IntArray currentUserIds = mUserProfiles.getCurrentProfileIds(); 3944 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory"); 3945 try { 3946 return mHistoryManager.readNotificationHistory(currentUserIds.toArray()); 3947 } finally { 3948 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 3949 } 3950 } 3951 return new NotificationHistory(); 3952 } 3953 3954 /** 3955 * Register a listener binder directly with the notification manager. 3956 * 3957 * Only works with system callers. Apps should extend 3958 * {@link android.service.notification.NotificationListenerService}. 3959 */ 3960 @Override 3961 public void registerListener(final INotificationListener listener, 3962 final ComponentName component, final int userid) { 3963 enforceSystemOrSystemUI("INotificationManager.registerListener"); 3964 mListeners.registerSystemService(listener, component, userid); 3965 } 3966 3967 /** 3968 * Remove a listener binder directly 3969 */ 3970 @Override 3971 public void unregisterListener(INotificationListener token, int userid) { 3972 mListeners.unregisterService(token, userid); 3973 } 3974 3975 /** 3976 * Allow an INotificationListener to simulate a "clear all" operation. 3977 * 3978 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 3979 * 3980 * @param token The binder for the listener, to check that the caller is allowed 3981 */ 3982 @Override 3983 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 3984 final int callingUid = Binder.getCallingUid(); 3985 final int callingPid = Binder.getCallingPid(); 3986 long identity = Binder.clearCallingIdentity(); 3987 try { 3988 synchronized (mNotificationLock) { 3989 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3990 3991 if (keys != null) { 3992 final int N = keys.length; 3993 for (int i = 0; i < N; i++) { 3994 NotificationRecord r = mNotificationsByKey.get(keys[i]); 3995 if (r == null) continue; 3996 final int userId = r.getSbn().getUserId(); 3997 if (userId != info.userid && userId != UserHandle.USER_ALL && 3998 !mUserProfiles.isCurrentProfile(userId)) { 3999 throw new SecurityException("Disallowed call from listener: " 4000 + info.service); 4001 } 4002 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 4003 r.getSbn().getPackageName(), r.getSbn().getTag(), 4004 r.getSbn().getId(), userId); 4005 } 4006 } else { 4007 cancelAllLocked(callingUid, callingPid, info.userid, 4008 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 4009 } 4010 } 4011 } finally { 4012 Binder.restoreCallingIdentity(identity); 4013 } 4014 } 4015 4016 /** 4017 * Handle request from an approved listener to re-enable itself. 4018 * 4019 * @param component The componenet to be re-enabled, caller must match package. 4020 */ 4021 @Override 4022 public void requestBindListener(ComponentName component) { 4023 checkCallerIsSystemOrSameApp(component.getPackageName()); 4024 long identity = Binder.clearCallingIdentity(); 4025 try { 4026 ManagedServices manager = 4027 mAssistants.isComponentEnabledForCurrentProfiles(component) 4028 ? mAssistants 4029 : mListeners; 4030 manager.setComponentState(component, true); 4031 } finally { 4032 Binder.restoreCallingIdentity(identity); 4033 } 4034 } 4035 4036 @Override 4037 public void requestUnbindListener(INotificationListener token) { 4038 long identity = Binder.clearCallingIdentity(); 4039 try { 4040 // allow bound services to disable themselves 4041 synchronized (mNotificationLock) { 4042 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4043 info.getOwner().setComponentState(info.component, false); 4044 } 4045 } finally { 4046 Binder.restoreCallingIdentity(identity); 4047 } 4048 } 4049 4050 @Override 4051 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 4052 long identity = Binder.clearCallingIdentity(); 4053 try { 4054 synchronized (mNotificationLock) { 4055 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4056 if (keys == null) { 4057 return; 4058 } 4059 ArrayList<NotificationRecord> seen = new ArrayList<>(); 4060 final int n = keys.length; 4061 for (int i = 0; i < n; i++) { 4062 NotificationRecord r = mNotificationsByKey.get(keys[i]); 4063 if (r == null) continue; 4064 final int userId = r.getSbn().getUserId(); 4065 if (userId != info.userid && userId != UserHandle.USER_ALL 4066 && !mUserProfiles.isCurrentProfile(userId)) { 4067 throw new SecurityException("Disallowed call from listener: " 4068 + info.service); 4069 } 4070 seen.add(r); 4071 if (!r.isSeen()) { 4072 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 4073 reportSeen(r); 4074 r.setSeen(); 4075 maybeRecordInterruptionLocked(r); 4076 } 4077 } 4078 if (!seen.isEmpty()) { 4079 mAssistants.onNotificationsSeenLocked(seen); 4080 } 4081 } 4082 } finally { 4083 Binder.restoreCallingIdentity(identity); 4084 } 4085 } 4086 4087 /** 4088 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 4089 * 4090 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 4091 * 4092 * @param info The binder for the listener, to check that the caller is allowed 4093 */ 4094 @GuardedBy("mNotificationLock") 4095 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 4096 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 4097 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 4098 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE, 4099 true, 4100 userId, REASON_LISTENER_CANCEL, info); 4101 } 4102 4103 /** 4104 * Allow an INotificationListener to snooze a single notification until a context. 4105 * 4106 * @param token The binder for the listener, to check that the caller is allowed 4107 */ 4108 @Override 4109 public void snoozeNotificationUntilContextFromListener(INotificationListener token, 4110 String key, String snoozeCriterionId) { 4111 long identity = Binder.clearCallingIdentity(); 4112 try { 4113 synchronized (mNotificationLock) { 4114 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4115 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); 4116 } 4117 } finally { 4118 Binder.restoreCallingIdentity(identity); 4119 } 4120 } 4121 4122 /** 4123 * Allow an INotificationListener to snooze a single notification until a time. 4124 * 4125 * @param token The binder for the listener, to check that the caller is allowed 4126 */ 4127 @Override 4128 public void snoozeNotificationUntilFromListener(INotificationListener token, String key, 4129 long duration) { 4130 long identity = Binder.clearCallingIdentity(); 4131 try { 4132 synchronized (mNotificationLock) { 4133 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4134 snoozeNotificationInt(key, duration, null, info); 4135 } 4136 } finally { 4137 Binder.restoreCallingIdentity(identity); 4138 } 4139 } 4140 4141 /** 4142 * Allows the notification assistant to un-snooze a single notification. 4143 * 4144 * @param token The binder for the assistant, to check that the caller is allowed 4145 */ 4146 @Override 4147 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { 4148 long identity = Binder.clearCallingIdentity(); 4149 try { 4150 synchronized (mNotificationLock) { 4151 final ManagedServiceInfo info = 4152 mAssistants.checkServiceTokenLocked(token); 4153 unsnoozeNotificationInt(key, info, false); 4154 } 4155 } finally { 4156 Binder.restoreCallingIdentity(identity); 4157 } 4158 } 4159 4160 /** 4161 * Allows the notification assistant to un-snooze a single notification. 4162 * 4163 * @param token The binder for the listener, to check that the caller is allowed 4164 */ 4165 @Override 4166 public void unsnoozeNotificationFromSystemListener(INotificationListener token, 4167 String key) { 4168 long identity = Binder.clearCallingIdentity(); 4169 try { 4170 synchronized (mNotificationLock) { 4171 final ManagedServiceInfo info = 4172 mListeners.checkServiceTokenLocked(token); 4173 if (!info.isSystem) { 4174 throw new SecurityException("Not allowed to unsnooze before deadline"); 4175 } 4176 unsnoozeNotificationInt(key, info, true); 4177 } 4178 } finally { 4179 Binder.restoreCallingIdentity(identity); 4180 } 4181 } 4182 4183 /** 4184 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 4185 * 4186 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 4187 * 4188 * @param token The binder for the listener, to check that the caller is allowed 4189 */ 4190 @Override 4191 public void cancelNotificationFromListener(INotificationListener token, String pkg, 4192 String tag, int id) { 4193 final int callingUid = Binder.getCallingUid(); 4194 final int callingPid = Binder.getCallingPid(); 4195 long identity = Binder.clearCallingIdentity(); 4196 try { 4197 synchronized (mNotificationLock) { 4198 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4199 if (info.supportsProfiles()) { 4200 Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 4201 + "from " + info.component 4202 + " use cancelNotification(key) instead."); 4203 } else { 4204 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 4205 pkg, tag, id, info.userid); 4206 } 4207 } 4208 } finally { 4209 Binder.restoreCallingIdentity(identity); 4210 } 4211 } 4212 4213 /** 4214 * Allow an INotificationListener to request the list of outstanding notifications seen by 4215 * the current user. Useful when starting up, after which point the listener callbacks 4216 * should be used. 4217 * 4218 * @param token The binder for the listener, to check that the caller is allowed 4219 * @param keys An array of notification keys to fetch, or null to fetch everything 4220 * @returns The return value will contain the notifications specified in keys, in that 4221 * order, or if keys is null, all the notifications, in natural order. 4222 */ 4223 @Override 4224 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 4225 INotificationListener token, String[] keys, int trim) { 4226 synchronized (mNotificationLock) { 4227 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4228 final boolean getKeys = keys != null; 4229 final int N = getKeys ? keys.length : mNotificationList.size(); 4230 final ArrayList<StatusBarNotification> list 4231 = new ArrayList<StatusBarNotification>(N); 4232 for (int i=0; i<N; i++) { 4233 final NotificationRecord r = getKeys 4234 ? mNotificationsByKey.get(keys[i]) 4235 : mNotificationList.get(i); 4236 if (r == null) continue; 4237 StatusBarNotification sbn = r.getSbn(); 4238 if (!isVisibleToListener(sbn, info)) continue; 4239 StatusBarNotification sbnToSend = 4240 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 4241 list.add(sbnToSend); 4242 } 4243 return new ParceledListSlice<StatusBarNotification>(list); 4244 } 4245 } 4246 4247 /** 4248 * Allow an INotificationListener to request the list of outstanding snoozed notifications 4249 * seen by the current user. Useful when starting up, after which point the listener 4250 * callbacks should be used. 4251 * 4252 * @param token The binder for the listener, to check that the caller is allowed 4253 * @returns The return value will contain the notifications specified in keys, in that 4254 * order, or if keys is null, all the notifications, in natural order. 4255 */ 4256 @Override 4257 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener( 4258 INotificationListener token, int trim) { 4259 synchronized (mNotificationLock) { 4260 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4261 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed(); 4262 final int N = snoozedRecords.size(); 4263 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 4264 for (int i=0; i < N; i++) { 4265 final NotificationRecord r = snoozedRecords.get(i); 4266 if (r == null) continue; 4267 StatusBarNotification sbn = r.getSbn(); 4268 if (!isVisibleToListener(sbn, info)) continue; 4269 StatusBarNotification sbnToSend = 4270 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 4271 list.add(sbnToSend); 4272 } 4273 return new ParceledListSlice<>(list); 4274 } 4275 } 4276 4277 @Override 4278 public void clearRequestedListenerHints(INotificationListener token) { 4279 final long identity = Binder.clearCallingIdentity(); 4280 try { 4281 synchronized (mNotificationLock) { 4282 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4283 removeDisabledHints(info); 4284 updateListenerHintsLocked(); 4285 updateEffectsSuppressorLocked(); 4286 } 4287 } finally { 4288 Binder.restoreCallingIdentity(identity); 4289 } 4290 } 4291 4292 @Override 4293 public void requestHintsFromListener(INotificationListener token, int hints) { 4294 final long identity = Binder.clearCallingIdentity(); 4295 try { 4296 synchronized (mNotificationLock) { 4297 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4298 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS 4299 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS 4300 | HINT_HOST_DISABLE_CALL_EFFECTS; 4301 final boolean disableEffects = (hints & disableEffectsMask) != 0; 4302 if (disableEffects) { 4303 addDisabledHints(info, hints); 4304 } else { 4305 removeDisabledHints(info, hints); 4306 } 4307 updateListenerHintsLocked(); 4308 updateEffectsSuppressorLocked(); 4309 } 4310 } finally { 4311 Binder.restoreCallingIdentity(identity); 4312 } 4313 } 4314 4315 @Override 4316 public int getHintsFromListener(INotificationListener token) { 4317 synchronized (mNotificationLock) { 4318 return mListenerHints; 4319 } 4320 } 4321 4322 @Override 4323 public void requestInterruptionFilterFromListener(INotificationListener token, 4324 int interruptionFilter) throws RemoteException { 4325 final long identity = Binder.clearCallingIdentity(); 4326 try { 4327 synchronized (mNotificationLock) { 4328 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4329 mZenModeHelper.requestFromListener(info.component, interruptionFilter); 4330 updateInterruptionFilterLocked(); 4331 } 4332 } finally { 4333 Binder.restoreCallingIdentity(identity); 4334 } 4335 } 4336 4337 @Override 4338 public int getInterruptionFilterFromListener(INotificationListener token) 4339 throws RemoteException { 4340 synchronized (mNotificationLock) { 4341 return mInterruptionFilter; 4342 } 4343 } 4344 4345 @Override 4346 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 4347 throws RemoteException { 4348 synchronized (mNotificationLock) { 4349 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 4350 if (info == null) return; 4351 mListeners.setOnNotificationPostedTrimLocked(info, trim); 4352 } 4353 } 4354 4355 @Override 4356 public int getZenMode() { 4357 return mZenModeHelper.getZenMode(); 4358 } 4359 4360 @Override 4361 public ZenModeConfig getZenModeConfig() { 4362 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig"); 4363 return mZenModeHelper.getConfig(); 4364 } 4365 4366 @Override 4367 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { 4368 enforceSystemOrSystemUI("INotificationManager.setZenMode"); 4369 final long identity = Binder.clearCallingIdentity(); 4370 try { 4371 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason); 4372 } finally { 4373 Binder.restoreCallingIdentity(identity); 4374 } 4375 } 4376 4377 @Override 4378 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException { 4379 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); 4380 return mZenModeHelper.getZenRules(); 4381 } 4382 4383 @Override 4384 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 4385 Objects.requireNonNull(id, "Id is null"); 4386 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); 4387 return mZenModeHelper.getAutomaticZenRule(id); 4388 } 4389 4390 @Override 4391 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) { 4392 Objects.requireNonNull(automaticZenRule, "automaticZenRule is null"); 4393 Objects.requireNonNull(automaticZenRule.getName(), "Name is null"); 4394 if (automaticZenRule.getOwner() == null 4395 && automaticZenRule.getConfigurationActivity() == null) { 4396 throw new NullPointerException( 4397 "Rule must have a conditionproviderservice and/or configuration activity"); 4398 } 4399 Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null"); 4400 if (automaticZenRule.getZenPolicy() != null 4401 && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { 4402 throw new IllegalArgumentException("ZenPolicy is only applicable to " 4403 + "INTERRUPTION_FILTER_PRIORITY filters"); 4404 } 4405 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 4406 4407 return mZenModeHelper.addAutomaticZenRule(automaticZenRule, 4408 "addAutomaticZenRule"); 4409 } 4410 4411 @Override 4412 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) 4413 throws RemoteException { 4414 Objects.requireNonNull(automaticZenRule, "automaticZenRule is null"); 4415 Objects.requireNonNull(automaticZenRule.getName(), "Name is null"); 4416 if (automaticZenRule.getOwner() == null 4417 && automaticZenRule.getConfigurationActivity() == null) { 4418 throw new NullPointerException( 4419 "Rule must have a conditionproviderservice and/or configuration activity"); 4420 } 4421 Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null"); 4422 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 4423 4424 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule, 4425 "updateAutomaticZenRule"); 4426 } 4427 4428 @Override 4429 public boolean removeAutomaticZenRule(String id) throws RemoteException { 4430 Objects.requireNonNull(id, "Id is null"); 4431 // Verify that they can modify zen rules. 4432 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 4433 4434 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule"); 4435 } 4436 4437 @Override 4438 public boolean removeAutomaticZenRules(String packageName) throws RemoteException { 4439 Objects.requireNonNull(packageName, "Package name is null"); 4440 enforceSystemOrSystemUI("removeAutomaticZenRules"); 4441 4442 return mZenModeHelper.removeAutomaticZenRules(packageName, 4443 packageName + "|removeAutomaticZenRules"); 4444 } 4445 4446 @Override 4447 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 4448 Objects.requireNonNull(owner, "Owner is null"); 4449 enforceSystemOrSystemUI("getRuleInstanceCount"); 4450 4451 return mZenModeHelper.getCurrentInstanceCount(owner); 4452 } 4453 4454 @Override 4455 public void setAutomaticZenRuleState(String id, Condition condition) { 4456 Objects.requireNonNull(id, "id is null"); 4457 Objects.requireNonNull(condition, "Condition is null"); 4458 4459 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState"); 4460 4461 mZenModeHelper.setAutomaticZenRuleState(id, condition); 4462 } 4463 4464 @Override 4465 public void setInterruptionFilter(String pkg, int filter) throws RemoteException { 4466 enforcePolicyAccess(pkg, "setInterruptionFilter"); 4467 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 4468 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 4469 final long identity = Binder.clearCallingIdentity(); 4470 try { 4471 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter"); 4472 } finally { 4473 Binder.restoreCallingIdentity(identity); 4474 } 4475 } 4476 4477 @Override 4478 public void notifyConditions(final String pkg, IConditionProvider provider, 4479 final Condition[] conditions) { 4480 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 4481 checkCallerIsSystemOrSameApp(pkg); 4482 mHandler.post(new Runnable() { 4483 @Override 4484 public void run() { 4485 mConditionProviders.notifyConditions(pkg, info, conditions); 4486 } 4487 }); 4488 } 4489 4490 @Override 4491 public void requestUnbindProvider(IConditionProvider provider) { 4492 long identity = Binder.clearCallingIdentity(); 4493 try { 4494 // allow bound services to disable themselves 4495 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 4496 info.getOwner().setComponentState(info.component, false); 4497 } finally { 4498 Binder.restoreCallingIdentity(identity); 4499 } 4500 } 4501 4502 @Override 4503 public void requestBindProvider(ComponentName component) { 4504 checkCallerIsSystemOrSameApp(component.getPackageName()); 4505 long identity = Binder.clearCallingIdentity(); 4506 try { 4507 mConditionProviders.setComponentState(component, true); 4508 } finally { 4509 Binder.restoreCallingIdentity(identity); 4510 } 4511 } 4512 4513 private void enforceSystemOrSystemUI(String message) { 4514 if (isCallerSystemOrPhone()) return; 4515 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 4516 message); 4517 } 4518 4519 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) { 4520 try { 4521 checkCallerIsSystemOrSameApp(pkg); 4522 } catch (SecurityException e) { 4523 getContext().enforceCallingPermission( 4524 android.Manifest.permission.STATUS_BAR_SERVICE, 4525 message); 4526 } 4527 } 4528 4529 private void enforcePolicyAccess(int uid, String method) { 4530 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 4531 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 4532 return; 4533 } 4534 boolean accessAllowed = false; 4535 String[] packages = mPackageManagerClient.getPackagesForUid(uid); 4536 final int packageCount = packages.length; 4537 for (int i = 0; i < packageCount; i++) { 4538 if (mConditionProviders.isPackageOrComponentAllowed( 4539 packages[i], UserHandle.getUserId(uid))) { 4540 accessAllowed = true; 4541 } 4542 } 4543 if (!accessAllowed) { 4544 Slog.w(TAG, "Notification policy access denied calling " + method); 4545 throw new SecurityException("Notification policy access denied"); 4546 } 4547 } 4548 4549 private void enforcePolicyAccess(String pkg, String method) { 4550 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 4551 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 4552 return; 4553 } 4554 checkCallerIsSameApp(pkg); 4555 if (!checkPolicyAccess(pkg)) { 4556 Slog.w(TAG, "Notification policy access denied calling " + method); 4557 throw new SecurityException("Notification policy access denied"); 4558 } 4559 } 4560 4561 private boolean checkPackagePolicyAccess(String pkg) { 4562 return mConditionProviders.isPackageOrComponentAllowed( 4563 pkg, getCallingUserHandle().getIdentifier()); 4564 } 4565 4566 private boolean checkPolicyAccess(String pkg) { 4567 try { 4568 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg, 4569 UserHandle.getCallingUserId()); 4570 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission( 4571 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, 4572 -1, true)) { 4573 return true; 4574 } 4575 } catch (NameNotFoundException e) { 4576 return false; 4577 } 4578 return checkPackagePolicyAccess(pkg) 4579 || mListeners.isComponentEnabledForPackage(pkg) 4580 || (mDpm != null && 4581 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(), 4582 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)); 4583 } 4584 4585 @Override 4586 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4587 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; 4588 final DumpFilter filter = DumpFilter.parseFromArguments(args); 4589 final long token = Binder.clearCallingIdentity(); 4590 try { 4591 if (filter.stats) { 4592 dumpJson(pw, filter); 4593 } else if (filter.rvStats) { 4594 dumpRemoteViewStats(pw, filter); 4595 } else if (filter.proto) { 4596 dumpProto(fd, filter); 4597 } else if (filter.criticalPriority) { 4598 dumpNotificationRecords(pw, filter); 4599 } else { 4600 dumpImpl(pw, filter); 4601 } 4602 } finally { 4603 Binder.restoreCallingIdentity(token); 4604 } 4605 } 4606 4607 @Override 4608 public ComponentName getEffectsSuppressor() { 4609 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null; 4610 } 4611 4612 @Override 4613 public boolean matchesCallFilter(Bundle extras) { 4614 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 4615 return mZenModeHelper.matchesCallFilter( 4616 Binder.getCallingUserHandle(), 4617 extras, 4618 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 4619 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 4620 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); 4621 } 4622 4623 @Override 4624 public boolean isSystemConditionProviderEnabled(String path) { 4625 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled"); 4626 return mConditionProviders.isSystemProviderEnabled(path); 4627 } 4628 4629 // Backup/restore interface 4630 @Override 4631 public byte[] getBackupPayload(int user) { 4632 checkCallerIsSystem(); 4633 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 4634 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 4635 try { 4636 writePolicyXml(baos, true /*forBackup*/, user); 4637 return baos.toByteArray(); 4638 } catch (IOException e) { 4639 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 4640 } 4641 return null; 4642 } 4643 4644 @Override 4645 public void applyRestore(byte[] payload, int user) { 4646 checkCallerIsSystem(); 4647 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 4648 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 4649 if (payload == null) { 4650 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 4651 return; 4652 } 4653 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 4654 try { 4655 readPolicyXml(bais, true /*forRestore*/, user); 4656 handleSavePolicyFile(); 4657 } catch (NumberFormatException | XmlPullParserException | IOException e) { 4658 Slog.w(TAG, "applyRestore: error reading payload", e); 4659 } 4660 } 4661 4662 @Override 4663 public boolean isNotificationPolicyAccessGranted(String pkg) { 4664 return checkPolicyAccess(pkg); 4665 } 4666 4667 @Override 4668 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {; 4669 enforceSystemOrSystemUIOrSamePackage(pkg, 4670 "request policy access status for another package"); 4671 return checkPolicyAccess(pkg); 4672 } 4673 4674 @Override 4675 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 4676 throws RemoteException { 4677 setNotificationPolicyAccessGrantedForUser( 4678 pkg, getCallingUserHandle().getIdentifier(), granted); 4679 } 4680 4681 @Override 4682 public void setNotificationPolicyAccessGrantedForUser( 4683 String pkg, int userId, boolean granted) { 4684 checkCallerIsSystemOrShell(); 4685 final long identity = Binder.clearCallingIdentity(); 4686 try { 4687 if (mAllowedManagedServicePackages.test( 4688 pkg, userId, mConditionProviders.getRequiredPermission())) { 4689 mConditionProviders.setPackageOrComponentEnabled( 4690 pkg, userId, true, granted); 4691 4692 getContext().sendBroadcastAsUser(new Intent( 4693 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4694 .setPackage(pkg) 4695 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 4696 UserHandle.of(userId), null); 4697 handleSavePolicyFile(); 4698 } 4699 } finally { 4700 Binder.restoreCallingIdentity(identity); 4701 } 4702 } 4703 4704 @Override 4705 public Policy getNotificationPolicy(String pkg) { 4706 final long identity = Binder.clearCallingIdentity(); 4707 try { 4708 return mZenModeHelper.getNotificationPolicy(); 4709 } finally { 4710 Binder.restoreCallingIdentity(identity); 4711 } 4712 } 4713 4714 @Override 4715 public Policy getConsolidatedNotificationPolicy() { 4716 final long identity = Binder.clearCallingIdentity(); 4717 try { 4718 return mZenModeHelper.getConsolidatedNotificationPolicy(); 4719 } finally { 4720 Binder.restoreCallingIdentity(identity); 4721 } 4722 } 4723 4724 /** 4725 * Sets the notification policy. Apps that target API levels below 4726 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to 4727 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS}, 4728 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and 4729 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd 4730 */ 4731 @Override 4732 public void setNotificationPolicy(String pkg, Policy policy) { 4733 enforcePolicyAccess(pkg, "setNotificationPolicy"); 4734 final long identity = Binder.clearCallingIdentity(); 4735 try { 4736 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg, 4737 0, UserHandle.getUserId(MY_UID)); 4738 Policy currPolicy = mZenModeHelper.getNotificationPolicy(); 4739 4740 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) { 4741 int priorityCategories = policy.priorityCategories; 4742 // ignore alarm and media values from new policy 4743 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS; 4744 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA; 4745 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM; 4746 // use user-designated values 4747 priorityCategories |= currPolicy.priorityCategories 4748 & Policy.PRIORITY_CATEGORY_ALARMS; 4749 priorityCategories |= currPolicy.priorityCategories 4750 & Policy.PRIORITY_CATEGORY_MEDIA; 4751 priorityCategories |= currPolicy.priorityCategories 4752 & Policy.PRIORITY_CATEGORY_SYSTEM; 4753 4754 policy = new Policy(priorityCategories, 4755 policy.priorityCallSenders, policy.priorityMessageSenders, 4756 policy.suppressedVisualEffects); 4757 } 4758 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) { 4759 int priorityCategories = correctCategory(policy.priorityCategories, 4760 Policy.PRIORITY_CATEGORY_CONVERSATIONS, 4761 currPolicy.priorityCategories); 4762 4763 policy = new Policy(priorityCategories, 4764 policy.priorityCallSenders, policy.priorityMessageSenders, 4765 policy.suppressedVisualEffects, currPolicy.priorityConversationSenders); 4766 } 4767 int newVisualEffects = calculateSuppressedVisualEffects( 4768 policy, currPolicy, applicationInfo.targetSdkVersion); 4769 policy = new Policy(policy.priorityCategories, 4770 policy.priorityCallSenders, policy.priorityMessageSenders, 4771 newVisualEffects, policy.priorityConversationSenders); 4772 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy); 4773 mZenModeHelper.setNotificationPolicy(policy); 4774 } catch (RemoteException e) { 4775 } finally { 4776 Binder.restoreCallingIdentity(identity); 4777 } 4778 } 4779 4780 4781 4782 @Override 4783 public List<String> getEnabledNotificationListenerPackages() { 4784 checkCallerIsSystem(); 4785 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier()); 4786 } 4787 4788 @Override 4789 public List<ComponentName> getEnabledNotificationListeners(int userId) { 4790 checkCallerIsSystem(); 4791 return mListeners.getAllowedComponents(userId); 4792 } 4793 4794 @Override 4795 public ComponentName getAllowedNotificationAssistantForUser(int userId) { 4796 checkCallerIsSystemOrSystemUiOrShell(); 4797 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 4798 if (allowedComponents.size() > 1) { 4799 throw new IllegalStateException( 4800 "At most one NotificationAssistant: " + allowedComponents.size()); 4801 } 4802 return CollectionUtils.firstOrNull(allowedComponents); 4803 } 4804 4805 @Override 4806 public ComponentName getAllowedNotificationAssistant() { 4807 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier()); 4808 } 4809 4810 @Override 4811 public boolean isNotificationListenerAccessGranted(ComponentName listener) { 4812 Objects.requireNonNull(listener); 4813 checkCallerIsSystemOrSameApp(listener.getPackageName()); 4814 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 4815 getCallingUserHandle().getIdentifier()); 4816 } 4817 4818 @Override 4819 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener, 4820 int userId) { 4821 Objects.requireNonNull(listener); 4822 checkCallerIsSystem(); 4823 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 4824 userId); 4825 } 4826 4827 @Override 4828 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { 4829 Objects.requireNonNull(assistant); 4830 checkCallerIsSystemOrSameApp(assistant.getPackageName()); 4831 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(), 4832 getCallingUserHandle().getIdentifier()); 4833 } 4834 4835 @Override 4836 public void setNotificationListenerAccessGranted(ComponentName listener, 4837 boolean granted) throws RemoteException { 4838 setNotificationListenerAccessGrantedForUser( 4839 listener, getCallingUserHandle().getIdentifier(), granted); 4840 } 4841 4842 @Override 4843 public void setNotificationAssistantAccessGranted(ComponentName assistant, 4844 boolean granted) { 4845 setNotificationAssistantAccessGrantedForUser( 4846 assistant, getCallingUserHandle().getIdentifier(), granted); 4847 } 4848 4849 @Override 4850 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, 4851 boolean granted) { 4852 Objects.requireNonNull(listener); 4853 checkCallerIsSystemOrShell(); 4854 final long identity = Binder.clearCallingIdentity(); 4855 try { 4856 if (mAllowedManagedServicePackages.test( 4857 listener.getPackageName(), userId, mListeners.getRequiredPermission())) { 4858 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(), 4859 userId, false, granted); 4860 mListeners.setPackageOrComponentEnabled(listener.flattenToString(), 4861 userId, true, granted); 4862 4863 getContext().sendBroadcastAsUser(new Intent( 4864 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4865 .setPackage(listener.getPackageName()) 4866 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 4867 UserHandle.of(userId), null); 4868 4869 handleSavePolicyFile(); 4870 } 4871 } finally { 4872 Binder.restoreCallingIdentity(identity); 4873 } 4874 } 4875 4876 @Override 4877 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, 4878 int userId, boolean granted) { 4879 checkCallerIsSystemOrSystemUiOrShell(); 4880 for (UserInfo ui : mUm.getEnabledProfiles(userId)) { 4881 mAssistants.setUserSet(ui.id, true); 4882 } 4883 final long identity = Binder.clearCallingIdentity(); 4884 try { 4885 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted); 4886 } finally { 4887 Binder.restoreCallingIdentity(identity); 4888 } 4889 } 4890 4891 @Override 4892 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token, 4893 Adjustment adjustment) { 4894 boolean foundEnqueued = false; 4895 final long identity = Binder.clearCallingIdentity(); 4896 try { 4897 synchronized (mNotificationLock) { 4898 mAssistants.checkServiceTokenLocked(token); 4899 int N = mEnqueuedNotifications.size(); 4900 for (int i = 0; i < N; i++) { 4901 final NotificationRecord r = mEnqueuedNotifications.get(i); 4902 if (Objects.equals(adjustment.getKey(), r.getKey()) 4903 && Objects.equals(adjustment.getUser(), r.getUserId()) 4904 && mAssistants.isSameUser(token, r.getUserId())) { 4905 applyAdjustment(r, adjustment); 4906 r.applyAdjustments(); 4907 // importance is checked at the beginning of the 4908 // PostNotificationRunnable, before the signal extractors are run, so 4909 // calculate the final importance here 4910 r.calculateImportance(); 4911 foundEnqueued = true; 4912 break; 4913 } 4914 } 4915 if (!foundEnqueued) { 4916 applyAdjustmentFromAssistant(token, adjustment); 4917 } 4918 } 4919 } finally { 4920 Binder.restoreCallingIdentity(identity); 4921 } 4922 } 4923 4924 @Override 4925 public void applyAdjustmentFromAssistant(INotificationListener token, 4926 Adjustment adjustment) { 4927 List<Adjustment> adjustments = new ArrayList<>(); 4928 adjustments.add(adjustment); 4929 applyAdjustmentsFromAssistant(token, adjustments); 4930 } 4931 4932 @Override 4933 public void applyAdjustmentsFromAssistant(INotificationListener token, 4934 List<Adjustment> adjustments) { 4935 4936 boolean needsSort = false; 4937 final long identity = Binder.clearCallingIdentity(); 4938 try { 4939 synchronized (mNotificationLock) { 4940 mAssistants.checkServiceTokenLocked(token); 4941 for (Adjustment adjustment : adjustments) { 4942 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey()); 4943 if (r != null && mAssistants.isSameUser(token, r.getUserId())) { 4944 applyAdjustment(r, adjustment); 4945 // If the assistant has blocked the notification, cancel it 4946 // This will trigger a sort, so we don't have to explicitly ask for 4947 // one here. 4948 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE) 4949 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE) 4950 == IMPORTANCE_NONE) { 4951 cancelNotificationsFromListener(token, new String[]{r.getKey()}); 4952 } else { 4953 needsSort = true; 4954 } 4955 } 4956 } 4957 } 4958 if (needsSort) { 4959 mRankingHandler.requestSort(); 4960 } 4961 } finally { 4962 Binder.restoreCallingIdentity(identity); 4963 } 4964 } 4965 4966 @Override 4967 public void updateNotificationChannelGroupFromPrivilegedListener( 4968 INotificationListener token, String pkg, UserHandle user, 4969 NotificationChannelGroup group) throws RemoteException { 4970 Objects.requireNonNull(user); 4971 verifyPrivilegedListener(token, user, false); 4972 createNotificationChannelGroup( 4973 pkg, getUidForPackageAndUser(pkg, user), group, false, true); 4974 handleSavePolicyFile(); 4975 } 4976 4977 @Override 4978 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, 4979 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { 4980 Objects.requireNonNull(channel); 4981 Objects.requireNonNull(pkg); 4982 Objects.requireNonNull(user); 4983 4984 verifyPrivilegedListener(token, user, false); 4985 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); 4986 } 4987 4988 @Override 4989 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( 4990 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 4991 Objects.requireNonNull(pkg); 4992 Objects.requireNonNull(user); 4993 verifyPrivilegedListener(token, user, true); 4994 4995 return mPreferencesHelper.getNotificationChannels(pkg, 4996 getUidForPackageAndUser(pkg, user), false /* includeDeleted */); 4997 } 4998 4999 @Override 5000 public ParceledListSlice<NotificationChannelGroup> 5001 getNotificationChannelGroupsFromPrivilegedListener( 5002 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 5003 Objects.requireNonNull(pkg); 5004 Objects.requireNonNull(user); 5005 verifyPrivilegedListener(token, user, true); 5006 5007 List<NotificationChannelGroup> groups = new ArrayList<>(); 5008 groups.addAll(mPreferencesHelper.getNotificationChannelGroups( 5009 pkg, getUidForPackageAndUser(pkg, user))); 5010 return new ParceledListSlice<>(groups); 5011 } 5012 5013 @Override 5014 public void setPrivateNotificationsAllowed(boolean allow) { 5015 if (PackageManager.PERMISSION_GRANTED 5016 != getContext().checkCallingPermission( 5017 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 5018 throw new SecurityException( 5019 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 5020 } 5021 if (allow != mLockScreenAllowSecureNotifications) { 5022 mLockScreenAllowSecureNotifications = allow; 5023 handleSavePolicyFile(); 5024 } 5025 } 5026 5027 @Override 5028 public boolean getPrivateNotificationsAllowed() { 5029 if (PackageManager.PERMISSION_GRANTED 5030 != getContext().checkCallingPermission( 5031 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 5032 throw new SecurityException( 5033 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 5034 } 5035 return mLockScreenAllowSecureNotifications; 5036 } 5037 5038 @Override 5039 public boolean isPackagePaused(String pkg) { 5040 Objects.requireNonNull(pkg); 5041 checkCallerIsSameApp(pkg); 5042 5043 return isPackagePausedOrSuspended(pkg, Binder.getCallingUid()); 5044 } 5045 5046 private void verifyPrivilegedListener(INotificationListener token, UserHandle user, 5047 boolean assistantAllowed) { 5048 ManagedServiceInfo info; 5049 synchronized (mNotificationLock) { 5050 info = mListeners.checkServiceTokenLocked(token); 5051 } 5052 if (!hasCompanionDevice(info)) { 5053 synchronized (mNotificationLock) { 5054 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) { 5055 throw new SecurityException(info + " does not have access"); 5056 } 5057 } 5058 } 5059 if (!info.enabledAndUserMatches(user.getIdentifier())) { 5060 throw new SecurityException(info + " does not have access"); 5061 } 5062 } 5063 5064 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { 5065 int uid = 0; 5066 long identity = Binder.clearCallingIdentity(); 5067 try { 5068 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); 5069 } finally { 5070 Binder.restoreCallingIdentity(identity); 5071 } 5072 return uid; 5073 } 5074 5075 @Override 5076 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 5077 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 5078 throws RemoteException { 5079 new NotificationShellCmd(NotificationManagerService.this) 5080 .exec(this, in, out, err, args, callback, resultReceiver); 5081 } 5082 5083 /** 5084 * Get stats committed after startNs 5085 * 5086 * @param startNs Report stats committed after this time in nanoseconds. 5087 * @param report Indicatess which section to include in the stats. 5088 * @param doAgg Whether to aggregate the stats or keep them separated. 5089 * @param out List of protos of individual commits or one representing the 5090 * aggregate. 5091 * @return the report time in nanoseconds, or 0 on error. 5092 */ 5093 @Override 5094 public long pullStats(long startNs, int report, boolean doAgg, 5095 List<ParcelFileDescriptor> out) { 5096 checkCallerIsSystemOrShell(); 5097 long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS); 5098 5099 final long identity = Binder.clearCallingIdentity(); 5100 try { 5101 switch (report) { 5102 case REPORT_REMOTE_VIEWS: 5103 Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: " 5104 + startMs + " wtih " + doAgg); 5105 PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg); 5106 if (stats != null) { 5107 out.add(stats.toParcelFileDescriptor(report)); 5108 Slog.e(TAG, "exiting pullStats with: " + out.size()); 5109 long endNs = TimeUnit.NANOSECONDS 5110 .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS); 5111 return endNs; 5112 } 5113 Slog.e(TAG, "null stats for: " + report); 5114 } 5115 } catch (IOException e) { 5116 5117 Slog.e(TAG, "exiting pullStats: on error", e); 5118 return 0; 5119 } finally { 5120 Binder.restoreCallingIdentity(identity); 5121 } 5122 Slog.e(TAG, "exiting pullStats: bad request"); 5123 return 0; 5124 } 5125 }; 5126 5127 @VisibleForTesting 5128 protected void setNotificationAssistantAccessGrantedForUserInternal( 5129 ComponentName assistant, int baseUserId, boolean granted) { 5130 List<UserInfo> users = mUm.getEnabledProfiles(baseUserId); 5131 if (users != null) { 5132 for (UserInfo user : users) { 5133 int userId = user.id; 5134 if (assistant == null) { 5135 ComponentName allowedAssistant = CollectionUtils.firstOrNull( 5136 mAssistants.getAllowedComponents(userId)); 5137 if (allowedAssistant != null) { 5138 setNotificationAssistantAccessGrantedForUserInternal( 5139 allowedAssistant, userId, false); 5140 } 5141 continue; 5142 } 5143 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), 5144 userId, mAssistants.getRequiredPermission())) { 5145 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(), 5146 userId, false, granted); 5147 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(), 5148 userId, true, granted); 5149 5150 getContext().sendBroadcastAsUser( 5151 new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 5152 .setPackage(assistant.getPackageName()) 5153 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 5154 UserHandle.of(userId), null); 5155 5156 handleSavePolicyFile(); 5157 } 5158 } 5159 } 5160 } 5161 5162 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) { 5163 if (r == null) { 5164 return; 5165 } 5166 if (adjustment.getSignals() != null) { 5167 final Bundle adjustments = adjustment.getSignals(); 5168 Bundle.setDefusable(adjustments, true); 5169 List<String> toRemove = new ArrayList<>(); 5170 for (String potentialKey : adjustments.keySet()) { 5171 if (!mAssistants.isAdjustmentAllowed(potentialKey)) { 5172 toRemove.add(potentialKey); 5173 } 5174 } 5175 for (String removeKey : toRemove) { 5176 adjustments.remove(removeKey); 5177 } 5178 r.addAdjustment(adjustment); 5179 } 5180 } 5181 5182 @GuardedBy("mNotificationLock") 5183 void addAutogroupKeyLocked(String key) { 5184 NotificationRecord r = mNotificationsByKey.get(key); 5185 if (r == null) { 5186 return; 5187 } 5188 if (r.getSbn().getOverrideGroupKey() == null) { 5189 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY); 5190 EventLogTags.writeNotificationAutogrouped(key); 5191 mRankingHandler.requestSort(); 5192 } 5193 } 5194 5195 @GuardedBy("mNotificationLock") 5196 void removeAutogroupKeyLocked(String key) { 5197 NotificationRecord r = mNotificationsByKey.get(key); 5198 if (r == null) { 5199 return; 5200 } 5201 if (r.getSbn().getOverrideGroupKey() != null) { 5202 addAutoGroupAdjustment(r, null); 5203 EventLogTags.writeNotificationUnautogrouped(key); 5204 mRankingHandler.requestSort(); 5205 } 5206 } 5207 5208 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) { 5209 Bundle signals = new Bundle(); 5210 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey); 5211 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 5212 r.getSbn().getUserId()); 5213 r.addAdjustment(adjustment); 5214 } 5215 5216 // Clears the 'fake' auto-group summary. 5217 @GuardedBy("mNotificationLock") 5218 private void clearAutogroupSummaryLocked(int userId, String pkg) { 5219 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 5220 if (summaries != null && summaries.containsKey(pkg)) { 5221 // Clear summary. 5222 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg)); 5223 if (removed != null) { 5224 boolean wasPosted = removeFromNotificationListsLocked(removed); 5225 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null); 5226 } 5227 } 5228 } 5229 5230 @GuardedBy("mNotificationLock") 5231 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) { 5232 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId()); 5233 return summaries != null && summaries.containsKey(sbn.getPackageName()); 5234 } 5235 5236 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit. 5237 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) { 5238 NotificationRecord summaryRecord = null; 5239 final boolean isAppForeground = 5240 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 5241 synchronized (mNotificationLock) { 5242 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey); 5243 if (notificationRecord == null) { 5244 // The notification could have been cancelled again already. A successive 5245 // adjustment will post a summary if needed. 5246 return; 5247 } 5248 final StatusBarNotification adjustedSbn = notificationRecord.getSbn(); 5249 userId = adjustedSbn.getUser().getIdentifier(); 5250 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 5251 if (summaries == null) { 5252 summaries = new ArrayMap<>(); 5253 } 5254 mAutobundledSummaries.put(userId, summaries); 5255 if (!summaries.containsKey(pkg)) { 5256 // Add summary 5257 final ApplicationInfo appInfo = 5258 adjustedSbn.getNotification().extras.getParcelable( 5259 Notification.EXTRA_BUILDER_APPLICATION_INFO); 5260 final Bundle extras = new Bundle(); 5261 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo); 5262 final String channelId = notificationRecord.getChannel().getId(); 5263 final Notification summaryNotification = 5264 new Notification.Builder(getContext(), channelId) 5265 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon()) 5266 .setGroupSummary(true) 5267 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) 5268 .setGroup(GroupHelper.AUTOGROUP_KEY) 5269 .setFlag(FLAG_AUTOGROUP_SUMMARY, true) 5270 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 5271 .setColor(adjustedSbn.getNotification().color) 5272 .setLocalOnly(true) 5273 .build(); 5274 summaryNotification.extras.putAll(extras); 5275 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); 5276 if (appIntent != null) { 5277 summaryNotification.contentIntent = PendingIntent.getActivityAsUser( 5278 getContext(), 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null, 5279 UserHandle.of(userId)); 5280 } 5281 final StatusBarNotification summarySbn = 5282 new StatusBarNotification(adjustedSbn.getPackageName(), 5283 adjustedSbn.getOpPkg(), 5284 Integer.MAX_VALUE, 5285 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(), 5286 adjustedSbn.getInitialPid(), summaryNotification, 5287 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY, 5288 mSystemClock.currentTimeMillis()); 5289 summaryRecord = new NotificationRecord(getContext(), summarySbn, 5290 notificationRecord.getChannel()); 5291 summaryRecord.setIsAppImportanceLocked( 5292 notificationRecord.getIsAppImportanceLocked()); 5293 summaries.put(pkg, summarySbn.getKey()); 5294 } 5295 } 5296 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID, 5297 summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord, 5298 true)) { 5299 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord, isAppForeground)); 5300 } 5301 } 5302 5303 private String disableNotificationEffects(NotificationRecord record) { 5304 if (mDisableNotificationEffects) { 5305 return "booleanState"; 5306 } 5307 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 5308 return "listenerHints"; 5309 } 5310 if (record != null && record.getAudioAttributes() != null) { 5311 if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 5312 if (record.getAudioAttributes().getUsage() 5313 != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { 5314 return "listenerNoti"; 5315 } 5316 } 5317 if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 5318 if (record.getAudioAttributes().getUsage() 5319 == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { 5320 return "listenerCall"; 5321 } 5322 } 5323 } 5324 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 5325 return "callState"; 5326 } 5327 return null; 5328 }; 5329 5330 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) { 5331 JSONObject dump = new JSONObject(); 5332 try { 5333 dump.put("service", "Notification Manager"); 5334 dump.put("bans", mPreferencesHelper.dumpBansJson(filter)); 5335 dump.put("ranking", mPreferencesHelper.dumpJson(filter)); 5336 dump.put("stats", mUsageStats.dumpJson(filter)); 5337 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter)); 5338 } catch (JSONException e) { 5339 e.printStackTrace(); 5340 } 5341 pw.println(dump); 5342 } 5343 5344 private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) { 5345 PulledStats stats = mUsageStats.remoteViewStats(filter.since, true); 5346 if (stats == null) { 5347 pw.println("no remote view stats reported."); 5348 return; 5349 } 5350 stats.dump(REPORT_REMOTE_VIEWS, pw, filter); 5351 } 5352 5353 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) { 5354 final ProtoOutputStream proto = new ProtoOutputStream(fd); 5355 synchronized (mNotificationLock) { 5356 int N = mNotificationList.size(); 5357 for (int i = 0; i < N; i++) { 5358 final NotificationRecord nr = mNotificationList.get(i); 5359 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 5360 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 5361 NotificationRecordProto.POSTED); 5362 } 5363 N = mEnqueuedNotifications.size(); 5364 for (int i = 0; i < N; i++) { 5365 final NotificationRecord nr = mEnqueuedNotifications.get(i); 5366 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 5367 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 5368 NotificationRecordProto.ENQUEUED); 5369 } 5370 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed(); 5371 N = snoozed.size(); 5372 for (int i = 0; i < N; i++) { 5373 final NotificationRecord nr = snoozed.get(i); 5374 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 5375 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 5376 NotificationRecordProto.SNOOZED); 5377 } 5378 5379 long zenLog = proto.start(NotificationServiceDumpProto.ZEN); 5380 mZenModeHelper.dump(proto); 5381 for (ComponentName suppressor : mEffectsSuppressors) { 5382 suppressor.dumpDebug(proto, ZenModeProto.SUPPRESSORS); 5383 } 5384 proto.end(zenLog); 5385 5386 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS); 5387 mListeners.dump(proto, filter); 5388 proto.end(listenersToken); 5389 5390 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints); 5391 5392 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) { 5393 long effectsToken = proto.start( 5394 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS); 5395 5396 proto.write( 5397 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i)); 5398 final ArraySet<ComponentName> listeners = 5399 mListenersDisablingEffects.valueAt(i); 5400 for (int j = 0; j < listeners.size(); j++) { 5401 final ComponentName componentName = listeners.valueAt(j); 5402 componentName.dumpDebug(proto, 5403 ListenersDisablingEffectsProto.LISTENER_COMPONENTS); 5404 } 5405 5406 proto.end(effectsToken); 5407 } 5408 5409 long assistantsToken = proto.start( 5410 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS); 5411 mAssistants.dump(proto, filter); 5412 proto.end(assistantsToken); 5413 5414 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS); 5415 mConditionProviders.dump(proto, filter); 5416 proto.end(conditionsToken); 5417 5418 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG); 5419 mRankingHelper.dump(proto, filter); 5420 mPreferencesHelper.dump(proto, filter); 5421 proto.end(rankingToken); 5422 } 5423 5424 proto.flush(); 5425 } 5426 5427 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) { 5428 synchronized (mNotificationLock) { 5429 int N; 5430 N = mNotificationList.size(); 5431 if (N > 0) { 5432 pw.println(" Notification List:"); 5433 for (int i = 0; i < N; i++) { 5434 final NotificationRecord nr = mNotificationList.get(i); 5435 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 5436 nr.dump(pw, " ", getContext(), filter.redact); 5437 } 5438 pw.println(" "); 5439 } 5440 } 5441 } 5442 5443 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) { 5444 pw.print("Current Notification Manager state"); 5445 if (filter.filtered) { 5446 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 5447 } 5448 pw.println(':'); 5449 int N; 5450 final boolean zenOnly = filter.filtered && filter.zen; 5451 5452 if (!zenOnly) { 5453 synchronized (mToastQueue) { 5454 N = mToastQueue.size(); 5455 if (N > 0) { 5456 pw.println(" Toast Queue:"); 5457 for (int i=0; i<N; i++) { 5458 mToastQueue.get(i).dump(pw, " ", filter); 5459 } 5460 pw.println(" "); 5461 } 5462 } 5463 } 5464 5465 synchronized (mNotificationLock) { 5466 if (!zenOnly) { 5467 // Priority filters are only set when called via bugreport. If set 5468 // skip sections that are part of the critical section. 5469 if (!filter.normalPriority) { 5470 dumpNotificationRecords(pw, filter); 5471 } 5472 if (!filter.filtered) { 5473 N = mLights.size(); 5474 if (N > 0) { 5475 pw.println(" Lights List:"); 5476 for (int i=0; i<N; i++) { 5477 if (i == N - 1) { 5478 pw.print(" > "); 5479 } else { 5480 pw.print(" "); 5481 } 5482 pw.println(mLights.get(i)); 5483 } 5484 pw.println(" "); 5485 } 5486 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 5487 pw.println(" mHasLight=" + mHasLight); 5488 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 5489 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 5490 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 5491 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 5492 pw.println(" mCallState=" + callStateToString(mCallState)); 5493 pw.println(" mSystemReady=" + mSystemReady); 5494 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate); 5495 } 5496 pw.println(" mArchive=" + mArchive.toString()); 5497 Iterator<Pair<StatusBarNotification, Integer>> iter = mArchive.descendingIterator(); 5498 int j=0; 5499 while (iter.hasNext()) { 5500 final StatusBarNotification sbn = iter.next().first; 5501 if (filter != null && !filter.matches(sbn)) continue; 5502 pw.println(" " + sbn); 5503 if (++j >= 5) { 5504 if (iter.hasNext()) pw.println(" ..."); 5505 break; 5506 } 5507 } 5508 5509 if (!zenOnly) { 5510 N = mEnqueuedNotifications.size(); 5511 if (N > 0) { 5512 pw.println(" Enqueued Notification List:"); 5513 for (int i = 0; i < N; i++) { 5514 final NotificationRecord nr = mEnqueuedNotifications.get(i); 5515 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 5516 nr.dump(pw, " ", getContext(), filter.redact); 5517 } 5518 pw.println(" "); 5519 } 5520 5521 mSnoozeHelper.dump(pw, filter); 5522 } 5523 5524 // Log delayed notification cancels 5525 pw.println(); 5526 pw.println(" Delayed notification cancels:"); 5527 if (mDelayedCancelations.isEmpty()) { 5528 pw.println(" None"); 5529 } else { 5530 Set<NotificationRecord> delayedKeys = mDelayedCancelations.keySet(); 5531 for (NotificationRecord record : delayedKeys) { 5532 ArrayList<CancelNotificationRunnable> queuedCancels = 5533 mDelayedCancelations.get(record); 5534 pw.println(" (" + queuedCancels.size() + ") cancels enqueued for" 5535 + record.getKey()); 5536 } 5537 } 5538 pw.println(); 5539 } 5540 5541 if (!zenOnly) { 5542 pw.println("\n Ranking Config:"); 5543 mRankingHelper.dump(pw, " ", filter); 5544 5545 pw.println("\n Notification Preferences:"); 5546 mPreferencesHelper.dump(pw, " ", filter); 5547 5548 pw.println("\n Notification listeners:"); 5549 mListeners.dump(pw, filter); 5550 pw.print(" mListenerHints: "); pw.println(mListenerHints); 5551 pw.print(" mListenersDisablingEffects: ("); 5552 N = mListenersDisablingEffects.size(); 5553 for (int i = 0; i < N; i++) { 5554 final int hint = mListenersDisablingEffects.keyAt(i); 5555 if (i > 0) pw.print(';'); 5556 pw.print("hint[" + hint + "]:"); 5557 5558 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 5559 final int listenerSize = listeners.size(); 5560 5561 for (int j = 0; j < listenerSize; j++) { 5562 if (j > 0) pw.print(','); 5563 final ComponentName listener = listeners.valueAt(j); 5564 if (listener != null) { 5565 pw.print(listener); 5566 } 5567 } 5568 } 5569 pw.println(')'); 5570 pw.println("\n Notification assistant services:"); 5571 mAssistants.dump(pw, filter); 5572 } 5573 5574 if (!filter.filtered || zenOnly) { 5575 pw.println("\n Zen Mode:"); 5576 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 5577 mZenModeHelper.dump(pw, " "); 5578 5579 pw.println("\n Zen Log:"); 5580 ZenLog.dump(pw, " "); 5581 } 5582 5583 pw.println("\n Condition providers:"); 5584 mConditionProviders.dump(pw, filter); 5585 5586 pw.println("\n Group summaries:"); 5587 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 5588 NotificationRecord r = entry.getValue(); 5589 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 5590 if (mNotificationsByKey.get(r.getKey()) != r) { 5591 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 5592 r.dump(pw, " ", getContext(), filter.redact); 5593 } 5594 } 5595 5596 if (!zenOnly) { 5597 pw.println("\n Usage Stats:"); 5598 mUsageStats.dump(pw, " ", filter); 5599 } 5600 } 5601 } 5602 5603 /** 5604 * The private API only accessible to the system process. 5605 */ 5606 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 5607 @Override 5608 public NotificationChannel getNotificationChannel(String pkg, int uid, String 5609 channelId) { 5610 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false); 5611 } 5612 5613 @Override 5614 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 5615 String tag, int id, Notification notification, int userId) { 5616 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 5617 userId); 5618 } 5619 5620 @Override 5621 public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid, 5622 String tag, int id, int userId) { 5623 cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId); 5624 } 5625 5626 @Override 5627 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 5628 int userId) { 5629 checkCallerIsSystem(); 5630 mHandler.post(() -> { 5631 synchronized (mNotificationLock) { 5632 // strip flag from all enqueued notifications. listeners will be informed 5633 // in post runnable. 5634 List<NotificationRecord> enqueued = findNotificationsByListLocked( 5635 mEnqueuedNotifications, pkg, null, notificationId, userId); 5636 for (int i = 0; i < enqueued.size(); i++) { 5637 removeForegroundServiceFlagLocked(enqueued.get(i)); 5638 } 5639 5640 // if posted notification exists, strip its flag and tell listeners 5641 NotificationRecord r = findNotificationByListLocked( 5642 mNotificationList, pkg, null, notificationId, userId); 5643 if (r != null) { 5644 removeForegroundServiceFlagLocked(r); 5645 mRankingHelper.sort(mNotificationList); 5646 mListeners.notifyPostedLocked(r, r); 5647 } 5648 } 5649 }); 5650 } 5651 5652 @Override 5653 public void onConversationRemoved(String pkg, int uid, String conversationId) { 5654 onConversationRemovedInternal(pkg, uid, conversationId); 5655 } 5656 5657 @GuardedBy("mNotificationLock") 5658 private void removeForegroundServiceFlagLocked(NotificationRecord r) { 5659 if (r == null) { 5660 return; 5661 } 5662 StatusBarNotification sbn = r.getSbn(); 5663 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 5664 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove 5665 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received 5666 // initially *and* force remove FLAG_FOREGROUND_SERVICE. 5667 sbn.getNotification().flags = 5668 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE); 5669 } 5670 }; 5671 5672 void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid, 5673 String tag, int id, int userId) { 5674 userId = ActivityManager.handleIncomingUser(callingPid, 5675 callingUid, userId, true, false, "cancelNotificationWithTag", pkg); 5676 5677 // ensure opPkg is delegate if does not match pkg 5678 int uid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 5679 5680 if (uid == INVALID_UID) { 5681 Slog.w(TAG, opPkg + ":" + callingUid + " trying to cancel notification " 5682 + "for nonexistent pkg " + pkg + " in user " + userId); 5683 return; 5684 } 5685 5686 // if opPkg is not the same as pkg, make sure the notification given was posted 5687 // by opPkg 5688 if (!Objects.equals(pkg, opPkg)) { 5689 synchronized (mNotificationLock) { 5690 // Look for the notification, searching both the posted and enqueued lists. 5691 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 5692 if (r != null) { 5693 if (!Objects.equals(opPkg, r.getSbn().getOpPkg())) { 5694 throw new SecurityException(opPkg + " does not have permission to " 5695 + "cancel a notification they did not post " + tag + " " + id); 5696 } 5697 } 5698 } 5699 } 5700 5701 // Don't allow client applications to cancel foreground service notis or autobundled 5702 // summaries. 5703 final int mustNotHaveFlags = isCallingUidSystem() ? 0 : 5704 (FLAG_FOREGROUND_SERVICE | FLAG_AUTOGROUP_SUMMARY); 5705 cancelNotification(uid, callingPid, pkg, tag, id, 0, 5706 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); 5707 } 5708 5709 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 5710 final int callingPid, final String tag, final int id, final Notification notification, 5711 int incomingUserId) { 5712 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 5713 incomingUserId, false); 5714 } 5715 5716 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 5717 final int callingPid, final String tag, final int id, final Notification notification, 5718 int incomingUserId, boolean postSilently) { 5719 if (DBG) { 5720 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 5721 + " notification=" + notification); 5722 } 5723 5724 if (pkg == null || notification == null) { 5725 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 5726 + " id=" + id + " notification=" + notification); 5727 } 5728 5729 final int userId = ActivityManager.handleIncomingUser(callingPid, 5730 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 5731 final UserHandle user = UserHandle.of(userId); 5732 5733 // Can throw a SecurityException if the calling uid doesn't have permission to post 5734 // as "pkg" 5735 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 5736 5737 if (notificationUid == INVALID_UID) { 5738 throw new SecurityException("Caller " + opPkg + ":" + callingUid 5739 + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId); 5740 } 5741 5742 checkRestrictedCategories(pkg, notification); 5743 5744 // Fix the notification as best we can. 5745 try { 5746 fixNotification(notification, pkg, tag, id, userId); 5747 5748 } catch (Exception e) { 5749 Slog.e(TAG, "Cannot fix notification", e); 5750 return; 5751 } 5752 5753 mUsageStats.registerEnqueuedByApp(pkg); 5754 5755 final StatusBarNotification n = new StatusBarNotification( 5756 pkg, opPkg, id, tag, notificationUid, callingPid, notification, 5757 user, null, mSystemClock.currentTimeMillis()); 5758 5759 // setup local book-keeping 5760 String channelId = notification.getChannelId(); 5761 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) { 5762 channelId = (new Notification.TvExtender(notification)).getChannelId(); 5763 } 5764 String shortcutId = n.getShortcutId(); 5765 final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel( 5766 pkg, notificationUid, channelId, shortcutId, 5767 true /* parent ok */, false /* includeDeleted */); 5768 if (channel == null) { 5769 final String noChannelStr = "No Channel found for " 5770 + "pkg=" + pkg 5771 + ", channelId=" + channelId 5772 + ", id=" + id 5773 + ", tag=" + tag 5774 + ", opPkg=" + opPkg 5775 + ", callingUid=" + callingUid 5776 + ", userId=" + userId 5777 + ", incomingUserId=" + incomingUserId 5778 + ", notificationUid=" + notificationUid 5779 + ", notification=" + notification; 5780 Slog.e(TAG, noChannelStr); 5781 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid) 5782 == NotificationManager.IMPORTANCE_NONE; 5783 5784 if (!appNotificationsOff) { 5785 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" + 5786 "Failed to post notification on channel \"" + channelId + "\"\n" + 5787 "See log for more details"); 5788 } 5789 return; 5790 } 5791 5792 final NotificationRecord r = new NotificationRecord(getContext(), n, channel); 5793 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid)); 5794 r.setPostSilently(postSilently); 5795 r.setFlagBubbleRemoved(false); 5796 r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg)); 5797 5798 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 5799 final boolean fgServiceShown = channel.isFgServiceShown(); 5800 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0 5801 || !fgServiceShown) 5802 && (r.getImportance() == IMPORTANCE_MIN 5803 || r.getImportance() == IMPORTANCE_NONE)) { 5804 // Increase the importance of foreground service notifications unless the user had 5805 // an opinion otherwise (and the channel hasn't yet shown a fg service). 5806 if (TextUtils.isEmpty(channelId) 5807 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 5808 r.setSystemImportance(IMPORTANCE_LOW); 5809 } else { 5810 channel.setImportance(IMPORTANCE_LOW); 5811 r.setSystemImportance(IMPORTANCE_LOW); 5812 if (!fgServiceShown) { 5813 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); 5814 channel.setFgServiceShown(true); 5815 } 5816 mPreferencesHelper.updateNotificationChannel( 5817 pkg, notificationUid, channel, false); 5818 r.updateNotificationChannel(channel); 5819 } 5820 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId) 5821 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 5822 channel.setFgServiceShown(true); 5823 r.updateNotificationChannel(channel); 5824 } 5825 } 5826 5827 ShortcutInfo info = mShortcutHelper != null 5828 ? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user) 5829 : null; 5830 if (notification.getShortcutId() != null && info == null) { 5831 Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut"); 5832 } 5833 r.setShortcutInfo(info); 5834 r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid)); 5835 r.userDemotedAppFromConvoSpace( 5836 mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid)); 5837 5838 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, 5839 r.getSbn().getOverrideGroupKey() != null)) { 5840 return; 5841 } 5842 5843 if (info != null) { 5844 // Cache the shortcut synchronously after the associated notification is posted in case 5845 // the app unpublishes this shortcut immediately after posting the notification. If the 5846 // user does not modify the notification settings on this conversation, the shortcut 5847 // will be uncached by People Service when all the associated notifications are removed. 5848 mShortcutHelper.cacheShortcut(info, user); 5849 } 5850 5851 // Whitelist pending intents. 5852 if (notification.allPendingIntents != null) { 5853 final int intentCount = notification.allPendingIntents.size(); 5854 if (intentCount > 0) { 5855 final ActivityManagerInternal am = LocalServices 5856 .getService(ActivityManagerInternal.class); 5857 final long duration = LocalServices.getService( 5858 DeviceIdleInternal.class).getNotificationWhitelistDuration(); 5859 for (int i = 0; i < intentCount; i++) { 5860 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); 5861 if (pendingIntent != null) { 5862 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), 5863 WHITELIST_TOKEN, duration); 5864 am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(), 5865 WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER 5866 | FLAG_SERVICE_SENDER)); 5867 } 5868 } 5869 } 5870 } 5871 5872 // Need escalated privileges to get package importance 5873 final long token = Binder.clearCallingIdentity(); 5874 boolean isAppForeground; 5875 try { 5876 isAppForeground = mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 5877 } finally { 5878 Binder.restoreCallingIdentity(token); 5879 } 5880 mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground)); 5881 } 5882 5883 private void onConversationRemovedInternal(String pkg, int uid, String conversationId) { 5884 checkCallerIsSystem(); 5885 Preconditions.checkStringNotEmpty(pkg); 5886 Preconditions.checkStringNotEmpty(conversationId); 5887 5888 mHistoryManager.deleteConversation(pkg, uid, conversationId); 5889 List<String> deletedChannelIds = 5890 mPreferencesHelper.deleteConversation(pkg, uid, conversationId); 5891 for (String channelId : deletedChannelIds) { 5892 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, 5893 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED, 5894 null); 5895 } 5896 handleSavePolicyFile(); 5897 } 5898 5899 @VisibleForTesting 5900 protected void fixNotification(Notification notification, String pkg, String tag, int id, 5901 int userId) throws NameNotFoundException { 5902 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( 5903 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 5904 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId); 5905 Notification.addFieldsFromContext(ai, notification); 5906 5907 int canColorize = mPackageManagerClient.checkPermission( 5908 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg); 5909 if (canColorize == PERMISSION_GRANTED) { 5910 notification.flags |= Notification.FLAG_CAN_COLORIZE; 5911 } else { 5912 notification.flags &= ~Notification.FLAG_CAN_COLORIZE; 5913 } 5914 5915 if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) { 5916 int fullscreenIntentPermission = mPackageManagerClient.checkPermission( 5917 android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg); 5918 if (fullscreenIntentPermission != PERMISSION_GRANTED) { 5919 notification.fullScreenIntent = null; 5920 Slog.w(TAG, "Package " + pkg + 5921 ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission"); 5922 } 5923 } 5924 5925 // Remote views? Are they too big? 5926 checkRemoteViews(pkg, tag, id, notification); 5927 } 5928 5929 private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { 5930 if (removeRemoteView(pkg, tag, id, notification.contentView)) { 5931 notification.contentView = null; 5932 } 5933 if (removeRemoteView(pkg, tag, id, notification.bigContentView)) { 5934 notification.bigContentView = null; 5935 } 5936 if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) { 5937 notification.headsUpContentView = null; 5938 } 5939 if (notification.publicVersion != null) { 5940 if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) { 5941 notification.publicVersion.contentView = null; 5942 } 5943 if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) { 5944 notification.publicVersion.bigContentView = null; 5945 } 5946 if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) { 5947 notification.publicVersion.headsUpContentView = null; 5948 } 5949 } 5950 } 5951 5952 private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) { 5953 if (contentView == null) { 5954 return false; 5955 } 5956 final int contentViewSize = contentView.estimateMemoryUsage(); 5957 if (contentViewSize > mWarnRemoteViewsSizeBytes 5958 && contentViewSize < mStripRemoteViewsSizeBytes) { 5959 Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id 5960 + " this might be stripped in a future release"); 5961 } 5962 if (contentViewSize >= mStripRemoteViewsSizeBytes) { 5963 mUsageStats.registerImageRemoved(pkg); 5964 Slog.w(TAG, "Removed too large RemoteViews (" + contentViewSize + " bytes) on pkg: " 5965 + pkg + " tag: " + tag + " id: " + id); 5966 return true; 5967 } 5968 return false; 5969 } 5970 5971 /** 5972 * Some bubble specific flags only work if the app is foreground, this will strip those flags 5973 * if the app wasn't foreground. 5974 */ 5975 private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) { 5976 // Remove any bubble specific flags that only work when foregrounded 5977 Notification notification = r.getNotification(); 5978 Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); 5979 if (!isAppForeground && metadata != null) { 5980 int flags = metadata.getFlags(); 5981 flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 5982 flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 5983 metadata.setFlags(flags); 5984 } 5985 } 5986 5987 private ShortcutHelper.ShortcutListener mShortcutListener = 5988 new ShortcutHelper.ShortcutListener() { 5989 @Override 5990 public void onShortcutRemoved(String key) { 5991 String packageName; 5992 synchronized (mNotificationLock) { 5993 NotificationRecord r = mNotificationsByKey.get(key); 5994 packageName = r != null ? r.getSbn().getPackageName() : null; 5995 } 5996 boolean isAppForeground = packageName != null 5997 && mActivityManager.getPackageImportance(packageName) 5998 == IMPORTANCE_FOREGROUND; 5999 synchronized (mNotificationLock) { 6000 NotificationRecord r = mNotificationsByKey.get(key); 6001 if (r != null) { 6002 r.setShortcutInfo(null); 6003 // Enqueue will trigger resort & flag is updated that way. 6004 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 6005 mHandler.post( 6006 new NotificationManagerService.EnqueueNotificationRunnable( 6007 r.getUser().getIdentifier(), r, isAppForeground)); 6008 } 6009 } 6010 } 6011 }; 6012 6013 private void doChannelWarningToast(CharSequence toastText) { 6014 Binder.withCleanCallingIdentity(() -> { 6015 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0; 6016 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(), 6017 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0; 6018 if (warningEnabled) { 6019 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText, 6020 Toast.LENGTH_SHORT); 6021 toast.show(); 6022 } 6023 }); 6024 } 6025 6026 @VisibleForTesting 6027 int resolveNotificationUid(String callingPkg, String targetPkg, int callingUid, int userId) { 6028 if (userId == UserHandle.USER_ALL) { 6029 userId = USER_SYSTEM; 6030 } 6031 // posted from app A on behalf of app A 6032 if (isCallerSameApp(targetPkg, callingUid, userId) 6033 && (TextUtils.equals(callingPkg, targetPkg) 6034 || isCallerSameApp(callingPkg, callingUid, userId))) { 6035 return callingUid; 6036 } 6037 6038 int targetUid = INVALID_UID; 6039 try { 6040 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 6041 } catch (NameNotFoundException e) { 6042 /* ignore, handled by caller */ 6043 } 6044 // posted from app A on behalf of app B 6045 if (isCallerAndroid(callingPkg, callingUid) 6046 || mPreferencesHelper.isDelegateAllowed( 6047 targetPkg, targetUid, callingPkg, callingUid)) { 6048 return targetUid; 6049 } 6050 6051 throw new SecurityException("Caller " + callingPkg + ":" + callingUid 6052 + " cannot post for pkg " + targetPkg + " in user " + userId); 6053 } 6054 6055 /** 6056 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking. 6057 * 6058 * Has side effects. 6059 */ 6060 private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag, 6061 NotificationRecord r, boolean isAutogroup) { 6062 final String pkg = r.getSbn().getPackageName(); 6063 final boolean isSystemNotification = 6064 isUidSystemOrPhone(uid) || ("android".equals(pkg)); 6065 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 6066 6067 // Limit the number of notifications that any given package except the android 6068 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 6069 if (!isSystemNotification && !isNotificationFromListener) { 6070 synchronized (mNotificationLock) { 6071 final int callingUid = Binder.getCallingUid(); 6072 if (mNotificationsByKey.get(r.getSbn().getKey()) == null 6073 && isCallerInstantApp(callingUid, userId)) { 6074 // Ephemeral apps have some special constraints for notifications. 6075 // They are not allowed to create new notifications however they are allowed to 6076 // update notifications created by the system (e.g. a foreground service 6077 // notification). 6078 throw new SecurityException("Instant app " + pkg 6079 + " cannot create notifications"); 6080 } 6081 6082 // rate limit updates that aren't completed progress notifications 6083 if (mNotificationsByKey.get(r.getSbn().getKey()) != null 6084 && !r.getNotification().hasCompletedProgress() 6085 && !isAutogroup) { 6086 6087 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); 6088 if (appEnqueueRate > mMaxPackageEnqueueRate) { 6089 mUsageStats.registerOverRateQuota(pkg); 6090 final long now = mSystemClock.elapsedRealtime(); 6091 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { 6092 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate 6093 + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg); 6094 mLastOverRateLogTime = now; 6095 } 6096 return false; 6097 } 6098 } 6099 6100 // limit the number of non-fgs outstanding notificationrecords an app can have 6101 if (!r.getNotification().isForegroundService()) { 6102 int count = getNotificationCountLocked(pkg, userId, id, tag); 6103 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 6104 mUsageStats.registerOverCountQuota(pkg); 6105 Slog.e(TAG, "Package has already posted or enqueued " + count 6106 + " notifications. Not showing more. package=" + pkg); 6107 return false; 6108 } 6109 } 6110 } 6111 } 6112 6113 synchronized (mNotificationLock) { 6114 // snoozed apps 6115 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) { 6116 MetricsLogger.action(r.getLogMaker() 6117 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE) 6118 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)); 6119 mNotificationRecordLogger.log( 6120 NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED, 6121 r); 6122 if (DBG) { 6123 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); 6124 } 6125 mSnoozeHelper.update(userId, r); 6126 handleSavePolicyFile(); 6127 return false; 6128 } 6129 6130 6131 // blocked apps 6132 if (isBlocked(r, mUsageStats)) { 6133 return false; 6134 } 6135 } 6136 6137 return true; 6138 } 6139 6140 @GuardedBy("mNotificationLock") 6141 protected int getNotificationCountLocked(String pkg, int userId, int excludedId, 6142 String excludedTag) { 6143 int count = 0; 6144 final int N = mNotificationList.size(); 6145 for (int i = 0; i < N; i++) { 6146 final NotificationRecord existing = mNotificationList.get(i); 6147 if (existing.getSbn().getPackageName().equals(pkg) 6148 && existing.getSbn().getUserId() == userId) { 6149 if (existing.getSbn().getId() == excludedId 6150 && TextUtils.equals(existing.getSbn().getTag(), excludedTag)) { 6151 continue; 6152 } 6153 count++; 6154 } 6155 } 6156 final int M = mEnqueuedNotifications.size(); 6157 for (int i = 0; i < M; i++) { 6158 final NotificationRecord existing = mEnqueuedNotifications.get(i); 6159 if (existing.getSbn().getPackageName().equals(pkg) 6160 && existing.getSbn().getUserId() == userId) { 6161 count++; 6162 } 6163 } 6164 return count; 6165 } 6166 6167 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) { 6168 if (isBlocked(r)) { 6169 if (DBG) { 6170 Slog.e(TAG, "Suppressing notification from package by user request."); 6171 } 6172 usageStats.registerBlocked(r); 6173 return true; 6174 } 6175 return false; 6176 } 6177 6178 private boolean isBlocked(NotificationRecord r) { 6179 final String pkg = r.getSbn().getPackageName(); 6180 final int callingUid = r.getSbn().getUid(); 6181 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup()) 6182 || mPreferencesHelper.getImportance(pkg, callingUid) 6183 == NotificationManager.IMPORTANCE_NONE 6184 || r.getImportance() == NotificationManager.IMPORTANCE_NONE; 6185 } 6186 6187 protected class SnoozeNotificationRunnable implements Runnable { 6188 private final String mKey; 6189 private final long mDuration; 6190 private final String mSnoozeCriterionId; 6191 6192 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) { 6193 mKey = key; 6194 mDuration = duration; 6195 mSnoozeCriterionId = snoozeCriterionId; 6196 } 6197 6198 @Override 6199 public void run() { 6200 synchronized (mNotificationLock) { 6201 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey); 6202 if (r != null) { 6203 snoozeLocked(r); 6204 } 6205 } 6206 } 6207 6208 @GuardedBy("mNotificationLock") 6209 void snoozeLocked(NotificationRecord r) { 6210 if (r.getSbn().isGroup()) { 6211 final List<NotificationRecord> groupNotifications = 6212 findCurrentAndSnoozedGroupNotificationsLocked( 6213 r.getSbn().getPackageName(), 6214 r.getSbn().getGroupKey(), r.getSbn().getUserId()); 6215 if (r.getNotification().isGroupSummary()) { 6216 // snooze all children 6217 for (int i = 0; i < groupNotifications.size(); i++) { 6218 if (mKey != groupNotifications.get(i).getKey()) { 6219 snoozeNotificationLocked(groupNotifications.get(i)); 6220 } 6221 } 6222 } else { 6223 // if there is a valid summary for this group, and we are snoozing the only 6224 // child, also snooze the summary 6225 if (mSummaryByGroupKey.containsKey(r.getSbn().getGroupKey())) { 6226 if (groupNotifications.size() == 2) { 6227 // snooze summary and the one child 6228 for (int i = 0; i < groupNotifications.size(); i++) { 6229 if (mKey != groupNotifications.get(i).getKey()) { 6230 snoozeNotificationLocked(groupNotifications.get(i)); 6231 } 6232 } 6233 } 6234 } 6235 } 6236 } 6237 // snooze the notification 6238 snoozeNotificationLocked(r); 6239 6240 } 6241 6242 @GuardedBy("mNotificationLock") 6243 void snoozeNotificationLocked(NotificationRecord r) { 6244 MetricsLogger.action(r.getLogMaker() 6245 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED) 6246 .setType(MetricsEvent.TYPE_CLOSE) 6247 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, 6248 mDuration) 6249 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA, 6250 mSnoozeCriterionId == null ? 0 : 1)); 6251 mNotificationRecordLogger.log( 6252 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, r); 6253 reportUserInteraction(r); 6254 boolean wasPosted = removeFromNotificationListsLocked(r); 6255 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null); 6256 updateLightsLocked(); 6257 if (mSnoozeCriterionId != null) { 6258 mAssistants.notifyAssistantSnoozedLocked(r.getSbn(), mSnoozeCriterionId); 6259 mSnoozeHelper.snooze(r, mSnoozeCriterionId); 6260 } else { 6261 mSnoozeHelper.snooze(r, mDuration); 6262 } 6263 r.recordSnoozed(); 6264 handleSavePolicyFile(); 6265 } 6266 } 6267 6268 protected class CancelNotificationRunnable implements Runnable { 6269 private final int mCallingUid; 6270 private final int mCallingPid; 6271 private final String mPkg; 6272 private final String mTag; 6273 private final int mId; 6274 private final int mMustHaveFlags; 6275 private final int mMustNotHaveFlags; 6276 private final boolean mSendDelete; 6277 private final int mUserId; 6278 private final int mReason; 6279 private final int mRank; 6280 private final int mCount; 6281 private final ManagedServiceInfo mListener; 6282 private final long mWhen; 6283 6284 CancelNotificationRunnable(final int callingUid, final int callingPid, 6285 final String pkg, final String tag, final int id, 6286 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 6287 final int userId, final int reason, int rank, int count, 6288 final ManagedServiceInfo listener) { 6289 this.mCallingUid = callingUid; 6290 this.mCallingPid = callingPid; 6291 this.mPkg = pkg; 6292 this.mTag = tag; 6293 this.mId = id; 6294 this.mMustHaveFlags = mustHaveFlags; 6295 this.mMustNotHaveFlags = mustNotHaveFlags; 6296 this.mSendDelete = sendDelete; 6297 this.mUserId = userId; 6298 this.mReason = reason; 6299 this.mRank = rank; 6300 this.mCount = count; 6301 this.mListener = listener; 6302 this.mWhen = mSystemClock.currentTimeMillis(); 6303 } 6304 6305 // Move the work to this function so it can be called from PostNotificationRunnable 6306 private void doNotificationCancelLocked() { 6307 // Look for the notification in the posted list, since we already checked enqueued. 6308 String listenerName = mListener == null ? null : mListener.component.toShortString(); 6309 NotificationRecord r = 6310 findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); 6311 if (r != null) { 6312 // The notification was found, check if it should be removed. 6313 6314 // Ideally we'd do this in the caller of this method. However, that would 6315 // require the caller to also find the notification. 6316 if (mReason == REASON_CLICK) { 6317 mUsageStats.registerClickedByUser(r); 6318 } 6319 6320 if (mReason == REASON_LISTENER_CANCEL 6321 && (r.getNotification().flags & FLAG_BUBBLE) != 0) { 6322 mNotificationDelegate.onBubbleNotificationSuppressionChanged( 6323 r.getKey(), /* suppressed */ true); 6324 return; 6325 } 6326 6327 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { 6328 return; 6329 } 6330 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { 6331 return; 6332 } 6333 6334 // Bubbled children get to stick around if the summary was manually cancelled 6335 // (user removed) from systemui. 6336 FlagChecker childrenFlagChecker = null; 6337 if (mReason == REASON_CANCEL 6338 || mReason == REASON_CLICK 6339 || mReason == REASON_CANCEL_ALL) { 6340 childrenFlagChecker = (flags) -> { 6341 if ((flags & FLAG_BUBBLE) != 0) { 6342 return false; 6343 } 6344 return true; 6345 }; 6346 } 6347 6348 // Cancel the notification. 6349 boolean wasPosted = removePreviousFromNotificationListsLocked(r, mWhen); 6350 cancelNotificationLocked( 6351 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName); 6352 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName, 6353 mSendDelete, childrenFlagChecker, mReason); 6354 updateLightsLocked(); 6355 if (mShortcutHelper != null) { 6356 mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, 6357 true /* isRemoved */, 6358 mHandler); 6359 } 6360 } else { 6361 // No notification was found, assume that it is snoozed and cancel it. 6362 if (mReason != REASON_SNOOZED) { 6363 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId); 6364 if (wasSnoozed) { 6365 handleSavePolicyFile(); 6366 } 6367 } 6368 } 6369 } 6370 6371 @Override 6372 public void run() { 6373 String listenerName = mListener == null ? null : mListener.component.toShortString(); 6374 if (DBG) { 6375 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag, 6376 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName); 6377 } 6378 6379 synchronized (mNotificationLock) { 6380 // Check to see if there is a notification in the enqueued list that hasn't had a 6381 // chance to post yet. 6382 List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria( 6383 mPkg, mTag, mId, mUserId); 6384 if (enqueued.size() > 0) { 6385 // We have found notifications that were enqueued before this cancel, but not 6386 // yet posted. Attach this cancel to the last enqueue (the most recent), and 6387 // we will be executed in that notification's PostNotificationRunnable 6388 NotificationRecord enqueuedToAttach = enqueued.get(enqueued.size() - 1); 6389 6390 ArrayList<CancelNotificationRunnable> delayed = 6391 mDelayedCancelations.get(enqueuedToAttach); 6392 if (delayed == null) { 6393 delayed = new ArrayList<>(); 6394 } 6395 6396 delayed.add(this); 6397 mDelayedCancelations.put(enqueuedToAttach, delayed); 6398 return; 6399 } 6400 6401 doNotificationCancelLocked(); 6402 } 6403 } 6404 } 6405 6406 protected class EnqueueNotificationRunnable implements Runnable { 6407 private final NotificationRecord r; 6408 private final int userId; 6409 private final boolean isAppForeground; 6410 6411 EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground) { 6412 this.userId = userId; 6413 this.r = r; 6414 this.isAppForeground = foreground; 6415 } 6416 6417 @Override 6418 public void run() { 6419 synchronized (mNotificationLock) { 6420 final Long snoozeAt = 6421 mSnoozeHelper.getSnoozeTimeForUnpostedNotification( 6422 r.getUser().getIdentifier(), 6423 r.getSbn().getPackageName(), r.getSbn().getKey()); 6424 final long currentTime = mSystemClock.currentTimeMillis(); 6425 if (snoozeAt.longValue() > currentTime) { 6426 (new SnoozeNotificationRunnable(r.getSbn().getKey(), 6427 snoozeAt.longValue() - currentTime, null)).snoozeLocked(r); 6428 return; 6429 } 6430 6431 final String contextId = 6432 mSnoozeHelper.getSnoozeContextForUnpostedNotification( 6433 r.getUser().getIdentifier(), 6434 r.getSbn().getPackageName(), r.getSbn().getKey()); 6435 if (contextId != null) { 6436 (new SnoozeNotificationRunnable(r.getSbn().getKey(), 6437 0, contextId)).snoozeLocked(r); 6438 return; 6439 } 6440 6441 mEnqueuedNotifications.add(r); 6442 scheduleTimeoutLocked(r); 6443 6444 final StatusBarNotification n = r.getSbn(); 6445 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 6446 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 6447 if (old != null) { 6448 // Retain ranking information from previous record 6449 r.copyRankingInformation(old); 6450 } 6451 6452 final int callingUid = n.getUid(); 6453 final int callingPid = n.getInitialPid(); 6454 final Notification notification = n.getNotification(); 6455 final String pkg = n.getPackageName(); 6456 final int id = n.getId(); 6457 final String tag = n.getTag(); 6458 6459 // We need to fix the notification up a little for bubbles 6460 updateNotificationBubbleFlags(r, isAppForeground); 6461 6462 // Handle grouped notifications and bail out early if we 6463 // can to avoid extracting signals. 6464 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 6465 6466 // if this is a group child, unsnooze parent summary 6467 if (n.isGroup() && notification.isGroupChild()) { 6468 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey()); 6469 } 6470 6471 // This conditional is a dirty hack to limit the logging done on 6472 // behalf of the download manager without affecting other apps. 6473 if (!pkg.equals("com.android.providers.downloads") 6474 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 6475 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 6476 if (old != null) { 6477 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 6478 } 6479 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 6480 pkg, id, tag, userId, notification.toString(), 6481 enqueueStatus); 6482 } 6483 6484 postPostNotificationRunnableMaybeDelayedLocked( 6485 r, new PostNotificationRunnable(r.getKey())); 6486 } 6487 } 6488 } 6489 6490 /** 6491 * Mainly needed as a hook for tests which require setting up enqueued-but-not-posted 6492 * notification records 6493 */ 6494 @GuardedBy("mNotificationLock") 6495 protected void postPostNotificationRunnableMaybeDelayedLocked( 6496 NotificationRecord r, 6497 PostNotificationRunnable runnable) { 6498 // tell the assistant service about the notification 6499 if (mAssistants.isEnabled()) { 6500 mAssistants.onNotificationEnqueuedLocked(r); 6501 mHandler.postDelayed(runnable, DELAY_FOR_ASSISTANT_TIME); 6502 } else { 6503 mHandler.post(runnable); 6504 } 6505 } 6506 6507 @GuardedBy("mNotificationLock") 6508 boolean isPackagePausedOrSuspended(String pkg, int uid) { 6509 boolean isPaused; 6510 6511 final PackageManagerInternal pmi = LocalServices.getService( 6512 PackageManagerInternal.class); 6513 int flags = pmi.getDistractingPackageRestrictions( 6514 pkg, Binder.getCallingUserHandle().getIdentifier()); 6515 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0); 6516 6517 isPaused |= isPackageSuspendedForUser(pkg, uid); 6518 6519 return isPaused; 6520 } 6521 6522 protected class PostNotificationRunnable implements Runnable { 6523 private final String key; 6524 6525 PostNotificationRunnable(String key) { 6526 this.key = key; 6527 } 6528 6529 @Override 6530 public void run() { 6531 synchronized (mNotificationLock) { 6532 try { 6533 NotificationRecord r = null; 6534 int N = mEnqueuedNotifications.size(); 6535 for (int i = 0; i < N; i++) { 6536 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 6537 if (Objects.equals(key, enqueued.getKey())) { 6538 r = enqueued; 6539 break; 6540 } 6541 } 6542 if (r == null) { 6543 Slog.i(TAG, "Cannot find enqueued record for key: " + key); 6544 return; 6545 } 6546 6547 if (isBlocked(r)) { 6548 Slog.i(TAG, "notification blocked by assistant request"); 6549 return; 6550 } 6551 6552 final boolean isPackageSuspended = 6553 isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid()); 6554 r.setHidden(isPackageSuspended); 6555 if (isPackageSuspended) { 6556 mUsageStats.registerSuspendedByAdmin(r); 6557 } 6558 NotificationRecord old = mNotificationsByKey.get(key); 6559 final StatusBarNotification n = r.getSbn(); 6560 final Notification notification = n.getNotification(); 6561 6562 // Make sure the SBN has an instance ID for statsd logging. 6563 if (old == null || old.getSbn().getInstanceId() == null) { 6564 n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6565 } else { 6566 n.setInstanceId(old.getSbn().getInstanceId()); 6567 } 6568 6569 int index = indexOfNotificationLocked(n.getKey()); 6570 if (index < 0) { 6571 mNotificationList.add(r); 6572 mUsageStats.registerPostedByApp(r); 6573 r.setInterruptive(isVisuallyInterruptive(null, r)); 6574 } else { 6575 old = mNotificationList.get(index); // Potentially *changes* old 6576 mNotificationList.set(index, r); 6577 mUsageStats.registerUpdatedByApp(r, old); 6578 // Make sure we don't lose the foreground service state. 6579 notification.flags |= 6580 old.getNotification().flags & FLAG_FOREGROUND_SERVICE; 6581 r.isUpdate = true; 6582 final boolean isInterruptive = isVisuallyInterruptive(old, r); 6583 r.setTextChanged(isInterruptive); 6584 r.setInterruptive(isInterruptive); 6585 } 6586 6587 mNotificationsByKey.put(n.getKey(), r); 6588 6589 // Ensure if this is a foreground service that the proper additional 6590 // flags are set. 6591 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) { 6592 notification.flags |= FLAG_ONGOING_EVENT 6593 | FLAG_NO_CLEAR; 6594 } 6595 6596 mRankingHelper.extractSignals(r); 6597 mRankingHelper.sort(mNotificationList); 6598 final int position = mRankingHelper.indexOf(mNotificationList, r); 6599 6600 int buzzBeepBlinkLoggingCode = 0; 6601 if (!r.isHidden()) { 6602 buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r); 6603 } 6604 6605 if (notification.getSmallIcon() != null) { 6606 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 6607 mListeners.notifyPostedLocked(r, old); 6608 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) 6609 && !isCritical(r)) { 6610 mHandler.post(new Runnable() { 6611 @Override 6612 public void run() { 6613 mGroupHelper.onNotificationPosted( 6614 n, hasAutoGroupSummaryLocked(n)); 6615 } 6616 }); 6617 } else if (oldSbn != null) { 6618 final NotificationRecord finalRecord = r; 6619 mHandler.post(() -> mGroupHelper.onNotificationUpdated( 6620 finalRecord.getSbn(), hasAutoGroupSummaryLocked(n))); 6621 } 6622 } else { 6623 Slog.e(TAG, "Not posting notification without small icon: " + notification); 6624 if (old != null && !old.isCanceled) { 6625 mListeners.notifyRemovedLocked(r, 6626 NotificationListenerService.REASON_ERROR, r.getStats()); 6627 mHandler.post(new Runnable() { 6628 @Override 6629 public void run() { 6630 mGroupHelper.onNotificationRemoved(n); 6631 } 6632 }); 6633 } 6634 // ATTENTION: in a future release we will bail out here 6635 // so that we do not play sounds, show lights, etc. for invalid 6636 // notifications 6637 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 6638 + n.getPackageName()); 6639 } 6640 6641 if (mShortcutHelper != null) { 6642 mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, 6643 false /* isRemoved */, 6644 mHandler); 6645 } 6646 6647 maybeRecordInterruptionLocked(r); 6648 maybeRegisterMessageSent(r); 6649 6650 // Log event to statsd 6651 mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position, 6652 buzzBeepBlinkLoggingCode, getGroupInstanceId(n.getGroupKey())); 6653 } finally { 6654 int N = mEnqueuedNotifications.size(); 6655 NotificationRecord enqueued = null; 6656 for (int i = 0; i < N; i++) { 6657 enqueued = mEnqueuedNotifications.get(i); 6658 if (Objects.equals(key, enqueued.getKey())) { 6659 mEnqueuedNotifications.remove(i); 6660 break; 6661 } 6662 } 6663 6664 // If the enqueued notification record had a cancel attached after it, execute 6665 // it right now 6666 if (enqueued != null && mDelayedCancelations.get(enqueued) != null) { 6667 for (CancelNotificationRunnable r : mDelayedCancelations.get(enqueued)) { 6668 r.doNotificationCancelLocked(); 6669 } 6670 mDelayedCancelations.remove(enqueued); 6671 } 6672 } 6673 } 6674 } 6675 } 6676 6677 /** 6678 * 6679 */ 6680 @GuardedBy("mNotificationLock") 6681 InstanceId getGroupInstanceId(String groupKey) { 6682 if (groupKey == null) { 6683 return null; 6684 } 6685 NotificationRecord group = mSummaryByGroupKey.get(groupKey); 6686 if (group == null) { 6687 return null; 6688 } 6689 return group.getSbn().getInstanceId(); 6690 } 6691 6692 /** 6693 * If the notification differs enough visually, consider it a new interruptive notification. 6694 */ 6695 @GuardedBy("mNotificationLock") 6696 @VisibleForTesting 6697 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) { 6698 // Ignore summary updates because we don't display most of the information. 6699 if (r.getSbn().isGroup() && r.getSbn().getNotification().isGroupSummary()) { 6700 if (DEBUG_INTERRUPTIVENESS) { 6701 Slog.v(TAG, "INTERRUPTIVENESS: " 6702 + r.getKey() + " is not interruptive: summary"); 6703 } 6704 return false; 6705 } 6706 6707 if (old == null) { 6708 if (DEBUG_INTERRUPTIVENESS) { 6709 Slog.v(TAG, "INTERRUPTIVENESS: " 6710 + r.getKey() + " is interruptive: new notification"); 6711 } 6712 return true; 6713 } 6714 6715 if (r == null) { 6716 if (DEBUG_INTERRUPTIVENESS) { 6717 Slog.v(TAG, "INTERRUPTIVENESS: " 6718 + r.getKey() + " is not interruptive: null"); 6719 } 6720 return false; 6721 } 6722 6723 Notification oldN = old.getSbn().getNotification(); 6724 Notification newN = r.getSbn().getNotification(); 6725 if (oldN.extras == null || newN.extras == null) { 6726 if (DEBUG_INTERRUPTIVENESS) { 6727 Slog.v(TAG, "INTERRUPTIVENESS: " 6728 + r.getKey() + " is not interruptive: no extras"); 6729 } 6730 return false; 6731 } 6732 6733 // Ignore visual interruptions from foreground services because users 6734 // consider them one 'session'. Count them for everything else. 6735 if ((r.getSbn().getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { 6736 if (DEBUG_INTERRUPTIVENESS) { 6737 Slog.v(TAG, "INTERRUPTIVENESS: " 6738 + r.getKey() + " is not interruptive: foreground service"); 6739 } 6740 return false; 6741 } 6742 6743 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); 6744 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); 6745 if (!Objects.equals(oldTitle, newTitle)) { 6746 if (DEBUG_INTERRUPTIVENESS) { 6747 Slog.v(TAG, "INTERRUPTIVENESS: " 6748 + r.getKey() + " is interruptive: changed title"); 6749 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)", 6750 oldTitle, oldTitle.getClass(), oldTitle.hashCode())); 6751 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)", 6752 newTitle, newTitle.getClass(), newTitle.hashCode())); 6753 } 6754 return true; 6755 } 6756 6757 // Do not compare Spannables (will always return false); compare unstyled Strings 6758 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT)); 6759 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT)); 6760 if (!Objects.equals(oldText, newText)) { 6761 if (DEBUG_INTERRUPTIVENESS) { 6762 Slog.v(TAG, "INTERRUPTIVENESS: " 6763 + r.getKey() + " is interruptive: changed text"); 6764 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)", 6765 oldText, oldText.getClass(), oldText.hashCode())); 6766 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)", 6767 newText, newText.getClass(), newText.hashCode())); 6768 } 6769 return true; 6770 } 6771 6772 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) { 6773 if (DEBUG_INTERRUPTIVENESS) { 6774 Slog.v(TAG, "INTERRUPTIVENESS: " 6775 + r.getKey() + " is interruptive: completed progress"); 6776 } 6777 return true; 6778 } 6779 6780 // Fields below are invisible to bubbles. 6781 if (r.canBubble()) { 6782 if (DEBUG_INTERRUPTIVENESS) { 6783 Slog.v(TAG, "INTERRUPTIVENESS: " 6784 + r.getKey() + " is not interruptive: bubble"); 6785 } 6786 return false; 6787 } 6788 6789 // Actions 6790 if (Notification.areActionsVisiblyDifferent(oldN, newN)) { 6791 if (DEBUG_INTERRUPTIVENESS) { 6792 Slog.v(TAG, "INTERRUPTIVENESS: " 6793 + r.getKey() + " is interruptive: changed actions"); 6794 } 6795 return true; 6796 } 6797 6798 try { 6799 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN); 6800 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN); 6801 6802 // Style based comparisons 6803 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) { 6804 if (DEBUG_INTERRUPTIVENESS) { 6805 Slog.v(TAG, "INTERRUPTIVENESS: " 6806 + r.getKey() + " is interruptive: styles differ"); 6807 } 6808 return true; 6809 } 6810 6811 // Remote views 6812 if (Notification.areRemoteViewsChanged(oldB, newB)) { 6813 if (DEBUG_INTERRUPTIVENESS) { 6814 Slog.v(TAG, "INTERRUPTIVENESS: " 6815 + r.getKey() + " is interruptive: remoteviews differ"); 6816 } 6817 return true; 6818 } 6819 } catch (Exception e) { 6820 Slog.w(TAG, "error recovering builder", e); 6821 } 6822 return false; 6823 } 6824 6825 /** 6826 * Check if the notification is classified as critical. 6827 * 6828 * @param record the record to test for criticality 6829 * @return {@code true} if notification is considered critical 6830 * 6831 * @see CriticalNotificationExtractor for criteria 6832 */ 6833 private boolean isCritical(NotificationRecord record) { 6834 // 0 is the most critical 6835 return record.getCriticality() < CriticalNotificationExtractor.NORMAL; 6836 } 6837 6838 /** 6839 * Ensures that grouped notification receive their special treatment. 6840 * 6841 * <p>Cancels group children if the new notification causes a group to lose 6842 * its summary.</p> 6843 * 6844 * <p>Updates mSummaryByGroupKey.</p> 6845 */ 6846 @GuardedBy("mNotificationLock") 6847 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 6848 int callingUid, int callingPid) { 6849 StatusBarNotification sbn = r.getSbn(); 6850 Notification n = sbn.getNotification(); 6851 if (n.isGroupSummary() && !sbn.isAppGroup()) { 6852 // notifications without a group shouldn't be a summary, otherwise autobundling can 6853 // lead to bugs 6854 n.flags &= ~Notification.FLAG_GROUP_SUMMARY; 6855 } 6856 6857 String group = sbn.getGroupKey(); 6858 boolean isSummary = n.isGroupSummary(); 6859 6860 Notification oldN = old != null ? old.getSbn().getNotification() : null; 6861 String oldGroup = old != null ? old.getSbn().getGroupKey() : null; 6862 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 6863 6864 if (oldIsSummary) { 6865 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 6866 if (removedSummary != old) { 6867 String removedKey = 6868 removedSummary != null ? removedSummary.getKey() : "<null>"; 6869 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 6870 ", removed=" + removedKey); 6871 } 6872 } 6873 if (isSummary) { 6874 mSummaryByGroupKey.put(group, r); 6875 } 6876 6877 // Clear out group children of the old notification if the update 6878 // causes the group summary to go away. This happens when the old 6879 // notification was a summary and the new one isn't, or when the old 6880 // notification was a summary and its group key changed. 6881 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 6882 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */, 6883 null, REASON_APP_CANCEL); 6884 } 6885 } 6886 6887 @VisibleForTesting 6888 @GuardedBy("mNotificationLock") 6889 void scheduleTimeoutLocked(NotificationRecord record) { 6890 if (record.getNotification().getTimeoutAfter() > 0) { 6891 final PendingIntent pi = PendingIntent.getBroadcast(getContext(), 6892 REQUEST_CODE_TIMEOUT, 6893 new Intent(ACTION_NOTIFICATION_TIMEOUT) 6894 .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME) 6895 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT) 6896 .appendPath(record.getKey()).build()) 6897 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 6898 .putExtra(EXTRA_KEY, record.getKey()), 6899 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 6900 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 6901 mSystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), 6902 pi); 6903 } 6904 } 6905 6906 @VisibleForTesting 6907 @GuardedBy("mNotificationLock") 6908 /** 6909 * Determine whether this notification should attempt to make noise, vibrate, or flash the LED 6910 * @return buzzBeepBlink - bitfield (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) 6911 */ 6912 int buzzBeepBlinkLocked(NotificationRecord record) { 6913 if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) { 6914 return 0; 6915 } 6916 boolean buzz = false; 6917 boolean beep = false; 6918 boolean blink = false; 6919 6920 final String key = record.getKey(); 6921 6922 // Should this notification make noise, vibe, or use the LED? 6923 final boolean aboveThreshold = 6924 mIsAutomotive 6925 ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT 6926 : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT; 6927 // Remember if this notification already owns the notification channels. 6928 boolean wasBeep = key != null && key.equals(mSoundNotificationKey); 6929 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey); 6930 // These are set inside the conditional if the notification is allowed to make noise. 6931 boolean hasValidVibrate = false; 6932 boolean hasValidSound = false; 6933 boolean sentAccessibilityEvent = false; 6934 6935 // If the notification will appear in the status bar, it should send an accessibility event 6936 final boolean suppressedByDnd = record.isIntercepted() 6937 && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0; 6938 if (!record.isUpdate 6939 && record.getImportance() > IMPORTANCE_MIN 6940 && !suppressedByDnd) { 6941 sendAccessibilityEvent(record); 6942 sentAccessibilityEvent = true; 6943 } 6944 6945 if (aboveThreshold && isNotificationForCurrentUser(record)) { 6946 if (mSystemReady && mAudioManager != null) { 6947 Uri soundUri = record.getSound(); 6948 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri); 6949 long[] vibration = record.getVibration(); 6950 // Demote sound to vibration if vibration missing & phone in vibration mode. 6951 if (vibration == null 6952 && hasValidSound 6953 && (mAudioManager.getRingerModeInternal() 6954 == AudioManager.RINGER_MODE_VIBRATE) 6955 && mAudioManager.getStreamVolume( 6956 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) { 6957 vibration = mFallbackVibrationPattern; 6958 } 6959 hasValidVibrate = vibration != null; 6960 boolean hasAudibleAlert = hasValidSound || hasValidVibrate; 6961 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { 6962 if (!sentAccessibilityEvent) { 6963 sendAccessibilityEvent(record); 6964 sentAccessibilityEvent = true; 6965 } 6966 if (DBG) Slog.v(TAG, "Interrupting!"); 6967 if (hasValidSound) { 6968 if (isInCall()) { 6969 playInCallNotification(); 6970 beep = true; 6971 } else { 6972 beep = playSound(record, soundUri); 6973 } 6974 if(beep) { 6975 mSoundNotificationKey = key; 6976 } 6977 } 6978 6979 final boolean ringerModeSilent = 6980 mAudioManager.getRingerModeInternal() 6981 == AudioManager.RINGER_MODE_SILENT; 6982 if (!isInCall() && hasValidVibrate && !ringerModeSilent) { 6983 buzz = playVibration(record, vibration, hasValidSound); 6984 if(buzz) { 6985 mVibrateNotificationKey = key; 6986 } 6987 } 6988 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) { 6989 hasValidSound = false; 6990 } 6991 } 6992 } 6993 // If a notification is updated to remove the actively playing sound or vibrate, 6994 // cancel that feedback now 6995 if (wasBeep && !hasValidSound) { 6996 clearSoundLocked(); 6997 } 6998 if (wasBuzz && !hasValidVibrate) { 6999 clearVibrateLocked(); 7000 } 7001 7002 // light 7003 // release the light 7004 boolean wasShowLights = mLights.remove(key); 7005 if (canShowLightsLocked(record, aboveThreshold)) { 7006 mLights.add(key); 7007 updateLightsLocked(); 7008 if (mUseAttentionLight && mAttentionLight != null) { 7009 mAttentionLight.pulse(); 7010 } 7011 blink = true; 7012 } else if (wasShowLights) { 7013 updateLightsLocked(); 7014 } 7015 final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0); 7016 if (buzzBeepBlink > 0) { 7017 // Ignore summary updates because we don't display most of the information. 7018 if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) { 7019 if (DEBUG_INTERRUPTIVENESS) { 7020 Slog.v(TAG, "INTERRUPTIVENESS: " 7021 + record.getKey() + " is not interruptive: summary"); 7022 } 7023 } else if (record.canBubble()) { 7024 if (DEBUG_INTERRUPTIVENESS) { 7025 Slog.v(TAG, "INTERRUPTIVENESS: " 7026 + record.getKey() + " is not interruptive: bubble"); 7027 } 7028 } else { 7029 record.setInterruptive(true); 7030 if (DEBUG_INTERRUPTIVENESS) { 7031 Slog.v(TAG, "INTERRUPTIVENESS: " 7032 + record.getKey() + " is interruptive: alerted"); 7033 } 7034 } 7035 MetricsLogger.action(record.getLogMaker() 7036 .setCategory(MetricsEvent.NOTIFICATION_ALERT) 7037 .setType(MetricsEvent.TYPE_OPEN) 7038 .setSubtype(buzzBeepBlink)); 7039 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 7040 } 7041 record.setAudiblyAlerted(buzz || beep); 7042 return buzzBeepBlink; 7043 } 7044 7045 @GuardedBy("mNotificationLock") 7046 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) { 7047 // device lacks light 7048 if (!mHasLight) { 7049 return false; 7050 } 7051 // user turned lights off globally 7052 if (!mNotificationPulseEnabled) { 7053 return false; 7054 } 7055 // the notification/channel has no light 7056 if (record.getLight() == null) { 7057 return false; 7058 } 7059 // unimportant notification 7060 if (!aboveThreshold) { 7061 return false; 7062 } 7063 // suppressed due to DND 7064 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) { 7065 return false; 7066 } 7067 // Suppressed because it's a silent update 7068 final Notification notification = record.getNotification(); 7069 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) { 7070 return false; 7071 } 7072 // Suppressed because another notification in its group handles alerting 7073 if (record.getSbn().isGroup() && record.getNotification().suppressAlertingDueToGrouping()) { 7074 return false; 7075 } 7076 // not if in call or the screen's on 7077 if (isInCall() || mScreenOn) { 7078 return false; 7079 } 7080 7081 return true; 7082 } 7083 7084 @GuardedBy("mNotificationLock") 7085 boolean shouldMuteNotificationLocked(final NotificationRecord record) { 7086 // Suppressed because it's a silent update 7087 final Notification notification = record.getNotification(); 7088 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) { 7089 return true; 7090 } 7091 7092 // Suppressed because a user manually unsnoozed something (or similar) 7093 if (record.shouldPostSilently()) { 7094 return true; 7095 } 7096 7097 // muted by listener 7098 final String disableEffects = disableNotificationEffects(record); 7099 if (disableEffects != null) { 7100 ZenLog.traceDisableEffects(record, disableEffects); 7101 return true; 7102 } 7103 7104 // suppressed due to DND 7105 if (record.isIntercepted()) { 7106 return true; 7107 } 7108 7109 // Suppressed because another notification in its group handles alerting 7110 if (record.getSbn().isGroup()) { 7111 if (notification.suppressAlertingDueToGrouping()) { 7112 return true; 7113 } 7114 } 7115 7116 // Suppressed for being too recently noisy 7117 final String pkg = record.getSbn().getPackageName(); 7118 if (mUsageStats.isAlertRateLimited(pkg)) { 7119 Slog.e(TAG, "Muting recently noisy " + record.getKey()); 7120 return true; 7121 } 7122 7123 // A looping ringtone, such as an incoming call is playing 7124 if (isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey)) 7125 || isLoopingRingtoneNotification( 7126 mNotificationsByKey.get(mVibrateNotificationKey))) { 7127 return true; 7128 } 7129 7130 return false; 7131 } 7132 7133 @GuardedBy("mNotificationLock") 7134 private boolean isLoopingRingtoneNotification(final NotificationRecord playingRecord) { 7135 if (playingRecord != null) { 7136 if (playingRecord.getAudioAttributes().getUsage() == USAGE_NOTIFICATION_RINGTONE 7137 && (playingRecord.getNotification().flags & FLAG_INSISTENT) != 0) { 7138 return true; 7139 } 7140 } 7141 return false; 7142 } 7143 7144 private boolean playSound(final NotificationRecord record, Uri soundUri) { 7145 boolean looping = (record.getNotification().flags & FLAG_INSISTENT) != 0; 7146 // play notifications if there is no user of exclusive audio focus 7147 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or 7148 // VIBRATE ringer mode) 7149 if (!mAudioManager.isAudioFocusExclusive() 7150 && (mAudioManager.getStreamVolume( 7151 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) { 7152 final long identity = Binder.clearCallingIdentity(); 7153 try { 7154 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 7155 if (player != null) { 7156 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 7157 + " with attributes " + record.getAudioAttributes()); 7158 player.playAsync(soundUri, record.getSbn().getUser(), looping, 7159 record.getAudioAttributes()); 7160 return true; 7161 } 7162 } catch (RemoteException e) { 7163 } finally { 7164 Binder.restoreCallingIdentity(identity); 7165 } 7166 } 7167 return false; 7168 } 7169 7170 private boolean playVibration(final NotificationRecord record, long[] vibration, 7171 boolean delayVibForSound) { 7172 // Escalate privileges so we can use the vibrator even if the 7173 // notifying app does not have the VIBRATE permission. 7174 long identity = Binder.clearCallingIdentity(); 7175 try { 7176 final VibrationEffect effect; 7177 try { 7178 final boolean insistent = 7179 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; 7180 effect = VibrationEffect.createWaveform( 7181 vibration, insistent ? 0 : -1 /*repeatIndex*/); 7182 } catch (IllegalArgumentException e) { 7183 Slog.e(TAG, "Error creating vibration waveform with pattern: " + 7184 Arrays.toString(vibration)); 7185 return false; 7186 } 7187 if (delayVibForSound) { 7188 new Thread(() -> { 7189 // delay the vibration by the same amount as the notification sound 7190 final int waitMs = mAudioManager.getFocusRampTimeMs( 7191 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 7192 record.getAudioAttributes()); 7193 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms"); 7194 try { 7195 Thread.sleep(waitMs); 7196 } catch (InterruptedException e) { } 7197 // Notifications might be canceled before it actually vibrates due to waitMs, 7198 // so need to check the notification still valide for vibrate. 7199 synchronized (mNotificationLock) { 7200 if (mNotificationsByKey.get(record.getKey()) != null) { 7201 vibrate(record, effect, true); 7202 } else { 7203 Slog.e(TAG, "No vibration for canceled notification : " 7204 + record.getKey()); 7205 } 7206 } 7207 }).start(); 7208 } else { 7209 vibrate(record, effect, false); 7210 } 7211 return true; 7212 } finally{ 7213 Binder.restoreCallingIdentity(identity); 7214 } 7215 } 7216 7217 private void vibrate(NotificationRecord record, VibrationEffect effect, boolean delayed) { 7218 // We need to vibrate as "android" so we can breakthrough DND. VibratorManagerService 7219 // doesn't have a concept of vibrating on an app's behalf, so add the app information 7220 // to the reason so we can still debug from bugreports 7221 String reason = "Notification (" + record.getSbn().getOpPkg() + " " 7222 + record.getSbn().getUid() + ") " + (delayed ? "(Delayed)" : ""); 7223 mVibrator.vibrate(Process.SYSTEM_UID, PackageManagerService.PLATFORM_PACKAGE_NAME, 7224 effect, reason, record.getAudioAttributes()); 7225 } 7226 7227 private boolean isNotificationForCurrentUser(NotificationRecord record) { 7228 final int currentUser; 7229 final long token = Binder.clearCallingIdentity(); 7230 try { 7231 currentUser = ActivityManager.getCurrentUser(); 7232 } finally { 7233 Binder.restoreCallingIdentity(token); 7234 } 7235 return (record.getUserId() == UserHandle.USER_ALL || 7236 record.getUserId() == currentUser || 7237 mUserProfiles.isCurrentProfile(record.getUserId())); 7238 } 7239 7240 protected void playInCallNotification() { 7241 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL 7242 && Settings.Secure.getInt(getContext().getContentResolver(), 7243 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) { 7244 new Thread() { 7245 @Override 7246 public void run() { 7247 final long identity = Binder.clearCallingIdentity(); 7248 try { 7249 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 7250 if (player != null) { 7251 if (mCallNotificationToken != null) { 7252 player.stop(mCallNotificationToken); 7253 } 7254 mCallNotificationToken = new Binder(); 7255 player.play(mCallNotificationToken, mInCallNotificationUri, 7256 mInCallNotificationAudioAttributes, 7257 mInCallNotificationVolume, false); 7258 } 7259 } catch (RemoteException e) { 7260 } finally { 7261 Binder.restoreCallingIdentity(identity); 7262 } 7263 } 7264 }.start(); 7265 } 7266 } 7267 7268 @GuardedBy("mToastQueue") 7269 void showNextToastLocked() { 7270 ToastRecord record = mToastQueue.get(0); 7271 while (record != null) { 7272 if (record.show()) { 7273 scheduleDurationReachedLocked(record); 7274 return; 7275 } 7276 int index = mToastQueue.indexOf(record); 7277 if (index >= 0) { 7278 mToastQueue.remove(index); 7279 } 7280 record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null; 7281 } 7282 } 7283 7284 @GuardedBy("mToastQueue") 7285 void cancelToastLocked(int index) { 7286 ToastRecord record = mToastQueue.get(index); 7287 record.hide(); 7288 7289 ToastRecord lastToast = mToastQueue.remove(index); 7290 7291 mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */, 7292 lastToast.displayId); 7293 // We passed 'false' for 'removeWindows' so that the client has time to stop 7294 // rendering (as hide above is a one-way message), otherwise we could crash 7295 // a client which was actively using a surface made from the token. However 7296 // we need to schedule a timeout to make sure the token is eventually killed 7297 // one way or another. 7298 scheduleKillTokenTimeout(lastToast); 7299 7300 keepProcessAliveForToastIfNeededLocked(record.pid); 7301 if (mToastQueue.size() > 0) { 7302 // Show the next one. If the callback fails, this will remove 7303 // it from the list, so don't assume that the list hasn't changed 7304 // after this point. 7305 showNextToastLocked(); 7306 } 7307 } 7308 7309 void finishWindowTokenLocked(IBinder t, int displayId) { 7310 mHandler.removeCallbacksAndMessages(t); 7311 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any 7312 // remaining surfaces as either the client has called finishToken indicating 7313 // it has successfully removed the views, or the client has timed out 7314 // at which point anything goes. 7315 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId); 7316 } 7317 7318 @GuardedBy("mToastQueue") 7319 private void scheduleDurationReachedLocked(ToastRecord r) 7320 { 7321 mHandler.removeCallbacksAndMessages(r); 7322 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r); 7323 int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 7324 // Accessibility users may need longer timeout duration. This api compares original delay 7325 // with user's preference and return longer one. It returns original delay if there's no 7326 // preference. 7327 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay, 7328 AccessibilityManager.FLAG_CONTENT_TEXT); 7329 mHandler.sendMessageDelayed(m, delay); 7330 } 7331 7332 private void handleDurationReached(ToastRecord record) 7333 { 7334 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " token=" + record.token); 7335 synchronized (mToastQueue) { 7336 int index = indexOfToastLocked(record.pkg, record.token); 7337 if (index >= 0) { 7338 cancelToastLocked(index); 7339 } 7340 } 7341 } 7342 7343 @GuardedBy("mToastQueue") 7344 private void scheduleKillTokenTimeout(ToastRecord r) 7345 { 7346 mHandler.removeCallbacksAndMessages(r); 7347 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r); 7348 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT); 7349 } 7350 7351 private void handleKillTokenTimeout(ToastRecord record) 7352 { 7353 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.windowToken); 7354 synchronized (mToastQueue) { 7355 finishWindowTokenLocked(record.windowToken, record.displayId); 7356 } 7357 } 7358 7359 @GuardedBy("mToastQueue") 7360 int indexOfToastLocked(String pkg, IBinder token) { 7361 ArrayList<ToastRecord> list = mToastQueue; 7362 int len = list.size(); 7363 for (int i=0; i<len; i++) { 7364 ToastRecord r = list.get(i); 7365 if (r.pkg.equals(pkg) && r.token == token) { 7366 return i; 7367 } 7368 } 7369 return -1; 7370 } 7371 7372 /** 7373 * Adjust process {@code pid} importance according to whether it has toasts in the queue or not. 7374 */ 7375 public void keepProcessAliveForToastIfNeeded(int pid) { 7376 synchronized (mToastQueue) { 7377 keepProcessAliveForToastIfNeededLocked(pid); 7378 } 7379 } 7380 7381 @GuardedBy("mToastQueue") 7382 private void keepProcessAliveForToastIfNeededLocked(int pid) { 7383 int toastCount = 0; // toasts from this pid 7384 ArrayList<ToastRecord> list = mToastQueue; 7385 int n = list.size(); 7386 for (int i = 0; i < n; i++) { 7387 ToastRecord r = list.get(i); 7388 if (r.pid == pid) { 7389 toastCount++; 7390 } 7391 } 7392 try { 7393 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast"); 7394 } catch (RemoteException e) { 7395 // Shouldn't happen. 7396 } 7397 } 7398 7399 private void handleRankingReconsideration(Message message) { 7400 if (!(message.obj instanceof RankingReconsideration)) return; 7401 RankingReconsideration recon = (RankingReconsideration) message.obj; 7402 recon.run(); 7403 boolean changed; 7404 synchronized (mNotificationLock) { 7405 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 7406 if (record == null) { 7407 return; 7408 } 7409 int indexBefore = findNotificationRecordIndexLocked(record); 7410 boolean interceptBefore = record.isIntercepted(); 7411 int visibilityBefore = record.getPackageVisibilityOverride(); 7412 boolean interruptiveBefore = record.isInterruptive(); 7413 7414 recon.applyChangesLocked(record); 7415 applyZenModeLocked(record); 7416 mRankingHelper.sort(mNotificationList); 7417 boolean indexChanged = indexBefore != findNotificationRecordIndexLocked(record); 7418 boolean interceptChanged = interceptBefore != record.isIntercepted(); 7419 boolean visibilityChanged = visibilityBefore != record.getPackageVisibilityOverride(); 7420 7421 // Broadcast isInterruptive changes for bubbles. 7422 boolean interruptiveChanged = 7423 record.canBubble() && (interruptiveBefore != record.isInterruptive()); 7424 7425 changed = indexChanged 7426 || interceptChanged 7427 || visibilityChanged 7428 || interruptiveChanged; 7429 if (interceptBefore && !record.isIntercepted() 7430 && record.isNewEnoughForAlerting(mSystemClock.currentTimeMillis())) { 7431 buzzBeepBlinkLocked(record); 7432 } 7433 } 7434 if (changed) { 7435 mHandler.scheduleSendRankingUpdate(); 7436 } 7437 } 7438 7439 void handleRankingSort() { 7440 if (mRankingHelper == null) return; 7441 synchronized (mNotificationLock) { 7442 final int N = mNotificationList.size(); 7443 // Any field that can change via one of the extractors needs to be added here. 7444 ArrayList<String> orderBefore = new ArrayList<>(N); 7445 int[] visibilities = new int[N]; 7446 boolean[] showBadges = new boolean[N]; 7447 boolean[] allowBubbles = new boolean[N]; 7448 boolean[] isBubble = new boolean[N]; 7449 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N); 7450 ArrayList<String> groupKeyBefore = new ArrayList<>(N); 7451 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N); 7452 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N); 7453 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N); 7454 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N); 7455 ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N); 7456 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N); 7457 int[] importancesBefore = new int[N]; 7458 for (int i = 0; i < N; i++) { 7459 final NotificationRecord r = mNotificationList.get(i); 7460 orderBefore.add(r.getKey()); 7461 visibilities[i] = r.getPackageVisibilityOverride(); 7462 showBadges[i] = r.canShowBadge(); 7463 allowBubbles[i] = r.canBubble(); 7464 isBubble[i] = r.getNotification().isBubbleNotification(); 7465 channelBefore.add(r.getChannel()); 7466 groupKeyBefore.add(r.getGroupKey()); 7467 overridePeopleBefore.add(r.getPeopleOverride()); 7468 snoozeCriteriaBefore.add(r.getSnoozeCriteria()); 7469 userSentimentBefore.add(r.getUserSentiment()); 7470 suppressVisuallyBefore.add(r.getSuppressedVisualEffects()); 7471 systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions()); 7472 smartRepliesBefore.add(r.getSmartReplies()); 7473 importancesBefore[i] = r.getImportance(); 7474 mRankingHelper.extractSignals(r); 7475 } 7476 mRankingHelper.sort(mNotificationList); 7477 for (int i = 0; i < N; i++) { 7478 final NotificationRecord r = mNotificationList.get(i); 7479 if (!orderBefore.get(i).equals(r.getKey()) 7480 || visibilities[i] != r.getPackageVisibilityOverride() 7481 || showBadges[i] != r.canShowBadge() 7482 || allowBubbles[i] != r.canBubble() 7483 || isBubble[i] != r.getNotification().isBubbleNotification() 7484 || !Objects.equals(channelBefore.get(i), r.getChannel()) 7485 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey()) 7486 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride()) 7487 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria()) 7488 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment()) 7489 || !Objects.equals(suppressVisuallyBefore.get(i), 7490 r.getSuppressedVisualEffects()) 7491 || !Objects.equals(systemSmartActionsBefore.get(i), 7492 r.getSystemGeneratedSmartActions()) 7493 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies()) 7494 || importancesBefore[i] != r.getImportance()) { 7495 mHandler.scheduleSendRankingUpdate(); 7496 return; 7497 } 7498 } 7499 } 7500 } 7501 7502 @GuardedBy("mNotificationLock") 7503 private void recordCallerLocked(NotificationRecord record) { 7504 if (mZenModeHelper.isCall(record)) { 7505 mZenModeHelper.recordCaller(record); 7506 } 7507 } 7508 7509 // let zen mode evaluate this record 7510 @GuardedBy("mNotificationLock") 7511 private void applyZenModeLocked(NotificationRecord record) { 7512 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 7513 if (record.isIntercepted()) { 7514 record.setSuppressedVisualEffects( 7515 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects); 7516 } else { 7517 record.setSuppressedVisualEffects(0); 7518 } 7519 } 7520 7521 @GuardedBy("mNotificationLock") 7522 private int findNotificationRecordIndexLocked(NotificationRecord target) { 7523 return mRankingHelper.indexOf(mNotificationList, target); 7524 } 7525 7526 private void handleSendRankingUpdate() { 7527 synchronized (mNotificationLock) { 7528 mListeners.notifyRankingUpdateLocked(null); 7529 } 7530 } 7531 7532 private void scheduleListenerHintsChanged(int state) { 7533 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 7534 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 7535 } 7536 7537 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 7538 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 7539 mHandler.obtainMessage( 7540 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 7541 listenerInterruptionFilter, 7542 0).sendToTarget(); 7543 } 7544 7545 private void handleListenerHintsChanged(int hints) { 7546 synchronized (mNotificationLock) { 7547 mListeners.notifyListenerHintsChangedLocked(hints); 7548 } 7549 } 7550 7551 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 7552 synchronized (mNotificationLock) { 7553 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 7554 } 7555 } 7556 7557 void handleOnPackageChanged(boolean removingPackage, int changeUserId, 7558 String[] pkgList, int[] uidList) { 7559 boolean preferencesChanged = removingPackage; 7560 mListeners.onPackagesChanged(removingPackage, pkgList, uidList); 7561 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList); 7562 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); 7563 preferencesChanged |= mPreferencesHelper.onPackagesChanged( 7564 removingPackage, changeUserId, pkgList, uidList); 7565 if (removingPackage) { 7566 int size = Math.min(pkgList.length, uidList.length); 7567 for (int i = 0; i < size; i++) { 7568 final String pkg = pkgList[i]; 7569 final int uid = uidList[i]; 7570 mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg); 7571 } 7572 } 7573 if (preferencesChanged) { 7574 handleSavePolicyFile(); 7575 } 7576 } 7577 7578 protected class WorkerHandler extends Handler 7579 { 7580 public WorkerHandler(Looper looper) { 7581 super(looper); 7582 } 7583 7584 @Override 7585 public void handleMessage(Message msg) 7586 { 7587 switch (msg.what) 7588 { 7589 case MESSAGE_DURATION_REACHED: 7590 handleDurationReached((ToastRecord) msg.obj); 7591 break; 7592 case MESSAGE_FINISH_TOKEN_TIMEOUT: 7593 handleKillTokenTimeout((ToastRecord) msg.obj); 7594 break; 7595 case MESSAGE_SEND_RANKING_UPDATE: 7596 handleSendRankingUpdate(); 7597 break; 7598 case MESSAGE_LISTENER_HINTS_CHANGED: 7599 handleListenerHintsChanged(msg.arg1); 7600 break; 7601 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 7602 handleListenerInterruptionFilterChanged(msg.arg1); 7603 break; 7604 case MESSAGE_ON_PACKAGE_CHANGED: 7605 SomeArgs args = (SomeArgs) msg.obj; 7606 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2, 7607 (int[]) args.arg3); 7608 args.recycle(); 7609 break; 7610 } 7611 } 7612 7613 protected void scheduleSendRankingUpdate() { 7614 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 7615 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); 7616 sendMessage(m); 7617 } 7618 } 7619 7620 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) { 7621 if (!hasCallbacks(cancelRunnable)) { 7622 sendMessage(Message.obtain(this, cancelRunnable)); 7623 } 7624 } 7625 7626 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId, 7627 String[] pkgList, int[] uidList) { 7628 SomeArgs args = SomeArgs.obtain(); 7629 args.arg1 = removingPackage; 7630 args.argi1 = changeUserId; 7631 args.arg2 = pkgList; 7632 args.arg3 = uidList; 7633 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args)); 7634 } 7635 } 7636 7637 private final class RankingHandlerWorker extends Handler implements RankingHandler 7638 { 7639 public RankingHandlerWorker(Looper looper) { 7640 super(looper); 7641 } 7642 7643 @Override 7644 public void handleMessage(Message msg) { 7645 switch (msg.what) { 7646 case MESSAGE_RECONSIDER_RANKING: 7647 handleRankingReconsideration(msg); 7648 break; 7649 case MESSAGE_RANKING_SORT: 7650 handleRankingSort(); 7651 break; 7652 } 7653 } 7654 7655 public void requestSort() { 7656 removeMessages(MESSAGE_RANKING_SORT); 7657 Message msg = Message.obtain(); 7658 msg.what = MESSAGE_RANKING_SORT; 7659 sendMessage(msg); 7660 } 7661 7662 public void requestReconsideration(RankingReconsideration recon) { 7663 Message m = Message.obtain(this, 7664 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 7665 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 7666 sendMessageDelayed(m, delay); 7667 } 7668 } 7669 7670 // Notifications 7671 // ============================================================================ 7672 static int clamp(int x, int low, int high) { 7673 return (x < low) ? low : ((x > high) ? high : x); 7674 } 7675 7676 void sendAccessibilityEvent(NotificationRecord record) { 7677 if (!mAccessibilityManager.isEnabled()) { 7678 return; 7679 } 7680 7681 final Notification notification = record.getNotification(); 7682 final CharSequence packageName = record.getSbn().getPackageName(); 7683 final AccessibilityEvent event = 7684 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 7685 event.setPackageName(packageName); 7686 event.setClassName(Notification.class.getName()); 7687 final int visibilityOverride = record.getPackageVisibilityOverride(); 7688 final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE 7689 ? notification.visibility : visibilityOverride; 7690 final int userId = record.getUser().getIdentifier(); 7691 final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId); 7692 if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) { 7693 // Emit the public version if we're on the lockscreen and this notification isn't 7694 // publicly visible. 7695 event.setParcelableData(notification.publicVersion); 7696 } else { 7697 event.setParcelableData(notification); 7698 } 7699 final CharSequence tickerText = notification.tickerText; 7700 if (!TextUtils.isEmpty(tickerText)) { 7701 event.getText().add(tickerText); 7702 } 7703 7704 mAccessibilityManager.sendAccessibilityEvent(event); 7705 } 7706 7707 /** 7708 * Removes all NotificationsRecords with the same key as the given notification record 7709 * from both lists. Do not call this method while iterating over either list. 7710 */ 7711 @GuardedBy("mNotificationLock") 7712 private boolean removeFromNotificationListsLocked(NotificationRecord r) { 7713 // Remove from both lists, either list could have a separate Record for what is 7714 // effectively the same notification. 7715 boolean wasPosted = false; 7716 NotificationRecord recordInList = null; 7717 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) 7718 != null) { 7719 mNotificationList.remove(recordInList); 7720 mNotificationsByKey.remove(recordInList.getSbn().getKey()); 7721 wasPosted = true; 7722 } 7723 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) 7724 != null) { 7725 mEnqueuedNotifications.remove(recordInList); 7726 } 7727 return wasPosted; 7728 } 7729 7730 /** 7731 * Similar to the above method, removes all NotificationRecords with the same key as the given 7732 * NotificationRecord, but skips any records which are newer than the given one. 7733 */ 7734 private boolean removePreviousFromNotificationListsLocked(NotificationRecord r, 7735 long removeBefore) { 7736 // Remove notification records that occurred before the given record from both lists, 7737 // specifically allowing newer ones to respect ordering 7738 boolean wasPosted = false; 7739 List<NotificationRecord> matching = 7740 findNotificationsByListLocked(mNotificationList, r.getKey()); 7741 for (NotificationRecord record : matching) { 7742 // We don't need to check against update time for posted notifs 7743 mNotificationList.remove(record); 7744 mNotificationsByKey.remove(record.getSbn().getKey()); 7745 wasPosted = true; 7746 } 7747 7748 matching = findNotificationsByListLocked(mEnqueuedNotifications, r.getKey()); 7749 for (NotificationRecord record : matching) { 7750 if (record.getUpdateTimeMs() <= removeBefore) { 7751 mNotificationList.remove(record); 7752 } 7753 } 7754 7755 return wasPosted; 7756 } 7757 7758 @GuardedBy("mNotificationLock") 7759 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, 7760 @NotificationListenerService.NotificationCancelReason int reason, 7761 boolean wasPosted, String listenerName) { 7762 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName); 7763 } 7764 7765 @GuardedBy("mNotificationLock") 7766 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, 7767 @NotificationListenerService.NotificationCancelReason int reason, 7768 int rank, int count, boolean wasPosted, String listenerName) { 7769 final String canceledKey = r.getKey(); 7770 7771 // Record caller. 7772 recordCallerLocked(r); 7773 7774 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) { 7775 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER); 7776 } 7777 7778 // tell the app 7779 if (sendDelete) { 7780 final PendingIntent deleteIntent = r.getNotification().deleteIntent; 7781 if (deleteIntent != null) { 7782 try { 7783 // make sure deleteIntent cannot be used to start activities from background 7784 LocalServices.getService(ActivityManagerInternal.class) 7785 .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(), 7786 WHITELIST_TOKEN); 7787 deleteIntent.send(); 7788 } catch (PendingIntent.CanceledException ex) { 7789 // do nothing - there's no relevant way to recover, and 7790 // no reason to let this propagate 7791 Slog.w(TAG, "canceled PendingIntent for " + r.getSbn().getPackageName(), ex); 7792 } 7793 } 7794 } 7795 7796 // Only cancel these if this notification actually got to be posted. 7797 if (wasPosted) { 7798 // status bar 7799 if (r.getNotification().getSmallIcon() != null) { 7800 if (reason != REASON_SNOOZED) { 7801 r.isCanceled = true; 7802 } 7803 mListeners.notifyRemovedLocked(r, reason, r.getStats()); 7804 mHandler.post(new Runnable() { 7805 @Override 7806 public void run() { 7807 mGroupHelper.onNotificationRemoved(r.getSbn()); 7808 } 7809 }); 7810 } 7811 7812 // sound 7813 if (canceledKey.equals(mSoundNotificationKey)) { 7814 mSoundNotificationKey = null; 7815 final long identity = Binder.clearCallingIdentity(); 7816 try { 7817 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 7818 if (player != null) { 7819 player.stopAsync(); 7820 } 7821 } catch (RemoteException e) { 7822 } finally { 7823 Binder.restoreCallingIdentity(identity); 7824 } 7825 } 7826 7827 // vibrate 7828 if (canceledKey.equals(mVibrateNotificationKey)) { 7829 mVibrateNotificationKey = null; 7830 long identity = Binder.clearCallingIdentity(); 7831 try { 7832 mVibrator.cancel(); 7833 } 7834 finally { 7835 Binder.restoreCallingIdentity(identity); 7836 } 7837 } 7838 7839 // light 7840 mLights.remove(canceledKey); 7841 } 7842 7843 // Record usage stats 7844 // TODO: add unbundling stats? 7845 switch (reason) { 7846 case REASON_CANCEL: 7847 case REASON_CANCEL_ALL: 7848 case REASON_LISTENER_CANCEL: 7849 case REASON_LISTENER_CANCEL_ALL: 7850 mUsageStats.registerDismissedByUser(r); 7851 break; 7852 case REASON_APP_CANCEL: 7853 case REASON_APP_CANCEL_ALL: 7854 mUsageStats.registerRemovedByApp(r); 7855 break; 7856 } 7857 7858 String groupKey = r.getGroupKey(); 7859 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 7860 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) { 7861 mSummaryByGroupKey.remove(groupKey); 7862 } 7863 final ArrayMap<String, String> summaries = 7864 mAutobundledSummaries.get(r.getSbn().getUserId()); 7865 if (summaries != null && r.getSbn().getKey().equals( 7866 summaries.get(r.getSbn().getPackageName()))) { 7867 summaries.remove(r.getSbn().getPackageName()); 7868 } 7869 7870 // Save it for users of getHistoricalNotifications() 7871 mArchive.record(r.getSbn(), reason); 7872 7873 final long now = mSystemClock.currentTimeMillis(); 7874 final LogMaker logMaker = r.getItemLogMaker() 7875 .setType(MetricsEvent.TYPE_DISMISS) 7876 .setSubtype(reason); 7877 if (rank != -1 && count != -1) { 7878 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank) 7879 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count); 7880 } 7881 MetricsLogger.action(logMaker); 7882 EventLogTags.writeNotificationCanceled(canceledKey, reason, 7883 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 7884 rank, count, listenerName); 7885 if (wasPosted) { 7886 mNotificationRecordLogger.logNotificationCancelled(r, reason, 7887 r.getStats().getDismissalSurface()); 7888 } 7889 } 7890 7891 @VisibleForTesting 7892 void updateUriPermissions(@Nullable NotificationRecord newRecord, 7893 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) { 7894 updateUriPermissions(newRecord, oldRecord, targetPkg, targetUserId, false); 7895 } 7896 7897 @VisibleForTesting 7898 void updateUriPermissions(@Nullable NotificationRecord newRecord, 7899 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId, 7900 boolean onlyRevokeCurrentTarget) { 7901 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey(); 7902 if (DBG) Slog.d(TAG, key + ": updating permissions"); 7903 7904 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null; 7905 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null; 7906 7907 // Shortcut when no Uris involved 7908 if (newUris == null && oldUris == null) { 7909 return; 7910 } 7911 7912 // Inherit any existing owner 7913 IBinder permissionOwner = null; 7914 if (newRecord != null && permissionOwner == null) { 7915 permissionOwner = newRecord.permissionOwner; 7916 } 7917 if (oldRecord != null && permissionOwner == null) { 7918 permissionOwner = oldRecord.permissionOwner; 7919 } 7920 7921 // If we have Uris to grant, but no owner yet, go create one 7922 if (newUris != null && permissionOwner == null) { 7923 if (DBG) Slog.d(TAG, key + ": creating owner"); 7924 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key); 7925 } 7926 7927 // If we have no Uris to grant, but an existing owner, go destroy it 7928 // When revoking permissions of a single listener, destroying the owner will revoke 7929 // permissions of other listeners who need to keep access. 7930 if (newUris == null && permissionOwner != null && !onlyRevokeCurrentTarget) { 7931 destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key); 7932 permissionOwner = null; 7933 } 7934 7935 // Grant access to new Uris 7936 if (newUris != null && permissionOwner != null) { 7937 for (int i = 0; i < newUris.size(); i++) { 7938 final Uri uri = newUris.valueAt(i); 7939 if (oldUris == null || !oldUris.contains(uri)) { 7940 Slog.d(TAG, key + ": granting " + uri); 7941 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg, 7942 targetUserId); 7943 } 7944 } 7945 } 7946 7947 // Revoke access to old Uris 7948 if (oldUris != null && permissionOwner != null) { 7949 for (int i = 0; i < oldUris.size(); i++) { 7950 final Uri uri = oldUris.valueAt(i); 7951 if (newUris == null || !newUris.contains(uri)) { 7952 if (DBG) Slog.d(TAG, key + ": revoking " + uri); 7953 if (onlyRevokeCurrentTarget) { 7954 // We're revoking permission from one listener only; other listeners may 7955 // still need access because the notification may still exist 7956 revokeUriPermission(permissionOwner, uri, 7957 UserHandle.getUserId(oldRecord.getUid()), targetPkg, targetUserId); 7958 } else { 7959 // This is broad to unilaterally revoke permissions to this Uri as granted 7960 // by this notification. But this code-path can only be used when the 7961 // reason for revoking is that the notification posted again without this 7962 // Uri, not when removing an individual listener. 7963 revokeUriPermission(permissionOwner, uri, 7964 UserHandle.getUserId(oldRecord.getUid()), 7965 null, UserHandle.USER_ALL); 7966 } 7967 } 7968 } 7969 } 7970 7971 if (newRecord != null) { 7972 newRecord.permissionOwner = permissionOwner; 7973 } 7974 } 7975 7976 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg, 7977 int targetUserId) { 7978 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 7979 final long ident = Binder.clearCallingIdentity(); 7980 try { 7981 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg, 7982 ContentProvider.getUriWithoutUserId(uri), 7983 Intent.FLAG_GRANT_READ_URI_PERMISSION, 7984 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)), 7985 targetUserId); 7986 } catch (RemoteException ignored) { 7987 // Ignored because we're in same process 7988 } catch (SecurityException e) { 7989 Slog.e(TAG, "Cannot grant uri access; " + sourceUid + " does not own " + uri); 7990 } finally { 7991 Binder.restoreCallingIdentity(ident); 7992 } 7993 } 7994 7995 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUserId, String targetPkg, 7996 int targetUserId) { 7997 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 7998 int userId = ContentProvider.getUserIdFromUri(uri, sourceUserId); 7999 8000 final long ident = Binder.clearCallingIdentity(); 8001 try { 8002 mUgmInternal.revokeUriPermissionFromOwner( 8003 owner, 8004 ContentProvider.getUriWithoutUserId(uri), 8005 Intent.FLAG_GRANT_READ_URI_PERMISSION, 8006 userId, targetPkg, targetUserId); 8007 } finally { 8008 Binder.restoreCallingIdentity(ident); 8009 } 8010 } 8011 8012 private void destroyPermissionOwner(IBinder owner, int userId, String logKey) { 8013 final long ident = Binder.clearCallingIdentity(); 8014 try { 8015 if (DBG) Slog.d(TAG, logKey + ": destroying owner"); 8016 mUgmInternal.revokeUriPermissionFromOwner(owner, null, ~0, userId); 8017 } finally { 8018 Binder.restoreCallingIdentity(ident); 8019 } 8020 } 8021 8022 /** 8023 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 8024 * and none of the {@code mustNotHaveFlags}. 8025 */ 8026 void cancelNotification(final int callingUid, final int callingPid, 8027 final String pkg, final String tag, final int id, 8028 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 8029 final int userId, final int reason, final ManagedServiceInfo listener) { 8030 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags, 8031 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener); 8032 } 8033 8034 /** 8035 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 8036 * and none of the {@code mustNotHaveFlags}. 8037 */ 8038 void cancelNotification(final int callingUid, final int callingPid, 8039 final String pkg, final String tag, final int id, 8040 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 8041 final int userId, final int reason, int rank, int count, 8042 final ManagedServiceInfo listener) { 8043 // In enqueueNotificationInternal notifications are added by scheduling the 8044 // work on the worker handler. Hence, we also schedule the cancel on this 8045 // handler to avoid a scenario where an add notification call followed by a 8046 // remove notification call ends up in not removing the notification. 8047 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid, 8048 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank, 8049 count, listener)); 8050 } 8051 8052 /** 8053 * Determine whether the userId applies to the notification in question, either because 8054 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 8055 */ 8056 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 8057 return 8058 // looking for USER_ALL notifications? match everything 8059 userId == UserHandle.USER_ALL 8060 // a notification sent to USER_ALL matches any query 8061 || r.getUserId() == UserHandle.USER_ALL 8062 // an exact user match 8063 || r.getUserId() == userId; 8064 } 8065 8066 /** 8067 * Determine whether the userId applies to the notification in question, either because 8068 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 8069 * because it matches one of the users profiles. 8070 */ 8071 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 8072 return notificationMatchesUserId(r, userId) 8073 || mUserProfiles.isCurrentProfile(r.getUserId()); 8074 } 8075 8076 /** 8077 * Cancels all notifications from a given package that have all of the 8078 * {@code mustHaveFlags}. 8079 */ 8080 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId, 8081 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason, 8082 ManagedServiceInfo listener) { 8083 mHandler.post(new Runnable() { 8084 @Override 8085 public void run() { 8086 String listenerName = listener == null ? null : listener.component.toShortString(); 8087 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 8088 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 8089 listenerName); 8090 8091 // Why does this parameter exist? Do we actually want to execute the above if doit 8092 // is false? 8093 if (!doit) { 8094 return; 8095 } 8096 8097 synchronized (mNotificationLock) { 8098 FlagChecker flagChecker = (int flags) -> { 8099 if ((flags & mustHaveFlags) != mustHaveFlags) { 8100 return false; 8101 } 8102 if ((flags & mustNotHaveFlags) != 0) { 8103 return false; 8104 } 8105 return true; 8106 }; 8107 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid, 8108 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 8109 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 8110 listenerName, true /* wasPosted */); 8111 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid, 8112 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, 8113 flagChecker, false /*includeCurrentProfiles*/, userId, 8114 false /*sendDelete*/, reason, listenerName, false /* wasPosted */); 8115 mSnoozeHelper.cancel(userId, pkg); 8116 } 8117 } 8118 }); 8119 } 8120 8121 private interface FlagChecker { 8122 // Returns false if these flags do not pass the defined flag test. 8123 public boolean apply(int flags); 8124 } 8125 8126 @GuardedBy("mNotificationLock") 8127 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList, 8128 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch, 8129 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, 8130 boolean sendDelete, int reason, String listenerName, boolean wasPosted) { 8131 ArrayList<NotificationRecord> canceledNotifications = null; 8132 for (int i = notificationList.size() - 1; i >= 0; --i) { 8133 NotificationRecord r = notificationList.get(i); 8134 if (includeCurrentProfiles) { 8135 if (!notificationMatchesCurrentProfiles(r, userId)) { 8136 continue; 8137 } 8138 } else if (!notificationMatchesUserId(r, userId)) { 8139 continue; 8140 } 8141 // Don't remove notifications to all, if there's no package name specified 8142 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) { 8143 continue; 8144 } 8145 if (!flagChecker.apply(r.getFlags())) { 8146 continue; 8147 } 8148 if (pkg != null && !r.getSbn().getPackageName().equals(pkg)) { 8149 continue; 8150 } 8151 if (channelId != null && !channelId.equals(r.getChannel().getId())) { 8152 continue; 8153 } 8154 if (canceledNotifications == null) { 8155 canceledNotifications = new ArrayList<>(); 8156 } 8157 notificationList.remove(i); 8158 mNotificationsByKey.remove(r.getKey()); 8159 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); 8160 canceledNotifications.add(r); 8161 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); 8162 } 8163 if (canceledNotifications != null) { 8164 final int M = canceledNotifications.size(); 8165 for (int i = 0; i < M; i++) { 8166 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 8167 listenerName, false /* sendDelete */, flagChecker, reason); 8168 } 8169 updateLightsLocked(); 8170 } 8171 } 8172 8173 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId, 8174 ManagedServiceInfo listener) { 8175 String listenerName = listener == null ? null : listener.component.toShortString(); 8176 if ((duration <= 0 && snoozeCriterionId == null) || key == null) { 8177 return; 8178 } 8179 8180 if (DBG) { 8181 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration, 8182 snoozeCriterionId, listenerName)); 8183 } 8184 // Needs to post so that it can cancel notifications not yet enqueued. 8185 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); 8186 } 8187 8188 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) { 8189 String listenerName = listener == null ? null : listener.component.toShortString(); 8190 if (DBG) { 8191 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); 8192 } 8193 mSnoozeHelper.repost(key, muteOnReturn); 8194 handleSavePolicyFile(); 8195 } 8196 8197 @GuardedBy("mNotificationLock") 8198 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 8199 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 8200 mHandler.post(new Runnable() { 8201 @Override 8202 public void run() { 8203 synchronized (mNotificationLock) { 8204 String listenerName = 8205 listener == null ? null : listener.component.toShortString(); 8206 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 8207 null, userId, 0, 0, reason, listenerName); 8208 8209 FlagChecker flagChecker = (int flags) -> { 8210 int flagsToCheck = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 8211 if (REASON_LISTENER_CANCEL_ALL == reason 8212 || REASON_CANCEL_ALL == reason) { 8213 flagsToCheck |= FLAG_BUBBLE; 8214 } 8215 if ((flags & flagsToCheck) != 0) { 8216 return false; 8217 } 8218 return true; 8219 }; 8220 8221 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid, 8222 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker, 8223 includeCurrentProfiles, userId, true /*sendDelete*/, reason, 8224 listenerName, true); 8225 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid, 8226 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null, 8227 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/, 8228 reason, listenerName, false); 8229 mSnoozeHelper.cancel(userId, includeCurrentProfiles); 8230 } 8231 } 8232 }); 8233 } 8234 8235 // Warning: The caller is responsible for invoking updateLightsLocked(). 8236 @GuardedBy("mNotificationLock") 8237 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 8238 String listenerName, boolean sendDelete, FlagChecker flagChecker, int reason) { 8239 Notification n = r.getNotification(); 8240 if (!n.isGroupSummary()) { 8241 return; 8242 } 8243 8244 String pkg = r.getSbn().getPackageName(); 8245 8246 if (pkg == null) { 8247 if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey()); 8248 return; 8249 } 8250 8251 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName, 8252 sendDelete, true, flagChecker, reason); 8253 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid, 8254 listenerName, sendDelete, false, flagChecker, reason); 8255 } 8256 8257 @GuardedBy("mNotificationLock") 8258 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList, 8259 NotificationRecord parentNotification, int callingUid, int callingPid, 8260 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker, 8261 int reason) { 8262 final String pkg = parentNotification.getSbn().getPackageName(); 8263 final int userId = parentNotification.getUserId(); 8264 final int childReason = REASON_GROUP_SUMMARY_CANCELED; 8265 for (int i = notificationList.size() - 1; i >= 0; i--) { 8266 final NotificationRecord childR = notificationList.get(i); 8267 final StatusBarNotification childSbn = childR.getSbn(); 8268 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 8269 childR.getGroupKey().equals(parentNotification.getGroupKey()) 8270 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0 8271 && (flagChecker == null || flagChecker.apply(childR.getFlags())) 8272 && (!childR.getChannel().isImportantConversation() 8273 || reason != REASON_CANCEL)) { 8274 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 8275 childSbn.getTag(), userId, 0, 0, childReason, listenerName); 8276 notificationList.remove(i); 8277 mNotificationsByKey.remove(childR.getKey()); 8278 cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName); 8279 } 8280 } 8281 } 8282 8283 @GuardedBy("mNotificationLock") 8284 void updateLightsLocked() 8285 { 8286 if (mNotificationLight == null) { 8287 return; 8288 } 8289 8290 // handle notification lights 8291 NotificationRecord ledNotification = null; 8292 while (ledNotification == null && !mLights.isEmpty()) { 8293 final String owner = mLights.get(mLights.size() - 1); 8294 ledNotification = mNotificationsByKey.get(owner); 8295 if (ledNotification == null) { 8296 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 8297 mLights.remove(owner); 8298 } 8299 } 8300 8301 // Don't flash while we are in a call or screen is on 8302 if (ledNotification == null || isInCall() || mScreenOn) { 8303 mNotificationLight.turnOff(); 8304 } else { 8305 NotificationRecord.Light light = ledNotification.getLight(); 8306 if (light != null && mNotificationPulseEnabled) { 8307 // pulse repeatedly 8308 mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED, 8309 light.onMs, light.offMs); 8310 } 8311 } 8312 } 8313 8314 @GuardedBy("mNotificationLock") 8315 @NonNull 8316 List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg, 8317 String groupKey, int userId) { 8318 List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId); 8319 records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId)); 8320 return records; 8321 } 8322 8323 @GuardedBy("mNotificationLock") 8324 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg, 8325 String groupKey, int userId) { 8326 List<NotificationRecord> records = new ArrayList<>(); 8327 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId)); 8328 records.addAll( 8329 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId)); 8330 return records; 8331 } 8332 8333 @GuardedBy("mNotificationLock") 8334 private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) { 8335 NotificationRecord r = findNotificationByKeyLocked(key); 8336 if (r == null) { 8337 r = mSnoozeHelper.getNotification(key); 8338 } 8339 return r; 8340 8341 } 8342 8343 @GuardedBy("mNotificationLock") 8344 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( 8345 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) { 8346 List<NotificationRecord> records = new ArrayList<>(); 8347 final int len = list.size(); 8348 for (int i = 0; i < len; i++) { 8349 NotificationRecord r = list.get(i); 8350 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey) 8351 && r.getSbn().getPackageName().equals(pkg)) { 8352 records.add(r); 8353 } 8354 } 8355 return records; 8356 } 8357 8358 // Searches both enqueued and posted notifications by key. 8359 // TODO: need to combine a bunch of these getters with slightly different behavior. 8360 // TODO: Should enqueuing just add to mNotificationsByKey instead? 8361 @GuardedBy("mNotificationLock") 8362 private NotificationRecord findNotificationByKeyLocked(String key) { 8363 NotificationRecord r; 8364 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) { 8365 return r; 8366 } 8367 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) { 8368 return r; 8369 } 8370 return null; 8371 } 8372 8373 @GuardedBy("mNotificationLock") 8374 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) { 8375 NotificationRecord r; 8376 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) { 8377 return r; 8378 } 8379 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId)) 8380 != null) { 8381 return r; 8382 } 8383 return null; 8384 } 8385 8386 @GuardedBy("mNotificationLock") 8387 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, 8388 String pkg, String tag, int id, int userId) { 8389 final int len = list.size(); 8390 for (int i = 0; i < len; i++) { 8391 NotificationRecord r = list.get(i); 8392 if (notificationMatchesUserId(r, userId) && r.getSbn().getId() == id && 8393 TextUtils.equals(r.getSbn().getTag(), tag) 8394 && r.getSbn().getPackageName().equals(pkg)) { 8395 return r; 8396 } 8397 } 8398 return null; 8399 } 8400 8401 @GuardedBy("mNotificationLock") 8402 private List<NotificationRecord> findNotificationsByListLocked( 8403 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { 8404 List<NotificationRecord> matching = new ArrayList<>(); 8405 final int len = list.size(); 8406 for (int i = 0; i < len; i++) { 8407 NotificationRecord r = list.get(i); 8408 if (notificationMatchesUserId(r, userId) && r.getSbn().getId() == id && 8409 TextUtils.equals(r.getSbn().getTag(), tag) 8410 && r.getSbn().getPackageName().equals(pkg)) { 8411 matching.add(r); 8412 } 8413 } 8414 return matching; 8415 } 8416 8417 @GuardedBy("mNotificationLock") 8418 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, 8419 String key) { 8420 final int N = list.size(); 8421 for (int i = 0; i < N; i++) { 8422 if (key.equals(list.get(i).getKey())) { 8423 return list.get(i); 8424 } 8425 } 8426 return null; 8427 } 8428 8429 @GuardedBy("mNotificationLock") 8430 private List<NotificationRecord> findNotificationsByListLocked( 8431 ArrayList<NotificationRecord> list, 8432 String key) { 8433 List<NotificationRecord> matching = new ArrayList<>(); 8434 final int n = list.size(); 8435 for (int i = 0; i < n; i++) { 8436 NotificationRecord r = list.get(i); 8437 if (key.equals(r.getKey())) { 8438 matching.add(r); 8439 } 8440 } 8441 return matching; 8442 } 8443 8444 /** 8445 * There may be multiple records that match your criteria. For instance if there have been 8446 * multiple notifications posted which are enqueued for the same pkg, tag, id, userId. This 8447 * method will find all of them in the given list 8448 * @return 8449 */ 8450 @GuardedBy("mNotificationLock") 8451 private List<NotificationRecord> findEnqueuedNotificationsForCriteria( 8452 String pkg, String tag, int id, int userId) { 8453 final ArrayList<NotificationRecord> records = new ArrayList<>(); 8454 final int n = mEnqueuedNotifications.size(); 8455 for (int i = 0; i < n; i++) { 8456 NotificationRecord r = mEnqueuedNotifications.get(i); 8457 if (notificationMatchesUserId(r, userId) 8458 && r.getSbn().getId() == id 8459 && TextUtils.equals(r.getSbn().getTag(), tag) 8460 && r.getSbn().getPackageName().equals(pkg)) { 8461 records.add(r); 8462 } 8463 } 8464 return records; 8465 } 8466 8467 @GuardedBy("mNotificationLock") 8468 int indexOfNotificationLocked(String key) { 8469 final int N = mNotificationList.size(); 8470 for (int i = 0; i < N; i++) { 8471 if (key.equals(mNotificationList.get(i).getKey())) { 8472 return i; 8473 } 8474 } 8475 return -1; 8476 } 8477 8478 @VisibleForTesting 8479 protected void hideNotificationsForPackages(String[] pkgs) { 8480 synchronized (mNotificationLock) { 8481 List<String> pkgList = Arrays.asList(pkgs); 8482 List<NotificationRecord> changedNotifications = new ArrayList<>(); 8483 int numNotifications = mNotificationList.size(); 8484 for (int i = 0; i < numNotifications; i++) { 8485 NotificationRecord rec = mNotificationList.get(i); 8486 if (pkgList.contains(rec.getSbn().getPackageName())) { 8487 rec.setHidden(true); 8488 changedNotifications.add(rec); 8489 } 8490 } 8491 8492 mListeners.notifyHiddenLocked(changedNotifications); 8493 } 8494 } 8495 8496 @VisibleForTesting 8497 protected void unhideNotificationsForPackages(String[] pkgs) { 8498 synchronized (mNotificationLock) { 8499 List<String> pkgList = Arrays.asList(pkgs); 8500 List<NotificationRecord> changedNotifications = new ArrayList<>(); 8501 int numNotifications = mNotificationList.size(); 8502 for (int i = 0; i < numNotifications; i++) { 8503 NotificationRecord rec = mNotificationList.get(i); 8504 if (pkgList.contains(rec.getSbn().getPackageName())) { 8505 rec.setHidden(false); 8506 changedNotifications.add(rec); 8507 } 8508 } 8509 8510 mListeners.notifyUnhiddenLocked(changedNotifications); 8511 } 8512 } 8513 8514 private void updateNotificationPulse() { 8515 synchronized (mNotificationLock) { 8516 updateLightsLocked(); 8517 } 8518 } 8519 8520 protected boolean isCallingUidSystem() { 8521 final int uid = Binder.getCallingUid(); 8522 return uid == Process.SYSTEM_UID; 8523 } 8524 8525 protected boolean isUidSystemOrPhone(int uid) { 8526 final int appid = UserHandle.getAppId(uid); 8527 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID 8528 || uid == Process.ROOT_UID); 8529 } 8530 8531 // TODO: Most calls should probably move to isCallerSystem. 8532 protected boolean isCallerSystemOrPhone() { 8533 return isUidSystemOrPhone(Binder.getCallingUid()); 8534 } 8535 8536 private boolean isCallerIsSystemOrSystemUi() { 8537 if (isCallerSystemOrPhone()) { 8538 return true; 8539 } 8540 return getContext().checkCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE) 8541 == PERMISSION_GRANTED; 8542 } 8543 8544 private boolean isCallerIsSystemOrSysemUiOrShell() { 8545 int callingUid = Binder.getCallingUid(); 8546 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 8547 return true; 8548 } 8549 return isCallerIsSystemOrSystemUi(); 8550 } 8551 8552 private void checkCallerIsSystemOrShell() { 8553 int callingUid = Binder.getCallingUid(); 8554 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 8555 return; 8556 } 8557 checkCallerIsSystem(); 8558 } 8559 8560 private void checkCallerIsSystem() { 8561 if (isCallerSystemOrPhone()) { 8562 return; 8563 } 8564 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 8565 } 8566 8567 private void checkCallerIsSystemOrSystemUiOrShell() { 8568 checkCallerIsSystemOrSystemUiOrShell(null); 8569 } 8570 8571 private void checkCallerIsSystemOrSystemUiOrShell(String message) { 8572 int callingUid = Binder.getCallingUid(); 8573 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 8574 return; 8575 } 8576 if (isCallerSystemOrPhone()) { 8577 return; 8578 } 8579 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 8580 message); 8581 } 8582 8583 private void checkCallerIsSystemOrSameApp(String pkg) { 8584 if (isCallerSystemOrPhone()) { 8585 return; 8586 } 8587 checkCallerIsSameApp(pkg); 8588 } 8589 8590 private boolean isCallerAndroid(String callingPkg, int uid) { 8591 return isUidSystemOrPhone(uid) && callingPkg != null 8592 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg); 8593 } 8594 8595 /** 8596 * Check if the notification is of a category type that is restricted to system use only, 8597 * if so throw SecurityException 8598 */ 8599 private void checkRestrictedCategories(final String pkg, final Notification notification) { 8600 try { 8601 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) { 8602 return; 8603 } 8604 } catch (RemoteException re) { 8605 if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category " 8606 + "restrictions check thus the check will be done anyway"); 8607 } 8608 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category) 8609 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)) { 8610 checkCallerIsSystem(); 8611 } 8612 8613 if (Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) { 8614 checkCallerIsSystemOrSUW(pkg); 8615 } 8616 } 8617 8618 private void checkCallerIsSystemOrSUW(final String pkg) { 8619 8620 final PackageManagerInternal pmi = LocalServices.getService( 8621 PackageManagerInternal.class); 8622 String suwPkg = pmi.getSetupWizardPackageName(); 8623 if (suwPkg != null && suwPkg.equals(pkg)) { 8624 return; 8625 } 8626 checkCallerIsSystem(); 8627 } 8628 8629 @VisibleForTesting 8630 boolean isCallerInstantApp(int callingUid, int userId) { 8631 // System is always allowed to act for ephemeral apps. 8632 if (isUidSystemOrPhone(callingUid)) { 8633 return false; 8634 } 8635 8636 if (userId == UserHandle.USER_ALL) { 8637 userId = USER_SYSTEM; 8638 } 8639 8640 try { 8641 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 8642 if (pkgs == null) { 8643 throw new SecurityException("Unknown uid " + callingUid); 8644 } 8645 final String pkg = pkgs[0]; 8646 mAppOps.checkPackage(callingUid, pkg); 8647 8648 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId); 8649 if (ai == null) { 8650 throw new SecurityException("Unknown package " + pkg); 8651 } 8652 return ai.isInstantApp(); 8653 } catch (RemoteException re) { 8654 throw new SecurityException("Unknown uid " + callingUid, re); 8655 } 8656 } 8657 8658 private void checkCallerIsSameApp(String pkg) { 8659 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId()); 8660 } 8661 8662 private void checkCallerIsSameApp(String pkg, int uid, int userId) { 8663 if (uid == Process.ROOT_UID && ROOT_PKG.equals(pkg)) { 8664 return; 8665 } 8666 try { 8667 ApplicationInfo ai = mPackageManager.getApplicationInfo( 8668 pkg, 0, userId); 8669 if (ai == null) { 8670 throw new SecurityException("Unknown package " + pkg); 8671 } 8672 if (!UserHandle.isSameApp(ai.uid, uid)) { 8673 throw new SecurityException("Calling uid " + uid + " gave package " 8674 + pkg + " which is owned by uid " + ai.uid); 8675 } 8676 } catch (RemoteException re) { 8677 throw new SecurityException("Unknown package " + pkg + "\n" + re); 8678 } 8679 } 8680 8681 private boolean isCallerSameApp(String pkg) { 8682 try { 8683 checkCallerIsSameApp(pkg); 8684 return true; 8685 } catch (SecurityException e) { 8686 return false; 8687 } 8688 } 8689 8690 private boolean isCallerSameApp(String pkg, int uid, int userId) { 8691 try { 8692 checkCallerIsSameApp(pkg, uid, userId); 8693 return true; 8694 } catch (SecurityException e) { 8695 return false; 8696 } 8697 } 8698 8699 private static String callStateToString(int state) { 8700 switch (state) { 8701 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 8702 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 8703 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 8704 default: return "CALL_STATE_UNKNOWN_" + state; 8705 } 8706 } 8707 8708 /** 8709 * Generates a NotificationRankingUpdate from 'sbns', considering only 8710 * notifications visible to the given listener. 8711 */ 8712 @GuardedBy("mNotificationLock") 8713 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 8714 final int N = mNotificationList.size(); 8715 final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>(); 8716 8717 for (int i = 0; i < N; i++) { 8718 NotificationRecord record = mNotificationList.get(i); 8719 if (!isVisibleToListener(record.getSbn(), info)) { 8720 continue; 8721 } 8722 final String key = record.getSbn().getKey(); 8723 final NotificationListenerService.Ranking ranking = 8724 new NotificationListenerService.Ranking(); 8725 ranking.populate( 8726 key, 8727 rankings.size(), 8728 !record.isIntercepted(), 8729 record.getPackageVisibilityOverride(), 8730 record.getSuppressedVisualEffects(), 8731 record.getImportance(), 8732 record.getImportanceExplanation(), 8733 record.getSbn().getOverrideGroupKey(), 8734 record.getChannel(), 8735 record.getPeopleOverride(), 8736 record.getSnoozeCriteria(), 8737 record.canShowBadge(), 8738 record.getUserSentiment(), 8739 record.isHidden(), 8740 record.getLastAudiblyAlertedMs(), 8741 record.getSound() != null || record.getVibration() != null, 8742 record.getSystemGeneratedSmartActions(), 8743 record.getSmartReplies(), 8744 record.canBubble(), 8745 record.isInterruptive(), 8746 record.isConversation(), 8747 record.getShortcutInfo(), 8748 record.getNotification().isBubbleNotification() 8749 ); 8750 rankings.add(ranking); 8751 } 8752 8753 return new NotificationRankingUpdate( 8754 rankings.toArray(new NotificationListenerService.Ranking[0])); 8755 } 8756 8757 boolean hasCompanionDevice(ManagedServiceInfo info) { 8758 if (mCompanionManager == null) { 8759 mCompanionManager = getCompanionManager(); 8760 } 8761 // Companion mgr doesn't exist on all device types 8762 if (mCompanionManager == null) { 8763 return false; 8764 } 8765 long identity = Binder.clearCallingIdentity(); 8766 try { 8767 List<String> associations = mCompanionManager.getAssociations( 8768 info.component.getPackageName(), info.userid); 8769 if (!ArrayUtils.isEmpty(associations)) { 8770 return true; 8771 } 8772 } catch (SecurityException se) { 8773 // Not a privileged listener 8774 } catch (RemoteException re) { 8775 Slog.e(TAG, "Cannot reach companion device service", re); 8776 } catch (Exception e) { 8777 Slog.e(TAG, "Cannot verify listener " + info, e); 8778 } finally { 8779 Binder.restoreCallingIdentity(identity); 8780 } 8781 return false; 8782 } 8783 8784 protected ICompanionDeviceManager getCompanionManager() { 8785 return ICompanionDeviceManager.Stub.asInterface( 8786 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); 8787 } 8788 8789 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 8790 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 8791 return false; 8792 } 8793 // TODO: remove this for older listeners. 8794 return true; 8795 } 8796 8797 private boolean isPackageSuspendedForUser(String pkg, int uid) { 8798 final long identity = Binder.clearCallingIdentity(); 8799 int userId = UserHandle.getUserId(uid); 8800 try { 8801 return mPackageManager.isPackageSuspendedForUser(pkg, userId); 8802 } catch (RemoteException re) { 8803 throw new SecurityException("Could not talk to package manager service"); 8804 } catch (IllegalArgumentException ex) { 8805 // Package not found. 8806 return false; 8807 } finally { 8808 Binder.restoreCallingIdentity(identity); 8809 } 8810 } 8811 8812 @VisibleForTesting 8813 boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) { 8814 boolean canUseManagedServices = true; 8815 if (requiredPermission != null) { 8816 try { 8817 if (mPackageManager.checkPermission(requiredPermission, pkg, userId) 8818 != PackageManager.PERMISSION_GRANTED) { 8819 canUseManagedServices = false; 8820 } 8821 } catch (RemoteException e) { 8822 Slog.e(TAG, "can't talk to pm", e); 8823 } 8824 } 8825 8826 return canUseManagedServices; 8827 } 8828 8829 private class TrimCache { 8830 StatusBarNotification heavy; 8831 StatusBarNotification sbnClone; 8832 StatusBarNotification sbnCloneLight; 8833 8834 TrimCache(StatusBarNotification sbn) { 8835 heavy = sbn; 8836 } 8837 8838 StatusBarNotification ForListener(ManagedServiceInfo info) { 8839 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 8840 if (sbnCloneLight == null) { 8841 sbnCloneLight = heavy.cloneLight(); 8842 } 8843 return sbnCloneLight; 8844 } else { 8845 if (sbnClone == null) { 8846 sbnClone = heavy.clone(); 8847 } 8848 return sbnClone; 8849 } 8850 } 8851 } 8852 8853 private boolean isInCall() { 8854 if (mInCallStateOffHook) { 8855 return true; 8856 } 8857 int audioMode = mAudioManager.getMode(); 8858 if (audioMode == AudioManager.MODE_IN_CALL 8859 || audioMode == AudioManager.MODE_IN_COMMUNICATION) { 8860 return true; 8861 } 8862 return false; 8863 } 8864 8865 public class NotificationAssistants extends ManagedServices { 8866 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants"; 8867 8868 private static final String ATT_USER_SET = "user_set"; 8869 private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "q_allowed_adjustments"; 8870 private static final String ATT_TYPES = "types"; 8871 8872 private final Object mLock = new Object(); 8873 8874 @GuardedBy("mLock") 8875 private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>(); 8876 private Set<String> mAllowedAdjustments = new ArraySet<>(); 8877 8878 @Override 8879 protected void loadDefaultsFromConfig() { 8880 ArraySet<String> assistants = new ArraySet<>(); 8881 assistants.addAll(Arrays.asList(mContext.getResources().getString( 8882 com.android.internal.R.string.config_defaultAssistantAccessComponent) 8883 .split(ManagedServices.ENABLED_SERVICES_SEPARATOR))); 8884 for (int i = 0; i < assistants.size(); i++) { 8885 ComponentName assistantCn = ComponentName 8886 .unflattenFromString(assistants.valueAt(i)); 8887 String packageName = assistants.valueAt(i); 8888 if (assistantCn != null) { 8889 packageName = assistantCn.getPackageName(); 8890 } 8891 if (TextUtils.isEmpty(packageName)) { 8892 continue; 8893 } 8894 ArraySet<ComponentName> approved = queryPackageForServices(packageName, 8895 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM); 8896 if (approved.contains(assistantCn)) { 8897 addDefaultComponentOrPackage(assistantCn.flattenToString()); 8898 } 8899 } 8900 } 8901 8902 public NotificationAssistants(Context context, Object lock, UserProfiles up, 8903 IPackageManager pm) { 8904 super(context, lock, up, pm); 8905 8906 // Add all default allowed adjustment types. Will be overwritten by values in xml, 8907 // if they exist 8908 for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) { 8909 mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]); 8910 } 8911 } 8912 8913 @Override 8914 protected Config getConfig() { 8915 Config c = new Config(); 8916 c.caption = "notification assistant"; 8917 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; 8918 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS; 8919 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; 8920 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; 8921 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 8922 c.clientLabel = R.string.notification_ranker_binding_label; 8923 return c; 8924 } 8925 8926 @Override 8927 protected IInterface asInterface(IBinder binder) { 8928 return INotificationListener.Stub.asInterface(binder); 8929 } 8930 8931 @Override 8932 protected boolean checkType(IInterface service) { 8933 return service instanceof INotificationListener; 8934 } 8935 8936 @Override 8937 protected void onServiceAdded(ManagedServiceInfo info) { 8938 mListeners.registerGuestService(info); 8939 } 8940 8941 @Override 8942 @GuardedBy("mNotificationLock") 8943 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 8944 mListeners.unregisterService(removed.service, removed.userid); 8945 } 8946 8947 @Override 8948 public void onUserUnlocked(int user) { 8949 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); 8950 // force rebind the assistant, as it might be keeping its own state in user locked 8951 // storage 8952 rebindServices(true, user); 8953 } 8954 8955 @Override 8956 protected String getRequiredPermission() { 8957 // only signature/privileged apps can be bound. 8958 return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE; 8959 } 8960 8961 @Override 8962 protected void writeExtraXmlTags(XmlSerializer out) throws IOException { 8963 synchronized (mLock) { 8964 out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES); 8965 out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments)); 8966 out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES); 8967 } 8968 } 8969 8970 @Override 8971 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException { 8972 if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) { 8973 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES); 8974 synchronized (mLock) { 8975 mAllowedAdjustments.clear(); 8976 if (!TextUtils.isEmpty(types)) { 8977 mAllowedAdjustments.addAll(Arrays.asList(types.split(","))); 8978 } 8979 } 8980 } 8981 } 8982 8983 protected void allowAdjustmentType(String type) { 8984 synchronized (mLock) { 8985 mAllowedAdjustments.add(type); 8986 } 8987 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 8988 mHandler.post(() -> notifyCapabilitiesChanged(info)); 8989 } 8990 } 8991 8992 protected void disallowAdjustmentType(String type) { 8993 synchronized (mLock) { 8994 mAllowedAdjustments.remove(type); 8995 } 8996 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 8997 mHandler.post(() -> notifyCapabilitiesChanged(info)); 8998 } 8999 } 9000 9001 protected List<String> getAllowedAssistantAdjustments() { 9002 synchronized (mLock) { 9003 List<String> types = new ArrayList<>(); 9004 types.addAll(mAllowedAdjustments); 9005 return types; 9006 } 9007 } 9008 9009 protected boolean isAdjustmentAllowed(String type) { 9010 synchronized (mLock) { 9011 return mAllowedAdjustments.contains(type); 9012 } 9013 } 9014 9015 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) { 9016 // There should be only one, but it's a list, so while we enforce 9017 // singularity elsewhere, we keep it general here, to avoid surprises. 9018 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 9019 ArrayList<String> keys = new ArrayList<>(records.size()); 9020 for (NotificationRecord r : records) { 9021 boolean sbnVisible = isVisibleToListener(r.getSbn(), info) 9022 && info.isSameUser(r.getUserId()); 9023 if (sbnVisible) { 9024 keys.add(r.getKey()); 9025 } 9026 } 9027 9028 if (!keys.isEmpty()) { 9029 mHandler.post(() -> notifySeen(info, keys)); 9030 } 9031 } 9032 } 9033 9034 protected void onPanelRevealed(int items) { 9035 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 9036 mHandler.post(() -> { 9037 final INotificationListener assistant = (INotificationListener) info.service; 9038 try { 9039 assistant.onPanelRevealed(items); 9040 } catch (RemoteException ex) { 9041 Slog.e(TAG, "unable to notify assistant (panel revealed): " + info, ex); 9042 } 9043 }); 9044 } 9045 } 9046 9047 protected void onPanelHidden() { 9048 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 9049 mHandler.post(() -> { 9050 final INotificationListener assistant = (INotificationListener) info.service; 9051 try { 9052 assistant.onPanelHidden(); 9053 } catch (RemoteException ex) { 9054 Slog.e(TAG, "unable to notify assistant (panel hidden): " + info, ex); 9055 } 9056 }); 9057 } 9058 } 9059 9060 boolean hasUserSet(int userId) { 9061 synchronized (mLock) { 9062 return mUserSetMap.getOrDefault(userId, false); 9063 } 9064 } 9065 9066 void setUserSet(int userId, boolean set) { 9067 synchronized (mLock) { 9068 mUserSetMap.put(userId, set); 9069 } 9070 } 9071 9072 @Override 9073 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException { 9074 out.attribute(null, ATT_USER_SET, Boolean.toString(hasUserSet(userId))); 9075 } 9076 9077 @Override 9078 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId) 9079 throws IOException { 9080 boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false); 9081 setUserSet(userId, userSet); 9082 } 9083 9084 private void notifyCapabilitiesChanged(final ManagedServiceInfo info) { 9085 final INotificationListener assistant = (INotificationListener) info.service; 9086 try { 9087 assistant.onAllowedAdjustmentsChanged(); 9088 } catch (RemoteException ex) { 9089 Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex); 9090 } 9091 } 9092 9093 private void notifySeen(final ManagedServiceInfo info, 9094 final ArrayList<String> keys) { 9095 final INotificationListener assistant = (INotificationListener) info.service; 9096 try { 9097 assistant.onNotificationsSeen(keys); 9098 } catch (RemoteException ex) { 9099 Slog.e(TAG, "unable to notify assistant (seen): " + info, ex); 9100 } 9101 } 9102 9103 @GuardedBy("mNotificationLock") 9104 private void onNotificationEnqueuedLocked(final NotificationRecord r) { 9105 final boolean debug = isVerboseLogEnabled(); 9106 if (debug) { 9107 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]"); 9108 } 9109 final StatusBarNotification sbn = r.getSbn(); 9110 notifyAssistantLocked( 9111 sbn, 9112 true /* sameUserOnly */, 9113 (assistant, sbnHolder) -> { 9114 try { 9115 if (debug) { 9116 Slog.v(TAG, 9117 "calling onNotificationEnqueuedWithChannel " + sbnHolder); 9118 } 9119 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel()); 9120 } catch (RemoteException ex) { 9121 Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); 9122 } 9123 }); 9124 } 9125 9126 @GuardedBy("mNotificationLock") 9127 void notifyAssistantVisibilityChangedLocked( 9128 final StatusBarNotification sbn, 9129 final boolean isVisible) { 9130 final String key = sbn.getKey(); 9131 if (DBG) { 9132 Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key); 9133 } 9134 notifyAssistantLocked( 9135 sbn, 9136 false /* sameUserOnly */, 9137 (assistant, sbnHolder) -> { 9138 try { 9139 assistant.onNotificationVisibilityChanged(key, isVisible); 9140 } catch (RemoteException ex) { 9141 Slog.e(TAG, "unable to notify assistant (visible): " + assistant, ex); 9142 } 9143 }); 9144 } 9145 9146 @GuardedBy("mNotificationLock") 9147 void notifyAssistantExpansionChangedLocked( 9148 final StatusBarNotification sbn, 9149 final boolean isUserAction, 9150 final boolean isExpanded) { 9151 final String key = sbn.getKey(); 9152 notifyAssistantLocked( 9153 sbn, 9154 false /* sameUserOnly */, 9155 (assistant, sbnHolder) -> { 9156 try { 9157 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded); 9158 } catch (RemoteException ex) { 9159 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 9160 } 9161 }); 9162 } 9163 9164 @GuardedBy("mNotificationLock") 9165 void notifyAssistantNotificationDirectReplyLocked( 9166 final StatusBarNotification sbn) { 9167 final String key = sbn.getKey(); 9168 notifyAssistantLocked( 9169 sbn, 9170 false /* sameUserOnly */, 9171 (assistant, sbnHolder) -> { 9172 try { 9173 assistant.onNotificationDirectReply(key); 9174 } catch (RemoteException ex) { 9175 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 9176 } 9177 }); 9178 } 9179 9180 @GuardedBy("mNotificationLock") 9181 void notifyAssistantSuggestedReplySent( 9182 final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) { 9183 final String key = sbn.getKey(); 9184 notifyAssistantLocked( 9185 sbn, 9186 false /* sameUserOnly */, 9187 (assistant, sbnHolder) -> { 9188 try { 9189 assistant.onSuggestedReplySent( 9190 key, 9191 reply, 9192 generatedByAssistant 9193 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 9194 : NotificationAssistantService.SOURCE_FROM_APP); 9195 } catch (RemoteException ex) { 9196 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 9197 } 9198 }); 9199 } 9200 9201 @GuardedBy("mNotificationLock") 9202 void notifyAssistantActionClicked( 9203 final StatusBarNotification sbn, int actionIndex, Notification.Action action, 9204 boolean generatedByAssistant) { 9205 final String key = sbn.getKey(); 9206 notifyAssistantLocked( 9207 sbn, 9208 false /* sameUserOnly */, 9209 (assistant, sbnHolder) -> { 9210 try { 9211 assistant.onActionClicked( 9212 key, 9213 action, 9214 generatedByAssistant 9215 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 9216 : NotificationAssistantService.SOURCE_FROM_APP); 9217 } catch (RemoteException ex) { 9218 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 9219 } 9220 }); 9221 } 9222 9223 /** 9224 * asynchronously notify the assistant that a notification has been snoozed until a 9225 * context 9226 */ 9227 @GuardedBy("mNotificationLock") 9228 private void notifyAssistantSnoozedLocked( 9229 final StatusBarNotification sbn, final String snoozeCriterionId) { 9230 notifyAssistantLocked( 9231 sbn, 9232 false /* sameUserOnly */, 9233 (assistant, sbnHolder) -> { 9234 try { 9235 assistant.onNotificationSnoozedUntilContext( 9236 sbnHolder, snoozeCriterionId); 9237 } catch (RemoteException ex) { 9238 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 9239 } 9240 }); 9241 } 9242 9243 /** 9244 * Notifies the assistant something about the specified notification, only assistant 9245 * that is visible to the notification will be notified. 9246 * 9247 * @param sbn the notification object that the update is about. 9248 * @param sameUserOnly should the update be sent to the assistant in the same user only. 9249 * @param callback the callback that provides the assistant to be notified, executed 9250 * in WorkerHandler. 9251 */ 9252 @GuardedBy("mNotificationLock") 9253 private void notifyAssistantLocked( 9254 final StatusBarNotification sbn, 9255 boolean sameUserOnly, 9256 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) { 9257 TrimCache trimCache = new TrimCache(sbn); 9258 // There should be only one, but it's a list, so while we enforce 9259 // singularity elsewhere, we keep it general here, to avoid surprises. 9260 9261 final boolean debug = isVerboseLogEnabled(); 9262 if (debug) { 9263 Slog.v(TAG, 9264 "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = [" 9265 + sameUserOnly + "], callback = [" + callback + "]"); 9266 } 9267 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 9268 boolean sbnVisible = isVisibleToListener(sbn, info) 9269 && (!sameUserOnly || info.isSameUser(sbn.getUserId())); 9270 if (debug) { 9271 Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible); 9272 } 9273 if (!sbnVisible) { 9274 continue; 9275 } 9276 final INotificationListener assistant = (INotificationListener) info.service; 9277 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 9278 final StatusBarNotificationHolder sbnHolder = 9279 new StatusBarNotificationHolder(sbnToPost); 9280 mHandler.post(() -> callback.accept(assistant, sbnHolder)); 9281 } 9282 } 9283 9284 public boolean isEnabled() { 9285 return !getServices().isEmpty(); 9286 } 9287 9288 protected void resetDefaultAssistantsIfNecessary() { 9289 final List<UserInfo> activeUsers = mUm.getUsers(true); 9290 for (UserInfo userInfo : activeUsers) { 9291 int userId = userInfo.getUserHandle().getIdentifier(); 9292 if (!hasUserSet(userId)) { 9293 Slog.d(TAG, "Approving default notification assistant for user " + userId); 9294 setDefaultAssistantForUser(userId); 9295 } 9296 } 9297 } 9298 9299 @Override 9300 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, 9301 boolean isPrimary, boolean enabled) { 9302 // Ensures that only one component is enabled at a time 9303 if (enabled) { 9304 List<ComponentName> allowedComponents = getAllowedComponents(userId); 9305 if (!allowedComponents.isEmpty()) { 9306 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents); 9307 if (currentComponent.flattenToString().equals(pkgOrComponent)) return; 9308 setNotificationAssistantAccessGrantedForUserInternal( 9309 currentComponent, userId, false); 9310 } 9311 } 9312 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled); 9313 } 9314 9315 @Override 9316 public void dump(PrintWriter pw, DumpFilter filter) { 9317 super.dump(pw, filter); 9318 pw.println(" Has user set:"); 9319 synchronized (mLock) { 9320 Set<Integer> userIds = mUserSetMap.keySet(); 9321 for (int userId : userIds) { 9322 pw.println(" userId=" + userId + " value=" + mUserSetMap.get(userId)); 9323 } 9324 } 9325 } 9326 9327 private boolean isVerboseLogEnabled() { 9328 return Log.isLoggable("notification_assistant", Log.VERBOSE); 9329 } 9330 } 9331 9332 public class NotificationListeners extends ManagedServices { 9333 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners"; 9334 9335 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 9336 9337 public NotificationListeners(IPackageManager pm) { 9338 super(getContext(), mNotificationLock, mUserProfiles, pm); 9339 } 9340 9341 @Override 9342 protected void loadDefaultsFromConfig() { 9343 String defaultListenerAccess = mContext.getResources().getString( 9344 R.string.config_defaultListenerAccessPackages); 9345 if (defaultListenerAccess != null) { 9346 String[] listeners = 9347 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR); 9348 for (int i = 0; i < listeners.length; i++) { 9349 if (TextUtils.isEmpty(listeners[i])) { 9350 continue; 9351 } 9352 ArraySet<ComponentName> approvedListeners = 9353 this.queryPackageForServices(listeners[i], 9354 MATCH_DIRECT_BOOT_AWARE 9355 | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM); 9356 for (int k = 0; k < approvedListeners.size(); k++) { 9357 ComponentName cn = approvedListeners.valueAt(k); 9358 addDefaultComponentOrPackage(cn.flattenToString()); 9359 } 9360 } 9361 } 9362 } 9363 9364 @Override 9365 protected int getBindFlags() { 9366 // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE 9367 // because too many 3P apps could be kept in memory as notification listeners and 9368 // cause extreme memory pressure. 9369 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation. 9370 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE 9371 | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT; 9372 } 9373 9374 @Override 9375 protected Config getConfig() { 9376 Config c = new Config(); 9377 c.caption = "notification listener"; 9378 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 9379 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS; 9380 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 9381 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 9382 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 9383 c.clientLabel = R.string.notification_listener_binding_label; 9384 return c; 9385 } 9386 9387 @Override 9388 protected IInterface asInterface(IBinder binder) { 9389 return INotificationListener.Stub.asInterface(binder); 9390 } 9391 9392 @Override 9393 protected boolean checkType(IInterface service) { 9394 return service instanceof INotificationListener; 9395 } 9396 9397 @Override 9398 public void onServiceAdded(ManagedServiceInfo info) { 9399 final INotificationListener listener = (INotificationListener) info.service; 9400 final NotificationRankingUpdate update; 9401 synchronized (mNotificationLock) { 9402 update = makeRankingUpdateLocked(info); 9403 updateUriPermissionsForActiveNotificationsLocked(info, true); 9404 } 9405 try { 9406 listener.onListenerConnected(update); 9407 } catch (RemoteException e) { 9408 // we tried 9409 } 9410 } 9411 9412 @Override 9413 @GuardedBy("mNotificationLock") 9414 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 9415 updateUriPermissionsForActiveNotificationsLocked(removed, false); 9416 if (removeDisabledHints(removed)) { 9417 updateListenerHintsLocked(); 9418 updateEffectsSuppressorLocked(); 9419 } 9420 mLightTrimListeners.remove(removed); 9421 } 9422 9423 @Override 9424 protected String getRequiredPermission() { 9425 return null; 9426 } 9427 9428 @GuardedBy("mNotificationLock") 9429 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 9430 if (trim == TRIM_LIGHT) { 9431 mLightTrimListeners.add(info); 9432 } else { 9433 mLightTrimListeners.remove(info); 9434 } 9435 } 9436 9437 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 9438 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 9439 } 9440 9441 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { 9442 for (final ManagedServiceInfo info : getServices()) { 9443 mHandler.post(() -> { 9444 final INotificationListener listener = (INotificationListener) info.service; 9445 try { 9446 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons); 9447 } catch (RemoteException ex) { 9448 Slog.e(TAG, "unable to notify listener " 9449 + "(hideSilentStatusIcons): " + info, ex); 9450 } 9451 }); 9452 } 9453 } 9454 9455 /** 9456 * asynchronously notify all listeners about a new notification 9457 * 9458 * <p> 9459 * Also takes care of removing a notification that has been visible to a listener before, 9460 * but isn't anymore. 9461 */ 9462 @GuardedBy("mNotificationLock") 9463 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) { 9464 notifyPostedLocked(r, old, true); 9465 } 9466 9467 /** 9468 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners 9469 * targetting <= O_MR1 9470 */ 9471 @GuardedBy("mNotificationLock") 9472 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old, 9473 boolean notifyAllListeners) { 9474 try { 9475 // Lazily initialized snapshots of the notification. 9476 StatusBarNotification sbn = r.getSbn(); 9477 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 9478 TrimCache trimCache = new TrimCache(sbn); 9479 9480 for (final ManagedServiceInfo info : getServices()) { 9481 boolean sbnVisible = isVisibleToListener(sbn, info); 9482 boolean oldSbnVisible = (oldSbn != null) && isVisibleToListener(oldSbn, info); 9483 // This notification hasn't been and still isn't visible -> ignore. 9484 if (!oldSbnVisible && !sbnVisible) { 9485 continue; 9486 } 9487 // If the notification is hidden, don't notifyPosted listeners targeting < P. 9488 // Instead, those listeners will receive notifyPosted when the notification is 9489 // unhidden. 9490 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 9491 continue; 9492 } 9493 9494 // If we shouldn't notify all listeners, this means the hidden state of 9495 // a notification was changed. Don't notifyPosted listeners targeting >= P. 9496 // Instead, those listeners will receive notifyRankingUpdate. 9497 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) { 9498 continue; 9499 } 9500 9501 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 9502 9503 // This notification became invisible -> remove the old one. 9504 if (oldSbnVisible && !sbnVisible) { 9505 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 9506 mHandler.post(() -> notifyRemoved( 9507 info, oldSbnLightClone, update, null, REASON_USER_STOPPED)); 9508 continue; 9509 } 9510 9511 // Grant access before listener is notified 9512 final int targetUserId = (info.userid == UserHandle.USER_ALL) 9513 ? UserHandle.USER_SYSTEM : info.userid; 9514 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId); 9515 9516 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 9517 mHandler.post(() -> notifyPosted(info, sbnToPost, update)); 9518 } 9519 } catch (Exception e) { 9520 Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e); 9521 } 9522 } 9523 9524 /** 9525 * Synchronously grant or revoke permissions to Uris for all active and visible 9526 * notifications to just the NotificationListenerService provided. 9527 */ 9528 @GuardedBy("mNotificationLock") 9529 private void updateUriPermissionsForActiveNotificationsLocked( 9530 ManagedServiceInfo info, boolean grant) { 9531 try { 9532 for (final NotificationRecord r : mNotificationList) { 9533 // When granting permissions, ignore notifications which are invisible. 9534 // When revoking permissions, all notifications are invisible, so process all. 9535 if (grant && !isVisibleToListener(r.getSbn(), info)) { 9536 continue; 9537 } 9538 // If the notification is hidden, permissions are not required by the listener. 9539 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 9540 continue; 9541 } 9542 // Grant or revoke access synchronously 9543 final int targetUserId = (info.userid == UserHandle.USER_ALL) 9544 ? UserHandle.USER_SYSTEM : info.userid; 9545 if (grant) { 9546 // Grant permissions by passing arguments as if the notification is new. 9547 updateUriPermissions(/* newRecord */ r, /* oldRecord */ null, 9548 info.component.getPackageName(), targetUserId); 9549 } else { 9550 // Revoke permissions by passing arguments as if the notification was 9551 // removed, but set `onlyRevokeCurrentTarget` to avoid revoking permissions 9552 // granted to *other* targets by this notification's URIs. 9553 updateUriPermissions(/* newRecord */ null, /* oldRecord */ r, 9554 info.component.getPackageName(), targetUserId, 9555 /* onlyRevokeCurrentTarget */ true); 9556 } 9557 } 9558 } catch (Exception e) { 9559 Slog.e(TAG, "Could not " + (grant ? "grant" : "revoke") + " Uri permissions to " 9560 + info.component, e); 9561 } 9562 } 9563 9564 /** 9565 * asynchronously notify all listeners about a removed notification 9566 */ 9567 @GuardedBy("mNotificationLock") 9568 public void notifyRemovedLocked(NotificationRecord r, int reason, 9569 NotificationStats notificationStats) { 9570 final StatusBarNotification sbn = r.getSbn(); 9571 9572 // make a copy in case changes are made to the underlying Notification object 9573 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 9574 // notification 9575 final StatusBarNotification sbnLight = sbn.cloneLight(); 9576 for (final ManagedServiceInfo info : getServices()) { 9577 if (!isVisibleToListener(sbn, info)) { 9578 continue; 9579 } 9580 9581 // don't notifyRemoved for listeners targeting < P 9582 // if not for reason package suspended 9583 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED 9584 && info.targetSdkVersion < Build.VERSION_CODES.P) { 9585 continue; 9586 } 9587 9588 // don't notifyRemoved for listeners targeting >= P 9589 // if the reason is package suspended 9590 if (reason == REASON_PACKAGE_SUSPENDED 9591 && info.targetSdkVersion >= Build.VERSION_CODES.P) { 9592 continue; 9593 } 9594 9595 // Only assistants can get stats 9596 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service) 9597 ? notificationStats : null; 9598 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 9599 mHandler.post(() -> notifyRemoved(info, sbnLight, update, stats, reason)); 9600 } 9601 9602 // Revoke access after all listeners have been updated 9603 mHandler.post(() -> updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM)); 9604 } 9605 9606 /** 9607 * Asynchronously notify all listeners about a reordering of notifications 9608 * unless changedHiddenNotifications is populated. 9609 * If changedHiddenNotifications is populated, there was a change in the hidden state 9610 * of the notifications. In this case, we only send updates to listeners that 9611 * target >= P. 9612 */ 9613 @GuardedBy("mNotificationLock") 9614 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { 9615 boolean isHiddenRankingUpdate = changedHiddenNotifications != null 9616 && changedHiddenNotifications.size() > 0; 9617 9618 for (final ManagedServiceInfo serviceInfo : getServices()) { 9619 if (!serviceInfo.isEnabledForCurrentProfiles()) { 9620 continue; 9621 } 9622 9623 boolean notifyThisListener = false; 9624 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >= 9625 Build.VERSION_CODES.P) { 9626 for (NotificationRecord rec : changedHiddenNotifications) { 9627 if (isVisibleToListener(rec.getSbn(), serviceInfo)) { 9628 notifyThisListener = true; 9629 break; 9630 } 9631 } 9632 } 9633 9634 if (notifyThisListener || !isHiddenRankingUpdate) { 9635 final NotificationRankingUpdate update = makeRankingUpdateLocked( 9636 serviceInfo); 9637 9638 mHandler.post(new Runnable() { 9639 @Override 9640 public void run() { 9641 notifyRankingUpdate(serviceInfo, update); 9642 } 9643 }); 9644 } 9645 } 9646 } 9647 9648 @GuardedBy("mNotificationLock") 9649 public void notifyListenerHintsChangedLocked(final int hints) { 9650 for (final ManagedServiceInfo serviceInfo : getServices()) { 9651 if (!serviceInfo.isEnabledForCurrentProfiles()) { 9652 continue; 9653 } 9654 mHandler.post(new Runnable() { 9655 @Override 9656 public void run() { 9657 notifyListenerHintsChanged(serviceInfo, hints); 9658 } 9659 }); 9660 } 9661 } 9662 9663 /** 9664 * asynchronously notify relevant listeners their notification is hidden 9665 * NotificationListenerServices that target P+: 9666 * NotificationListenerService#notifyRankingUpdateLocked() 9667 * NotificationListenerServices that target <= P: 9668 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED. 9669 */ 9670 @GuardedBy("mNotificationLock") 9671 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) { 9672 if (changedNotifications == null || changedNotifications.size() == 0) { 9673 return; 9674 } 9675 9676 notifyRankingUpdateLocked(changedNotifications); 9677 9678 // for listeners that target < P, notifyRemoveLocked 9679 int numChangedNotifications = changedNotifications.size(); 9680 for (int i = 0; i < numChangedNotifications; i++) { 9681 NotificationRecord rec = changedNotifications.get(i); 9682 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats()); 9683 } 9684 } 9685 9686 /** 9687 * asynchronously notify relevant listeners their notification is unhidden 9688 * NotificationListenerServices that target P+: 9689 * NotificationListenerService#notifyRankingUpdateLocked() 9690 * NotificationListenerServices that target <= P: 9691 * NotificationListeners#notifyPostedLocked() 9692 */ 9693 @GuardedBy("mNotificationLock") 9694 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) { 9695 if (changedNotifications == null || changedNotifications.size() == 0) { 9696 return; 9697 } 9698 9699 notifyRankingUpdateLocked(changedNotifications); 9700 9701 // for listeners that target < P, notifyPostedLocked 9702 int numChangedNotifications = changedNotifications.size(); 9703 for (int i = 0; i < numChangedNotifications; i++) { 9704 NotificationRecord rec = changedNotifications.get(i); 9705 mListeners.notifyPostedLocked(rec, rec, false); 9706 } 9707 } 9708 9709 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 9710 for (final ManagedServiceInfo serviceInfo : getServices()) { 9711 if (!serviceInfo.isEnabledForCurrentProfiles()) { 9712 continue; 9713 } 9714 mHandler.post(new Runnable() { 9715 @Override 9716 public void run() { 9717 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 9718 } 9719 }); 9720 } 9721 } 9722 9723 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, 9724 final NotificationChannel channel, final int modificationType) { 9725 if (channel == null) { 9726 return; 9727 } 9728 for (final ManagedServiceInfo serviceInfo : getServices()) { 9729 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { 9730 continue; 9731 } 9732 9733 BackgroundThread.getHandler().post(() -> { 9734 if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) { 9735 notifyNotificationChannelChanged( 9736 serviceInfo, pkg, user, channel, modificationType); 9737 } 9738 }); 9739 } 9740 } 9741 9742 protected void notifyNotificationChannelGroupChanged( 9743 final String pkg, final UserHandle user, final NotificationChannelGroup group, 9744 final int modificationType) { 9745 if (group == null) { 9746 return; 9747 } 9748 for (final ManagedServiceInfo serviceInfo : getServices()) { 9749 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { 9750 continue; 9751 } 9752 9753 BackgroundThread.getHandler().post(() -> { 9754 if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) { 9755 notifyNotificationChannelGroupChanged( 9756 serviceInfo, pkg, user, group, modificationType); 9757 } 9758 }); 9759 } 9760 } 9761 9762 private void notifyPosted(final ManagedServiceInfo info, 9763 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 9764 final INotificationListener listener = (INotificationListener) info.service; 9765 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 9766 try { 9767 listener.onNotificationPosted(sbnHolder, rankingUpdate); 9768 } catch (RemoteException ex) { 9769 Slog.e(TAG, "unable to notify listener (posted): " + info, ex); 9770 } 9771 } 9772 9773 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 9774 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) { 9775 if (!info.enabledAndUserMatches(sbn.getUserId())) { 9776 return; 9777 } 9778 final INotificationListener listener = (INotificationListener) info.service; 9779 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 9780 try { 9781 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason); 9782 } catch (RemoteException ex) { 9783 Slog.e(TAG, "unable to notify listener (removed): " + info, ex); 9784 } 9785 } 9786 9787 private void notifyRankingUpdate(ManagedServiceInfo info, 9788 NotificationRankingUpdate rankingUpdate) { 9789 final INotificationListener listener = (INotificationListener) info.service; 9790 try { 9791 listener.onNotificationRankingUpdate(rankingUpdate); 9792 } catch (RemoteException ex) { 9793 Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex); 9794 } 9795 } 9796 9797 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 9798 final INotificationListener listener = (INotificationListener) info.service; 9799 try { 9800 listener.onListenerHintsChanged(hints); 9801 } catch (RemoteException ex) { 9802 Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex); 9803 } 9804 } 9805 9806 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 9807 int interruptionFilter) { 9808 final INotificationListener listener = (INotificationListener) info.service; 9809 try { 9810 listener.onInterruptionFilterChanged(interruptionFilter); 9811 } catch (RemoteException ex) { 9812 Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex); 9813 } 9814 } 9815 9816 void notifyNotificationChannelChanged(ManagedServiceInfo info, 9817 final String pkg, final UserHandle user, final NotificationChannel channel, 9818 final int modificationType) { 9819 final INotificationListener listener = (INotificationListener) info.service; 9820 try { 9821 listener.onNotificationChannelModification(pkg, user, channel, modificationType); 9822 } catch (RemoteException ex) { 9823 Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex); 9824 } 9825 } 9826 9827 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, 9828 final String pkg, final UserHandle user, final NotificationChannelGroup group, 9829 final int modificationType) { 9830 final INotificationListener listener = (INotificationListener) info.service; 9831 try { 9832 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); 9833 } catch (RemoteException ex) { 9834 Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex); 9835 } 9836 } 9837 9838 public boolean isListenerPackage(String packageName) { 9839 if (packageName == null) { 9840 return false; 9841 } 9842 // TODO: clean up locking object later 9843 synchronized (mNotificationLock) { 9844 for (final ManagedServiceInfo serviceInfo : getServices()) { 9845 if (packageName.equals(serviceInfo.component.getPackageName())) { 9846 return true; 9847 } 9848 } 9849 } 9850 return false; 9851 } 9852 } 9853 9854 class RoleObserver implements OnRoleHoldersChangedListener { 9855 // Role name : user id : list of approved packages 9856 private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps; 9857 9858 private final RoleManager mRm; 9859 private final IPackageManager mPm; 9860 private final Executor mExecutor; 9861 9862 RoleObserver(@NonNull RoleManager roleManager, 9863 @NonNull IPackageManager pkgMgr, 9864 @NonNull @CallbackExecutor Executor executor) { 9865 mRm = roleManager; 9866 mPm = pkgMgr; 9867 mExecutor = executor; 9868 } 9869 9870 public void init() { 9871 List<UserInfo> users = mUm.getUsers(); 9872 mNonBlockableDefaultApps = new ArrayMap<>(); 9873 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 9874 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>(); 9875 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList); 9876 for (int j = 0; j < users.size(); j++) { 9877 Integer userId = users.get(j).getUserHandle().getIdentifier(); 9878 ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser( 9879 NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId))); 9880 ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>(); 9881 for (String pkg : approvedForUserId) { 9882 approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId))); 9883 } 9884 userToApprovedList.put(userId, approvedForUserId); 9885 mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids); 9886 } 9887 } 9888 9889 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); 9890 } 9891 9892 @VisibleForTesting 9893 public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) { 9894 return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg); 9895 } 9896 9897 /** 9898 * Convert the assistant-role holder into settings. The rest of the system uses the 9899 * settings. 9900 * 9901 * @param roleName the name of the role whose holders are changed 9902 * @param user the user for this role holder change 9903 */ 9904 @Override 9905 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { 9906 // we only care about a couple of the roles they'll tell us about 9907 boolean relevantChange = false; 9908 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 9909 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) { 9910 relevantChange = true; 9911 break; 9912 } 9913 } 9914 9915 if (!relevantChange) { 9916 return; 9917 } 9918 9919 ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user)); 9920 9921 // find the diff 9922 ArrayMap<Integer, ArraySet<String>> prevApprovedForRole = 9923 mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>()); 9924 ArraySet<String> previouslyApproved = 9925 prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>()); 9926 9927 ArraySet<String> toRemove = new ArraySet<>(); 9928 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 9929 9930 for (String previous : previouslyApproved) { 9931 if (!roleHolders.contains(previous)) { 9932 toRemove.add(previous); 9933 } 9934 } 9935 for (String nowApproved : roleHolders) { 9936 if (!previouslyApproved.contains(nowApproved)) { 9937 toAdd.add(new Pair(nowApproved, 9938 getUidForPackage(nowApproved, user.getIdentifier()))); 9939 } 9940 } 9941 9942 // store newly approved apps 9943 prevApprovedForRole.put(user.getIdentifier(), roleHolders); 9944 mNonBlockableDefaultApps.put(roleName, prevApprovedForRole); 9945 9946 // update what apps can be blocked 9947 mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd); 9948 9949 // RoleManager is the source of truth for this data so we don't need to trigger a 9950 // write of the notification policy xml for this change 9951 } 9952 9953 private int getUidForPackage(String pkg, int userId) { 9954 try { 9955 return mPm.getPackageUid(pkg, MATCH_ALL, userId); 9956 } catch (RemoteException e) { 9957 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId); 9958 } 9959 return -1; 9960 } 9961 } 9962 9963 public static final class DumpFilter { 9964 public boolean filtered = false; 9965 public String pkgFilter; 9966 public boolean zen; 9967 public long since; 9968 public boolean stats; 9969 public boolean rvStats; 9970 public boolean redact = true; 9971 public boolean proto = false; 9972 public boolean criticalPriority = false; 9973 public boolean normalPriority = false; 9974 9975 @NonNull 9976 public static DumpFilter parseFromArguments(String[] args) { 9977 final DumpFilter filter = new DumpFilter(); 9978 for (int ai = 0; ai < args.length; ai++) { 9979 final String a = args[ai]; 9980 if ("--proto".equals(a)) { 9981 filter.proto = true; 9982 } else if ("--noredact".equals(a) || "--reveal".equals(a)) { 9983 filter.redact = false; 9984 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 9985 if (ai < args.length-1) { 9986 ai++; 9987 filter.pkgFilter = args[ai].trim().toLowerCase(); 9988 if (filter.pkgFilter.isEmpty()) { 9989 filter.pkgFilter = null; 9990 } else { 9991 filter.filtered = true; 9992 } 9993 } 9994 } else if ("--zen".equals(a) || "zen".equals(a)) { 9995 filter.filtered = true; 9996 filter.zen = true; 9997 } else if ("--stats".equals(a)) { 9998 filter.stats = true; 9999 if (ai < args.length-1) { 10000 ai++; 10001 filter.since = Long.parseLong(args[ai]); 10002 } else { 10003 filter.since = 0; 10004 } 10005 } else if ("--remote-view-stats".equals(a)) { 10006 filter.rvStats = true; 10007 if (ai < args.length-1) { 10008 ai++; 10009 filter.since = Long.parseLong(args[ai]); 10010 } else { 10011 filter.since = 0; 10012 } 10013 } else if (PRIORITY_ARG.equals(a)) { 10014 // Bugreport will call the service twice with priority arguments, first to dump 10015 // critical sections and then non critical ones. Set approriate filters 10016 // to generate the desired data. 10017 if (ai < args.length - 1) { 10018 ai++; 10019 switch (args[ai]) { 10020 case PRIORITY_ARG_CRITICAL: 10021 filter.criticalPriority = true; 10022 break; 10023 case PRIORITY_ARG_NORMAL: 10024 filter.normalPriority = true; 10025 break; 10026 } 10027 } 10028 } 10029 } 10030 return filter; 10031 } 10032 10033 public boolean matches(StatusBarNotification sbn) { 10034 if (!filtered) return true; 10035 return zen ? true : sbn != null 10036 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 10037 } 10038 10039 public boolean matches(ComponentName component) { 10040 if (!filtered) return true; 10041 return zen ? true : component != null && matches(component.getPackageName()); 10042 } 10043 10044 public boolean matches(String pkg) { 10045 if (!filtered) return true; 10046 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 10047 } 10048 10049 @Override 10050 public String toString() { 10051 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 10052 } 10053 } 10054 10055 @VisibleForTesting 10056 void resetAssistantUserSet(int userId) { 10057 checkCallerIsSystemOrShell(); 10058 mAssistants.setUserSet(userId, false); 10059 handleSavePolicyFile(); 10060 } 10061 10062 @VisibleForTesting 10063 @Nullable 10064 ComponentName getApprovedAssistant(int userId) { 10065 checkCallerIsSystemOrShell(); 10066 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 10067 return CollectionUtils.firstOrNull(allowedComponents); 10068 } 10069 10070 @VisibleForTesting 10071 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) { 10072 checkCallerIsSystemOrShell(); 10073 // only use for testing: mimic receive broadcast that package is (un)suspended 10074 // but does not actually (un)suspend the package 10075 final Bundle extras = new Bundle(); 10076 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, 10077 new String[]{pkg}); 10078 10079 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED 10080 : Intent.ACTION_PACKAGES_UNSUSPENDED; 10081 final Intent intent = new Intent(action); 10082 intent.putExtras(extras); 10083 10084 mPackageIntentReceiver.onReceive(getContext(), intent); 10085 } 10086 10087 @VisibleForTesting 10088 protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) { 10089 checkCallerIsSystemOrShell(); 10090 // only use for testing: mimic receive broadcast that package is (un)distracting 10091 // but does not actually register that info with packagemanager 10092 final Bundle extras = new Bundle(); 10093 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); 10094 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); 10095 10096 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 10097 intent.putExtras(extras); 10098 10099 mPackageIntentReceiver.onReceive(getContext(), intent); 10100 } 10101 10102 /** 10103 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 10104 * binder without sending large amounts of data over a oneway transaction. 10105 */ 10106 private static final class StatusBarNotificationHolder 10107 extends IStatusBarNotificationHolder.Stub { 10108 private StatusBarNotification mValue; 10109 10110 public StatusBarNotificationHolder(StatusBarNotification value) { 10111 mValue = value; 10112 } 10113 10114 /** Get the held value and clear it. This function should only be called once per holder */ 10115 @Override 10116 public StatusBarNotification get() { 10117 StatusBarNotification value = mValue; 10118 mValue = null; 10119 return value; 10120 } 10121 } 10122 10123 private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException { 10124 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 10125 out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, 10126 Boolean.toString(mLockScreenAllowSecureNotifications)); 10127 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 10128 } 10129 10130 private static boolean safeBoolean(String val, boolean defValue) { 10131 if (TextUtils.isEmpty(val)) return defValue; 10132 return Boolean.parseBoolean(val); 10133 } 10134 } 10135