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