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.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS; 20 import static android.Manifest.permission.RECEIVE_SENSITIVE_NOTIFICATIONS; 21 import static android.Manifest.permission.STATUS_BAR_SERVICE; 22 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 23 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE; 24 import static android.app.AppOpsManager.MODE_ALLOWED; 25 import static android.app.AppOpsManager.MODE_DEFAULT; 26 import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS; 27 import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR; 28 import static android.app.Flags.lifetimeExtensionRefactor; 29 import static android.app.Flags.nmSummarization; 30 import static android.app.Flags.nmSummarizationUi; 31 import static android.app.Flags.notificationClassificationUi; 32 import static android.app.Flags.sortSectionByTime; 33 import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 34 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO; 35 import static android.app.Notification.EXTRA_LARGE_ICON_BIG; 36 import static android.app.Notification.EXTRA_SUB_TEXT; 37 import static android.app.Notification.EXTRA_TEXT; 38 import static android.app.Notification.EXTRA_TEXT_LINES; 39 import static android.app.Notification.EXTRA_TITLE; 40 import static android.app.Notification.EXTRA_TITLE_BIG; 41 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; 42 import static android.app.Notification.FLAG_AUTO_CANCEL; 43 import static android.app.Notification.FLAG_BUBBLE; 44 import static android.app.Notification.FLAG_FOREGROUND_SERVICE; 45 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED; 46 import static android.app.Notification.FLAG_GROUP_SUMMARY; 47 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 48 import static android.app.Notification.FLAG_NO_CLEAR; 49 import static android.app.Notification.FLAG_NO_DISMISS; 50 import static android.app.Notification.FLAG_ONGOING_EVENT; 51 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; 52 import static android.app.Notification.FLAG_PROMOTED_ONGOING; 53 import static android.app.Notification.FLAG_USER_INITIATED_JOB; 54 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; 55 import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS; 56 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED; 57 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; 58 import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED; 59 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; 60 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL; 61 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED; 62 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED; 63 import static android.app.NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED; 64 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED; 65 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED; 66 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 67 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; 68 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; 69 import static android.app.NotificationManager.EXTRA_NOTIFICATION_POLICY; 70 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 71 import static android.app.NotificationManager.IMPORTANCE_LOW; 72 import static android.app.NotificationManager.IMPORTANCE_MIN; 73 import static android.app.NotificationManager.IMPORTANCE_NONE; 74 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET; 76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 78 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 79 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 80 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 81 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 82 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 83 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 84 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 85 import static android.app.NotificationManager.zenModeFromInterruptionFilter; 86 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; 87 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; 88 import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; 89 import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING; 90 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; 91 import static android.content.Context.BIND_AUTO_CREATE; 92 import static android.content.Context.BIND_FOREGROUND_SERVICE; 93 import static android.content.Context.BIND_NOT_PERCEPTIBLE; 94 import static android.content.pm.PackageManager.FEATURE_LEANBACK; 95 import static android.content.pm.PackageManager.FEATURE_TELECOM; 96 import static android.content.pm.PackageManager.FEATURE_TELEVISION; 97 import static android.content.pm.PackageManager.MATCH_ALL; 98 import static android.content.pm.PackageManager.MATCH_ANY_USER; 99 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; 100 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 101 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 102 import static android.os.Flags.allowPrivateProfile; 103 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; 104 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; 105 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; 106 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 107 import static android.os.UserHandle.USER_ALL; 108 import static android.os.UserHandle.USER_NULL; 109 import static android.os.UserHandle.USER_SYSTEM; 110 import static android.service.notification.Adjustment.KEY_SUMMARIZATION; 111 import static android.service.notification.Adjustment.KEY_TYPE; 112 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; 113 import static android.service.notification.Adjustment.TYPE_NEWS; 114 import static android.service.notification.Adjustment.TYPE_PROMOTION; 115 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA; 116 import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT; 117 import static android.service.notification.Flags.callstyleCallbackApi; 118 import static android.service.notification.Flags.notificationClassification; 119 import static android.service.notification.Flags.notificationForceGrouping; 120 import static android.service.notification.Flags.notificationRegroupOnClassification; 121 import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle; 122 import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners; 123 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; 124 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; 125 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; 126 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; 127 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 128 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 129 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 130 import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES; 131 import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES; 132 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; 133 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; 134 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; 135 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 136 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; 137 import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL; 138 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 139 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; 140 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; 141 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_REMOVED; 142 import static android.service.notification.NotificationListenerService.REASON_CLEAR_DATA; 143 import static android.service.notification.NotificationListenerService.REASON_CLICK; 144 import static android.service.notification.NotificationListenerService.REASON_ERROR; 145 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; 146 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; 147 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; 148 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; 149 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; 150 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; 151 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; 152 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF; 153 import static android.service.notification.NotificationListenerService.REASON_SNOOZED; 154 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; 155 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; 156 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; 157 import static android.service.notification.NotificationListenerService.Ranking.RANKING_DEMOTED; 158 import static android.service.notification.NotificationListenerService.Ranking.RANKING_PROMOTED; 159 import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED; 160 import static android.service.notification.NotificationListenerService.TRIM_FULL; 161 import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 162 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 163 import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled; 164 165 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; 166 import static com.android.internal.util.FrameworkStatsLog.NOTIFICATION_BUNDLE_PREFERENCES; 167 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES; 168 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES; 169 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES; 170 import static com.android.internal.util.Preconditions.checkArgument; 171 import static com.android.internal.util.Preconditions.checkNotNull; 172 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 173 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 174 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 175 import static com.android.server.notification.Flags.expireBitmaps; 176 import static com.android.server.notification.Flags.managedServicesConcurrentMultiuser; 177 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER; 178 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 179 import static com.android.server.utils.PriorityDump.PRIORITY_ARG; 180 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; 181 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; 182 183 import android.Manifest; 184 import android.Manifest.permission; 185 import android.annotation.DurationMillisLong; 186 import android.annotation.ElapsedRealtimeLong; 187 import android.annotation.EnforcePermission; 188 import android.annotation.FlaggedApi; 189 import android.annotation.MainThread; 190 import android.annotation.NonNull; 191 import android.annotation.Nullable; 192 import android.annotation.RequiresPermission; 193 import android.annotation.UserIdInt; 194 import android.annotation.WorkerThread; 195 import android.app.ActivityManager; 196 import android.app.ActivityManagerInternal; 197 import android.app.ActivityManagerInternal.ServiceNotificationPolicy; 198 import android.app.ActivityTaskManager; 199 import android.app.AlarmManager; 200 import android.app.AppGlobals; 201 import android.app.AppOpsManager; 202 import android.app.AutomaticZenRule; 203 import android.app.IActivityManager; 204 import android.app.ICallNotificationEventCallback; 205 import android.app.INotificationManager; 206 import android.app.ITransientNotification; 207 import android.app.ITransientNotificationCallback; 208 import android.app.IUriGrantsManager; 209 import android.app.Notification; 210 import android.app.Notification.MessagingStyle; 211 import android.app.NotificationChannel; 212 import android.app.NotificationChannelGroup; 213 import android.app.NotificationHistory; 214 import android.app.NotificationHistory.HistoricalNotification; 215 import android.app.NotificationManager; 216 import android.app.NotificationManager.Policy; 217 import android.app.PendingIntent; 218 import android.app.Person; 219 import android.app.RemoteServiceException.BadForegroundServiceNotificationException; 220 import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException; 221 import android.app.StatsManager; 222 import android.app.UriGrantsManager; 223 import android.app.ZenBypassingApp; 224 import android.app.admin.DevicePolicyManagerInternal; 225 import android.app.backup.BackupManager; 226 import android.app.backup.BackupRestoreEventLogger; 227 import android.app.compat.CompatChanges; 228 import android.app.role.OnRoleHoldersChangedListener; 229 import android.app.role.RoleManager; 230 import android.app.usage.UsageEvents; 231 import android.app.usage.UsageStatsManagerInternal; 232 import android.companion.AssociationInfo; 233 import android.companion.AssociationRequest; 234 import android.companion.ICompanionDeviceManager; 235 import android.compat.annotation.ChangeId; 236 import android.compat.annotation.EnabledAfter; 237 import android.compat.annotation.EnabledSince; 238 import android.compat.annotation.LoggingOnly; 239 import android.content.AttributionSource; 240 import android.content.BroadcastReceiver; 241 import android.content.ComponentName; 242 import android.content.ContentProvider; 243 import android.content.ContentResolver; 244 import android.content.Context; 245 import android.content.Intent; 246 import android.content.IntentFilter; 247 import android.content.pm.ApplicationInfo; 248 import android.content.pm.IPackageManager; 249 import android.content.pm.LauncherApps; 250 import android.content.pm.ModuleInfo; 251 import android.content.pm.PackageManager; 252 import android.content.pm.PackageManager.NameNotFoundException; 253 import android.content.pm.PackageManagerInternal; 254 import android.content.pm.ParceledListSlice; 255 import android.content.pm.ServiceInfo; 256 import android.content.pm.ShortcutInfo; 257 import android.content.pm.ShortcutServiceInternal; 258 import android.content.pm.UserInfo; 259 import android.content.pm.VersionedPackage; 260 import android.content.res.Resources; 261 import android.database.ContentObserver; 262 import android.metrics.LogMaker; 263 import android.net.Uri; 264 import android.os.Binder; 265 import android.os.Build; 266 import android.os.Bundle; 267 import android.os.DeadObjectException; 268 import android.os.DeviceIdleManager; 269 import android.os.Environment; 270 import android.os.Handler; 271 import android.os.HandlerThread; 272 import android.os.IBinder; 273 import android.os.IInterface; 274 import android.os.Looper; 275 import android.os.Message; 276 import android.os.ParcelFileDescriptor; 277 import android.os.PowerManager; 278 import android.os.PowerManager.WakeLock; 279 import android.os.Process; 280 import android.os.RemoteCallbackList; 281 import android.os.RemoteException; 282 import android.os.ResultReceiver; 283 import android.os.ServiceManager; 284 import android.os.ShellCallback; 285 import android.os.SystemClock; 286 import android.os.SystemProperties; 287 import android.os.Trace; 288 import android.os.UserHandle; 289 import android.os.UserManager; 290 import android.os.WorkSource; 291 import android.permission.PermissionManager; 292 import android.provider.Settings; 293 import android.provider.Settings.Secure; 294 import android.service.notification.Adjustment; 295 import android.service.notification.Adjustment.Types; 296 import android.service.notification.Condition; 297 import android.service.notification.ConversationChannelWrapper; 298 import android.service.notification.DeviceEffectsApplier; 299 import android.service.notification.IConditionProvider; 300 import android.service.notification.INotificationListener; 301 import android.service.notification.IStatusBarNotificationHolder; 302 import android.service.notification.ListenersDisablingEffectsProto; 303 import android.service.notification.NotificationAssistantService; 304 import android.service.notification.NotificationListenerFilter; 305 import android.service.notification.NotificationListenerService; 306 import android.service.notification.NotificationRankingUpdate; 307 import android.service.notification.NotificationRecordProto; 308 import android.service.notification.NotificationServiceDumpProto; 309 import android.service.notification.NotificationStats; 310 import android.service.notification.StatusBarNotification; 311 import android.service.notification.ZenDeviceEffects; 312 import android.service.notification.ZenModeConfig; 313 import android.service.notification.ZenModeProto; 314 import android.service.notification.ZenPolicy; 315 import android.telecom.TelecomManager; 316 import android.telephony.TelephonyManager; 317 import android.text.TextUtils; 318 import android.text.format.DateUtils; 319 import android.util.ArrayMap; 320 import android.util.ArraySet; 321 import android.util.AtomicFile; 322 import android.util.IntArray; 323 import android.util.Log; 324 import android.util.Pair; 325 import android.util.Slog; 326 import android.util.SparseArray; 327 import android.util.SparseBooleanArray; 328 import android.util.StatsEvent; 329 import android.util.Xml; 330 import android.util.proto.ProtoOutputStream; 331 import android.view.Display; 332 import android.view.accessibility.AccessibilityManager; 333 import android.widget.RemoteViews; 334 import android.widget.Toast; 335 336 import com.android.internal.R; 337 import com.android.internal.annotations.GuardedBy; 338 import com.android.internal.annotations.VisibleForTesting; 339 import com.android.internal.compat.IPlatformCompat; 340 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; 341 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags; 342 import com.android.internal.logging.InstanceId; 343 import com.android.internal.logging.InstanceIdSequence; 344 import com.android.internal.logging.MetricsLogger; 345 import com.android.internal.logging.nano.MetricsProto; 346 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 347 import com.android.internal.messages.nano.SystemMessageProto; 348 import com.android.internal.notification.NotificationChannelGroupsHelper; 349 import com.android.internal.notification.SystemNotificationChannels; 350 import com.android.internal.os.BackgroundThread; 351 import com.android.internal.os.SomeArgs; 352 import com.android.internal.statusbar.NotificationVisibility; 353 import com.android.internal.util.ArrayUtils; 354 import com.android.internal.util.CollectionUtils; 355 import com.android.internal.util.ConcurrentUtils; 356 import com.android.internal.util.DumpUtils; 357 import com.android.internal.util.FrameworkStatsLog; 358 import com.android.internal.util.Preconditions; 359 import com.android.internal.util.XmlUtils; 360 import com.android.internal.util.function.TriPredicate; 361 import com.android.internal.widget.LockPatternUtils; 362 import com.android.modules.expresslog.Counter; 363 import com.android.modules.utils.TypedXmlPullParser; 364 import com.android.modules.utils.TypedXmlSerializer; 365 import com.android.server.DeviceIdleInternal; 366 import com.android.server.EventLogTags; 367 import com.android.server.IoThread; 368 import com.android.server.LocalServices; 369 import com.android.server.SystemService; 370 import com.android.server.job.JobSchedulerInternal; 371 import com.android.server.lights.LightsManager; 372 import com.android.server.notification.GroupHelper.NotificationAttributes; 373 import com.android.server.notification.ManagedServices.ManagedServiceInfo; 374 import com.android.server.notification.ManagedServices.UserProfiles; 375 import com.android.server.notification.NotificationRecordLogger.NotificationPullStatsEvent; 376 import com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent; 377 import com.android.server.notification.toast.CustomToastRecord; 378 import com.android.server.notification.toast.TextToastRecord; 379 import com.android.server.notification.toast.ToastRecord; 380 import com.android.server.pm.PackageManagerService; 381 import com.android.server.pm.UserManagerInternal; 382 import com.android.server.policy.PermissionPolicyInternal; 383 import com.android.server.statusbar.StatusBarManagerInternal; 384 import com.android.server.uri.UriGrantsManagerInternal; 385 import com.android.server.utils.Slogf; 386 import com.android.server.utils.quota.MultiRateLimiter; 387 import com.android.server.wm.ActivityTaskManagerInternal; 388 import com.android.server.wm.BackgroundActivityStartCallback; 389 import com.android.server.wm.WindowManagerInternal; 390 391 import libcore.io.IoUtils; 392 393 import org.json.JSONException; 394 import org.json.JSONObject; 395 import org.xmlpull.v1.XmlPullParserException; 396 397 import java.io.ByteArrayInputStream; 398 import java.io.ByteArrayOutputStream; 399 import java.io.File; 400 import java.io.FileDescriptor; 401 import java.io.FileNotFoundException; 402 import java.io.FileOutputStream; 403 import java.io.IOException; 404 import java.io.InputStream; 405 import java.io.OutputStream; 406 import java.io.PrintWriter; 407 import java.nio.charset.StandardCharsets; 408 import java.time.Clock; 409 import java.time.Duration; 410 import java.util.ArrayList; 411 import java.util.Arrays; 412 import java.util.Collection; 413 import java.util.HashSet; 414 import java.util.Iterator; 415 import java.util.LinkedList; 416 import java.util.List; 417 import java.util.Map; 418 import java.util.Map.Entry; 419 import java.util.Objects; 420 import java.util.Set; 421 import java.util.concurrent.Executor; 422 import java.util.concurrent.TimeUnit; 423 import java.util.function.BiConsumer; 424 import java.util.function.Predicate; 425 import java.util.stream.Collectors; 426 427 /** {@hide} */ 428 public class NotificationManagerService extends SystemService { 429 public static final String TAG = "NotificationService"; 430 public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 431 public static final boolean ENABLE_CHILD_NOTIFICATIONS 432 = SystemProperties.getBoolean("debug.child_notifs", true); 433 434 // pullStats report request: undecorated remote view stats 435 public static final int REPORT_REMOTE_VIEWS = 0x01; 436 437 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean( 438 "debug.notification.interruptiveness", false); 439 440 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 441 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f; 442 443 // To limit bad UX of seeing a toast many seconds after if was triggered. 444 static final int MAX_PACKAGE_TOASTS = 5; 445 446 // message codes 447 static final int MESSAGE_DURATION_REACHED = 2; 448 // 3: removed to a different handler 449 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 450 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 451 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 452 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7; 453 static final int MESSAGE_ON_PACKAGE_CHANGED = 8; 454 455 static final Duration BITMAP_DURATION = Duration.ofHours(24); 456 457 // ranking thread messages 458 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 459 private static final int MESSAGE_RANKING_SORT = 1001; 460 461 static final int LONG_DELAY = TOAST_WINDOW_TIMEOUT - TOAST_WINDOW_ANIM_BUFFER; // 3.5 seconds 462 static final int SHORT_DELAY = 2000; // 2 seconds 463 464 // 1 second past the ANR timeout. 465 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000; 466 467 static final long SNOOZE_UNTIL_UNSPECIFIED = -1; 468 469 /** 470 * The threshold, in milliseconds, to determine whether a notification has been 471 * cleared too quickly. 472 */ 473 private static final int NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS = 5000; 474 475 static final int INVALID_UID = -1; 476 static final String ROOT_PKG = "root"; 477 478 static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] { 479 Adjustment.KEY_PEOPLE, 480 Adjustment.KEY_SNOOZE_CRITERIA, 481 Adjustment.KEY_USER_SENTIMENT, 482 Adjustment.KEY_CONTEXTUAL_ACTIONS, 483 Adjustment.KEY_TEXT_REPLIES, 484 Adjustment.KEY_IMPORTANCE, 485 Adjustment.KEY_IMPORTANCE_PROPOSAL, 486 Adjustment.KEY_SENSITIVE_CONTENT, 487 Adjustment.KEY_RANKING_SCORE, 488 Adjustment.KEY_NOT_CONVERSATION, 489 Adjustment.KEY_TYPE, 490 Adjustment.KEY_SUMMARIZATION 491 }; 492 493 static final Integer[] DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES = new Integer[] { 494 TYPE_PROMOTION, 495 TYPE_NEWS, 496 TYPE_CONTENT_RECOMMENDATION, 497 TYPE_SOCIAL_MEDIA 498 }; 499 500 static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] { 501 RoleManager.ROLE_DIALER, 502 RoleManager.ROLE_EMERGENCY 503 }; 504 505 // Used for rate limiting toasts by package. 506 static final String TOAST_QUOTA_TAG = "toast_quota_tag"; 507 508 // This constant defines rate limits applied to showing toasts. The numbers are set in a way 509 // such that an aggressive toast showing strategy would result in a roughly 1.5x longer wait 510 // time (before the package is allowed to show toasts again) each time the toast rate limit is 511 // reached. It's meant to protect the user against apps spamming them with toasts (either 512 // accidentally or on purpose). 513 private static final MultiRateLimiter.RateLimit[] TOAST_RATE_LIMITS = { 514 MultiRateLimiter.RateLimit.create(3, Duration.ofSeconds(20)), 515 MultiRateLimiter.RateLimit.create(5, Duration.ofSeconds(42)), 516 MultiRateLimiter.RateLimit.create(6, Duration.ofSeconds(68)), 517 }; 518 519 // When #matchesCallFilter is called from the ringer, wait at most 520 // 3s to resolve the contacts. This timeout is required since 521 // ContactsProvider might take a long time to start up. 522 // 523 // Return STARRED_CONTACT when the timeout is hit in order to avoid 524 // missed calls in ZEN mode "Important". 525 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 526 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 527 ValidateNotificationPeople.STARRED_CONTACT; 528 529 /** notification_enqueue status value for a newly enqueued notification. */ 530 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 531 532 /** notification_enqueue status value for an existing notification. */ 533 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 534 535 /** notification_enqueue status value for an ignored notification. */ 536 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 537 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds 538 539 private static final long DELAY_FOR_ASSISTANT_TIME = 200; 540 541 private static final long DELAY_FORCE_REGROUP_TIME = 3000; 542 543 544 private static final String ACTION_NOTIFICATION_TIMEOUT = 545 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 546 private static final int REQUEST_CODE_TIMEOUT = 1; 547 private static final String SCHEME_TIMEOUT = "timeout"; 548 private static final String EXTRA_KEY = "key"; 549 550 private static final int NOTIFICATION_INSTANCE_ID_MAX = (1 << 13); 551 552 // States for the review permissions notification 553 static final int REVIEW_NOTIF_STATE_UNKNOWN = -1; 554 static final int REVIEW_NOTIF_STATE_SHOULD_SHOW = 0; 555 static final int REVIEW_NOTIF_STATE_USER_INTERACTED = 1; 556 static final int REVIEW_NOTIF_STATE_DISMISSED = 2; 557 static final int REVIEW_NOTIF_STATE_RESHOWN = 3; 558 559 // Action strings for review permissions notification 560 static final String REVIEW_NOTIF_ACTION_REMIND = "REVIEW_NOTIF_ACTION_REMIND"; 561 static final String REVIEW_NOTIF_ACTION_DISMISS = "REVIEW_NOTIF_ACTION_DISMISS"; 562 static final String REVIEW_NOTIF_ACTION_CANCELED = "REVIEW_NOTIF_ACTION_CANCELED"; 563 564 /** 565 * Apps that post custom toasts in the background will have those blocked. Apps can 566 * still post toasts created with 567 * {@link Toast#makeText(Context, CharSequence, int)} and its variants while 568 * in the background. 569 */ 570 @ChangeId 571 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) 572 private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; 573 574 /** 575 * Activity starts coming from broadcast receivers or services in response to notification and 576 * notification action clicks will be blocked for UX and performance reasons. Instead start the 577 * activity directly from the PendingIntent. 578 */ 579 @ChangeId 580 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) 581 private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L; 582 583 /** 584 * Activity starts coming from broadcast receivers or services in response to notification and 585 * notification action clicks will be blocked for UX and performance reasons for previously 586 * exempt role holders (browser). 587 */ 588 @ChangeId 589 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) 590 private static final long NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES = 227752274L; 591 592 /** 593 * Whether a notification listeners can understand new, more specific, cancellation reasons. 594 */ 595 @ChangeId 596 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) 597 private static final long NOTIFICATION_CANCELLATION_REASONS = 175319604L; 598 599 /** 600 * Rate limit showing toasts, on a per package basis. 601 * 602 * It limits the number of {@link Toast#show()} calls to prevent overburdening 603 * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed 604 * in a certain time frame will result in the toast being discarded. 605 */ 606 @ChangeId 607 @LoggingOnly 608 private static final long RATE_LIMIT_TOASTS = 174840628L; 609 610 /** 611 * Whether listeners understand the more specific reason provided for notification 612 * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL. 613 */ 614 @ChangeId 615 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) 616 private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L; 617 618 /** 619 * NO_CLEAR flag will be set for any media notification. 620 */ 621 @ChangeId 622 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 623 static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L; 624 625 /** 626 * App calls to {@link NotificationManager#setInterruptionFilter} and 627 * {@link NotificationManager#setNotificationPolicy} manage DND through the 628 * creation and activation of an implicit {@link AutomaticZenRule}. 629 */ 630 @ChangeId 631 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 632 static final long MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES = 308670109L; 633 634 private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30); 635 636 static final long NOTIFICATION_TTL = Duration.ofDays(3).toMillis(); 637 638 static final long NOTIFICATION_MAX_AGE_AT_POST = Duration.ofDays(14).toMillis(); 639 640 // Minium number of sparse groups for a package before autogrouping them 641 private static final int AUTOGROUP_SPARSE_GROUPS_AT_COUNT = 6; 642 643 private static final Duration ZEN_BROADCAST_DELAY = Duration.ofMillis(250); 644 645 private IActivityManager mAm; 646 private ActivityTaskManagerInternal mAtm; 647 private ActivityManager mActivityManager; 648 private ActivityManagerInternal mAmi; 649 @VisibleForTesting 650 IPackageManager mPackageManager; 651 private PackageManager mPackageManagerClient; 652 PackageManagerInternal mPackageManagerInternal; 653 private PermissionManager mPermissionManager; 654 private PermissionPolicyInternal mPermissionPolicyInternal; 655 656 // Can be null for wear 657 @Nullable StatusBarManagerInternal mStatusBar; 658 private WindowManagerInternal mWindowManagerInternal; 659 private AlarmManager mAlarmManager; 660 @VisibleForTesting 661 ICompanionDeviceManager mCompanionManager; 662 private AccessibilityManager mAccessibilityManager; 663 private DeviceIdleManager mDeviceIdleManager; 664 private IUriGrantsManager mUgm; 665 private UriGrantsManagerInternal mUgmInternal; 666 private volatile RoleObserver mRoleObserver; 667 private UserManager mUm; 668 private UserManagerInternal mUmInternal; 669 private IPlatformCompat mPlatformCompat; 670 private ShortcutHelper mShortcutHelper; 671 private PermissionHelper mPermissionHelper; 672 private UsageStatsManagerInternal mUsageStatsManagerInternal; 673 private TelecomManager mTelecomManager; 674 private PowerManager mPowerManager; 675 private PostNotificationTrackerFactory mPostNotificationTrackerFactory; 676 677 private LockPatternUtils mLockUtils; 678 679 final IBinder mForegroundToken = new Binder(); 680 @VisibleForTesting 681 WorkerHandler mHandler; 682 private final HandlerThread mRankingThread = new HandlerThread("ranker", 683 Process.THREAD_PRIORITY_BACKGROUND); 684 @FlaggedApi(Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST) 685 private Handler mBroadcastsHandler; 686 687 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects = 688 new SparseArray<>(); 689 private List<ComponentName> mEffectsSuppressors = new ArrayList<>(); 690 private int mListenerHints; // right now, all hints are global 691 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 692 693 private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver; 694 695 // used as a mutex for access to all active notifications & listeners 696 final Object mNotificationLock = new Object(); 697 @GuardedBy("mNotificationLock") 698 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>(); 699 @GuardedBy("mNotificationLock") 700 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>(); 701 @GuardedBy("mNotificationLock") 702 final ArrayMap<String, InlineReplyUriRecord> mInlineReplyRecordsByKey = new ArrayMap<>(); 703 @GuardedBy("mNotificationLock") 704 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>(); 705 @GuardedBy("mNotificationLock") 706 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); 707 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>(); 708 // set of uids for which toast rate limiting is disabled 709 @GuardedBy("mToastQueue") 710 private final Set<Integer> mToastRateLimitingDisabledUids = new ArraySet<>(); 711 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 712 713 // True if the toast that's on top of the queue is being shown at the moment. 714 @GuardedBy("mToastQueue") 715 private boolean mIsCurrentToastShown = false; 716 717 // Used for rate limiting toasts by package. 718 private MultiRateLimiter mToastRateLimiter; 719 720 private AppOpsManager mAppOps; 721 private UsageStatsManagerInternal mAppUsageStats; 722 private DevicePolicyManagerInternal mDpm; 723 private StatsManager mStatsManager; 724 private StatsPullAtomCallbackImpl mPullAtomCallback; 725 726 private Archive mArchive; 727 728 // Persistent storage for notification policy 729 private AtomicFile mPolicyFile; 730 731 private static final int DB_VERSION = 1; 732 733 734 private static final String ADSERVICES_MODULE_PKG_NAME = 735 "com.android.adservices"; 736 737 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 738 private static final String ATTR_VERSION = "version"; 739 740 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG = 741 "allow-secure-notifications-on-lockscreen"; 742 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value"; 743 744 @VisibleForTesting 745 RankingHelper mRankingHelper; 746 @VisibleForTesting 747 PreferencesHelper mPreferencesHelper; 748 749 private final UserProfiles mUserProfiles = new UserProfiles(); 750 private NotificationListeners mListeners; 751 @VisibleForTesting 752 NotificationAssistants mAssistants; 753 private ConditionProviders mConditionProviders; 754 private NotificationUsageStats mUsageStats; 755 private boolean mLockScreenAllowSecureNotifications = true; 756 final ArrayMap<String, ArrayMap<Integer, 757 RemoteCallbackList<ICallNotificationEventCallback>>> 758 mCallNotificationEventCallbacks = new ArrayMap<>(); 759 760 private static final int MY_UID = Process.myUid(); 761 private static final int MY_PID = Process.myPid(); 762 static final IBinder ALLOWLIST_TOKEN = new Binder(); 763 protected RankingHandler mRankingHandler; 764 private long mLastOverRateLogTime; 765 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 766 767 private boolean mRedactOtpNotifications = true; 768 769 private NotificationHistoryManager mHistoryManager; 770 protected SnoozeHelper mSnoozeHelper; 771 private TimeToLiveHelper mTtlHelper; 772 private GroupHelper mGroupHelper; 773 private int mAutoGroupAtCount; 774 private boolean mIsTelevision; 775 protected NotificationAttentionHelper mAttentionHelper; 776 777 private int mWarnRemoteViewsSizeBytes; 778 private int mStripRemoteViewsSizeBytes; 779 protected String[] mDefaultUnsupportedAdjustments; 780 781 @VisibleForTesting 782 protected boolean mShowReviewPermissionsNotification; 783 784 private MetricsLogger mMetricsLogger; 785 private NotificationChannelLogger mNotificationChannelLogger; 786 private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; 787 788 private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); 789 private NotificationRecordLogger mNotificationRecordLogger; 790 private InstanceIdSequence mNotificationInstanceIdSequence; 791 private Set<String> mMsgPkgsAllowedAsConvos = new HashSet(); 792 private String mDefaultSearchSelectorPkg; 793 794 // Broadcast intent receiver for notification permissions review-related intents 795 private ReviewNotificationPermissionsReceiver mReviewNotificationPermissionsReceiver; 796 797 private AppOpsManager.OnOpChangedListener mAppOpsListener; 798 799 private ModuleInfo mAdservicesModuleInfo; 800 801 static class Archive { 802 final SparseArray<Boolean> mEnabled; 803 final int mBufferSize; 804 final Object mBufferLock = new Object(); 805 @GuardedBy("mBufferLock") 806 final LinkedList<Pair<StatusBarNotification, Integer>> mBuffer; 807 Archive(int size)808 public Archive(int size) { 809 mBufferSize = size; 810 mBuffer = new LinkedList<>(); 811 mEnabled = new SparseArray<>(); 812 } 813 toString()814 public String toString() { 815 final StringBuilder sb = new StringBuilder(); 816 final int N = mBuffer.size(); 817 sb.append("Archive ("); 818 sb.append(N); 819 sb.append(" notification"); 820 sb.append((N == 1) ? ")" : "s)"); 821 return sb.toString(); 822 } 823 record(StatusBarNotification sbn, int reason)824 public void record(StatusBarNotification sbn, int reason) { 825 if (!mEnabled.get(sbn.getNormalizedUserId(), false)) { 826 return; 827 } 828 synchronized (mBufferLock) { 829 if (mBuffer.size() == mBufferSize) { 830 mBuffer.removeFirst(); 831 } 832 833 // We don't want to store the heavy bits of the notification in the archive, 834 // but other clients in the system process might be using the object, so we 835 // store a (lightened) copy. 836 mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason)); 837 } 838 } 839 descendingIterator()840 public Iterator<Pair<StatusBarNotification, Integer>> descendingIterator() { 841 return mBuffer.descendingIterator(); 842 } 843 getArray(UserManager um, int count, boolean includeSnoozed)844 public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) { 845 ArrayList<Integer> currentUsers = new ArrayList<>(); 846 currentUsers.add(USER_ALL); 847 Binder.withCleanCallingIdentity(() -> { 848 for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) { 849 currentUsers.add(user); 850 } 851 }); 852 synchronized (mBufferLock) { 853 if (count == 0) count = mBufferSize; 854 List<StatusBarNotification> a = new ArrayList(); 855 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); 856 int i = 0; 857 while (iter.hasNext() && i < count) { 858 Pair<StatusBarNotification, Integer> pair = iter.next(); 859 if (pair.second != REASON_SNOOZED || includeSnoozed) { 860 if (currentUsers.contains(pair.first.getUserId())) { 861 i++; 862 a.add(pair.first); 863 } 864 } 865 } 866 return a.toArray(new StatusBarNotification[a.size()]); 867 } 868 } 869 updateHistoryEnabled(@serIdInt int userId, boolean enabled)870 public void updateHistoryEnabled(@UserIdInt int userId, boolean enabled) { 871 mEnabled.put(userId, enabled); 872 873 if (!enabled) { 874 synchronized (mBufferLock) { 875 for (int i = mBuffer.size() - 1; i >= 0; i--) { 876 if (userId == mBuffer.get(i).first.getNormalizedUserId()) { 877 mBuffer.remove(i); 878 } 879 } 880 } 881 } 882 } 883 884 // Remove notifications with the specified user & channel ID. removeChannelNotifications(String pkg, @UserIdInt int userId, String channelId)885 public void removeChannelNotifications(String pkg, @UserIdInt int userId, 886 String channelId) { 887 synchronized (mBufferLock) { 888 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); 889 while (bufferIter.hasNext()) { 890 final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); 891 if (pair.first != null 892 && userId == pair.first.getNormalizedUserId() 893 && pkg != null && pkg.equals(pair.first.getPackageName()) 894 && pair.first.getNotification() != null 895 && Objects.equals(channelId, 896 pair.first.getNotification().getChannelId())) { 897 bufferIter.remove(); 898 } 899 } 900 } 901 } 902 903 // Removes all notifications with the specified user & package. removePackageNotifications(String pkg, @UserIdInt int userId)904 public void removePackageNotifications(String pkg, @UserIdInt int userId) { 905 synchronized (mBufferLock) { 906 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); 907 while (bufferIter.hasNext()) { 908 final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); 909 if (pair.first != null 910 && userId == pair.first.getNormalizedUserId() 911 && pkg != null && pkg.equals(pair.first.getPackageName()) 912 && pair.first.getNotification() != null) { 913 bufferIter.remove(); 914 } 915 } 916 } 917 } 918 dumpImpl(PrintWriter pw, @NonNull DumpFilter filter)919 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) { 920 synchronized (mBufferLock) { 921 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); 922 int i = 0; 923 while (iter.hasNext()) { 924 final StatusBarNotification sbn = iter.next().first; 925 if (filter != null && !filter.matches(sbn)) continue; 926 pw.println(" " + sbn); 927 if (++i >= 5) { 928 if (iter.hasNext()) pw.println(" ..."); 929 break; 930 } 931 } 932 } 933 } 934 } 935 loadDefaultApprovedServices(int userId)936 void loadDefaultApprovedServices(int userId) { 937 mListeners.loadDefaultsFromConfig(); 938 939 mConditionProviders.loadDefaultsFromConfig(); 940 941 mAssistants.loadDefaultsFromConfig(); 942 } 943 allowDefaultApprovedServices(int userId)944 protected void allowDefaultApprovedServices(int userId) { 945 ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents(); 946 for (int i = 0; i < defaultListeners.size(); i++) { 947 ComponentName cn = defaultListeners.valueAt(i); 948 allowNotificationListener(userId, cn); 949 } 950 951 allowDndPackages(userId); 952 953 setDefaultAssistantForUser(userId); 954 } 955 956 @VisibleForTesting allowDndPackages(int userId)957 void allowDndPackages(int userId) { 958 ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages(); 959 for (int i = 0; i < defaultDnds.size(); i++) { 960 allowDndPackage(userId, defaultDnds.valueAt(i)); 961 } 962 if (!isDNDMigrationDone(userId)) { 963 setDNDMigrationDone(userId); 964 } 965 } 966 967 @VisibleForTesting isDNDMigrationDone(int userId)968 boolean isDNDMigrationDone(int userId) { 969 return Secure.getIntForUser(getContext().getContentResolver(), 970 Secure.DND_CONFIGS_MIGRATED, 0, userId) == 1; 971 } 972 973 @VisibleForTesting setDNDMigrationDone(int userId)974 void setDNDMigrationDone(int userId) { 975 Secure.putIntForUser(getContext().getContentResolver(), 976 Secure.DND_CONFIGS_MIGRATED, 1, userId); 977 } 978 migrateDefaultNAS()979 protected void migrateDefaultNAS() { 980 final List<UserInfo> activeUsers = mUm.getUsers(); 981 for (UserInfo userInfo : activeUsers) { 982 int userId = userInfo.getUserHandle().getIdentifier(); 983 if (isNASMigrationDone(userId) || isProfileUser(userInfo)) { 984 continue; 985 } 986 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 987 if (allowedComponents.size() == 0) { // user set to none 988 Slog.d(TAG, "NAS Migration: user set to none, disable new NAS setting"); 989 setNASMigrationDone(userId); 990 mAssistants.clearDefaults(); 991 } else { 992 Slog.d(TAG, "Reset NAS setting and migrate to new default"); 993 resetAssistantUserSet(userId); 994 // migrate to new default and set migration done 995 mAssistants.resetDefaultAssistantsIfNecessary(); 996 } 997 } 998 } 999 1000 @VisibleForTesting setNASMigrationDone(int baseUserId)1001 void setNASMigrationDone(int baseUserId) { 1002 for (int profileId : mUm.getProfileIds(baseUserId, false)) { 1003 Secure.putIntForUser(getContext().getContentResolver(), 1004 Secure.NAS_SETTINGS_UPDATED, 1, profileId); 1005 } 1006 } 1007 1008 @VisibleForTesting isNASMigrationDone(int userId)1009 boolean isNASMigrationDone(int userId) { 1010 return (Secure.getIntForUser(getContext().getContentResolver(), 1011 Secure.NAS_SETTINGS_UPDATED, 0, userId) == 1); 1012 } 1013 isProfileUser(UserInfo userInfo)1014 boolean isProfileUser(UserInfo userInfo) { 1015 if (privateSpaceFlagsEnabled()) { 1016 return userInfo.isProfile() && hasParent(userInfo); 1017 } 1018 return userInfo.isManagedProfile() || userInfo.isCloneProfile(); 1019 } 1020 hasParent(UserInfo profile)1021 boolean hasParent(UserInfo profile) { 1022 return mUmInternal.getProfileParentId(profile.id) != profile.id; 1023 } 1024 setDefaultAssistantForUser(int userId)1025 protected void setDefaultAssistantForUser(int userId) { 1026 ArraySet<ComponentName> defaults = mAssistants.getDefaultComponents(); 1027 // We should have only one default assistant by default 1028 // allowAssistant should execute once in practice 1029 for (int i = 0; i < defaults.size(); i++) { 1030 ComponentName cn = defaults.valueAt(i); 1031 if (allowAssistant(userId, cn)) return; 1032 } 1033 } 1034 1035 /** 1036 * This method will update the flags and/or the icon of the summary. 1037 * It will set it to FLAG_ONGOING_EVENT if any of its group members 1038 * has the same flag. It will delete the flag otherwise. 1039 * It will update the summary notification icon if the group children's 1040 * icons are different. 1041 * @param userId user id of the autogroup summary 1042 * @param pkg package of the autogroup summary 1043 * @param groupKey group key of the autogroup summary 1044 * @param summaryAttr the new flags and/or icon & color for this summary 1045 * @param isAppForeground true if the app is currently in the foreground. 1046 */ 1047 @GuardedBy("mNotificationLock") updateAutobundledSummaryLocked(int userId, String pkg, String groupKey, NotificationAttributes summaryAttr, boolean isAppForeground)1048 protected void updateAutobundledSummaryLocked(int userId, String pkg, String groupKey, 1049 NotificationAttributes summaryAttr, boolean isAppForeground) { 1050 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 1051 if (summaries == null) { 1052 return; 1053 } 1054 final String autbundledGroupKey; 1055 if (notificationForceGrouping()) { 1056 autbundledGroupKey = groupKey; 1057 } else { 1058 autbundledGroupKey = pkg; 1059 } 1060 1061 String summaryKey = summaries.get(autbundledGroupKey); 1062 if (summaryKey == null) { 1063 return; 1064 } 1065 NotificationRecord summary = mNotificationsByKey.get(summaryKey); 1066 if (summary == null) { 1067 return; 1068 } 1069 1070 int oldFlags = summary.getSbn().getNotification().flags; 1071 1072 boolean attributesUpdated = 1073 !summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon()) 1074 || summaryAttr.iconColor != summary.getSbn().getNotification().color 1075 || summaryAttr.visibility != summary.getSbn().getNotification().visibility 1076 || summaryAttr.groupAlertBehavior != 1077 summary.getSbn().getNotification().getGroupAlertBehavior(); 1078 1079 if (notificationForceGrouping()) { 1080 summary.getNotification().flags |= Notification.FLAG_SILENT; 1081 if (!summary.getChannel().getId().equals(summaryAttr.channelId)) { 1082 NotificationChannel newChannel = mPreferencesHelper.getNotificationChannel(pkg, 1083 summary.getUid(), summaryAttr.channelId, false); 1084 if (newChannel != null) { 1085 summary.updateNotificationChannel(newChannel); 1086 attributesUpdated = true; 1087 } 1088 } 1089 } 1090 1091 if (oldFlags != summaryAttr.flags || attributesUpdated) { 1092 summary.getSbn().getNotification().flags = 1093 summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags; 1094 summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon); 1095 summary.getSbn().getNotification().color = summaryAttr.iconColor; 1096 summary.getSbn().getNotification().visibility = summaryAttr.visibility; 1097 summary.getSbn().getNotification() 1098 .setGroupAlertBehavior(summaryAttr.groupAlertBehavior); 1099 mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground, 1100 /* isAppProvided= */ false, mPostNotificationTrackerFactory.newTracker(null))); 1101 } 1102 } 1103 allowDndPackage(int userId, String packageName)1104 private void allowDndPackage(int userId, String packageName) { 1105 try { 1106 getBinderService().setNotificationPolicyAccessGrantedForUser(packageName, userId, true); 1107 } catch (RemoteException e) { 1108 e.printStackTrace(); 1109 } 1110 } 1111 allowNotificationListener(int userId, ComponentName cn)1112 private void allowNotificationListener(int userId, ComponentName cn) { 1113 1114 try { 1115 getBinderService().setNotificationListenerAccessGrantedForUser(cn, 1116 userId, true, true); 1117 } catch (RemoteException e) { 1118 e.printStackTrace(); 1119 } 1120 } 1121 allowAssistant(int userId, ComponentName candidate)1122 private boolean allowAssistant(int userId, ComponentName candidate) { 1123 Set<ComponentName> validAssistants = 1124 mAssistants.queryPackageForServices( 1125 null, 1126 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); 1127 if (candidate != null && validAssistants.contains(candidate)) { 1128 setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true, false); 1129 return true; 1130 } 1131 return false; 1132 } 1133 readPolicyXml(InputStream stream, boolean forRestore, int userId, @Nullable BackupRestoreEventLogger logger)1134 void readPolicyXml(InputStream stream, boolean forRestore, int userId, 1135 @Nullable BackupRestoreEventLogger logger) 1136 throws XmlPullParserException, NumberFormatException, IOException { 1137 final TypedXmlPullParser parser; 1138 if (forRestore) { 1139 parser = Xml.newFastPullParser(); 1140 parser.setInput(stream, StandardCharsets.UTF_8.name()); 1141 } else { 1142 parser = Xml.resolvePullParser(stream); 1143 } 1144 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY); 1145 boolean migratedManagedServices = false; 1146 UserInfo userInfo = mUmInternal.getUserInfo(userId); 1147 boolean ineligibleForManagedServices = forRestore && isProfileUser(userInfo); 1148 int outerDepth = parser.getDepth(); 1149 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 1150 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) { 1151 int successfulReads = 0; 1152 int unsuccessfulReads = 0; 1153 try { 1154 boolean loadedCorrectly = 1155 mZenModeHelper.readXml(parser, forRestore, userId, logger); 1156 if (loadedCorrectly) 1157 successfulReads++; 1158 else 1159 unsuccessfulReads++; 1160 } catch (Exception e) { 1161 Slog.wtf(TAG, "failed to read config", e); 1162 unsuccessfulReads++; 1163 } 1164 if (logger != null) { 1165 logger.logItemsRestored(DATA_TYPE_ZEN_CONFIG, successfulReads); 1166 if (unsuccessfulReads > 0) { 1167 logger.logItemsRestoreFailed( 1168 DATA_TYPE_ZEN_CONFIG, unsuccessfulReads, ERROR_XML_PARSING); 1169 } 1170 } 1171 1172 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){ 1173 mPreferencesHelper.readXml(parser, forRestore, userId); 1174 } 1175 if (mListeners.getConfig().xmlTag.equals(parser.getName())) { 1176 if (ineligibleForManagedServices) { 1177 continue; 1178 } 1179 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 1180 migratedManagedServices = true; 1181 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) { 1182 if (ineligibleForManagedServices) { 1183 continue; 1184 } 1185 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 1186 migratedManagedServices = true; 1187 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) { 1188 if (ineligibleForManagedServices) { 1189 continue; 1190 } 1191 mConditionProviders.readXml( 1192 parser, mAllowedManagedServicePackages, forRestore, userId); 1193 migratedManagedServices = true; 1194 } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) { 1195 mSnoozeHelper.readXml(parser, System.currentTimeMillis()); 1196 } 1197 if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) { 1198 if (forRestore && userId != USER_SYSTEM) { 1199 continue; 1200 } 1201 mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null, 1202 LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true); 1203 } 1204 } 1205 1206 if (!migratedManagedServices) { 1207 mListeners.migrateToXml(); 1208 mAssistants.migrateToXml(); 1209 mConditionProviders.migrateToXml(); 1210 handleSavePolicyFile(); 1211 } 1212 1213 mAssistants.resetDefaultAssistantsIfNecessary(); 1214 mPreferencesHelper.syncHasPriorityChannels(); 1215 } 1216 1217 @VisibleForTesting resetDefaultDndIfNecessary()1218 void resetDefaultDndIfNecessary() { 1219 boolean removed = false; 1220 final List<UserInfo> activeUsers = mUm.getAliveUsers(); 1221 for (UserInfo userInfo : activeUsers) { 1222 int userId = userInfo.getUserHandle().getIdentifier(); 1223 if (isDNDMigrationDone(userId)) { 1224 continue; 1225 } 1226 removed |= mConditionProviders.removeDefaultFromConfig(userId); 1227 mConditionProviders.resetDefaultFromConfig(); 1228 allowDndPackages(userId); 1229 } 1230 if (removed) { 1231 handleSavePolicyFile(); 1232 } 1233 } 1234 1235 @VisibleForTesting loadPolicyFile()1236 protected void loadPolicyFile() { 1237 if (DBG) Slog.d(TAG, "loadPolicyFile"); 1238 synchronized (mPolicyFile) { 1239 InputStream infile = null; 1240 try { 1241 infile = mPolicyFile.openRead(); 1242 readPolicyXml(infile, false /*forRestore*/, USER_ALL, null); 1243 1244 // We re-load the default dnd packages to allow the newly added and denined. 1245 final boolean isWatch = mPackageManagerClient.hasSystemFeature( 1246 PackageManager.FEATURE_WATCH); 1247 if (isWatch) { 1248 resetDefaultDndIfNecessary(); 1249 } 1250 } catch (FileNotFoundException e) { 1251 // No data yet 1252 // Load default managed services approvals 1253 loadDefaultApprovedServices(USER_SYSTEM); 1254 allowDefaultApprovedServices(USER_SYSTEM); 1255 } catch (IOException e) { 1256 Log.wtf(TAG, "Unable to read notification policy", e); 1257 } catch (NumberFormatException e) { 1258 Log.wtf(TAG, "Unable to parse notification policy", e); 1259 } catch (XmlPullParserException e) { 1260 Log.wtf(TAG, "Unable to parse notification policy", e); 1261 } finally { 1262 IoUtils.closeQuietly(infile); 1263 } 1264 } 1265 } 1266 1267 @VisibleForTesting handleSavePolicyFile()1268 protected void handleSavePolicyFile() { 1269 if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) { 1270 IoThread.getHandler().postDelayed(mSavePolicyFile, 250); 1271 } 1272 } 1273 privateSpaceFlagsEnabled()1274 protected static boolean privateSpaceFlagsEnabled() { 1275 return allowPrivateProfile() && android.multiuser.Flags.enablePrivateSpaceFeatures(); 1276 } 1277 1278 private final class SavePolicyFileRunnable implements Runnable { 1279 @Override run()1280 public void run() { 1281 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 1282 synchronized (mPolicyFile) { 1283 final FileOutputStream stream; 1284 try { 1285 stream = mPolicyFile.startWrite(); 1286 } catch (IOException e) { 1287 Slog.w(TAG, "Failed to save policy file", e); 1288 return; 1289 } 1290 1291 try { 1292 writePolicyXml(stream, false /*forBackup*/, USER_ALL, null); 1293 mPolicyFile.finishWrite(stream); 1294 } catch (IOException e) { 1295 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 1296 mPolicyFile.failWrite(stream); 1297 } 1298 } 1299 BackupManager.dataChanged(getContext().getPackageName()); 1300 } 1301 } 1302 writePolicyXml(OutputStream stream, boolean forBackup, int userId, BackupRestoreEventLogger logger)1303 void writePolicyXml(OutputStream stream, boolean forBackup, int userId, 1304 BackupRestoreEventLogger logger) throws IOException { 1305 final TypedXmlSerializer out; 1306 if (forBackup) { 1307 out = Xml.newFastSerializer(); 1308 out.setOutput(stream, StandardCharsets.UTF_8.name()); 1309 } else { 1310 out = Xml.resolveSerializer(stream); 1311 } 1312 out.startDocument(null, true); 1313 out.startTag(null, TAG_NOTIFICATION_POLICY); 1314 out.attributeInt(null, ATTR_VERSION, DB_VERSION); 1315 mZenModeHelper.writeXml(out, forBackup, null, userId, logger); 1316 mPreferencesHelper.writeXml(out, forBackup, userId); 1317 mListeners.writeXml(out, forBackup, userId); 1318 mAssistants.writeXml(out, forBackup, userId); 1319 mSnoozeHelper.writeXml(out); 1320 mConditionProviders.writeXml(out, forBackup, userId); 1321 if (!forBackup || userId == USER_SYSTEM) { 1322 writeSecureNotificationsPolicy(out); 1323 } 1324 out.endTag(null, TAG_NOTIFICATION_POLICY); 1325 out.endDocument(); 1326 } 1327 1328 @VisibleForTesting 1329 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 1330 1331 @Override 1332 public void prepareForPossibleShutdown() { 1333 mHistoryManager.triggerWriteToDisk(); 1334 } 1335 1336 @Override 1337 public void onSetDisabled(int status) { 1338 synchronized (mNotificationLock) { 1339 mAttentionHelper.updateDisableNotificationEffectsLocked(status); 1340 } 1341 } 1342 1343 @Override 1344 public void onClearAll(int callingUid, int callingPid, int userId) { 1345 synchronized (mNotificationLock) { 1346 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null, 1347 /*includeCurrentProfiles*/ true, FLAG_ONGOING_EVENT | FLAG_NO_CLEAR); 1348 } 1349 } 1350 1351 @Override 1352 public void onNotificationClick(int callingUid, int callingPid, String key, 1353 NotificationVisibility nv) { 1354 exitIdle(); 1355 synchronized (mNotificationLock) { 1356 NotificationRecord r = mNotificationsByKey.get(key); 1357 if (r == null) { 1358 Slog.w(TAG, "No notification with key: " + key); 1359 return; 1360 } 1361 final long now = System.currentTimeMillis(); 1362 MetricsLogger.action(r.getItemLogMaker() 1363 .setType(MetricsEvent.TYPE_ACTION) 1364 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 1365 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); 1366 mNotificationRecordLogger.log( 1367 NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, r); 1368 EventLogTags.writeNotificationClicked(key, 1369 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 1370 nv.rank, nv.count); 1371 1372 StatusBarNotification sbn = r.getSbn(); 1373 // Notifications should be cancelled on click if they have been lifetime extended, 1374 // regardless of presence or absence of FLAG_AUTO_CANCEL. 1375 if (lifetimeExtensionRefactor() 1376 && (sbn.getNotification().flags 1377 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) != 0) { 1378 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 1379 sbn.getId(), FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 1380 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 1381 | FLAG_BUBBLE, 1382 false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null); 1383 1384 } else { 1385 // Otherwise, only FLAG_AUTO_CANCEL notifications should be canceled on click. 1386 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 1387 sbn.getId(), FLAG_AUTO_CANCEL, 1388 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_BUBBLE, 1389 false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null); 1390 } 1391 nv.recycle(); 1392 reportUserInteraction(r); 1393 mAssistants.notifyAssistantNotificationClicked(r); 1394 } 1395 } 1396 1397 @Override 1398 public void onNotificationActionClick(int callingUid, int callingPid, String key, 1399 int actionIndex, Notification.Action action, NotificationVisibility nv, 1400 boolean generatedByAssistant) { 1401 exitIdle(); 1402 synchronized (mNotificationLock) { 1403 NotificationRecord r = mNotificationsByKey.get(key); 1404 if (r == null) { 1405 Slog.w(TAG, "No notification with key: " + key); 1406 return; 1407 } 1408 final long now = System.currentTimeMillis(); 1409 MetricsLogger.action(r.getLogMaker(now) 1410 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) 1411 .setType(MetricsEvent.TYPE_ACTION) 1412 .setSubtype(actionIndex) 1413 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 1414 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count) 1415 .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART, 1416 action.isContextual() ? 1 : 0) 1417 .addTaggedData( 1418 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1419 generatedByAssistant ? 1 : 0) 1420 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 1421 nv.location.toMetricsEventEnum())); 1422 mNotificationRecordLogger.log( 1423 NotificationRecordLogger.NotificationEvent.fromAction(actionIndex, 1424 generatedByAssistant, action.isContextual()), r); 1425 EventLogTags.writeNotificationActionClicked(key, 1426 action.actionIntent.getTarget().toString(), 1427 action.actionIntent.getIntent().toString(), actionIndex, 1428 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 1429 nv.rank, nv.count); 1430 nv.recycle(); 1431 reportUserInteraction(r); 1432 mAssistants.notifyAssistantActionClicked(r, action, generatedByAssistant); 1433 // Notifications that have been interacted with should no longer be lifetime 1434 // extended. 1435 if (lifetimeExtensionRefactor()) { 1436 // This cancellation should only work if 1437 // the notification still has FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY 1438 // We wait for 200 milliseconds before posting the cancel, to allow the app 1439 // time to update the notification in response instead. 1440 // If that update goes through, the notification won't have the lifetime 1441 // extended flag, and this cancellation will be dropped. 1442 mHandler.scheduleCancelNotification( 1443 new CancelNotificationRunnable( 1444 callingUid, 1445 callingPid, 1446 r.getSbn().getPackageName(), 1447 r.getSbn().getTag(), 1448 r.getSbn().getId(), 1449 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY /*=mustHaveFlags*/, 1450 FLAG_NO_DISMISS /*=mustNotHaveFlags*/, 1451 false /*=sendDelete*/, 1452 r.getUserId(), 1453 REASON_CLICK, 1454 -1 /*=rank*/, 1455 -1 /*=count*/, 1456 null /*=listener*/, 1457 SystemClock.elapsedRealtime()), 1458 200); 1459 } 1460 } 1461 } 1462 1463 @Override 1464 public void onNotificationClear(int callingUid, int callingPid, 1465 String pkg, int userId, String key, 1466 @NotificationStats.DismissalSurface int dismissalSurface, 1467 @NotificationStats.DismissalSentiment int dismissalSentiment, 1468 NotificationVisibility nv) { 1469 String tag = null; 1470 int id = 0; 1471 synchronized (mNotificationLock) { 1472 NotificationRecord r = mNotificationsByKey.get(key); 1473 if (r != null) { 1474 r.recordDismissalSurface(dismissalSurface); 1475 r.recordDismissalSentiment(dismissalSentiment); 1476 tag = r.getSbn().getTag(); 1477 id = r.getSbn().getId(); 1478 } 1479 } 1480 1481 int mustNotHaveFlags = FLAG_NO_DISMISS; 1482 cancelNotification(callingUid, callingPid, pkg, tag, id, 1483 /* mustHaveFlags= */ 0, 1484 /* mustNotHaveFlags= */ mustNotHaveFlags, 1485 /* sendDelete= */ true, 1486 userId, REASON_CANCEL, nv.rank, nv.count, /* listener= */ null); 1487 nv.recycle(); 1488 } 1489 1490 @Override 1491 public void onPanelRevealed(boolean clearEffects, int items) { 1492 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL); 1493 MetricsLogger.histogram(getContext(), "note_load", items); 1494 mNotificationRecordLogger.log( 1495 NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN); 1496 EventLogTags.writeNotificationPanelRevealed(items); 1497 if (clearEffects) { 1498 clearEffects(); 1499 } 1500 mAssistants.onPanelRevealed(items); 1501 } 1502 1503 @Override 1504 public void onPanelHidden() { 1505 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL); 1506 mNotificationRecordLogger.log( 1507 NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE); 1508 EventLogTags.writeNotificationPanelHidden(); 1509 mAssistants.onPanelHidden(); 1510 } 1511 1512 @Override 1513 public void clearEffects() { 1514 synchronized (mNotificationLock) { 1515 if (DBG) Slog.d(TAG, "clearEffects"); 1516 mAttentionHelper.clearAttentionEffects(); 1517 } 1518 } 1519 1520 @Override 1521 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, 1522 int id, int uid, int initialPid, String message, int userId) { 1523 final boolean fgService; 1524 final boolean uiJob; 1525 synchronized (mNotificationLock) { 1526 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 1527 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; 1528 uiJob = r != null && (r.getNotification().flags & FLAG_USER_INITIATED_JOB) != 0; 1529 } 1530 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 1531 REASON_ERROR, null); 1532 if (fgService || uiJob) { 1533 // Still crash for foreground services or user-initiated jobs, preventing the 1534 // not-crash behaviour abused by apps to give us a garbage notification and 1535 // silently start a fg service or user-initiated job. 1536 final int exceptionTypeId = fgService 1537 ? BadForegroundServiceNotificationException.TYPE_ID 1538 : BadUserInitiatedJobNotificationException.TYPE_ID; 1539 Binder.withCleanCallingIdentity( 1540 () -> mAm.crashApplicationWithType(uid, initialPid, pkg, -1, 1541 "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " 1542 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " 1543 + message, true /* force */, exceptionTypeId)); 1544 } 1545 } 1546 1547 @Override 1548 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 1549 NotificationVisibility[] noLongerVisibleKeys) { 1550 synchronized (mNotificationLock) { 1551 for (NotificationVisibility nv : newlyVisibleKeys) { 1552 NotificationRecord r = mNotificationsByKey.get(nv.key); 1553 if (r == null) continue; 1554 if (!r.isSeen()) { 1555 // Report to usage stats that notification was made visible 1556 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key); 1557 reportSeen(r); 1558 } 1559 r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger); 1560 mAssistants.notifyAssistantVisibilityChangedLocked(r, true); 1561 boolean isHun = (nv.location 1562 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP); 1563 // hasBeenVisiblyExpanded must be called after updating the expansion state of 1564 // the NotificationRecord to ensure the expansion state is up-to-date. 1565 if (isHun || r.hasBeenVisiblyExpanded()) { 1566 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum()); 1567 } 1568 maybeRecordInterruptionLocked(r); 1569 nv.recycle(); 1570 } 1571 // Note that we might receive this event after notifications 1572 // have already left the system, e.g. after dismissing from the 1573 // shade. Hence not finding notifications in 1574 // mNotificationsByKey is not an exceptional condition. 1575 for (NotificationVisibility nv : noLongerVisibleKeys) { 1576 NotificationRecord r = mNotificationsByKey.get(nv.key); 1577 if (r == null) continue; 1578 r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger); 1579 mAssistants.notifyAssistantVisibilityChangedLocked(r, false); 1580 nv.recycle(); 1581 } 1582 } 1583 } 1584 1585 @Override 1586 public void onNotificationExpansionChanged(String key, 1587 boolean userAction, boolean expanded, int notificationLocation) { 1588 synchronized (mNotificationLock) { 1589 NotificationRecord r = mNotificationsByKey.get(key); 1590 if (r != null) { 1591 r.stats.onExpansionChanged(userAction, expanded); 1592 // hasBeenVisiblyExpanded must be called after updating the expansion state of 1593 // the NotificationRecord to ensure the expansion state is up-to-date. 1594 if (r.hasBeenVisiblyExpanded()) { 1595 logSmartSuggestionsVisible(r, notificationLocation); 1596 } 1597 if (userAction) { 1598 MetricsLogger.action(r.getItemLogMaker() 1599 .setType(expanded ? MetricsEvent.TYPE_DETAIL 1600 : MetricsEvent.TYPE_COLLAPSE)); 1601 mNotificationRecordLogger.log( 1602 NotificationRecordLogger.NotificationEvent.fromExpanded(expanded, 1603 userAction), 1604 r); 1605 } 1606 if (expanded && userAction) { 1607 r.recordExpanded(); 1608 reportUserInteraction(r); 1609 } 1610 mAssistants.notifyAssistantExpansionChangedLocked( 1611 r.getSbn(), r.getNotificationType(), userAction, expanded); 1612 } 1613 } 1614 } 1615 1616 @Override 1617 public void onNotificationDirectReplied(String key) { 1618 exitIdle(); 1619 String packageName = null; 1620 final int packageImportance; 1621 synchronized (mNotificationLock) { 1622 NotificationRecord r = mNotificationsByKey.get(key); 1623 if (r != null) { 1624 packageName = r.getSbn().getPackageName(); 1625 } 1626 } 1627 if (lifetimeExtensionRefactor() && packageName != null) { 1628 packageImportance = getPackageImportanceWithIdentity(packageName); 1629 } else { 1630 packageImportance = IMPORTANCE_NONE; 1631 } 1632 synchronized (mNotificationLock) { 1633 NotificationRecord r = mNotificationsByKey.get(key); 1634 if (r != null) { 1635 // If the notification is already marked as lifetime extended before we record 1636 // the new direct reply, there must have been a previous lifetime extension 1637 // event, and the app has already cancelled the notification, or does not 1638 // respond to direct replies with updates. So we need to update System UI 1639 // immediately. 1640 if (lifetimeExtensionRefactor()) { 1641 // We need to reset this to allow the notif to be updated again. 1642 r.setCanceledAfterLifetimeExtension(false); 1643 maybeNotifySystemUiListenerLifetimeExtendedLocked(r, 1644 r.getSbn().getPackageName(), packageImportance); 1645 } 1646 1647 r.recordDirectReplied(); 1648 mMetricsLogger.write(r.getLogMaker() 1649 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION) 1650 .setType(MetricsEvent.TYPE_ACTION)); 1651 mNotificationRecordLogger.log( 1652 NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED, 1653 r); 1654 reportUserInteraction(r); 1655 mAssistants.notifyAssistantNotificationDirectReplyLocked(r); 1656 } 1657 } 1658 } 1659 1660 @Override 1661 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, 1662 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) { 1663 synchronized (mNotificationLock) { 1664 NotificationRecord r = mNotificationsByKey.get(key); 1665 if (r != null) { 1666 r.setNumSmartRepliesAdded(smartReplyCount); 1667 r.setNumSmartActionsAdded(smartActionCount); 1668 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 1669 r.setEditChoicesBeforeSending(editBeforeSending); 1670 } 1671 } 1672 } 1673 1674 @Override 1675 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply, 1676 int notificationLocation, boolean modifiedBeforeSending) { 1677 String packageName = null; 1678 final int packageImportance; 1679 synchronized (mNotificationLock) { 1680 NotificationRecord r = mNotificationsByKey.get(key); 1681 if (r != null) { 1682 packageName = r.getSbn().getPackageName(); 1683 } 1684 } 1685 if (lifetimeExtensionRefactor() && packageName != null) { 1686 packageImportance = getPackageImportanceWithIdentity(packageName); 1687 } else { 1688 packageImportance = IMPORTANCE_NONE; 1689 } 1690 synchronized (mNotificationLock) { 1691 NotificationRecord r = mNotificationsByKey.get(key); 1692 if (r != null) { 1693 // If the notification is already marked as lifetime extended before we record 1694 // the new direct reply, there must have been a previous lifetime extension 1695 // event, and the app has already cancelled the notification, or does not 1696 // respond to direct replies with updates. So we need to update System UI 1697 // immediately. 1698 if (lifetimeExtensionRefactor()) { 1699 // We need to reset this to allow the notif to be updated again. 1700 r.setCanceledAfterLifetimeExtension(false); 1701 maybeNotifySystemUiListenerLifetimeExtendedLocked(r, 1702 r.getSbn().getPackageName(), packageImportance); 1703 } 1704 1705 r.recordSmartReplied(); 1706 LogMaker logMaker = r.getLogMaker() 1707 .setCategory(MetricsEvent.SMART_REPLY_ACTION) 1708 .setSubtype(replyIndex) 1709 .addTaggedData( 1710 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1711 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1712 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 1713 notificationLocation) 1714 .addTaggedData( 1715 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1716 r.getEditChoicesBeforeSending() ? 1 : 0) 1717 .addTaggedData( 1718 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING, 1719 modifiedBeforeSending ? 1 : 0); 1720 mMetricsLogger.write(logMaker); 1721 mNotificationRecordLogger.log( 1722 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED, 1723 r); 1724 // Treat clicking on a smart reply as a user interaction. 1725 reportUserInteraction(r); 1726 mAssistants.notifyAssistantSuggestedReplySent( 1727 r.getSbn(), r.getNotificationType(), reply, 1728 r.getSuggestionsGeneratedByAssistant()); 1729 } 1730 } 1731 } 1732 1733 @Override 1734 public void onNotificationSettingsViewed(String key) { 1735 synchronized (mNotificationLock) { 1736 NotificationRecord r = mNotificationsByKey.get(key); 1737 if (r != null) { 1738 r.recordViewedSettings(); 1739 } 1740 } 1741 } 1742 1743 @Override 1744 public void onNotificationBubbleChanged(String key, boolean isBubble, int bubbleFlags) { 1745 synchronized (mNotificationLock) { 1746 NotificationRecord r = mNotificationsByKey.get(key); 1747 if (r != null) { 1748 if (!isBubble) { 1749 // This happens if the user has dismissed the bubble but the notification 1750 // is still active in the shade, enqueuing would create a bubble since 1751 // the notification is technically allowed. Flip the flag so that 1752 // apps querying noMan will know that their notification is not showing 1753 // as a bubble. 1754 r.getNotification().flags &= ~FLAG_BUBBLE; 1755 r.setFlagBubbleRemoved(true); 1756 } else { 1757 // Enqueue will trigger resort & if the flag is allowed to be true it'll 1758 // be applied there. 1759 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 1760 r.setFlagBubbleRemoved(false); 1761 if (r.getNotification().getBubbleMetadata() != null) { 1762 r.getNotification().getBubbleMetadata().setFlags(bubbleFlags); 1763 } 1764 // Force isAppForeground true here, because for sysui's purposes we 1765 // want to adjust the flag behaviour. 1766 mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), 1767 r, /* isAppForeground= */ true , /* isAppProvided= */ false, 1768 mPostNotificationTrackerFactory.newTracker(null))); 1769 } 1770 } 1771 } 1772 } 1773 1774 @Override 1775 public void onBubbleMetadataFlagChanged(String key, int flags) { 1776 synchronized (mNotificationLock) { 1777 NotificationRecord r = mNotificationsByKey.get(key); 1778 if (r != null) { 1779 Notification.BubbleMetadata data = r.getNotification().getBubbleMetadata(); 1780 if (data == null) { 1781 // No data, do nothing 1782 return; 1783 } 1784 1785 if (flags != data.getFlags()) { 1786 int changedFlags = data.getFlags() ^ flags; 1787 if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) { 1788 // Suppress notification flag changed, clear any effects 1789 mAttentionHelper.clearEffectsLocked(key); 1790 } 1791 data.setFlags(flags); 1792 // Shouldn't alert again just because of a flag change. 1793 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 1794 // Force isAppForeground true here, because for sysui's purposes we 1795 // want to be able to adjust the flag behaviour. 1796 mHandler.post( 1797 new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r, 1798 /* foreground= */ true, /* isAppProvided= */ false, 1799 mPostNotificationTrackerFactory.newTracker(null))); 1800 } 1801 } 1802 } 1803 } 1804 1805 /** 1806 * Grant permission to read the specified URI to the package specified in the 1807 * NotificationRecord associated with the given key. The callingUid represents the UID of 1808 * SystemUI from which this method is being called. 1809 * 1810 * For this to work, SystemUI must have permission to read the URI when running under the 1811 * user associated with the NotificationRecord, and this grant will fail when trying 1812 * to grant URI permissions across users. 1813 */ 1814 @Override 1815 public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, 1816 String packageName, int callingUid) { 1817 synchronized (mNotificationLock) { 1818 InlineReplyUriRecord r = mInlineReplyRecordsByKey.get(key); 1819 if (r == null) { 1820 InlineReplyUriRecord newRecord = new InlineReplyUriRecord( 1821 mUgmInternal.newUriPermissionOwner("INLINE_REPLY:" + key), 1822 user, 1823 packageName, 1824 key); 1825 r = newRecord; 1826 mInlineReplyRecordsByKey.put(key, r); 1827 } 1828 IBinder owner = r.getPermissionOwner(); 1829 int uid = callingUid; 1830 int userId = r.getUserId(); 1831 if (UserHandle.getUserId(uid) != userId) { 1832 try { 1833 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 1834 if (pkgs == null) { 1835 Log.e(TAG, "Cannot grant uri permission to unknown UID: " 1836 + callingUid); 1837 } 1838 final String pkg = pkgs[0]; // Get the SystemUI package 1839 // Find the UID for SystemUI for the correct user 1840 uid = mPackageManager.getPackageUid(pkg, 0, userId); 1841 } catch (RemoteException re) { 1842 Log.e(TAG, "Cannot talk to package manager", re); 1843 } 1844 } 1845 r.addUri(uri); 1846 grantUriPermission(owner, uri, uid, r.getPackageName(), userId); 1847 } 1848 } 1849 1850 @Override 1851 /** 1852 * Clears inline URI permission grants by destroying the permission owner for the specified 1853 * notification. 1854 */ 1855 public void clearInlineReplyUriPermissions(String key, int callingUid) { 1856 synchronized (mNotificationLock) { 1857 InlineReplyUriRecord uriRecord = mInlineReplyRecordsByKey.get(key); 1858 if (uriRecord != null) { 1859 destroyPermissionOwner(uriRecord.getPermissionOwner(), uriRecord.getUserId(), 1860 "INLINE_REPLY: " + uriRecord.getKey()); 1861 mInlineReplyRecordsByKey.remove(key); 1862 } 1863 } 1864 } 1865 1866 @Override 1867 public void onNotificationFeedbackReceived(String key, Bundle feedback) { 1868 exitIdle(); 1869 synchronized (mNotificationLock) { 1870 NotificationRecord r = mNotificationsByKey.get(key); 1871 if (r == null) { 1872 if (DBG) Slog.w(TAG, "No notification with key: " + key); 1873 return; 1874 } 1875 mAssistants.notifyAssistantFeedbackReceived(r, feedback); 1876 } 1877 } 1878 }; 1879 applyNotificationUpdateForUser(final int userId, NotificationUpdate notificationUpdate)1880 private void applyNotificationUpdateForUser(final int userId, 1881 NotificationUpdate notificationUpdate) { 1882 applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId, 1883 notificationUpdate); 1884 } 1885 applyNotificationUpdateForUid(final int userId, @NonNull final String pkg, NotificationUpdate notificationUpdate)1886 private void applyNotificationUpdateForUid(final int userId, @NonNull final String pkg, 1887 NotificationUpdate notificationUpdate) { 1888 applyUpdateForNotificationsFiltered((r) -> 1889 r.getUserId() == userId 1890 && Objects.equals(r.getSbn().getPackageName(), pkg), 1891 notificationUpdate); 1892 } 1893 applyNotificationUpdateForUserAndChannelType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate)1894 private void applyNotificationUpdateForUserAndChannelType(final int userId, 1895 final @Types int bundleType, NotificationUpdate notificationUpdate) { 1896 final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType); 1897 applyUpdateForNotificationsFiltered((r) -> 1898 r.getUserId() == userId 1899 && r.getChannel() != null 1900 && Objects.equals(bundleChannelId, r.getChannel().getId()), 1901 notificationUpdate); 1902 } 1903 applyNotificationUpdateForUserAndType(final int userId, final @Types int bundleType, NotificationUpdate notificationUpdate)1904 private void applyNotificationUpdateForUserAndType(final int userId, 1905 final @Types int bundleType, NotificationUpdate notificationUpdate) { 1906 applyUpdateForNotificationsFiltered( 1907 (r) -> r.getUserId() == userId && r.getBundleType() == bundleType, 1908 notificationUpdate); 1909 } 1910 1911 @VisibleForTesting unclassifyNotification(final String key)1912 void unclassifyNotification(final String key) { 1913 if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { 1914 return; 1915 } 1916 synchronized (mNotificationLock) { 1917 NotificationRecord r = mNotificationsByKey.get(key); 1918 if (r == null) { 1919 return; 1920 } 1921 unclassifyNotificationLocked(r, true); 1922 } 1923 } 1924 1925 @VisibleForTesting reclassifyNotification(String key)1926 void reclassifyNotification(String key) { 1927 if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { 1928 return; 1929 } 1930 synchronized (mNotificationLock) { 1931 NotificationRecord r = mNotificationsByKey.get(key); 1932 if (r == null) { 1933 return; 1934 } 1935 reclassifyNotificationLocked(r, true); 1936 } 1937 } 1938 1939 @GuardedBy("mNotificationLock") unclassifyNotificationLocked(@onNull final NotificationRecord r, boolean isPosted)1940 private void unclassifyNotificationLocked(@NonNull final NotificationRecord r, 1941 boolean isPosted) { 1942 if (DBG) { 1943 Slog.v(TAG, "unclassifyNotification: " + r); 1944 } 1945 // Only NotificationRecord's mChannel is updated when bundled, the Notification 1946 // mChannelId will always be the original channel. 1947 String origChannelId = r.getNotification().getChannelId(); 1948 NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( 1949 r.getSbn().getPackageName(), r.getUid(), origChannelId, false); 1950 String currChannelId = r.getChannel().getId(); 1951 boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId); 1952 if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) { 1953 r.updateNotificationChannel(originalChannel); 1954 mGroupHelper.onNotificationUnbundled(r, 1955 GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey)); 1956 } 1957 } 1958 1959 @GuardedBy("mNotificationLock") unsummarizeNotificationLocked(@onNull final NotificationRecord r, boolean isPosted)1960 private void unsummarizeNotificationLocked(@NonNull final NotificationRecord r, 1961 boolean isPosted) { 1962 Bundle signals = new Bundle(); 1963 signals.putString(KEY_SUMMARIZATION, null); 1964 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 1965 r.getSbn().getUserId()); 1966 r.addAdjustment(adjustment); 1967 mRankingHandler.requestSort(); 1968 1969 } 1970 1971 @GuardedBy("mNotificationLock") reclassifyNotificationLocked(@onNull final NotificationRecord r, final boolean isPosted)1972 private void reclassifyNotificationLocked(@NonNull final NotificationRecord r, 1973 final boolean isPosted) { 1974 if (DBG) { 1975 Slog.v(TAG, "reclassifyNotification: " + r); 1976 } 1977 1978 boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains( 1979 r.getChannel().getId()); 1980 if (r.getBundleType() != Adjustment.TYPE_OTHER && !isClassified) { 1981 final Bundle classifBundle = new Bundle(); 1982 classifBundle.putInt(KEY_TYPE, r.getBundleType()); 1983 Adjustment adj = new Adjustment(r.getSbn().getPackageName(), r.getKey(), 1984 classifBundle, "reclassify", r.getUserId()); 1985 applyAdjustmentLocked(r, adj, isPosted); 1986 mRankingHandler.requestSort(); 1987 } else { 1988 if (DBG) { 1989 Slog.w(TAG, "Can't reclassify. No valid bundle type or already bundled: " + r); 1990 } 1991 } 1992 } 1993 1994 /** 1995 * Given a filter and a function to update a notification record, runs that function on all 1996 * enqueued and posted notifications that match the filter 1997 */ applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter, NotificationUpdate notificationUpdate)1998 private void applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter, 1999 NotificationUpdate notificationUpdate) { 2000 synchronized (mNotificationLock) { 2001 for (int i = 0; i < mEnqueuedNotifications.size(); i++) { 2002 final NotificationRecord r = mEnqueuedNotifications.get(i); 2003 if (filter.test(r)) { 2004 notificationUpdate.apply(r, false); 2005 } 2006 } 2007 2008 for (int i = 0; i < mNotificationList.size(); i++) { 2009 final NotificationRecord r = mNotificationList.get(i); 2010 if (filter.test(r)) { 2011 notificationUpdate.apply(r, true); 2012 } 2013 } 2014 } 2015 } 2016 2017 private interface NotificationUpdate { apply(NotificationRecord r, boolean isPosted)2018 void apply(NotificationRecord r, boolean isPosted); 2019 } 2020 2021 NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() { 2022 @Nullable 2023 @Override 2024 public NotificationRecord getNotificationByKey(String key) { 2025 synchronized (mNotificationLock) { 2026 return mNotificationsByKey.get(key); 2027 } 2028 } 2029 2030 @Override 2031 @FlaggedApi(Flags.FLAG_ALL_NOTIFS_NEED_TTL) 2032 public void timeoutNotification(String key) { 2033 boolean foundNotification = false; 2034 int uid = 0; 2035 int pid = 0; 2036 String packageName = null; 2037 String tag = null; 2038 int id = 0; 2039 int userId = 0; 2040 2041 synchronized (mNotificationLock) { 2042 NotificationRecord record = findNotificationByKeyLocked(key); 2043 if (record != null) { 2044 foundNotification = true; 2045 uid = record.getUid(); 2046 pid = record.getSbn().getInitialPid(); 2047 packageName = record.getSbn().getPackageName(); 2048 tag = record.getSbn().getTag(); 2049 id = record.getSbn().getId(); 2050 userId = record.getUserId(); 2051 } 2052 } 2053 if (foundNotification) { 2054 if (lifetimeExtensionRefactor()) { 2055 cancelNotification(uid, pid, packageName, tag, id, 0, 2056 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 2057 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 2058 true, userId, REASON_TIMEOUT, null); 2059 } else { 2060 cancelNotification(uid, pid, packageName, tag, id, 0, 2061 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, 2062 true, userId, REASON_TIMEOUT, null); 2063 } 2064 } 2065 } 2066 }; 2067 2068 @VisibleForTesting logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)2069 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) { 2070 // If the newly visible notification has smart suggestions 2071 // then log that the user has seen them. 2072 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0) 2073 && !r.hasSeenSmartReplies()) { 2074 r.setSeenSmartReplies(true); 2075 LogMaker logMaker = r.getLogMaker() 2076 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE) 2077 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT, 2078 r.getNumSmartRepliesAdded()) 2079 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT, 2080 r.getNumSmartActionsAdded()) 2081 .addTaggedData( 2082 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 2083 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 2084 // The fields in the NotificationVisibility.NotificationLocation enum map 2085 // directly to the fields in the MetricsEvent.NotificationLocation enum. 2086 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation) 2087 .addTaggedData( 2088 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 2089 r.getEditChoicesBeforeSending() ? 1 : 0); 2090 mMetricsLogger.write(logMaker); 2091 mNotificationRecordLogger.log( 2092 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLY_VISIBLE, 2093 r); 2094 } 2095 } 2096 logSensitiveAdjustmentReceived(boolean hasPosted, boolean hasSensitiveContent, int lifespanMs)2097 protected void logSensitiveAdjustmentReceived(boolean hasPosted, 2098 boolean hasSensitiveContent, int lifespanMs) { 2099 FrameworkStatsLog.write(FrameworkStatsLog.SENSITIVE_NOTIFICATION_REDACTION, hasPosted, 2100 hasSensitiveContent, lifespanMs); 2101 } 2102 logClassificationChannelAdjustmentReceived(NotificationRecord r, boolean hasPosted, int classification)2103 protected void logClassificationChannelAdjustmentReceived(NotificationRecord r, 2104 boolean hasPosted, 2105 int classification) { 2106 // Note that this value of isAlerting does not fully indicate whether a notif 2107 // would make a sound or HUN on device; it is an approximation for metrics. 2108 boolean isAlerting = r.getChannel().getImportance() >= IMPORTANCE_DEFAULT; 2109 int instanceId = r.getSbn().getInstanceId() == null 2110 ? 0 : r.getSbn().getInstanceId().getId(); 2111 2112 FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_CLASSIFICATION, 2113 hasPosted, isAlerting, classification, 2114 r.getLifespanMs(System.currentTimeMillis()), 2115 NotificationReportedEvent.NOTIFICATION_ADJUSTED.getId(), 2116 instanceId, r.getUid()); 2117 } 2118 2119 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { 2120 @Override 2121 public void onReceive(Context context, Intent intent) { 2122 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 2123 // update system notification channels 2124 SystemNotificationChannels.createAll(context); 2125 mZenModeHelper.updateZenRulesOnLocaleChange(); 2126 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser()); 2127 } 2128 } 2129 }; 2130 2131 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() { 2132 @Override 2133 public void onReceive(Context context, Intent intent) { 2134 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) { 2135 try { 2136 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); 2137 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); 2138 int restoredFromSdkInt = intent.getIntExtra( 2139 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0); 2140 mListeners.onSettingRestored( 2141 element, newValue, restoredFromSdkInt, getSendingUserId()); 2142 mConditionProviders.onSettingRestored( 2143 element, newValue, restoredFromSdkInt, getSendingUserId()); 2144 } catch (Exception e) { 2145 Slog.wtf(TAG, "Cannot restore managed services from settings", e); 2146 } 2147 } 2148 } 2149 }; 2150 2151 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() { 2152 @Override 2153 public void onReceive(Context context, Intent intent) { 2154 String action = intent.getAction(); 2155 if (action == null) { 2156 return; 2157 } 2158 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) { 2159 final NotificationRecord record; 2160 // TODO: b/323013410 - Record should be cloned instead of used directly. 2161 synchronized (mNotificationLock) { 2162 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY)); 2163 } 2164 if (record != null) { 2165 if (lifetimeExtensionRefactor()) { 2166 cancelNotification(record.getSbn().getUid(), 2167 record.getSbn().getInitialPid(), 2168 record.getSbn().getPackageName(), record.getSbn().getTag(), 2169 record.getSbn().getId(), 0, 2170 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 2171 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 2172 true, record.getUserId(), REASON_TIMEOUT, null); 2173 } else { 2174 cancelNotification(record.getSbn().getUid(), 2175 record.getSbn().getInitialPid(), 2176 record.getSbn().getPackageName(), record.getSbn().getTag(), 2177 record.getSbn().getId(), 0, 2178 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, 2179 true, record.getUserId(), REASON_TIMEOUT, null); 2180 } 2181 } 2182 } 2183 } 2184 }; 2185 2186 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 2187 @Override 2188 public void onReceive(Context context, Intent intent) { 2189 String action = intent.getAction(); 2190 if (action == null) { 2191 return; 2192 } 2193 2194 boolean queryRemove = false; 2195 boolean packageChanged = false; 2196 boolean cancelNotifications = true; 2197 boolean hideNotifications = false; 2198 boolean unhideNotifications = false; 2199 int reason = REASON_PACKAGE_CHANGED; 2200 2201 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 2202 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 2203 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 2204 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 2205 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) 2206 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED) 2207 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED) 2208 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 2209 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 2210 USER_ALL); 2211 String pkgList[] = null; 2212 int uidList[] = null; 2213 boolean removingPackage = queryRemove && 2214 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 2215 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage); 2216 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 2217 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 2218 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 2219 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 2220 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 2221 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 2222 cancelNotifications = false; 2223 hideNotifications = true; 2224 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { 2225 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 2226 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 2227 cancelNotifications = false; 2228 unhideNotifications = true; 2229 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 2230 final int distractionRestrictions = 2231 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS, 2232 PackageManager.RESTRICTION_NONE); 2233 if ((distractionRestrictions 2234 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) { 2235 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 2236 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 2237 cancelNotifications = false; 2238 hideNotifications = true; 2239 } else { 2240 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 2241 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 2242 cancelNotifications = false; 2243 unhideNotifications = true; 2244 } 2245 } else { 2246 Uri uri = intent.getData(); 2247 if (uri == null) { 2248 return; 2249 } 2250 String pkgName = uri.getSchemeSpecificPart(); 2251 if (pkgName == null) { 2252 return; 2253 } 2254 if (packageChanged) { 2255 // We cancel notifications for packages which have just been disabled 2256 try { 2257 final int enabled = mPackageManager.getApplicationEnabledSetting( 2258 pkgName, 2259 changeUserId != USER_ALL ? changeUserId : 2260 USER_SYSTEM); 2261 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 2262 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 2263 cancelNotifications = false; 2264 } 2265 } catch (IllegalArgumentException e) { 2266 // Package doesn't exist; probably racing with uninstall. 2267 // cancelNotifications is already true, so nothing to do here. 2268 if (DBG) { 2269 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 2270 } 2271 } catch (RemoteException e) { 2272 // Failed to talk to PackageManagerService Should never happen! 2273 } 2274 } 2275 pkgList = new String[]{pkgName}; 2276 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 2277 } 2278 if (pkgList != null && (pkgList.length > 0)) { 2279 if (cancelNotifications) { 2280 for (String pkgName : pkgList) { 2281 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, 2282 changeUserId, reason); 2283 } 2284 } else if (hideNotifications && uidList != null && (uidList.length > 0)) { 2285 hideNotificationsForPackages(pkgList, uidList); 2286 } else if (unhideNotifications && uidList != null && (uidList.length > 0)) { 2287 unhideNotificationsForPackages(pkgList, uidList); 2288 } 2289 } 2290 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList); 2291 } 2292 } 2293 }; 2294 2295 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 2296 @Override 2297 public void onReceive(Context context, Intent intent) { 2298 String action = intent.getAction(); 2299 2300 if (action.equals(Intent.ACTION_USER_STOPPED)) { 2301 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 2302 if (userHandle >= 0) { 2303 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle, 2304 REASON_USER_STOPPED); 2305 mConditionProviders.onUserStopped(userHandle); 2306 mListeners.onUserStopped(userHandle); 2307 mAssistants.onUserStopped(userHandle); 2308 } 2309 } else if ( 2310 isProfileUnavailable(action)) { 2311 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 2312 if (userHandle >= 0) { 2313 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle, 2314 REASON_PROFILE_TURNED_OFF); 2315 mSnoozeHelper.clearData(userHandle); 2316 } 2317 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 2318 if (!Flags.useSsmUserSwitchSignal()) { 2319 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2320 mUserProfiles.updateCache(context); 2321 if (!mUserProfiles.isProfileUser(userId, context)) { 2322 // reload per-user settings 2323 mSettingsObserver.update(null); 2324 // Refresh managed services 2325 mConditionProviders.onUserSwitched(userId); 2326 mListeners.onUserSwitched(userId); 2327 mZenModeHelper.onUserSwitched(userId); 2328 mPreferencesHelper.syncHasPriorityChannels(); 2329 } 2330 // assistant is the only thing that cares about managed profiles specifically 2331 mAssistants.onUserSwitched(userId); 2332 } 2333 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 2334 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2335 if (userId != USER_NULL) { 2336 mUserProfiles.updateCache(context); 2337 if (!mUserProfiles.isProfileUser(userId, context)) { 2338 allowDefaultApprovedServices(userId); 2339 } 2340 mHistoryManager.onUserAdded(userId); 2341 mSettingsObserver.update(null, userId); 2342 } 2343 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 2344 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2345 mUserProfiles.updateCache(context); 2346 mZenModeHelper.onUserRemoved(userId); 2347 mPreferencesHelper.onUserRemoved(userId); 2348 mListeners.onUserRemoved(userId); 2349 mConditionProviders.onUserRemoved(userId); 2350 mAssistants.onUserRemoved(userId); 2351 mHistoryManager.onUserRemoved(userId); 2352 mPreferencesHelper.syncHasPriorityChannels(); 2353 handleSavePolicyFile(); 2354 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { 2355 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2356 mUserProfiles.updateCache(context); 2357 mAssistants.onUserUnlocked(userId); 2358 if (!mUserProfiles.isProfileUser(userId, context)) { 2359 mConditionProviders.onUserUnlocked(userId); 2360 mListeners.onUserUnlocked(userId); 2361 } 2362 } 2363 } 2364 2365 private boolean isProfileUnavailable(String action) { 2366 return privateSpaceFlagsEnabled() ? 2367 action.equals(Intent.ACTION_PROFILE_UNAVAILABLE) : 2368 action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 2369 } 2370 }; 2371 2372 private final class SettingsObserver extends ContentObserver { 2373 private final Uri NOTIFICATION_BADGING_URI 2374 = Secure.getUriFor(Secure.NOTIFICATION_BADGING); 2375 private final Uri NOTIFICATION_BUBBLES_URI 2376 = Secure.getUriFor(Secure.NOTIFICATION_BUBBLES); 2377 private final Uri NOTIFICATION_RATE_LIMIT_URI 2378 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); 2379 private final Uri NOTIFICATION_HISTORY_ENABLED 2380 = Secure.getUriFor(Secure.NOTIFICATION_HISTORY_ENABLED); 2381 private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI 2382 = Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS); 2383 private final Uri LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS 2384 = Secure.getUriFor( 2385 Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS); 2386 private final Uri LOCK_SCREEN_SHOW_NOTIFICATIONS 2387 = Secure.getUriFor(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS); 2388 private final Uri SHOW_NOTIFICATION_SNOOZE 2389 = Secure.getUriFor(Secure.SHOW_NOTIFICATION_SNOOZE); 2390 private final Uri REDACT_OTP_NOTIFICATIONS = Settings.Global.getUriFor( 2391 Settings.Global.REDACT_OTP_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 2392 SettingsObserver(Handler handler)2393 SettingsObserver(Handler handler) { 2394 super(handler); 2395 } 2396 observe()2397 void observe() { 2398 ContentResolver resolver = getContext().getContentResolver(); 2399 resolver.registerContentObserver(NOTIFICATION_BADGING_URI, 2400 false, this, USER_ALL); 2401 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, 2402 false, this, USER_ALL); 2403 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI, 2404 false, this, USER_ALL); 2405 resolver.registerContentObserver(NOTIFICATION_HISTORY_ENABLED, 2406 false, this, USER_ALL); 2407 resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI, 2408 false, this, USER_ALL); 2409 2410 resolver.registerContentObserver(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 2411 false, this, USER_ALL); 2412 resolver.registerContentObserver(LOCK_SCREEN_SHOW_NOTIFICATIONS, 2413 false, this, USER_ALL); 2414 2415 resolver.registerContentObserver(SHOW_NOTIFICATION_SNOOZE, 2416 false, this, USER_ALL); 2417 resolver.registerContentObserver(REDACT_OTP_NOTIFICATIONS, 2418 false, this, USER_ALL); 2419 2420 update(null); 2421 } 2422 destroy()2423 void destroy() { 2424 getContext().getContentResolver().unregisterContentObserver(this); 2425 } 2426 onChange(boolean selfChange, Uri uri, int userId)2427 @Override public void onChange(boolean selfChange, Uri uri, int userId) { 2428 update(uri); 2429 } 2430 update(Uri uri)2431 public void update(Uri uri) { 2432 ContentResolver resolver = getContext().getContentResolver(); 2433 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) { 2434 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver, 2435 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate); 2436 } 2437 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { 2438 mPreferencesHelper.updateBadgingEnabled(); 2439 } 2440 if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) { 2441 mPreferencesHelper.updateBubblesEnabled(); 2442 } 2443 if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) { 2444 for (UserInfo userInfo : mUm.getUsers()) { 2445 update(uri, userInfo.id); 2446 } 2447 } 2448 if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) { 2449 mPreferencesHelper.updateMediaNotificationFilteringEnabled(); 2450 } 2451 if (uri == null || LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS.equals(uri)) { 2452 mPreferencesHelper.updateLockScreenPrivateNotifications(); 2453 } 2454 if (uri == null || LOCK_SCREEN_SHOW_NOTIFICATIONS.equals(uri)) { 2455 mPreferencesHelper.updateLockScreenShowNotifications(); 2456 } 2457 if (SHOW_NOTIFICATION_SNOOZE.equals(uri)) { 2458 final boolean snoozeEnabled = Secure.getIntForUser(resolver, 2459 Secure.SHOW_NOTIFICATION_SNOOZE, 0, UserHandle.USER_CURRENT) 2460 != 0; 2461 if (!snoozeEnabled) { 2462 unsnoozeAll(); 2463 } 2464 } 2465 if (REDACT_OTP_NOTIFICATIONS.equals(uri)) { 2466 mRedactOtpNotifications = Settings.Global.getInt(resolver, 2467 Settings.Global.REDACT_OTP_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS, 1) != 0; 2468 } 2469 } 2470 update(Uri uri, int userId)2471 public void update(Uri uri, int userId) { 2472 ContentResolver resolver = getContext().getContentResolver(); 2473 if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) { 2474 mArchive.updateHistoryEnabled(userId, 2475 Secure.getIntForUser(resolver, 2476 Secure.NOTIFICATION_HISTORY_ENABLED, 0, 2477 userId) == 1); 2478 // note: this setting is also handled in NotificationHistoryManager 2479 } 2480 } 2481 } 2482 2483 private SettingsObserver mSettingsObserver; 2484 protected ZenModeHelper mZenModeHelper; 2485 2486 protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { 2487 2488 SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray(); 2489 StrongAuthTracker(Context context)2490 StrongAuthTracker(Context context) { 2491 super(context); 2492 } 2493 containsFlag(int haystack, int needle)2494 private boolean containsFlag(int haystack, int needle) { 2495 return (haystack & needle) != 0; 2496 } 2497 2498 // Return whether the user is in lockdown mode. 2499 // If the flag is not set, we assume the user is not in lockdown. isInLockDownMode(int userId)2500 public boolean isInLockDownMode(int userId) { 2501 return mUserInLockDownMode.get(userId, false); 2502 } 2503 2504 @Override onStrongAuthRequiredChanged(int userId)2505 public synchronized void onStrongAuthRequiredChanged(int userId) { 2506 boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId), 2507 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 2508 2509 // Nothing happens if the lockdown mode of userId keeps the same. 2510 if (userInLockDownModeNext == isInLockDownMode(userId)) { 2511 return; 2512 } 2513 2514 // When the lockdown mode is changed, we perform the following steps. 2515 // If the userInLockDownModeNext is true, all the function calls to 2516 // notifyPostedLocked and notifyRemovedLocked will not be executed. 2517 // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked 2518 // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked. 2519 // So we shall call cancelNotificationsWhenEnterLockDownMode before 2520 // we set mUserInLockDownMode as true. 2521 // On the other hand, if the userInLockDownModeNext is false, we shall call 2522 // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode 2523 if (userInLockDownModeNext) { 2524 cancelNotificationsWhenEnterLockDownMode(userId); 2525 } 2526 2527 mUserInLockDownMode.put(userId, userInLockDownModeNext); 2528 2529 if (!userInLockDownModeNext) { 2530 postNotificationsWhenExitLockDownMode(userId); 2531 } 2532 } 2533 } 2534 2535 private StrongAuthTracker mStrongAuthTracker; 2536 NotificationManagerService(Context context)2537 public NotificationManagerService(Context context) { 2538 this(context, 2539 new NotificationRecordLoggerImpl(), 2540 new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX)); 2541 } 2542 2543 @VisibleForTesting NotificationManagerService(Context context, NotificationRecordLogger notificationRecordLogger, InstanceIdSequence notificationInstanceIdSequence)2544 public NotificationManagerService(Context context, 2545 NotificationRecordLogger notificationRecordLogger, 2546 InstanceIdSequence notificationInstanceIdSequence) { 2547 super(context); 2548 mNotificationRecordLogger = notificationRecordLogger; 2549 mNotificationInstanceIdSequence = notificationInstanceIdSequence; 2550 Notification.processAllowlistToken = ALLOWLIST_TOKEN; 2551 } 2552 2553 // TODO - replace these methods with new fields in the VisibleForTesting constructor 2554 @VisibleForTesting setStrongAuthTracker(StrongAuthTracker strongAuthTracker)2555 void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) { 2556 mStrongAuthTracker = strongAuthTracker; 2557 } 2558 2559 @VisibleForTesting setLockPatternUtils(LockPatternUtils lockUtils)2560 void setLockPatternUtils(LockPatternUtils lockUtils) { 2561 mLockUtils = lockUtils; 2562 } 2563 2564 @VisibleForTesting getShortcutHelper()2565 ShortcutHelper getShortcutHelper() { 2566 return mShortcutHelper; 2567 } 2568 2569 @VisibleForTesting setShortcutHelper(ShortcutHelper helper)2570 void setShortcutHelper(ShortcutHelper helper) { 2571 mShortcutHelper = helper; 2572 } 2573 2574 @VisibleForTesting getNotificationRecordCount()2575 int getNotificationRecordCount() { 2576 synchronized (mNotificationLock) { 2577 int count = mNotificationList.size() + mNotificationsByKey.size() 2578 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size(); 2579 // subtract duplicates 2580 for (NotificationRecord posted : mNotificationList) { 2581 if (mNotificationsByKey.containsKey(posted.getKey())) { 2582 count--; 2583 } 2584 if (posted.getSbn().isGroup() && posted.getNotification().isGroupSummary()) { 2585 count--; 2586 } 2587 } 2588 2589 return count; 2590 } 2591 } 2592 2593 @VisibleForTesting clearNotifications()2594 void clearNotifications() { 2595 synchronized (mNotificationLock) { 2596 mEnqueuedNotifications.clear(); 2597 mNotificationList.clear(); 2598 mNotificationsByKey.clear(); 2599 mSummaryByGroupKey.clear(); 2600 } 2601 } 2602 2603 @VisibleForTesting addNotification(NotificationRecord r)2604 void addNotification(NotificationRecord r) { 2605 synchronized (mNotificationLock) { 2606 mNotificationList.add(r); 2607 mNotificationsByKey.put(r.getSbn().getKey(), r); 2608 if (r.getSbn().isGroup()) { 2609 mSummaryByGroupKey.put(r.getGroupKey(), r); 2610 } 2611 } 2612 } 2613 2614 @VisibleForTesting addEnqueuedNotification(NotificationRecord r)2615 void addEnqueuedNotification(NotificationRecord r) { 2616 synchronized (mNotificationLock) { 2617 mEnqueuedNotifications.add(r); 2618 } 2619 } 2620 2621 @VisibleForTesting getNotificationRecord(String key)2622 NotificationRecord getNotificationRecord(String key) { 2623 synchronized (mNotificationLock) { 2624 return mNotificationsByKey.get(key); 2625 } 2626 } 2627 2628 @VisibleForTesting setHandler(WorkerHandler handler)2629 void setHandler(WorkerHandler handler) { 2630 mHandler = handler; 2631 } 2632 2633 @VisibleForTesting setRankingHelper(RankingHelper rankingHelper)2634 void setRankingHelper(RankingHelper rankingHelper) { 2635 mRankingHelper = rankingHelper; 2636 } 2637 2638 @VisibleForTesting setPreferencesHelper(PreferencesHelper prefHelper)2639 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; } 2640 2641 @VisibleForTesting setZenHelper(ZenModeHelper zenHelper)2642 void setZenHelper(ZenModeHelper zenHelper) { 2643 mZenModeHelper = zenHelper; 2644 } 2645 2646 @VisibleForTesting setAttentionHelper(NotificationAttentionHelper nah)2647 void setAttentionHelper(NotificationAttentionHelper nah) { 2648 mAttentionHelper = nah; 2649 } 2650 2651 @VisibleForTesting setIsTelevision(boolean isTelevision)2652 void setIsTelevision(boolean isTelevision) { 2653 mIsTelevision = isTelevision; 2654 } 2655 2656 @VisibleForTesting setTelecomManager(TelecomManager tm)2657 void setTelecomManager(TelecomManager tm) { 2658 mTelecomManager = tm; 2659 } 2660 2661 // TODO: All tests should use this init instead of the one-off setters above. 2662 @VisibleForTesting init(WorkerHandler handler, RankingHandler rankingHandler, Handler broadcastsHandler, 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, ActivityManagerInternal ami, MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper, UsageStatsManagerInternal usageStatsManagerInternal, TelecomManager telecomManager, NotificationChannelLogger channelLogger, SystemUiSystemPropertiesFlags.FlagResolver flagResolver, PermissionManager permissionManager, PowerManager powerManager, PostNotificationTrackerFactory postNotificationTrackerFactory)2663 void init(WorkerHandler handler, RankingHandler rankingHandler, Handler broadcastsHandler, 2664 IPackageManager packageManager, PackageManager packageManagerClient, 2665 LightsManager lightsManager, NotificationListeners notificationListeners, 2666 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, 2667 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, 2668 NotificationUsageStats usageStats, AtomicFile policyFile, 2669 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, 2670 ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats, 2671 DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, 2672 UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, 2673 NotificationHistoryManager historyManager, StatsManager statsManager, 2674 ActivityManagerInternal ami, 2675 MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper, 2676 UsageStatsManagerInternal usageStatsManagerInternal, 2677 TelecomManager telecomManager, NotificationChannelLogger channelLogger, 2678 SystemUiSystemPropertiesFlags.FlagResolver flagResolver, 2679 PermissionManager permissionManager, PowerManager powerManager, 2680 PostNotificationTrackerFactory postNotificationTrackerFactory) { 2681 mHandler = handler; 2682 if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { 2683 mBroadcastsHandler = broadcastsHandler; 2684 } 2685 Resources resources = getContext().getResources(); 2686 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), 2687 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, 2688 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); 2689 2690 mAccessibilityManager = 2691 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 2692 mAm = am; 2693 mAtm = atm; 2694 mAtm.setBackgroundActivityStartCallback(new NotificationTrampolineCallback()); 2695 mUgm = ugm; 2696 mUgmInternal = ugmInternal; 2697 mPackageManager = packageManager; 2698 mPackageManagerClient = packageManagerClient; 2699 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 2700 mPermissionManager = permissionManager; 2701 mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class); 2702 mUmInternal = LocalServices.getService(UserManagerInternal.class); 2703 mUsageStatsManagerInternal = usageStatsManagerInternal; 2704 mAppOps = appOps; 2705 mAppUsageStats = appUsageStats; 2706 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 2707 mCompanionManager = companionManager; 2708 mActivityManager = activityManager; 2709 mAmi = ami; 2710 mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class); 2711 mDpm = dpm; 2712 mUm = userManager; 2713 mTelecomManager = telecomManager; 2714 mPowerManager = powerManager; 2715 mPostNotificationTrackerFactory = postNotificationTrackerFactory; 2716 mPlatformCompat = IPlatformCompat.Stub.asInterface( 2717 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); 2718 2719 mStrongAuthTracker = new StrongAuthTracker(getContext()); 2720 String[] extractorNames; 2721 try { 2722 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 2723 } catch (Resources.NotFoundException e) { 2724 extractorNames = new String[0]; 2725 } 2726 mUsageStats = usageStats; 2727 mMetricsLogger = new MetricsLogger(); 2728 mRankingHandler = rankingHandler; 2729 mConditionProviders = conditionProviders; 2730 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(), 2731 mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient)); 2732 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 2733 @Override 2734 public void onConfigChanged() { 2735 handleSavePolicyFile(); 2736 } 2737 2738 @Override 2739 void onZenModeChanged() { 2740 Binder.withCleanCallingIdentity(() -> { 2741 sendRegisteredOnlyBroadcast(ACTION_INTERRUPTION_FILTER_CHANGED); 2742 getContext().sendBroadcastAsUser( 2743 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 2744 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 2745 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); 2746 synchronized (mNotificationLock) { 2747 updateInterruptionFilterLocked(); 2748 } 2749 mRankingHandler.requestSort(); 2750 }); 2751 } 2752 2753 @Override 2754 void onPolicyChanged(Policy newPolicy) { 2755 Binder.withCleanCallingIdentity(() -> { 2756 Intent intent = new Intent(ACTION_NOTIFICATION_POLICY_CHANGED); 2757 intent.putExtra(EXTRA_NOTIFICATION_POLICY, newPolicy); 2758 sendRegisteredOnlyBroadcast(intent); 2759 mRankingHandler.requestSort(); 2760 }); 2761 } 2762 2763 @Override 2764 void onConsolidatedPolicyChanged(Policy newConsolidatedPolicy) { 2765 Binder.withCleanCallingIdentity(() -> { 2766 Intent intent = new Intent(ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED); 2767 intent.putExtra(EXTRA_NOTIFICATION_POLICY, newConsolidatedPolicy); 2768 sendRegisteredOnlyBroadcast(intent); 2769 2770 mRankingHandler.requestSort(); 2771 }); 2772 } 2773 2774 @Override 2775 void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) { 2776 Binder.withCleanCallingIdentity(() -> { 2777 Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED); 2778 intent.setPackage(pkg); 2779 intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id); 2780 intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status); 2781 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2782 getContext().sendBroadcastAsUser(intent, UserHandle.of(userId)); 2783 }); 2784 } 2785 }); 2786 mPermissionHelper = permissionHelper; 2787 mNotificationChannelLogger = channelLogger; 2788 mUserProfiles.updateCache(getContext()); 2789 mPreferencesHelper = new PreferencesHelper(getContext(), 2790 mPackageManagerClient, 2791 mRankingHandler, 2792 mZenModeHelper, 2793 mPermissionHelper, 2794 mPermissionManager, 2795 mNotificationChannelLogger, 2796 mAppOps, 2797 mUserProfiles, 2798 mShowReviewPermissionsNotification, 2799 Clock.systemUTC()); 2800 mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, 2801 mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat, groupHelper); 2802 mSnoozeHelper = snoozeHelper; 2803 mGroupHelper = groupHelper; 2804 mHistoryManager = historyManager; 2805 if (Flags.allNotifsNeedTtl()) { 2806 mTtlHelper = new TimeToLiveHelper(mNotificationManagerPrivate, getContext()); 2807 } 2808 2809 // This is a ManagedServices object that keeps track of the listeners. 2810 mListeners = notificationListeners; 2811 2812 // This is a MangedServices object that keeps track of the assistant. 2813 mAssistants = notificationAssistants; 2814 2815 // Needs to be set before loadPolicyFile 2816 mAllowedManagedServicePackages = this::canUseManagedServices; 2817 2818 mPolicyFile = policyFile; 2819 loadPolicyFile(); 2820 mStatusBar = getLocalService(StatusBarManagerInternal.class); 2821 if (mStatusBar != null) { 2822 mStatusBar.setNotificationDelegate(mNotificationDelegate); 2823 } 2824 2825 mZenModeHelper.initZenMode(); 2826 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 2827 2828 mSettingsObserver = new SettingsObserver(mHandler); 2829 2830 mArchive = new Archive(resources.getInteger( 2831 R.integer.config_notificationServiceArchiveSize)); 2832 2833 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK) 2834 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION); 2835 2836 mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( 2837 com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); 2838 2839 mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger( 2840 com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes); 2841 mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( 2842 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); 2843 2844 mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource( 2845 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos)); 2846 mDefaultSearchSelectorPkg = getContext().getString(getContext().getResources() 2847 .getIdentifier("config_defaultSearchSelectorPackageName", "string", "android")); 2848 2849 mFlagResolver = flagResolver; 2850 2851 mStatsManager = statsManager; 2852 2853 mToastRateLimiter = toastRateLimiter; 2854 2855 mAttentionHelper = new NotificationAttentionHelper(getContext(), mNotificationLock, 2856 lightsManager, mAccessibilityManager, mPackageManagerClient, userManager, 2857 usageStats, mNotificationManagerPrivate, mZenModeHelper, flagResolver); 2858 2859 // register for various Intents. 2860 // If this is called within a test, make sure to unregister the intent receivers by 2861 // calling onDestroy() 2862 IntentFilter filter = new IntentFilter(); 2863 filter.addAction(Intent.ACTION_USER_STOPPED); 2864 if (!Flags.useSsmUserSwitchSignal()) { 2865 filter.addAction(Intent.ACTION_USER_SWITCHED); 2866 } 2867 filter.addAction(Intent.ACTION_USER_ADDED); 2868 filter.addAction(Intent.ACTION_USER_REMOVED); 2869 filter.addAction(Intent.ACTION_USER_UNLOCKED); 2870 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 2871 if (privateSpaceFlagsEnabled()){ 2872 filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE); 2873 } 2874 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null); 2875 2876 IntentFilter pkgFilter = new IntentFilter(); 2877 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 2878 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 2879 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 2880 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 2881 pkgFilter.addDataScheme("package"); 2882 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 2883 null); 2884 2885 IntentFilter suspendedPkgFilter = new IntentFilter(); 2886 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 2887 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); 2888 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 2889 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, 2890 suspendedPkgFilter, null, null); 2891 2892 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 2893 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 2894 null); 2895 2896 if (!Flags.allNotifsNeedTtl()) { 2897 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT); 2898 timeoutFilter.addDataScheme(SCHEME_TIMEOUT); 2899 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter, 2900 Context.RECEIVER_EXPORTED_UNAUDITED); 2901 } 2902 2903 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED); 2904 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter); 2905 2906 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED); 2907 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter); 2908 2909 mReviewNotificationPermissionsReceiver = new ReviewNotificationPermissionsReceiver(); 2910 getContext().registerReceiver(mReviewNotificationPermissionsReceiver, 2911 ReviewNotificationPermissionsReceiver.getFilter(), 2912 Context.RECEIVER_NOT_EXPORTED); 2913 2914 mAppOpsListener = new AppOpsManager.OnOpChangedInternalListener() { 2915 @Override 2916 public void onOpChanged(@NonNull String op, @NonNull String packageName, 2917 int userId) { 2918 mHandler.post( 2919 () -> handleNotificationPermissionChange(packageName, userId)); 2920 } 2921 }; 2922 2923 mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsListener); 2924 } 2925 2926 /** 2927 * Cleanup broadcast receivers change listeners. 2928 */ onDestroy()2929 public void onDestroy() { 2930 if (mIntentReceiver != null) { 2931 getContext().unregisterReceiver(mIntentReceiver); 2932 } 2933 if (mPackageIntentReceiver != null) { 2934 getContext().unregisterReceiver(mPackageIntentReceiver); 2935 } 2936 if (Flags.allNotifsNeedTtl()) { 2937 if (mTtlHelper != null) { 2938 mTtlHelper.destroy(); 2939 } 2940 } else { 2941 if (mNotificationTimeoutReceiver != null) { 2942 getContext().unregisterReceiver(mNotificationTimeoutReceiver); 2943 } 2944 } 2945 if (mRestoreReceiver != null) { 2946 getContext().unregisterReceiver(mRestoreReceiver); 2947 } 2948 if (mLocaleChangeReceiver != null) { 2949 getContext().unregisterReceiver(mLocaleChangeReceiver); 2950 } 2951 if (mSettingsObserver != null) { 2952 mSettingsObserver.destroy(); 2953 } 2954 if (mRoleObserver != null) { 2955 mRoleObserver.destroy(); 2956 } 2957 if (mShortcutHelper != null) { 2958 mShortcutHelper.destroy(); 2959 } 2960 if (mStatsManager != null) { 2961 mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES); 2962 mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES); 2963 mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES); 2964 mStatsManager.clearPullAtomCallback(NOTIFICATION_BUNDLE_PREFERENCES); 2965 mStatsManager.clearPullAtomCallback(DND_MODE_RULE); 2966 } 2967 if (mAppOps != null) { 2968 mAppOps.stopWatchingMode(mAppOpsListener); 2969 } 2970 if (mAlarmManager != null) { 2971 mAlarmManager.cancelAll(); 2972 } 2973 } 2974 getStringArrayResource(int key)2975 protected String[] getStringArrayResource(int key) { 2976 return getContext().getResources().getStringArray(key); 2977 } 2978 2979 @Override onStart()2980 public void onStart() { 2981 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> { 2982 try { 2983 if (DBG) { 2984 Slog.d(TAG, "Reposting " + r.getKey() + " " + muteOnReturn); 2985 } 2986 enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), 2987 r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), 2988 r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn, 2989 /* byForegroundService= */ false, /* isAppProvided= */ false); 2990 } catch (Exception e) { 2991 Slog.e(TAG, "Cannot un-snooze notification", e); 2992 } 2993 }, mUserProfiles); 2994 2995 final File systemDir = new File(Environment.getDataDirectory(), "system"); 2996 mRankingThread.start(); 2997 2998 WorkerHandler handler = new WorkerHandler(Looper.myLooper()); 2999 3000 Handler broadcastsHandler; 3001 if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { 3002 HandlerThread broadcastsThread = new HandlerThread("NMS Broadcasts"); 3003 broadcastsThread.start(); 3004 broadcastsHandler = new Handler(broadcastsThread.getLooper()); 3005 } else { 3006 broadcastsHandler = null; 3007 } 3008 3009 mShowReviewPermissionsNotification = getContext().getResources().getBoolean( 3010 R.bool.config_notificationReviewPermissions); 3011 3012 mDefaultUnsupportedAdjustments = getContext().getResources().getStringArray( 3013 R.array.config_notificationDefaultUnsupportedAdjustments); 3014 3015 init(handler, new RankingHandlerWorker(mRankingThread.getLooper()), broadcastsHandler, 3016 AppGlobals.getPackageManager(), getContext().getPackageManager(), 3017 getLocalService(LightsManager.class), 3018 new NotificationListeners(getContext(), mNotificationLock, mUserProfiles, 3019 AppGlobals.getPackageManager()), 3020 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles, 3021 AppGlobals.getPackageManager()), 3022 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()), 3023 null /*CDM is not initialized yet*/, snoozeHelper, 3024 new NotificationUsageStats(getContext()), 3025 new AtomicFile(new File( 3026 systemDir, "notification_policy.xml"), "notification-policy"), 3027 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE), 3028 getGroupHelper(), ActivityManager.getService(), 3029 LocalServices.getService(ActivityTaskManagerInternal.class), 3030 LocalServices.getService(UsageStatsManagerInternal.class), 3031 LocalServices.getService(DevicePolicyManagerInternal.class), 3032 UriGrantsManager.getService(), 3033 LocalServices.getService(UriGrantsManagerInternal.class), 3034 getContext().getSystemService(AppOpsManager.class), 3035 getContext().getSystemService(UserManager.class), 3036 new NotificationHistoryManager(getContext(), handler), 3037 mStatsManager = (StatsManager) getContext().getSystemService( 3038 Context.STATS_MANAGER), 3039 LocalServices.getService(ActivityManagerInternal.class), 3040 createToastRateLimiter(), new PermissionHelper(getContext(), 3041 AppGlobals.getPackageManager(), 3042 AppGlobals.getPermissionManager()), 3043 LocalServices.getService(UsageStatsManagerInternal.class), 3044 getContext().getSystemService(TelecomManager.class), 3045 new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(), 3046 getContext().getSystemService(PermissionManager.class), 3047 getContext().getSystemService(PowerManager.class), 3048 new PostNotificationTrackerFactory() {}); 3049 3050 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, 3051 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); 3052 publishLocalService(NotificationManagerInternal.class, mInternalService); 3053 } 3054 registerNotificationPreferencesPullers()3055 private void registerNotificationPreferencesPullers() { 3056 mPullAtomCallback = new StatsPullAtomCallbackImpl(); 3057 mStatsManager.setPullAtomCallback( 3058 PACKAGE_NOTIFICATION_PREFERENCES, 3059 null, // use default PullAtomMetadata values 3060 ConcurrentUtils.DIRECT_EXECUTOR, 3061 mPullAtomCallback 3062 ); 3063 mStatsManager.setPullAtomCallback( 3064 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES, 3065 null, // use default PullAtomMetadata values 3066 ConcurrentUtils.DIRECT_EXECUTOR, 3067 mPullAtomCallback 3068 ); 3069 mStatsManager.setPullAtomCallback( 3070 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES, 3071 null, // use default PullAtomMetadata values 3072 ConcurrentUtils.DIRECT_EXECUTOR, 3073 mPullAtomCallback 3074 ); 3075 mStatsManager.setPullAtomCallback( 3076 DND_MODE_RULE, 3077 null, // use default PullAtomMetadata values 3078 ConcurrentUtils.DIRECT_EXECUTOR, 3079 mPullAtomCallback 3080 ); 3081 mStatsManager.setPullAtomCallback( 3082 NOTIFICATION_BUNDLE_PREFERENCES, 3083 null, // use default PullAtomMetadata values 3084 ConcurrentUtils.DIRECT_EXECUTOR, 3085 mPullAtomCallback 3086 ); 3087 } 3088 3089 private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { 3090 @Override onPullAtom(int atomTag, List<StatsEvent> data)3091 public int onPullAtom(int atomTag, List<StatsEvent> data) { 3092 switch (atomTag) { 3093 case PACKAGE_NOTIFICATION_PREFERENCES: 3094 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: 3095 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: 3096 case NOTIFICATION_BUNDLE_PREFERENCES: 3097 case DND_MODE_RULE: 3098 return pullNotificationStates(atomTag, data); 3099 default: 3100 throw new UnsupportedOperationException("Unknown tagId=" + atomTag); 3101 } 3102 } 3103 } 3104 pullNotificationStates(int atomTag, List<StatsEvent> data)3105 private int pullNotificationStates(int atomTag, List<StatsEvent> data) { 3106 switch(atomTag) { 3107 case PACKAGE_NOTIFICATION_PREFERENCES: 3108 if (notificationClassificationUi()) { 3109 mPreferencesHelper.pullPackagePreferencesStats(data, 3110 getAllUsersNotificationPermissions(), 3111 new ArrayMap<>()); 3112 } else { 3113 mPreferencesHelper.pullPackagePreferencesStats(data, 3114 getAllUsersNotificationPermissions()); 3115 } 3116 break; 3117 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: 3118 mPreferencesHelper.pullPackageChannelPreferencesStats(data); 3119 break; 3120 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: 3121 mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data); 3122 break; 3123 case NOTIFICATION_BUNDLE_PREFERENCES: 3124 if (notificationClassification() && notificationClassificationUi()) { 3125 mAssistants.pullBundlePreferencesStats(data); 3126 } 3127 break; 3128 case DND_MODE_RULE: 3129 mZenModeHelper.pullRules(data); 3130 break; 3131 } 3132 return StatsManager.PULL_SUCCESS; 3133 } 3134 getGroupHelper()3135 private GroupHelper getGroupHelper() { 3136 mAutoGroupAtCount = 3137 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount); 3138 return new GroupHelper(getContext(), getContext().getPackageManager(), 3139 mAutoGroupAtCount, AUTOGROUP_SPARSE_GROUPS_AT_COUNT, new GroupHelper.Callback() { 3140 @Override 3141 public void addAutoGroup(String key, String groupName, boolean requestSort) { 3142 synchronized (mNotificationLock) { 3143 if (notificationForceGrouping()) { 3144 convertSummaryToNotificationLocked(key); 3145 addAutogroupKeyLocked(key, groupName, requestSort); 3146 } else { 3147 addAutogroupKeyLocked(key, groupName, requestSort); 3148 } 3149 } 3150 } 3151 3152 @Override 3153 public void removeAutoGroup(String key) { 3154 synchronized (mNotificationLock) { 3155 removeAutogroupKeyLocked(key); 3156 } 3157 } 3158 3159 @Override 3160 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey, 3161 String groupName, int summaryId, NotificationAttributes summaryAttr) { 3162 NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey, 3163 groupName, summaryId, summaryAttr); 3164 if (r != null) { 3165 final boolean isAppForeground = 3166 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 3167 mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, 3168 /* isAppProvided= */ false, 3169 mPostNotificationTrackerFactory.newTracker(null))); 3170 } 3171 } 3172 3173 @Override 3174 public void removeAutoGroupSummary(int userId, String pkg, String groupKey) { 3175 synchronized (mNotificationLock) { 3176 clearAutogroupSummaryLocked(userId, pkg, groupKey); 3177 } 3178 } 3179 3180 @Override 3181 public void updateAutogroupSummary(int userId, String pkg, String groupKey, 3182 NotificationAttributes summaryAttr) { 3183 boolean isAppForeground = pkg != null 3184 && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 3185 synchronized (mNotificationLock) { 3186 updateAutobundledSummaryLocked(userId, pkg, groupKey, summaryAttr, 3187 isAppForeground); 3188 } 3189 } 3190 3191 @Override 3192 public void removeAppProvidedSummary(String key) { 3193 synchronized (mNotificationLock) { 3194 removeAppSummaryLocked(key); 3195 } 3196 } 3197 3198 @Override 3199 public void sendAppProvidedSummaryDeleteIntent(String pkg, PendingIntent deleteIntent) { 3200 sendDeleteIntent(deleteIntent, pkg); 3201 } 3202 3203 @Override 3204 public void removeNotificationFromCanceledGroup(int userId, String pkg, 3205 String groupKey, int cancelReason) { 3206 synchronized (mNotificationLock) { 3207 final int mustNotHaveFlags; 3208 if (lifetimeExtensionRefactor()) { 3209 // Also don't allow client apps to cancel lifetime extended notifs. 3210 mustNotHaveFlags = (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 3211 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3212 } else { 3213 mustNotHaveFlags = (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB); 3214 } 3215 FlagChecker childrenFlagChecker = (flags) -> { 3216 if (cancelReason == REASON_CANCEL 3217 || cancelReason == REASON_CLICK 3218 || cancelReason == REASON_CANCEL_ALL) { 3219 if ((flags & FLAG_BUBBLE) != 0) { 3220 return false; 3221 } 3222 } 3223 return (flags & mustNotHaveFlags) == 0; 3224 }; 3225 cancelGroupChildrenLocked(userId, pkg, Binder.getCallingUid(), 3226 Binder.getCallingPid(), null, 3227 false, childrenFlagChecker, 3228 NotificationManagerService::wasChildOfForceRegroupedGroupChecker, 3229 groupKey, REASON_APP_CANCEL, SystemClock.elapsedRealtime()); 3230 } 3231 } 3232 3233 @Override 3234 @Nullable 3235 public NotificationRecord removeAppProvidedSummaryOnClassification(String triggeringKey, 3236 @Nullable String oldGroupKey) { 3237 synchronized (mNotificationLock) { 3238 return removeAppProvidedSummaryOnClassificationLocked(triggeringKey, 3239 oldGroupKey); 3240 } 3241 } 3242 }); 3243 } 3244 3245 //Enables tests running in TH mode to be exempted from forced grouping of notifications 3246 void setTestHarnessExempted(boolean isExempted) { 3247 mGroupHelper.setTestHarnessExempted(isExempted); 3248 } 3249 3250 private void sendRegisteredOnlyBroadcast(String action) { 3251 sendRegisteredOnlyBroadcast(new Intent(action)); 3252 } 3253 3254 /** 3255 * Schedules a broadcast to be sent to runtime receivers and DND-policy-access packages. The 3256 * broadcast will be sent after {@link #ZEN_BROADCAST_DELAY}, unless a new broadcast is 3257 * scheduled in the interim, in which case the previous one is dropped and the waiting period 3258 * is <em>restarted</em>. 3259 * 3260 * <p>Note that this uses <em>equality of the {@link Intent#getAction}</em> as the criteria for 3261 * deduplicating pending broadcasts, ignoring the extras and anything else. This is intentional 3262 * so that e.g. rapidly changing some value A -> B -> C will only produce a broadcast for C 3263 * (instead of every time because the extras are different). 3264 */ 3265 @FlaggedApi(Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST) 3266 private void sendZenBroadcastWithDelay(Intent intent) { 3267 String token = "zen_broadcast:" + intent.getAction(); 3268 mBroadcastsHandler.removeCallbacksAndEqualMessages(token); 3269 mBroadcastsHandler.postDelayed(() -> sendRegisteredOnlyBroadcast(intent), token, 3270 ZEN_BROADCAST_DELAY.toMillis()); 3271 } 3272 3273 private void sendRegisteredOnlyBroadcast(Intent baseIntent) { 3274 int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true); 3275 if (Flags.nmBinderPerfReduceZenBroadcasts()) { 3276 for (int userId : userIds) { 3277 Context userContext = getContext().createContextAsUser(UserHandle.of(userId), 0); 3278 String[] dndPackages = mConditionProviders.getAllowedPackages(userId) 3279 .toArray(new String[0]); 3280 3281 // We send the broadcast to all DND packages in the second step, so leave them out 3282 // of this first broadcast for *running* receivers. That ensures each package only 3283 // receives it once. 3284 Intent registeredOnlyIntent = new Intent(baseIntent) 3285 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 3286 userContext.sendBroadcastMultiplePermissions(registeredOnlyIntent, 3287 /* receiverPermissions= */ new String[0], 3288 /* excludedPermissions= */ new String[0], 3289 /* excludedPackages= */ dndPackages); 3290 3291 for (String pkg : dndPackages) { 3292 Intent pkgIntent = new Intent(baseIntent).setPackage(pkg) 3293 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3294 userContext.sendBroadcast(pkgIntent); 3295 } 3296 } 3297 } else { 3298 Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 3299 for (int userId : userIds) { 3300 getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null); 3301 } 3302 3303 // explicitly send the broadcast to all DND packages, even if they aren't currently 3304 // running 3305 for (int userId : userIds) { 3306 for (String pkg : mConditionProviders.getAllowedPackages(userId)) { 3307 Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags( 3308 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3309 getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId)); 3310 } 3311 } 3312 } 3313 } 3314 3315 @Override 3316 public void onBootPhase(int phase) { 3317 onBootPhase(phase, Looper.getMainLooper()); 3318 } 3319 3320 @VisibleForTesting 3321 void onBootPhase(int phase, Looper mainLooper) { 3322 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 3323 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 3324 mZenModeHelper.onSystemReady(); 3325 RoleObserver roleObserver = new RoleObserver(getContext(), 3326 getContext().getSystemService(RoleManager.class), 3327 mPackageManager, mainLooper); 3328 roleObserver.init(); 3329 mRoleObserver = roleObserver; 3330 LauncherApps launcherApps = 3331 (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE); 3332 UserManager userManager = (UserManager) getContext().getSystemService( 3333 Context.USER_SERVICE); 3334 mShortcutHelper = new ShortcutHelper(launcherApps, mShortcutListener, getLocalService( 3335 ShortcutServiceInternal.class), userManager); 3336 BubbleExtractor bubbsExtractor = mRankingHelper.findExtractor(BubbleExtractor.class); 3337 if (bubbsExtractor != null) { 3338 bubbsExtractor.setShortcutHelper(mShortcutHelper); 3339 bubbsExtractor.setPackageManager(mPackageManagerClient); 3340 } 3341 registerNotificationPreferencesPullers(); 3342 if (mLockUtils == null) { 3343 mLockUtils = new LockPatternUtils(getContext()); 3344 } 3345 mLockUtils.registerStrongAuthTracker(mStrongAuthTracker); 3346 mAttentionHelper.onSystemReady(); 3347 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 3348 // This observer will force an update when observe is called, causing us to 3349 // bind to listener services. 3350 mSettingsObserver.observe(); 3351 mListeners.onBootPhaseAppsCanStart(); 3352 mAssistants.onBootPhaseAppsCanStart(); 3353 mConditionProviders.onBootPhaseAppsCanStart(); 3354 mHistoryManager.onBootPhaseAppsCanStart(); 3355 mPreferencesHelper.onBootPhaseAppsCanStart(); 3356 migrateDefaultNAS(); 3357 maybeShowInitialReviewPermissionsNotification(); 3358 3359 if (!mZenModeHelper.hasDeviceEffectsApplier()) { 3360 // Cannot be done earlier, as some services aren't ready until this point. 3361 mZenModeHelper.setDeviceEffectsApplier( 3362 new DefaultDeviceEffectsApplier(getContext())); 3363 } 3364 List<ModuleInfo> moduleInfoList = 3365 mPackageManagerClient.getInstalledModules( 3366 PackageManager.MATCH_DEBUG_TRIAGED_MISSING); 3367 // Cache adservices module info 3368 for (ModuleInfo mi : moduleInfoList) { 3369 if (Objects.equals(mi.getApexModuleName(), ADSERVICES_MODULE_PKG_NAME)) { 3370 mAdservicesModuleInfo = mi; 3371 } 3372 } 3373 } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 3374 mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis()); 3375 } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) { 3376 mPreferencesHelper.updateFixedImportance(mUm.getUsers()); 3377 mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers()); 3378 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { 3379 if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) { 3380 new Thread(() -> { 3381 while (true) { 3382 try { 3383 Thread.sleep(5000); 3384 } catch (InterruptedException e) { } 3385 mInternalService.removeBitmaps(); 3386 } 3387 }).start(); 3388 } else if (expireBitmaps()) { 3389 NotificationBitmapJobService.scheduleJob(getContext()); 3390 } 3391 } 3392 } 3393 3394 @Override 3395 public void onUserUnlocked(@NonNull TargetUser user) { 3396 mHandler.post(() -> { 3397 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser"); 3398 try { 3399 mHistoryManager.onUserUnlocked(user.getUserIdentifier()); 3400 } finally { 3401 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 3402 } 3403 }); 3404 } 3405 3406 private void sendAppBlockStateChangedBroadcast(String pkg, int uid, boolean blocked) { 3407 // From Android T, revoking the notification permission will cause the app to be killed. 3408 // delay this broadcast so it doesn't race with that process death 3409 mHandler.postDelayed(() -> { 3410 try { 3411 getContext().sendBroadcastAsUser( 3412 new Intent(ACTION_APP_BLOCK_STATE_CHANGED) 3413 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, blocked) 3414 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3415 .setPackage(pkg), 3416 UserHandle.of(UserHandle.getUserId(uid)), null); 3417 } catch (SecurityException e) { 3418 Slog.w(TAG, "Can't notify app about app block change", e); 3419 } 3420 }, 500); 3421 } 3422 3423 @Override 3424 public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { 3425 if (!Flags.useSsmUserSwitchSignal()) { 3426 return; 3427 } 3428 final int userId = to.getUserIdentifier(); 3429 mUserProfiles.updateCache(getContext()); 3430 if (!mUserProfiles.isProfileUser(userId, getContext())) { 3431 // reload per-user settings 3432 mSettingsObserver.update(null); 3433 // Refresh managed services 3434 mConditionProviders.onUserSwitched(userId); 3435 mListeners.onUserSwitched(userId); 3436 mZenModeHelper.onUserSwitched(userId); 3437 mPreferencesHelper.syncHasPriorityChannels(); 3438 } 3439 // assistant is the only thing that cares about managed profiles specifically 3440 mAssistants.onUserSwitched(userId); 3441 } 3442 3443 @Override 3444 public void onUserStopping(@NonNull TargetUser user) { 3445 mHandler.post(() -> { 3446 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser"); 3447 try { 3448 mHistoryManager.onUserStopped(user.getUserIdentifier()); 3449 } finally { 3450 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 3451 } 3452 }); 3453 } 3454 3455 @GuardedBy("mNotificationLock") 3456 private void updateListenerHintsLocked() { 3457 final int hints = calculateHints(); 3458 if (hints == mListenerHints) return; 3459 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size()); 3460 mListenerHints = hints; 3461 scheduleListenerHintsChanged(hints); 3462 } 3463 3464 @GuardedBy("mNotificationLock") 3465 private void updateEffectsSuppressorLocked() { 3466 final long oldSuppressedEffects = mZenModeHelper.getSuppressedEffects(); 3467 final long updatedSuppressedEffects = calculateSuppressedEffects(); 3468 if (updatedSuppressedEffects == oldSuppressedEffects) return; 3469 3470 final List<ComponentName> suppressors = getSuppressors(); 3471 ZenLog.traceEffectsSuppressorChanged( 3472 mEffectsSuppressors, suppressors, oldSuppressedEffects, updatedSuppressedEffects); 3473 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); 3474 3475 if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { 3476 if (!suppressors.equals(mEffectsSuppressors)) { 3477 mEffectsSuppressors = suppressors; 3478 sendZenBroadcastWithDelay( 3479 new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)); 3480 } 3481 } else { 3482 mEffectsSuppressors = suppressors; 3483 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 3484 } 3485 } 3486 3487 private void exitIdle() { 3488 if (mDeviceIdleManager != null) { 3489 mDeviceIdleManager.endIdle("notification interaction"); 3490 } 3491 } 3492 3493 void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel, 3494 boolean fromListener) { 3495 if (channel.getImportance() == IMPORTANCE_NONE) { 3496 // cancel 3497 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, 3498 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED 3499 ); 3500 if (isUidSystemOrPhone(uid)) { 3501 IntArray profileIds = mUserProfiles.getCurrentProfileIds(); 3502 int N = profileIds.size(); 3503 for (int i = 0; i < N; i++) { 3504 int profileId = profileIds.get(i); 3505 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, 3506 profileId, REASON_CHANNEL_BANNED 3507 ); 3508 } 3509 } 3510 } 3511 final NotificationChannel preUpdate = 3512 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true); 3513 3514 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true, 3515 Binder.getCallingUid(), isCallerSystemOrSystemUi()); 3516 if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) { 3517 mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid), 3518 channel.getImportance() != IMPORTANCE_NONE, true); 3519 } 3520 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel); 3521 3522 if (!fromListener) { 3523 final NotificationChannel modifiedChannel = mPreferencesHelper.getNotificationChannel( 3524 pkg, uid, channel.getId(), false); 3525 mListeners.notifyNotificationChannelChanged( 3526 pkg, UserHandle.getUserHandleForUid(uid), 3527 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); 3528 } 3529 3530 if (notificationForceGrouping()) { 3531 final NotificationChannel updatedChannel = mPreferencesHelper.getNotificationChannel( 3532 pkg, uid, channel.getId(), false); 3533 mHandler.postDelayed(() -> { 3534 synchronized (mNotificationLock) { 3535 mGroupHelper.onChannelUpdated( 3536 UserHandle.getUserHandleForUid(uid).getIdentifier(), pkg, 3537 updatedChannel, mNotificationList, mSummaryByGroupKey); 3538 } 3539 }, DELAY_FORCE_REGROUP_TIME); 3540 } 3541 3542 handleSavePolicyFile(); 3543 } 3544 3545 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate, 3546 NotificationChannel update) { 3547 try { 3548 if ((preUpdate.getImportance() == IMPORTANCE_NONE 3549 && update.getImportance() != IMPORTANCE_NONE) 3550 || (preUpdate.getImportance() != IMPORTANCE_NONE 3551 && update.getImportance() == IMPORTANCE_NONE)) { 3552 getContext().sendBroadcastAsUser( 3553 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED) 3554 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID, 3555 update.getId()) 3556 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 3557 update.getImportance() == IMPORTANCE_NONE) 3558 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3559 .setPackage(pkg), 3560 UserHandle.of(UserHandle.getUserId(uid)), null); 3561 } 3562 } catch (SecurityException e) { 3563 Slog.w(TAG, "Can't notify app about channel change", e); 3564 } 3565 } 3566 3567 void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, 3568 boolean fromApp, boolean fromListener) { 3569 Objects.requireNonNull(group); 3570 Objects.requireNonNull(pkg); 3571 3572 final NotificationChannelGroup preUpdate = 3573 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid); 3574 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group, 3575 fromApp, Binder.getCallingUid(), isCallerSystemOrSystemUi()); 3576 if (!fromApp) { 3577 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group); 3578 } 3579 if (!fromListener) { 3580 mListeners.notifyNotificationChannelGroupChanged(pkg, 3581 UserHandle.of(UserHandle.getCallingUserId()), group, 3582 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 3583 } 3584 } 3585 3586 private void maybeNotifyChannelGroupOwner(String pkg, int uid, 3587 NotificationChannelGroup preUpdate, NotificationChannelGroup update) { 3588 try { 3589 if (preUpdate.isBlocked() != update.isBlocked()) { 3590 getContext().sendBroadcastAsUser( 3591 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED) 3592 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID, 3593 update.getId()) 3594 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 3595 update.isBlocked()) 3596 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3597 .setPackage(pkg), 3598 UserHandle.of(UserHandle.getUserId(uid)), null); 3599 } 3600 } catch (SecurityException e) { 3601 Slog.w(TAG, "Can't notify app about group change", e); 3602 } 3603 } 3604 3605 private ArrayList<ComponentName> getSuppressors() { 3606 ArrayList<ComponentName> names = new ArrayList<>(); 3607 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 3608 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 3609 3610 for (ComponentName info : serviceInfoList) { 3611 if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { 3612 if (!names.contains(info)) { 3613 names.add(info); 3614 } 3615 } else { 3616 names.add(info); 3617 } 3618 } 3619 } 3620 3621 return names; 3622 } 3623 3624 private boolean removeDisabledHints(ManagedServiceInfo info) { 3625 return removeDisabledHints(info, 0); 3626 } 3627 3628 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) { 3629 boolean removed = false; 3630 3631 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 3632 final int hint = mListenersDisablingEffects.keyAt(i); 3633 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 3634 3635 if (hints == 0 || (hint & hints) == hint) { 3636 removed |= listeners.remove(info.component); 3637 } 3638 } 3639 3640 return removed; 3641 } 3642 3643 private void addDisabledHints(ManagedServiceInfo info, int hints) { 3644 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 3645 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS); 3646 } 3647 3648 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 3649 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 3650 } 3651 3652 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 3653 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS); 3654 } 3655 } 3656 3657 private void addDisabledHint(ManagedServiceInfo info, int hint) { 3658 if (mListenersDisablingEffects.indexOfKey(hint) < 0) { 3659 mListenersDisablingEffects.put(hint, new ArraySet<>()); 3660 } 3661 3662 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint); 3663 hintListeners.add(info.component); 3664 } 3665 3666 private int calculateHints() { 3667 int hints = 0; 3668 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 3669 int hint = mListenersDisablingEffects.keyAt(i); 3670 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 3671 3672 if (!serviceInfoList.isEmpty()) { 3673 hints |= hint; 3674 } 3675 } 3676 3677 return hints; 3678 } 3679 3680 private long calculateSuppressedEffects() { 3681 int hints = calculateHints(); 3682 long suppressedEffects = 0; 3683 3684 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 3685 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL; 3686 } 3687 3688 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 3689 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS; 3690 } 3691 3692 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 3693 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS; 3694 } 3695 3696 return suppressedEffects; 3697 } 3698 3699 @GuardedBy("mNotificationLock") 3700 private void updateInterruptionFilterLocked() { 3701 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 3702 if (interruptionFilter == mInterruptionFilter) return; 3703 mInterruptionFilter = interruptionFilter; 3704 scheduleInterruptionFilterChanged(interruptionFilter); 3705 } 3706 3707 int correctCategory(int requestedCategoryList, int categoryType, 3708 int currentCategoryList) { 3709 if ((requestedCategoryList & categoryType) != 0 3710 && (currentCategoryList & categoryType) == 0) { 3711 requestedCategoryList &= ~categoryType; 3712 } else if ((requestedCategoryList & categoryType) == 0 3713 && (currentCategoryList & categoryType) != 0){ 3714 requestedCategoryList |= categoryType; 3715 } 3716 return requestedCategoryList; 3717 } 3718 3719 @VisibleForTesting 3720 INotificationManager getBinderService() { 3721 return INotificationManager.Stub.asInterface(mService); 3722 } 3723 3724 /** 3725 * Report to usage stats that the notification was seen. 3726 * @param r notification record 3727 */ 3728 @GuardedBy("mNotificationLock") 3729 protected void reportSeen(NotificationRecord r) { 3730 if (!r.isProxied()) { 3731 mAppUsageStats.reportEvent(r.getSbn().getPackageName(), 3732 getRealUserId(r.getSbn().getUserId()), 3733 UsageEvents.Event.NOTIFICATION_SEEN); 3734 } 3735 } 3736 3737 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy, 3738 int targetSdkVersion) { 3739 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) { 3740 return incomingPolicy.suppressedVisualEffects; 3741 } 3742 final int[] effectsIntroducedInP = { 3743 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT, 3744 SUPPRESSED_EFFECT_LIGHTS, 3745 SUPPRESSED_EFFECT_PEEK, 3746 SUPPRESSED_EFFECT_STATUS_BAR, 3747 SUPPRESSED_EFFECT_BADGE, 3748 SUPPRESSED_EFFECT_AMBIENT, 3749 SUPPRESSED_EFFECT_NOTIFICATION_LIST 3750 }; 3751 3752 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects; 3753 if (targetSdkVersion < Build.VERSION_CODES.P) { 3754 // unset higher order bits introduced in P, maintain the user's higher order bits 3755 for (int i = 0; i < effectsIntroducedInP.length ; i++) { 3756 newSuppressedVisualEffects &= ~effectsIntroducedInP[i]; 3757 newSuppressedVisualEffects |= 3758 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]); 3759 } 3760 // set higher order bits according to lower order bits 3761 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 3762 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 3763 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 3764 } 3765 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 3766 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 3767 } 3768 } else { 3769 boolean hasNewEffects = (newSuppressedVisualEffects 3770 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0; 3771 // if any of the new effects introduced in P are set 3772 if (hasNewEffects) { 3773 // clear out the deprecated effects 3774 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON 3775 | SUPPRESSED_EFFECT_SCREEN_OFF); 3776 3777 // set the deprecated effects according to the new more specific effects 3778 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) != 0) { 3779 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON; 3780 } 3781 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) != 0 3782 && (newSuppressedVisualEffects 3783 & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0 3784 && (newSuppressedVisualEffects 3785 & SUPPRESSED_EFFECT_AMBIENT) != 0) { 3786 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF; 3787 } 3788 } else { 3789 // set higher order bits according to lower order bits 3790 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 3791 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 3792 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 3793 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT; 3794 } 3795 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 3796 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 3797 } 3798 } 3799 } 3800 3801 return newSuppressedVisualEffects; 3802 } 3803 3804 @GuardedBy("mNotificationLock") 3805 protected void maybeRecordInterruptionLocked(NotificationRecord r) { 3806 if (r.isInterruptive() && !r.hasRecordedInterruption()) { 3807 mAppUsageStats.reportInterruptiveNotification(r.getSbn().getPackageName(), 3808 r.getChannel().getId(), 3809 getRealUserId(r.getSbn().getUserId())); 3810 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryAddItem"); 3811 try { 3812 if (r.getNotification().getSmallIcon() != null) { 3813 mHistoryManager.addNotification(new HistoricalNotification.Builder() 3814 .setPackage(r.getSbn().getPackageName()) 3815 .setUid(r.getSbn().getUid()) 3816 .setUserId(r.getSbn().getNormalizedUserId()) 3817 .setChannelId(r.getChannel().getId()) 3818 .setChannelName(r.getChannel().getName().toString()) 3819 .setPostedTimeMs(System.currentTimeMillis()) 3820 .setTitle(getHistoryTitle(r.getNotification())) 3821 .setText(getHistoryText(r.getNotification())) 3822 .setIcon(r.getNotification().getSmallIcon()) 3823 .build()); 3824 } 3825 } finally { 3826 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 3827 } 3828 r.setRecordedInterruption(true); 3829 } 3830 } 3831 3832 protected void reportForegroundServiceUpdate(boolean shown, 3833 final Notification notification, final int id, final String pkg, final int userId) { 3834 mHandler.post(() -> { 3835 mAmi.onForegroundServiceNotificationUpdate(shown, notification, id, pkg, userId); 3836 }); 3837 } 3838 3839 protected void maybeReportForegroundServiceUpdate(final NotificationRecord r, boolean shown) { 3840 if (r.isForegroundService()) { 3841 // snapshot live state for the asynchronous operation 3842 final StatusBarNotification sbn = r.getSbn(); 3843 reportForegroundServiceUpdate(shown, sbn.getNotification(), sbn.getId(), 3844 sbn.getPackageName(), sbn.getUser().getIdentifier()); 3845 } 3846 } 3847 3848 private String getHistoryTitle(Notification n) { 3849 CharSequence title = null; 3850 if (n.extras != null) { 3851 title = n.extras.getCharSequence(EXTRA_TITLE); 3852 if (title == null) { 3853 title = n.extras.getCharSequence(EXTRA_TITLE_BIG); 3854 } 3855 } 3856 return title == null ? getContext().getResources().getString( 3857 com.android.internal.R.string.notification_history_title_placeholder) 3858 : String.valueOf(title); 3859 } 3860 3861 /** 3862 * Returns the appropriate substring for this notification based on the style of notification. 3863 */ 3864 private String getHistoryText(Notification n) { 3865 CharSequence text = null; 3866 if (n.extras != null) { 3867 text = n.extras.getCharSequence(EXTRA_TEXT); 3868 Notification.Builder nb = Notification.Builder.recoverBuilder(getContext(), n); 3869 3870 if (nb.getStyle() instanceof Notification.BigTextStyle) { 3871 text = ((Notification.BigTextStyle) nb.getStyle()).getBigText(); 3872 } else if (nb.getStyle() instanceof MessagingStyle) { 3873 MessagingStyle ms = (MessagingStyle) nb.getStyle(); 3874 final List<MessagingStyle.Message> messages = ms.getMessages(); 3875 if (messages != null && messages.size() > 0) { 3876 text = messages.get(messages.size() - 1).getText(); 3877 } 3878 } 3879 3880 if (TextUtils.isEmpty(text)) { 3881 text = n.extras.getCharSequence(EXTRA_TEXT); 3882 } 3883 } 3884 return text == null ? null : String.valueOf(text); 3885 } 3886 3887 protected void maybeRegisterMessageSent(NotificationRecord r) { 3888 if (r.isConversation()) { 3889 if (r.getShortcutInfo() != null) { 3890 if (mPreferencesHelper.setValidMessageSent( 3891 r.getSbn().getPackageName(), r.getUid())) { 3892 handleSavePolicyFile(); 3893 } else if (r.getNotification().getBubbleMetadata() != null) { 3894 // If bubble metadata is present it is valid (if invalid it's removed 3895 // via BubbleExtractor). 3896 if (mPreferencesHelper.setValidBubbleSent( 3897 r.getSbn().getPackageName(), r.getUid())) { 3898 handleSavePolicyFile(); 3899 } 3900 } 3901 } else { 3902 if (mPreferencesHelper.setInvalidMessageSent( 3903 r.getSbn().getPackageName(), r.getUid())) { 3904 handleSavePolicyFile(); 3905 } 3906 } 3907 } 3908 } 3909 3910 /** 3911 * Report to usage stats that the user interacted with the notification. 3912 * @param r notification record 3913 */ 3914 protected void reportUserInteraction(NotificationRecord r) { 3915 mAppUsageStats.reportEvent(r.getSbn().getPackageName(), 3916 getRealUserId(r.getSbn().getUserId()), 3917 UsageEvents.Event.USER_INTERACTION); 3918 3919 if (Flags.politeNotifications()) { 3920 mAttentionHelper.onUserInteraction(r); 3921 } 3922 } 3923 3924 private int getRealUserId(int userId) { 3925 return userId == USER_ALL ? USER_SYSTEM : userId; 3926 } 3927 3928 private ToastRecord getToastRecord(int uid, int pid, String packageName, boolean isSystemToast, 3929 IBinder token, @Nullable CharSequence text, @Nullable ITransientNotification callback, 3930 int duration, Binder windowToken, int displayId, 3931 @Nullable ITransientNotificationCallback textCallback) { 3932 if (callback == null) { 3933 return new TextToastRecord(this, mStatusBar, uid, pid, packageName, 3934 isSystemToast, token, text, duration, windowToken, displayId, textCallback); 3935 } else { 3936 return new CustomToastRecord(this, uid, pid, packageName, 3937 isSystemToast, token, callback, duration, windowToken, displayId); 3938 } 3939 } 3940 3941 @VisibleForTesting 3942 NotificationManagerInternal getInternalService() { 3943 return mInternalService; 3944 } 3945 3946 private MultiRateLimiter createToastRateLimiter() { 3947 return new MultiRateLimiter.Builder(getContext()).addRateLimits(TOAST_RATE_LIMITS).build(); 3948 } 3949 3950 protected int checkComponentPermission(String permission, int uid, int owningUid, 3951 boolean exported) { 3952 return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); 3953 } 3954 3955 @VisibleForTesting 3956 final IBinder mService = new INotificationManager.Stub() { 3957 // Toasts 3958 // ============================================================================ 3959 3960 @Override 3961 public boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, 3962 boolean isUiContext, int displayId, 3963 @Nullable ITransientNotificationCallback textCallback) { 3964 return enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext, 3965 displayId, textCallback); 3966 } 3967 3968 @Override 3969 public boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback, 3970 int duration, boolean isUiContext, int displayId) { 3971 return enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext, 3972 displayId, /* textCallback= */ null); 3973 } 3974 3975 private boolean enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, 3976 @Nullable ITransientNotification callback, int duration, boolean isUiContext, 3977 int displayId, @Nullable ITransientNotificationCallback textCallback) { 3978 if (DBG) { 3979 Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration 3980 + " isUiContext=" + isUiContext + " displayId=" + displayId); 3981 } 3982 3983 if (pkg == null || (text == null && callback == null) 3984 || (text != null && callback != null) || token == null) { 3985 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback=" 3986 + " token=" + token); 3987 return false; 3988 } 3989 3990 final int callingUid = Binder.getCallingUid(); 3991 if (!isUiContext && displayId == Display.DEFAULT_DISPLAY 3992 && mUm.isVisibleBackgroundUsersSupported()) { 3993 // When the caller is a visible background user using a non-UI context (like the 3994 // application context), the Toast must be displayed in the display the user was 3995 // started visible on. 3996 int userId = UserHandle.getUserId(callingUid); 3997 int userDisplayId = mUmInternal.getMainDisplayAssignedToUser(userId); 3998 if (displayId != userDisplayId) { 3999 if (DBG) { 4000 Slogf.d(TAG, "Changing display id from %d to %d on user %d", displayId, 4001 userDisplayId, userId); 4002 } 4003 displayId = userDisplayId; 4004 } 4005 } 4006 4007 checkCallerIsSameApp(pkg); 4008 final boolean isSystemToast = isCallerSystemOrSystemUi() 4009 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); 4010 boolean isAppRenderedToast = (callback != null); 4011 if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast, 4012 isSystemToast)) { 4013 return false; 4014 } 4015 4016 synchronized (mToastQueue) { 4017 int callingPid = Binder.getCallingPid(); 4018 final long callingId = Binder.clearCallingIdentity(); 4019 try { 4020 ToastRecord record; 4021 int index = indexOfToastLocked(pkg, token); 4022 // If it's already in the queue, we update it in place, we don't 4023 // move it to the end of the queue. 4024 if (index >= 0) { 4025 record = mToastQueue.get(index); 4026 record.update(duration); 4027 } else { 4028 // Limit the number of toasts that any given package can enqueue. 4029 // Prevents DOS attacks and deals with leaks. 4030 int count = 0; 4031 final int N = mToastQueue.size(); 4032 for (int i = 0; i < N; i++) { 4033 final ToastRecord r = mToastQueue.get(i); 4034 if (r.pkg.equals(pkg)) { 4035 count++; 4036 if (count >= MAX_PACKAGE_TOASTS) { 4037 Slog.e(TAG, "Package has already queued " + count 4038 + " toasts. Not showing more. Package=" + pkg); 4039 return false; 4040 } 4041 } 4042 } 4043 4044 Binder windowToken = new Binder(); 4045 mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId, 4046 null /* options */); 4047 record = getToastRecord(callingUid, callingPid, pkg, isSystemToast, token, 4048 text, callback, duration, windowToken, displayId, textCallback); 4049 4050 // Insert system toasts at the front of the queue 4051 int systemToastInsertIdx = mToastQueue.size(); 4052 if (isSystemToast) { 4053 systemToastInsertIdx = getInsertIndexForSystemToastLocked(); 4054 } 4055 if (systemToastInsertIdx < mToastQueue.size()) { 4056 index = systemToastInsertIdx; 4057 mToastQueue.add(index, record); 4058 } else { 4059 mToastQueue.add(record); 4060 index = mToastQueue.size() - 1; 4061 } 4062 keepProcessAliveForToastIfNeededLocked(callingPid); 4063 } 4064 // If it's at index 0, it's the current toast. It doesn't matter if it's 4065 // new or just been updated, show it. 4066 // If the callback fails, this will remove it from the list, so don't 4067 // assume that it's valid after this. 4068 if (index == 0) { 4069 showNextToastLocked(false); 4070 } 4071 } finally { 4072 Binder.restoreCallingIdentity(callingId); 4073 } 4074 } 4075 return true; 4076 } 4077 4078 @GuardedBy("mToastQueue") 4079 private int getInsertIndexForSystemToastLocked() { 4080 // If there are other system toasts: insert after the last one 4081 int idx = 0; 4082 for (ToastRecord r : mToastQueue) { 4083 if (idx == 0 && mIsCurrentToastShown) { 4084 idx++; 4085 continue; 4086 } 4087 if (!r.isSystemToast) { 4088 return idx; 4089 } 4090 idx++; 4091 } 4092 return idx; 4093 } 4094 4095 private boolean checkCanEnqueueToast(String pkg, int callingUid, int displayId, 4096 boolean isAppRenderedToast, boolean isSystemToast) { 4097 final boolean isPackageSuspended = isPackagePaused(pkg); 4098 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, 4099 callingUid); 4100 4101 final boolean appIsForeground; 4102 final long callingIdentity = Binder.clearCallingIdentity(); 4103 try { 4104 appIsForeground = mActivityManager.getUidImportance(callingUid) 4105 == IMPORTANCE_FOREGROUND; 4106 } finally { 4107 Binder.restoreCallingIdentity(callingIdentity); 4108 } 4109 4110 if (!isSystemToast && ((notificationsDisabledForPackage && !appIsForeground) 4111 || isPackageSuspended)) { 4112 Slog.e(TAG, "Suppressing toast from package " + pkg 4113 + (isPackageSuspended ? " due to package suspended." 4114 : " by user request.")); 4115 return false; 4116 } 4117 4118 if (blockToast(callingUid, isSystemToast, isAppRenderedToast, 4119 isPackageInForegroundForToast(callingUid))) { 4120 Slog.w(TAG, "Blocking custom toast from package " + pkg 4121 + " due to package not in the foreground at time the toast was posted"); 4122 return false; 4123 } 4124 4125 int userId = UserHandle.getUserId(callingUid); 4126 if (!isSystemToast && !mUmInternal.isUserVisible(userId, displayId)) { 4127 Slog.e(TAG, "Suppressing toast from package " + pkg + "/" + callingUid + " as user " 4128 + userId + " is not visible on display " + displayId); 4129 return false; 4130 } 4131 4132 return true; 4133 } 4134 4135 @Override 4136 public void cancelToast(String pkg, IBinder token) { 4137 Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token); 4138 4139 if (pkg == null || token == null) { 4140 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token); 4141 return; 4142 } 4143 4144 synchronized (mToastQueue) { 4145 final long callingId = Binder.clearCallingIdentity(); 4146 try { 4147 int index = indexOfToastLocked(pkg, token); 4148 if (index >= 0) { 4149 cancelToastLocked(index); 4150 } else { 4151 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 4152 + " token=" + token); 4153 } 4154 } finally { 4155 Binder.restoreCallingIdentity(callingId); 4156 } 4157 } 4158 } 4159 4160 @Override 4161 @EnforcePermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) 4162 public void setToastRateLimitingEnabled(boolean enable) { 4163 4164 super.setToastRateLimitingEnabled_enforcePermission(); 4165 4166 synchronized (mToastQueue) { 4167 int uid = Binder.getCallingUid(); 4168 int userId = UserHandle.getUserId(uid); 4169 if (enable) { 4170 mToastRateLimitingDisabledUids.remove(uid); 4171 try { 4172 String[] packages = mPackageManager.getPackagesForUid(uid); 4173 if (packages == null) { 4174 Slog.e(TAG, "setToastRateLimitingEnabled method haven't found any " 4175 + "packages for the given uid: " + uid + ", toast rate " 4176 + "limiter not reset for that uid."); 4177 return; 4178 } 4179 for (String pkg : packages) { 4180 mToastRateLimiter.clear(userId, pkg); 4181 } 4182 } catch (RemoteException e) { 4183 Slog.e(TAG, "Failed to reset toast rate limiter for given uid", e); 4184 } 4185 } else { 4186 mToastRateLimitingDisabledUids.add(uid); 4187 } 4188 } 4189 } 4190 4191 @Override 4192 public void finishToken(String pkg, IBinder token) { 4193 synchronized (mToastQueue) { 4194 final long callingId = Binder.clearCallingIdentity(); 4195 try { 4196 int index = indexOfToastLocked(pkg, token); 4197 if (index >= 0) { 4198 ToastRecord record = mToastQueue.get(index); 4199 finishWindowTokenLocked(record.windowToken, record.displayId); 4200 } else { 4201 Slog.w(TAG, "Toast already killed. pkg=" + pkg 4202 + " token=" + token); 4203 } 4204 } finally { 4205 Binder.restoreCallingIdentity(callingId); 4206 } 4207 } 4208 } 4209 4210 @Override 4211 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 4212 Notification notification, int userId) throws RemoteException { 4213 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 4214 Binder.getCallingPid(), tag, id, notification, userId, 4215 /* byForegroundService= */ false, /* isAppProvided= */ true); 4216 } 4217 4218 @Override 4219 public void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id, 4220 int userId) { 4221 // Don't allow client applications to cancel foreground service notifs, user-initiated 4222 // job notifs, autobundled summaries, or notifs that have been replied to. 4223 int mustNotHaveFlags = isCallingUidSystem() ? 0 : 4224 (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY); 4225 if (lifetimeExtensionRefactor()) { 4226 // Also don't allow client apps to cancel lifetime extended notifs. 4227 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 4228 } 4229 4230 cancelNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), 4231 tag, id, userId, mustNotHaveFlags); 4232 } 4233 4234 @Override 4235 public void cancelAllNotifications(String pkg, int userId) { 4236 checkCallerIsSystemOrSameApp(pkg); 4237 4238 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 4239 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 4240 4241 // Don't allow the app to cancel active FGS or UIJ notifications 4242 if (lifetimeExtensionRefactor()) { 4243 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 4244 pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 4245 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 4246 userId, REASON_APP_CANCEL_ALL); 4247 final int packageImportance = getPackageImportanceWithIdentity(pkg); 4248 // If cancellation will be prevented due to lifetime extension, we send updates 4249 // to system UI. 4250 synchronized (mNotificationLock) { 4251 maybeNotifySystemUiListenerLifetimeExtendedListLocked(mNotificationList, 4252 packageImportance); 4253 maybeNotifySystemUiListenerLifetimeExtendedListLocked(mEnqueuedNotifications, 4254 packageImportance); 4255 } 4256 } else { 4257 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 4258 pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, 4259 userId, REASON_APP_CANCEL_ALL); 4260 } 4261 } 4262 4263 @Override 4264 public void silenceNotificationSound() { 4265 checkCallerIsSystem(); 4266 4267 mNotificationDelegate.clearEffects(); 4268 } 4269 4270 @Override 4271 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 4272 enforceSystemOrSystemUI("setNotificationsEnabledForPackage"); 4273 boolean wasEnabled = mPermissionHelper.hasPermission(uid); 4274 if (wasEnabled == enabled) { 4275 return; 4276 } 4277 mPermissionHelper.setNotificationPermission( 4278 pkg, UserHandle.getUserId(uid), enabled, true); 4279 sendAppBlockStateChangedBroadcast(pkg, uid, !enabled); 4280 4281 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) 4282 .setType(MetricsEvent.TYPE_ACTION) 4283 .setPackageName(pkg) 4284 .setSubtype(enabled ? 1 : 0)); 4285 mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled); 4286 4287 // Outstanding notifications from this package will be cancelled as soon as we get the 4288 // callback from AppOpsManager. 4289 } 4290 4291 /** 4292 * Updates the enabled state for notifications for the given package (and uid). 4293 * Additionally, this method marks the app importance as locked by the user, which 4294 * means 4295 * that notifications from the app will <b>not</b> be considered for showing a 4296 * blocking helper. 4297 * 4298 * @param pkg package that owns the notifications to update 4299 * @param uid uid of the app providing notifications 4300 * @param enabled whether notifications should be enabled for the app 4301 * @see #setNotificationsEnabledForPackage(String, int, boolean) 4302 */ 4303 @Override 4304 public void setNotificationsEnabledWithImportanceLockForPackage( 4305 String pkg, int uid, boolean enabled) { 4306 setNotificationsEnabledForPackage(pkg, uid, enabled); 4307 } 4308 4309 /** 4310 * Use this when you just want to know if notifications are OK for this package. 4311 */ 4312 @Override 4313 public boolean areNotificationsEnabled(String pkg) { 4314 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()); 4315 } 4316 4317 /** 4318 * Use this when you just want to know if notifications are OK for this package. 4319 */ 4320 @Override 4321 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 4322 enforceSystemOrSystemUIOrSamePackage(pkg, 4323 "Caller not system or systemui or same package"); 4324 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 4325 getContext().enforceCallingPermission( 4326 android.Manifest.permission.INTERACT_ACROSS_USERS, 4327 "canNotifyAsPackage for uid " + uid); 4328 } 4329 4330 return areNotificationsEnabledForPackageInt(uid); 4331 } 4332 4333 /** 4334 * @return true if and only if "all" bubbles are allowed from the provided package. 4335 */ 4336 @Override 4337 public boolean areBubblesAllowed(String pkg) { 4338 return getBubblePreferenceForPackage(pkg, Binder.getCallingUid()) 4339 == BUBBLE_PREFERENCE_ALL; 4340 } 4341 4342 /** 4343 * @return true if this user has bubbles enabled at the feature-level. 4344 */ 4345 @Override 4346 public boolean areBubblesEnabled(UserHandle user) { 4347 if (UserHandle.getCallingUserId() != user.getIdentifier()) { 4348 getContext().enforceCallingPermission( 4349 android.Manifest.permission.INTERACT_ACROSS_USERS, 4350 "areBubblesEnabled for user " + user.getIdentifier()); 4351 } 4352 return mPreferencesHelper.bubblesEnabled(user); 4353 } 4354 4355 @Override 4356 public int getBubblePreferenceForPackage(String pkg, int uid) { 4357 enforceSystemOrSystemUIOrSamePackage(pkg, 4358 "Caller not system or systemui or same package"); 4359 4360 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 4361 getContext().enforceCallingPermission( 4362 android.Manifest.permission.INTERACT_ACROSS_USERS, 4363 "getBubblePreferenceForPackage for uid " + uid); 4364 } 4365 4366 return mPreferencesHelper.getBubblePreference(pkg, uid); 4367 } 4368 4369 @Override 4370 public void setBubblesAllowed(String pkg, int uid, int bubblePreference) { 4371 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 4372 mPreferencesHelper.setBubblesAllowed(pkg, uid, bubblePreference); 4373 handleSavePolicyFile(); 4374 } 4375 4376 @Override 4377 public boolean shouldHideSilentStatusIcons(String callingPkg) { 4378 checkCallerIsSameApp(callingPkg); 4379 4380 if (isCallerSystemOrPhone() 4381 || mListeners.isListenerPackage(callingPkg)) { 4382 return mPreferencesHelper.shouldHideSilentStatusIcons(); 4383 } else { 4384 throw new SecurityException("Only available for notification listeners"); 4385 } 4386 } 4387 4388 @Override 4389 public void setHideSilentStatusIcons(boolean hide) { 4390 checkCallerIsSystem(); 4391 4392 mPreferencesHelper.setHideSilentStatusIcons(hide); 4393 handleSavePolicyFile(); 4394 4395 mListeners.onStatusBarIconsBehaviorChanged(hide); 4396 } 4397 4398 @Override 4399 public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) { 4400 checkCallerIsSystem(); 4401 mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime); 4402 } 4403 4404 @Override 4405 public NotificationListenerFilter getListenerFilter(ComponentName cn, int userId) { 4406 checkCallerIsSystem(); 4407 return mListeners.getNotificationListenerFilter(Pair.create(cn, userId)); 4408 } 4409 4410 @Override 4411 public void setListenerFilter(ComponentName cn, int userId, 4412 NotificationListenerFilter nlf) { 4413 checkCallerIsSystem(); 4414 mListeners.setNotificationListenerFilter(Pair.create(cn, userId), nlf); 4415 // TODO (b/173052211): cancel notifications for listeners that can no longer see them 4416 handleSavePolicyFile(); 4417 } 4418 4419 @Override 4420 public int getPackageImportance(String pkg) { 4421 checkCallerIsSystemOrSameApp(pkg); 4422 if (mPermissionHelper.hasPermission(Binder.getCallingUid())) { 4423 return IMPORTANCE_DEFAULT; 4424 } else { 4425 return IMPORTANCE_NONE; 4426 } 4427 } 4428 4429 @Override 4430 public boolean isImportanceLocked(String pkg, int uid) { 4431 checkCallerIsSystem(); 4432 return mPreferencesHelper.isImportanceLocked(pkg, uid); 4433 } 4434 4435 @Override 4436 public boolean canShowBadge(String pkg, int uid) { 4437 checkCallerIsSystem(); 4438 return mPreferencesHelper.canShowBadge(pkg, uid); 4439 } 4440 4441 @Override 4442 public void setShowBadge(String pkg, int uid, boolean showBadge) { 4443 checkCallerIsSystem(); 4444 mPreferencesHelper.setShowBadge(pkg, uid, showBadge); 4445 handleSavePolicyFile(); 4446 } 4447 4448 @Override 4449 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 4450 public void allowAssistantAdjustment(String adjustmentType) { 4451 checkCallerIsSystemOrSystemUiOrShell(); 4452 mAssistants.allowAdjustmentType(adjustmentType); 4453 int userId = UserHandle.getUserId(Binder.getCallingUid()); 4454 if ((notificationClassificationUi() && notificationRegroupOnClassification())) { 4455 if (KEY_TYPE.equals(adjustmentType)) { 4456 applyNotificationUpdateForUser(userId, 4457 NotificationManagerService.this::reclassifyNotificationLocked); 4458 } 4459 } 4460 handleSavePolicyFile(); 4461 } 4462 4463 @Override 4464 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 4465 public void disallowAssistantAdjustment(String adjustmentType) { 4466 checkCallerIsSystemOrSystemUiOrShell(); 4467 mAssistants.disallowAdjustmentType(adjustmentType); 4468 int userId = UserHandle.getUserId(Binder.getCallingUid()); 4469 if ((notificationClassificationUi() && notificationRegroupOnClassification())) { 4470 if (KEY_TYPE.equals(adjustmentType)) { 4471 applyNotificationUpdateForUser(userId, 4472 NotificationManagerService.this::unclassifyNotificationLocked); 4473 } 4474 } 4475 if (nmSummarizationUi() || nmSummarization()) { 4476 if (KEY_SUMMARIZATION.equals(adjustmentType)) { 4477 applyNotificationUpdateForUser(userId, 4478 NotificationManagerService.this::unsummarizeNotificationLocked); 4479 } 4480 } 4481 handleSavePolicyFile(); 4482 } 4483 4484 @Override 4485 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 4486 public void setAdjustmentTypeSupportedState(INotificationListener token, 4487 @Adjustment.Keys String key, boolean supported) { 4488 final long identity = Binder.clearCallingIdentity(); 4489 try { 4490 synchronized (mNotificationLock) { 4491 final ManagedServiceInfo info = mAssistants.checkServiceTokenLocked(token); 4492 if (key == null) { 4493 return; 4494 } 4495 mAssistants.setAdjustmentTypeSupportedState(info.userid, key, supported); 4496 } 4497 } finally { 4498 Binder.restoreCallingIdentity(identity); 4499 } 4500 handleSavePolicyFile(); 4501 } 4502 4503 @Override 4504 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 4505 public @NonNull List<String> getUnsupportedAdjustmentTypes() { 4506 checkCallerIsSystemOrSystemUiOrShell(); 4507 synchronized (mNotificationLock) { 4508 return new ArrayList(mAssistants.getUnsupportedAdjustments( 4509 UserHandle.getUserId(Binder.getCallingUid()))); 4510 } 4511 } 4512 4513 @Override 4514 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 4515 public @NonNull int[] getAllowedAdjustmentKeyTypes() { 4516 checkCallerIsSystemOrSystemUiOrShell(); 4517 return mAssistants.getAllowedClassificationTypes(); 4518 } 4519 4520 @Override 4521 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 4522 public void setAssistantAdjustmentKeyTypeState(int type, boolean enabled) { 4523 checkCallerIsSystemOrSystemUiOrShell(); 4524 mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled); 4525 if ((notificationClassificationUi() && notificationRegroupOnClassification())) { 4526 if (enabled) { 4527 applyNotificationUpdateForUserAndType( 4528 UserHandle.getUserId(Binder.getCallingUid()), type, 4529 NotificationManagerService.this::reclassifyNotificationLocked); 4530 } else { 4531 applyNotificationUpdateForUserAndChannelType( 4532 UserHandle.getUserId(Binder.getCallingUid()), type, 4533 NotificationManagerService.this::unclassifyNotificationLocked); 4534 } 4535 } 4536 handleSavePolicyFile(); 4537 } 4538 4539 @Override 4540 public String[] getAdjustmentDeniedPackages(String key) { 4541 checkCallerIsSystemOrSystemUiOrShell(); 4542 return mAssistants.getAdjustmentDeniedPackages(key); 4543 } 4544 4545 @Override 4546 public boolean isAdjustmentSupportedForPackage(String key, String pkg) { 4547 checkCallerIsSystemOrSystemUiOrShell(); 4548 return mAssistants.isAdjustmentAllowedForPackage(key, pkg); 4549 } 4550 4551 @Override 4552 public void setAdjustmentSupportedForPackage(@Adjustment.Keys String key, String pkg, 4553 boolean enabled) { 4554 checkCallerIsSystemOrSystemUiOrShell(); 4555 mAssistants.setAdjustmentSupportedForPackage(key, pkg, enabled); 4556 if (notificationClassificationUi() && notificationRegroupOnClassification() 4557 && key.equals(KEY_TYPE)) { 4558 if (enabled) { 4559 applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), 4560 pkg, NotificationManagerService.this::reclassifyNotificationLocked); 4561 } else { 4562 applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), 4563 pkg, NotificationManagerService.this::unclassifyNotificationLocked); 4564 } 4565 } 4566 if (nmSummarization() || nmSummarizationUi()) { 4567 if (KEY_SUMMARIZATION.equals(key) && !enabled) { 4568 applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()), 4569 pkg, NotificationManagerService.this::unsummarizeNotificationLocked); 4570 } 4571 } 4572 handleSavePolicyFile(); 4573 } 4574 4575 @Override 4576 @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) 4577 public boolean appCanBePromoted(String pkg, int uid) { 4578 checkCallerIsSystemOrSystemUiOrShell(); 4579 if (!android.app.Flags.apiRichOngoing()) { 4580 return false; 4581 } 4582 return mPreferencesHelper.canBePromoted(pkg, uid); 4583 } 4584 4585 @Override 4586 @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) 4587 public boolean canBePromoted(String callingPkg) { 4588 checkCallerIsSameApp(callingPkg); 4589 if (!android.app.Flags.apiRichOngoing()) { 4590 return false; 4591 } 4592 return mPreferencesHelper.canBePromoted(callingPkg, Binder.getCallingUid()); 4593 } 4594 4595 4596 /** 4597 * Any changes from SystemUI or Settings should be fromUser == true. Any changes the 4598 * allowlist should be fromUser == false. 4599 */ 4600 @Override 4601 @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) 4602 public void setCanBePromoted(String pkg, int uid, boolean promote, boolean fromUser) { 4603 checkCallerIsSystemOrSystemUiOrShell(); 4604 if (!android.app.Flags.apiRichOngoing()) { 4605 return; 4606 } 4607 boolean changed = mPreferencesHelper.setCanBePromoted(pkg, uid, promote, fromUser); 4608 if (changed) { 4609 // check for pending/posted notifs from this app and update the flag 4610 synchronized (mNotificationLock) { 4611 // for enqueued we just need to update the flag 4612 List<NotificationRecord> enqueued = findAppNotificationByListLocked( 4613 mEnqueuedNotifications, pkg, UserHandle.getUserId(uid)); 4614 for (NotificationRecord r : enqueued) { 4615 if (promote 4616 && r.getNotification().hasPromotableCharacteristics() 4617 && r.getImportance() > IMPORTANCE_MIN) { 4618 r.getNotification().flags |= FLAG_PROMOTED_ONGOING; 4619 } else if (!promote) { 4620 r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING; 4621 } 4622 } 4623 // if the notification is posted we need to update the flag and tell listeners 4624 List<NotificationRecord> posted = findAppNotificationByListLocked( 4625 mNotificationList, pkg, UserHandle.getUserId(uid)); 4626 for (NotificationRecord r : posted) { 4627 if (promote 4628 && !hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING) 4629 && r.getNotification().hasPromotableCharacteristics() 4630 && r.getImportance() > IMPORTANCE_MIN) { 4631 r.getNotification().flags |= FLAG_PROMOTED_ONGOING; 4632 // we could set a wake lock here but this value should only change 4633 // in response to user action, so the device should be awake long enough 4634 // to post 4635 PostNotificationTracker tracker = 4636 mPostNotificationTrackerFactory.newTracker(null); 4637 // Set false for isAppForeground because that field is only used 4638 // for bubbles and messagingstyle can not be promoted 4639 mHandler.post(new EnqueueNotificationRunnable( 4640 r.getUser().getIdentifier(), 4641 r, /* isAppForeground */ false, /* isAppProvided= */ false, 4642 tracker)); 4643 } else if (!promote 4644 && hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING)){ 4645 r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING; 4646 PostNotificationTracker tracker = 4647 mPostNotificationTrackerFactory.newTracker(null); 4648 mHandler.post(new EnqueueNotificationRunnable( 4649 r.getUser().getIdentifier(), 4650 r, /* isAppForeground */ false, /* isAppProvided= */ false, 4651 tracker)); 4652 } 4653 } 4654 } 4655 handleSavePolicyFile(); 4656 } 4657 } 4658 4659 @Override 4660 public boolean hasSentValidMsg(String pkg, int uid) { 4661 checkCallerIsSystem(); 4662 return mPreferencesHelper.hasSentValidMsg(pkg, uid); 4663 } 4664 4665 @Override 4666 public boolean isInInvalidMsgState(String pkg, int uid) { 4667 checkCallerIsSystem(); 4668 return mPreferencesHelper.isInInvalidMsgState(pkg, uid); 4669 } 4670 4671 @Override 4672 public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) { 4673 checkCallerIsSystem(); 4674 return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid); 4675 } 4676 4677 @Override 4678 public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) { 4679 checkCallerIsSystem(); 4680 mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted); 4681 handleSavePolicyFile(); 4682 } 4683 4684 @Override 4685 public boolean hasSentValidBubble(String pkg, int uid) { 4686 checkCallerIsSystem(); 4687 return mPreferencesHelper.hasSentValidBubble(pkg, uid); 4688 } 4689 4690 @Override 4691 public void setNotificationDelegate(String callingPkg, String delegate) { 4692 checkCallerIsSameApp(callingPkg); 4693 final int callingUid = Binder.getCallingUid(); 4694 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 4695 if (delegate == null) { 4696 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid()); 4697 handleSavePolicyFile(); 4698 } else { 4699 try { 4700 ApplicationInfo info = 4701 mPackageManager.getApplicationInfo(delegate, 4702 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 4703 user.getIdentifier()); 4704 if (info != null) { 4705 mPreferencesHelper.setNotificationDelegate( 4706 callingPkg, callingUid, delegate, info.uid); 4707 handleSavePolicyFile(); 4708 } 4709 } catch (RemoteException e) { 4710 e.rethrowFromSystemServer(); 4711 } 4712 } 4713 } 4714 4715 @Override 4716 public String getNotificationDelegate(String callingPkg) { 4717 // callable by Settings also 4718 checkCallerIsSystemOrSameApp(callingPkg); 4719 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid()); 4720 } 4721 4722 @Override 4723 public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) { 4724 checkCallerIsSameApp(callingPkg); 4725 final int callingUid = Binder.getCallingUid(); 4726 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 4727 if (user.getIdentifier() != userId) { 4728 getContext().enforceCallingPermission( 4729 android.Manifest.permission.INTERACT_ACROSS_USERS, 4730 "canNotifyAsPackage for user " + userId); 4731 } 4732 if (callingPkg.equals(targetPkg)) { 4733 return true; 4734 } 4735 try { 4736 ApplicationInfo info = 4737 mPackageManager.getApplicationInfo(targetPkg, 4738 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 4739 userId); 4740 if (info != null) { 4741 return mPreferencesHelper.isDelegateAllowed( 4742 targetPkg, info.uid, callingPkg, callingUid); 4743 } 4744 } catch (RemoteException e) { 4745 // :( 4746 } 4747 return false; 4748 } 4749 4750 @Override 4751 public boolean canUseFullScreenIntent(@NonNull AttributionSource attributionSource) { 4752 final String packageName = attributionSource.getPackageName(); 4753 final int uid = attributionSource.getUid(); 4754 final int userId = UserHandle.getUserId(uid); 4755 checkCallerIsSameApp(packageName, uid, userId); 4756 4757 final ApplicationInfo applicationInfo; 4758 try { 4759 applicationInfo = mPackageManagerClient.getApplicationInfoAsUser( 4760 packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId); 4761 } catch (NameNotFoundException e) { 4762 Slog.e(TAG, "Failed to getApplicationInfo() in canUseFullScreenIntent()", e); 4763 return false; 4764 } 4765 return checkUseFullScreenIntentPermission(attributionSource, applicationInfo, 4766 false /* forDataDelivery */); 4767 } 4768 4769 @Override 4770 public void updateNotificationChannelGroupForPackage(String pkg, int uid, 4771 NotificationChannelGroup group) throws RemoteException { 4772 enforceSystemOrSystemUI("Caller not system or systemui"); 4773 createNotificationChannelGroup(pkg, uid, group, false, false); 4774 handleSavePolicyFile(); 4775 } 4776 4777 @Override 4778 public void createNotificationChannelGroups(String pkg, 4779 ParceledListSlice channelGroupList) throws RemoteException { 4780 checkCallerIsSystemOrSameApp(pkg); 4781 List<NotificationChannelGroup> groups = channelGroupList.getList(); 4782 final int groupSize = groups.size(); 4783 for (int i = 0; i < groupSize; i++) { 4784 final NotificationChannelGroup group = groups.get(i); 4785 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false); 4786 } 4787 handleSavePolicyFile(); 4788 } 4789 4790 private void createNotificationChannelsImpl(String pkg, int uid, 4791 ParceledListSlice channelsList) { 4792 createNotificationChannelsImpl(pkg, uid, channelsList, 4793 ActivityTaskManager.INVALID_TASK_ID); 4794 } 4795 4796 private void createNotificationChannelsImpl(String pkg, int uid, 4797 ParceledListSlice channelsList, int startingTaskId) { 4798 List<NotificationChannel> channels = channelsList.getList(); 4799 final int channelsSize = channels.size(); 4800 ParceledListSlice<NotificationChannel> oldChannels = 4801 mPreferencesHelper.getNotificationChannels(pkg, uid, true, false); 4802 final boolean hadNonBundleChannel = 4803 oldChannels != null && !oldChannels.getList().isEmpty(); 4804 boolean needsPolicyFileChange = false; 4805 boolean hasRequestedNotificationPermission = false; 4806 for (int i = 0; i < channelsSize; i++) { 4807 final NotificationChannel channel = channels.get(i); 4808 Objects.requireNonNull(channel, "channel in list is null"); 4809 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid, 4810 channel, true /* fromTargetApp */, 4811 mConditionProviders.isPackageOrComponentAllowed( 4812 pkg, UserHandle.getUserId(uid)), Binder.getCallingUid(), 4813 isCallerSystemOrSystemUi()); 4814 if (needsPolicyFileChange) { 4815 mListeners.notifyNotificationChannelChanged(pkg, 4816 UserHandle.getUserHandleForUid(uid), 4817 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), 4818 false), 4819 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 4820 boolean hasNonBundleChannel = 4821 hadNonBundleChannel || hasRequestedNotificationPermission; 4822 if (!hasNonBundleChannel) { 4823 ParceledListSlice<NotificationChannel> currChannels = 4824 mPreferencesHelper.getNotificationChannels(pkg, uid, true, false); 4825 hasNonBundleChannel = 4826 currChannels != null && !currChannels.getList().isEmpty(); 4827 } 4828 // show perm prompt if new non-bundle channel added and the user has not 4829 // seen the prompt 4830 if (!hadNonBundleChannel && hasNonBundleChannel 4831 && !hasRequestedNotificationPermission 4832 && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) { 4833 hasRequestedNotificationPermission = true; 4834 if (mPermissionPolicyInternal == null) { 4835 mPermissionPolicyInternal = 4836 LocalServices.getService(PermissionPolicyInternal.class); 4837 } 4838 mHandler.post(new ShowNotificationPermissionPromptRunnable(pkg, 4839 UserHandle.getUserId(uid), startingTaskId, 4840 mPermissionPolicyInternal)); 4841 } 4842 } 4843 } 4844 if (needsPolicyFileChange) { 4845 handleSavePolicyFile(); 4846 } 4847 } 4848 4849 @Override 4850 public void createNotificationChannels(String pkg, ParceledListSlice channelsList) { 4851 checkCallerIsSystemOrSameApp(pkg); 4852 int taskId = ActivityTaskManager.INVALID_TASK_ID; 4853 try { 4854 int uid = mPackageManager.getPackageUid(pkg, 0, 4855 UserHandle.getUserId(Binder.getCallingUid())); 4856 taskId = mAtm.getTaskToShowPermissionDialogOn(pkg, uid); 4857 } catch (RemoteException e) { 4858 // Do nothing 4859 } 4860 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList, taskId); 4861 } 4862 4863 @Override 4864 public void createNotificationChannelsForPackage(String pkg, int uid, 4865 ParceledListSlice channelsList) { 4866 enforceSystemOrSystemUI("only system can call this"); 4867 createNotificationChannelsImpl(pkg, uid, channelsList); 4868 } 4869 4870 @Override 4871 public void createConversationNotificationChannelForPackage(String pkg, int uid, 4872 NotificationChannel parentChannel, String conversationId) { 4873 enforceSystemOrSystemUI("only system can call this"); 4874 checkNotNull(parentChannel); 4875 checkNotNull(conversationId); 4876 String parentId = parentChannel.getId(); 4877 NotificationChannel conversationChannel = parentChannel; 4878 conversationChannel.setId(String.format( 4879 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId)); 4880 conversationChannel.setConversationId(parentId, conversationId); 4881 createNotificationChannelsImpl( 4882 pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel))); 4883 mRankingHandler.requestSort(); 4884 handleSavePolicyFile(); 4885 } 4886 4887 @Override 4888 public NotificationChannel getNotificationChannel(String callingPkg, int userId, 4889 String targetPkg, String channelId) { 4890 return getConversationNotificationChannel( 4891 callingPkg, userId, targetPkg, channelId, true, null); 4892 } 4893 4894 @Override 4895 public NotificationChannel getConversationNotificationChannel(String callingPkg, int userId, 4896 String targetPkg, String channelId, boolean returnParentIfNoConversationChannel, 4897 String conversationId) { 4898 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 4899 || isCallerSystemOrSystemUiOrShell()) { 4900 int targetUid = -1; 4901 try { 4902 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 4903 } catch (NameNotFoundException e) { 4904 /* ignore */ 4905 } 4906 return mPreferencesHelper.getConversationNotificationChannel( 4907 targetPkg, targetUid, channelId, conversationId, 4908 returnParentIfNoConversationChannel, false /* includeDeleted */); 4909 } 4910 throw new SecurityException("Pkg " + callingPkg 4911 + " cannot read channels for " + targetPkg + " in " + userId); 4912 } 4913 4914 @Override 4915 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, 4916 String channelId, String conversationId, boolean includeDeleted) { 4917 checkCallerIsSystem(); 4918 return mPreferencesHelper.getConversationNotificationChannel( 4919 pkg, uid, channelId, conversationId, true, includeDeleted); 4920 } 4921 4922 // Returns 'true' if the given channel has a notification associated 4923 // with an active foreground service. 4924 private void enforceDeletingChannelHasNoFgService(String pkg, int userId, 4925 String channelId) { 4926 if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { 4927 Slog.w(TAG, "Package u" + userId + "/" + pkg 4928 + " may not delete notification channel '" 4929 + channelId + "' with fg service"); 4930 throw new SecurityException("Not allowed to delete channel " + channelId 4931 + " with a foreground service"); 4932 } 4933 } 4934 4935 // Throws a security exception if the given channel has a notification associated 4936 // with an active user-initiated job. 4937 private void enforceDeletingChannelHasNoUserInitiatedJob(String pkg, int userId, 4938 String channelId) { 4939 final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); 4940 if (js != null && js.isNotificationChannelAssociatedWithAnyUserInitiatedJobs( 4941 channelId, userId, pkg)) { 4942 Slog.w(TAG, "Package u" + userId + "/" + pkg 4943 + " may not delete notification channel '" 4944 + channelId + "' with user-initiated job"); 4945 throw new SecurityException("Not allowed to delete channel " + channelId 4946 + " with a user-initiated job"); 4947 } 4948 } 4949 4950 @Override 4951 public void deleteNotificationChannel(String pkg, String channelId) { 4952 checkCallerIsSystemOrSameApp(pkg); 4953 final int callingUid = Binder.getCallingUid(); 4954 final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi(); 4955 final int callingUser = UserHandle.getUserId(callingUid); 4956 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 4957 throw new IllegalArgumentException("Cannot delete default channel"); 4958 } 4959 if (notificationClassification()) { 4960 // Check for all reserved channels, but do not throw because it's a common 4961 // preexisting pattern for apps to (try to) delete all channels that don't match 4962 // their current desired channel structure 4963 if (SYSTEM_RESERVED_IDS.contains(channelId)) { 4964 Log.v(TAG, "Package " + pkg + " cannot delete a reserved channel"); 4965 return; 4966 } 4967 } 4968 enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); 4969 enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId); 4970 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, 4971 callingUser, REASON_CHANNEL_REMOVED); 4972 boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel( 4973 pkg, callingUid, channelId, callingUid, isSystemOrSystemUi); 4974 if (previouslyExisted) { 4975 // Remove from both recent notification archive (recently dismissed notifications) 4976 // and notification history 4977 mArchive.removeChannelNotifications(pkg, callingUser, channelId); 4978 mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId); 4979 mListeners.notifyNotificationChannelChanged(pkg, 4980 UserHandle.getUserHandleForUid(callingUid), 4981 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true), 4982 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 4983 handleSavePolicyFile(); 4984 } 4985 } 4986 4987 @Override 4988 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) { 4989 checkCallerIsSystemOrSameApp(pkg); 4990 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 4991 pkg, Binder.getCallingUid(), groupId, false); 4992 } 4993 4994 @Override 4995 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups( 4996 String pkg) { 4997 checkCallerIsSystemOrSameApp(pkg); 4998 return mPreferencesHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid(), 4999 NotificationChannelGroupsHelper.Params.forAllGroups()); 5000 } 5001 5002 @Override 5003 public ParceledListSlice<NotificationChannelGroup> 5004 getNotificationChannelGroupsWithoutChannels(String pkg) { 5005 checkCallerIsSystemOrSameApp(pkg); 5006 List<NotificationChannelGroup> groups = new ArrayList<>(); 5007 groups.addAll(mPreferencesHelper.getNotificationChannelGroupsWithoutChannels(pkg, 5008 Binder.getCallingUid())); 5009 return new ParceledListSlice<>(groups); 5010 } 5011 5012 @Override 5013 public void deleteNotificationChannelGroup(String pkg, String groupId) { 5014 checkCallerIsSystemOrSameApp(pkg); 5015 5016 final int callingUid = Binder.getCallingUid(); 5017 final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi(); 5018 NotificationChannelGroup groupToDelete = 5019 mPreferencesHelper.getNotificationChannelGroupWithChannels( 5020 pkg, callingUid, groupId, false); 5021 if (groupToDelete != null) { 5022 // Preflight for allowability 5023 final int userId = UserHandle.getUserId(callingUid); 5024 List<NotificationChannel> groupChannels = groupToDelete.getChannels(); 5025 for (int i = 0; i < groupChannels.size(); i++) { 5026 final String channelId = groupChannels.get(i).getId(); 5027 enforceDeletingChannelHasNoFgService(pkg, userId, channelId); 5028 enforceDeletingChannelHasNoUserInitiatedJob(pkg, userId, channelId); 5029 } 5030 List<NotificationChannel> deletedChannels = 5031 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId, 5032 callingUid, isSystemOrSystemUi); 5033 for (int i = 0; i < deletedChannels.size(); i++) { 5034 final NotificationChannel deletedChannel = deletedChannels.get(i); 5035 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, 5036 userId, REASON_CHANNEL_REMOVED 5037 ); 5038 mListeners.notifyNotificationChannelChanged(pkg, 5039 UserHandle.getUserHandleForUid(callingUid), 5040 deletedChannel, 5041 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 5042 } 5043 mListeners.notifyNotificationChannelGroupChanged( 5044 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, 5045 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 5046 handleSavePolicyFile(); 5047 } 5048 } 5049 5050 @Override 5051 public void updateNotificationChannelForPackage(String pkg, int uid, 5052 NotificationChannel channel) { 5053 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 5054 Objects.requireNonNull(channel); 5055 updateNotificationChannelInt(pkg, uid, channel, false); 5056 } 5057 5058 @Override 5059 public void unlockNotificationChannel(String pkg, int uid, String channelId) { 5060 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 5061 mPreferencesHelper.unlockNotificationChannelImportance(pkg, uid, channelId); 5062 handleSavePolicyFile(); 5063 } 5064 5065 @Override 5066 public void unlockAllNotificationChannels() { 5067 checkCallerIsSystem(); 5068 mPreferencesHelper.unlockAllNotificationChannels(); 5069 handleSavePolicyFile(); 5070 } 5071 5072 @Override 5073 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg, 5074 int uid, boolean includeDeleted) { 5075 enforceSystemOrSystemUI("getNotificationChannelsForPackage"); 5076 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted, true); 5077 } 5078 5079 @Override 5080 public int getNumNotificationChannelsForPackage(String pkg, int uid, 5081 boolean includeDeleted) { 5082 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage"); 5083 return NotificationManagerService.this 5084 .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted); 5085 } 5086 5087 @Override 5088 public boolean onlyHasDefaultChannel(String pkg, int uid) { 5089 enforceSystemOrSystemUI("onlyHasDefaultChannel"); 5090 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid); 5091 } 5092 5093 @Override 5094 public int getDeletedChannelCount(String pkg, int uid) { 5095 enforceSystemOrSystemUI("getDeletedChannelCount"); 5096 return mPreferencesHelper.getDeletedChannelCount(pkg, uid); 5097 } 5098 5099 @Override 5100 public int getBlockedChannelCount(String pkg, int uid) { 5101 enforceSystemOrSystemUI("getBlockedChannelCount"); 5102 return mPreferencesHelper.getBlockedChannelCount(pkg, uid); 5103 } 5104 5105 @Override 5106 public ParceledListSlice<ConversationChannelWrapper> getConversations( 5107 boolean onlyImportant) { 5108 enforceSystemOrSystemUI("getConversations"); 5109 IntArray userIds = mUserProfiles.getCurrentProfileIds(); 5110 ArrayList<ConversationChannelWrapper> conversations = 5111 mPreferencesHelper.getConversations(userIds, onlyImportant); 5112 for (ConversationChannelWrapper conversation : conversations) { 5113 if (mShortcutHelper == null) { 5114 conversation.setShortcutInfo(null); 5115 } else { 5116 conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo( 5117 conversation.getNotificationChannel().getConversationId(), 5118 conversation.getPkg(), 5119 UserHandle.of(UserHandle.getUserId(conversation.getUid())))); 5120 } 5121 } 5122 return new ParceledListSlice<>(conversations); 5123 } 5124 5125 @Override 5126 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage( 5127 String pkg, int uid, boolean includeDeleted) { 5128 enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage"); 5129 return mPreferencesHelper.getNotificationChannelGroups(pkg, uid, 5130 new NotificationChannelGroupsHelper.Params(includeDeleted, true, false, true, 5131 null)); 5132 } 5133 5134 @Override 5135 public ParceledListSlice<NotificationChannelGroup> 5136 getRecentBlockedNotificationChannelGroupsForPackage(String pkg, int uid) { 5137 enforceSystemOrSystemUI("getRecentBlockedNotificationChannelGroupsForPackage"); 5138 Set<String> recentlySentChannels = new HashSet<>(); 5139 long now = System.currentTimeMillis(); 5140 long startTime = now - (DateUtils.DAY_IN_MILLIS * 14); 5141 UsageEvents events = mUsageStatsManagerInternal.queryEventsForUser( 5142 UserHandle.getUserId(uid), startTime, now, UsageEvents.SHOW_ALL_EVENT_DATA); 5143 // get all channelids that sent notifs in the past 2 weeks 5144 if (events != null) { 5145 UsageEvents.Event event = new UsageEvents.Event(); 5146 while (events.hasNextEvent()) { 5147 events.getNextEvent(event); 5148 if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { 5149 if (pkg.equals(event.mPackage)) { 5150 String channelId = event.mNotificationChannelId; 5151 if (channelId != null) { 5152 recentlySentChannels.add(channelId); 5153 } 5154 } 5155 } 5156 } 5157 } 5158 5159 return mPreferencesHelper.getNotificationChannelGroups(pkg, uid, 5160 NotificationChannelGroupsHelper.Params.onlySpecifiedOrBlockedChannels( 5161 recentlySentChannels)); 5162 } 5163 5164 @Override 5165 public ParceledListSlice<ConversationChannelWrapper> getConversationsForPackage(String pkg, 5166 int uid) { 5167 enforceSystemOrSystemUI("getConversationsForPackage"); 5168 ArrayList<ConversationChannelWrapper> conversations = 5169 mPreferencesHelper.getConversations(pkg, uid); 5170 for (ConversationChannelWrapper conversation : conversations) { 5171 if (mShortcutHelper == null) { 5172 conversation.setShortcutInfo(null); 5173 } else { 5174 conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo( 5175 conversation.getNotificationChannel().getConversationId(), 5176 pkg, 5177 UserHandle.of(UserHandle.getUserId(uid)))); 5178 } 5179 } 5180 return new ParceledListSlice<>(conversations); 5181 } 5182 5183 @Override 5184 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage( 5185 String pkg, int uid, String groupId, boolean includeDeleted) { 5186 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage"); 5187 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 5188 pkg, uid, groupId, includeDeleted); 5189 } 5190 5191 @Override 5192 public NotificationChannelGroup getNotificationChannelGroupForPackage( 5193 String groupId, String pkg, int uid) { 5194 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage"); 5195 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid); 5196 } 5197 5198 @Override 5199 public ParceledListSlice<NotificationChannel> getNotificationChannels(String callingPkg, 5200 String targetPkg, int userId) { 5201 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 5202 || isCallingUidSystem()) { 5203 int targetUid = -1; 5204 try { 5205 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 5206 } catch (NameNotFoundException e) { 5207 /* ignore */ 5208 } 5209 return mPreferencesHelper.getNotificationChannels( 5210 targetPkg, targetUid, false /* includeDeleted */, true); 5211 } 5212 throw new SecurityException("Pkg " + callingPkg 5213 + " cannot read channels for " + targetPkg + " in " + userId); 5214 } 5215 5216 @Override 5217 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( 5218 String pkg, int uid) { 5219 checkCallerIsSystem(); 5220 if (!areNotificationsEnabledForPackage(pkg, uid)) { 5221 return ParceledListSlice.emptyList(); 5222 } 5223 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid); 5224 } 5225 5226 @Override 5227 public ParceledListSlice<ZenBypassingApp> getPackagesBypassingDnd(int userId) 5228 throws RemoteException { 5229 checkCallerIsSystem(); 5230 5231 UserHandle user = UserHandle.of(userId); 5232 ArrayList<ZenBypassingApp> bypassing = 5233 mPreferencesHelper.getPackagesBypassingDnd(userId); 5234 for (int i = bypassing.size() - 1; i >= 0; i--) { 5235 String pkg = bypassing.get(i).getPkg(); 5236 if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) { 5237 bypassing.remove(i); 5238 } 5239 } 5240 return new ParceledListSlice<>(bypassing); 5241 } 5242 5243 @Override 5244 public boolean areChannelsBypassingDnd() { 5245 return mZenModeHelper.getConsolidatedNotificationPolicy().allowPriorityChannels() 5246 && mPreferencesHelper.hasPriorityChannels(); 5247 } 5248 5249 @Override 5250 @FlaggedApi(android.app.Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS) 5251 public List<String> getPackagesWithAnyChannels(int userId) throws RemoteException { 5252 checkCallerIsSystem(); 5253 UserHandle user = UserHandle.of(userId); 5254 List<String> packages = mPreferencesHelper.getPackagesWithAnyChannels(userId); 5255 for (int i = packages.size() - 1; i >= 0; i--) { 5256 String pkg = packages.get(i); 5257 if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) { 5258 packages.remove(i); 5259 } 5260 } 5261 return packages; 5262 } 5263 5264 @Override 5265 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException { 5266 boolean packagesChanged = false; 5267 checkCallerIsSystem(); 5268 // Cancel posted notifications 5269 final int userId = UserHandle.getUserId(uid); 5270 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, 5271 UserHandle.getUserId(Binder.getCallingUid()), REASON_CLEAR_DATA); 5272 5273 // Zen 5274 packagesChanged |= 5275 mConditionProviders.resetPackage(packageName, userId); 5276 5277 // Listener 5278 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 5279 mListeners.resetComponents(packageName, userId); 5280 packagesChanged |= changedListeners.get(true).size() > 0 5281 || changedListeners.get(false).size() > 0; 5282 5283 // When a listener is enabled, we enable the dnd package as a secondary 5284 for (int i = 0; i < changedListeners.get(true).size(); i++) { 5285 mConditionProviders.setPackageOrComponentEnabled( 5286 changedListeners.get(true).get(i).getPackageName(), 5287 userId, false, true); 5288 } 5289 5290 // Assistant 5291 ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants = 5292 mAssistants.resetComponents(packageName, userId); 5293 packagesChanged |= changedAssistants.get(true).size() > 0 5294 || changedAssistants.get(false).size() > 0; 5295 5296 // we want only one assistant enabled 5297 for (int i = 1; i < changedAssistants.get(true).size(); i++) { 5298 mAssistants.setPackageOrComponentEnabled( 5299 changedAssistants.get(true).get(i).flattenToString(), 5300 userId, true, false); 5301 } 5302 5303 // When the default assistant is enabled, we enable the dnd package as a secondary 5304 if (changedAssistants.get(true).size() > 0) { 5305 //we want only one assistant active 5306 mConditionProviders 5307 .setPackageOrComponentEnabled( 5308 changedAssistants.get(true).get(0).getPackageName(), 5309 userId, false, true); 5310 5311 } 5312 5313 // Snoozing 5314 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName); 5315 5316 // Reset notification preferences 5317 if (!fromApp) { 5318 mPreferencesHelper.clearData(packageName, uid); 5319 } 5320 5321 if (packagesChanged) { 5322 getContext().sendBroadcastAsUser(new Intent( 5323 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 5324 .setPackage(packageName) 5325 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 5326 UserHandle.of(userId), null); 5327 } 5328 5329 handleSavePolicyFile(); 5330 } 5331 5332 @Override 5333 public List<String> getAllowedAssistantAdjustments(String pkg) { 5334 checkCallerIsSystemOrSameApp(pkg); 5335 5336 if (!isCallerSystemOrPhone() 5337 && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) { 5338 throw new SecurityException("Not currently an assistant"); 5339 } 5340 5341 return new ArrayList<>(mAssistants.getAllowedAssistantAdjustments()); 5342 } 5343 5344 /** 5345 * @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead. 5346 */ 5347 @Deprecated 5348 @Override 5349 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 5350 return getActiveNotificationsWithAttribution(callingPkg, null); 5351 } 5352 5353 /** 5354 * System-only API for getting a list of current (i.e. not cleared) notifications. 5355 * 5356 * Requires ACCESS_NOTIFICATIONS which is signature|system. 5357 * @returns A list of all the notifications, in natural order. 5358 */ 5359 @Override 5360 @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 5361 public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg, 5362 String callingAttributionTag) { 5363 // enforce() will ensure the calling uid has the correct permission 5364 getActiveNotificationsWithAttribution_enforcePermission(); 5365 5366 ArrayList<StatusBarNotification> tmp = new ArrayList<>(); 5367 int uid = Binder.getCallingUid(); 5368 5369 ArrayList<Integer> currentUsers = new ArrayList<>(); 5370 currentUsers.add(USER_ALL); 5371 Binder.withCleanCallingIdentity(() -> { 5372 for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) { 5373 currentUsers.add(user); 5374 } 5375 }); 5376 5377 // noteOp will check to make sure the callingPkg matches the uid 5378 int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 5379 callingAttributionTag, null); 5380 if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { 5381 synchronized (mNotificationLock) { 5382 final int N = mNotificationList.size(); 5383 for (int i = 0; i < N; i++) { 5384 final StatusBarNotification sbn = mNotificationList.get(i).getSbn(); 5385 if (currentUsers.contains(sbn.getUserId())) { 5386 tmp.add(sbn); 5387 } 5388 } 5389 } 5390 } 5391 return tmp.toArray(new StatusBarNotification[tmp.size()]); 5392 } 5393 5394 /** 5395 * Public API for getting a list of current notifications for the calling package/uid. 5396 * 5397 * Note that since notification posting is done asynchronously, this will not return 5398 * notifications that are in the process of being posted. 5399 * 5400 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as 5401 * an app's notification delegate via 5402 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}. 5403 * 5404 * @returns A list of all the package's notifications, in natural order. 5405 */ 5406 @Override 5407 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 5408 int incomingUserId) { 5409 checkCallerIsSystemOrSameApp(pkg); 5410 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 5411 Binder.getCallingUid(), incomingUserId, true, false, 5412 "getAppActiveNotifications", pkg); 5413 synchronized (mNotificationLock) { 5414 final ArrayMap<String, StatusBarNotification> map 5415 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); 5416 final int N = mNotificationList.size(); 5417 for (int i = 0; i < N; i++) { 5418 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 5419 mNotificationList.get(i).getSbn()); 5420 if (sbn != null) { 5421 map.put(sbn.getKey(), sbn); 5422 } 5423 } 5424 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) { 5425 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.getSbn()); 5426 if (sbn != null) { 5427 map.put(sbn.getKey(), sbn); 5428 } 5429 } 5430 final int M = mEnqueuedNotifications.size(); 5431 for (int i = 0; i < M; i++) { 5432 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 5433 mEnqueuedNotifications.get(i).getSbn()); 5434 if (sbn != null) { 5435 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here 5436 } 5437 } 5438 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); 5439 list.addAll(map.values()); 5440 return new ParceledListSlice<StatusBarNotification>(list); 5441 } 5442 } 5443 5444 /** Notifications returned here will have allowlistToken stripped from them. */ 5445 private StatusBarNotification sanitizeSbn(String pkg, int userId, 5446 StatusBarNotification sbn) { 5447 if (sbn.getUserId() == userId) { 5448 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) { 5449 // We could pass back a cloneLight() but clients might get confused and 5450 // try to send this thing back to notify() again, which would not work 5451 // very well. 5452 Notification notification = sbn.getNotification().clone(); 5453 // Remove background token before returning notification to untrusted app, this 5454 // ensures the app isn't able to perform background operations that are 5455 // associated with notification interactions. 5456 notification.overrideAllowlistToken(null); 5457 return new StatusBarNotification( 5458 sbn.getPackageName(), 5459 sbn.getOpPkg(), 5460 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 5461 notification, 5462 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); 5463 } 5464 } 5465 return null; 5466 } 5467 5468 /** 5469 * @deprecated Use {@link #getHistoricalNotificationsWithAttribution} instead. 5470 */ 5471 @Deprecated 5472 @Override 5473 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 5474 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count, 5475 boolean includeSnoozed) { 5476 return getHistoricalNotificationsWithAttribution(callingPkg, null, count, 5477 includeSnoozed); 5478 } 5479 5480 /** 5481 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 5482 */ 5483 @Override 5484 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 5485 @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 5486 public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg, 5487 String callingAttributionTag, int count, boolean includeSnoozed) { 5488 // enforce() will ensure the calling uid has the correct permission 5489 getHistoricalNotificationsWithAttribution_enforcePermission(); 5490 5491 StatusBarNotification[] tmp = null; 5492 int uid = Binder.getCallingUid(); 5493 5494 // noteOp will check to make sure the callingPkg matches the uid 5495 int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 5496 callingAttributionTag, null); 5497 if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { 5498 synchronized (mArchive) { 5499 tmp = mArchive.getArray(mUm, count, includeSnoozed); 5500 } 5501 } 5502 return tmp; 5503 } 5504 5505 /** 5506 * System-only API for getting a list of historical notifications. May contain multiple days 5507 * of notifications. 5508 */ 5509 @Override 5510 @WorkerThread 5511 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 5512 @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 5513 public NotificationHistory getNotificationHistory(String callingPkg, 5514 String callingAttributionTag) { 5515 // enforce() will ensure the calling uid has the correct permission 5516 getNotificationHistory_enforcePermission(); 5517 int uid = Binder.getCallingUid(); 5518 5519 // noteOp will check to make sure the callingPkg matches the uid 5520 int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 5521 callingAttributionTag, null); 5522 if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { 5523 IntArray currentUserIds = mUserProfiles.getCurrentProfileIds(); 5524 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory"); 5525 try { 5526 return mHistoryManager.readNotificationHistory(currentUserIds.toArray()); 5527 } finally { 5528 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 5529 } 5530 } 5531 return new NotificationHistory(); 5532 } 5533 5534 /** 5535 * Register a listener to be notified when a call notification is posted or removed 5536 * for a specific package and user. 5537 * @param packageName Which package to monitor 5538 * @param userHandle Which user to monitor 5539 * @param listener Listener to register 5540 */ 5541 @Override 5542 @EnforcePermission(allOf = { 5543 android.Manifest.permission.INTERACT_ACROSS_USERS, 5544 android.Manifest.permission.ACCESS_NOTIFICATIONS}) 5545 public void registerCallNotificationEventListener(String packageName, UserHandle userHandle, 5546 ICallNotificationEventCallback listener) { 5547 registerCallNotificationEventListener_enforcePermission(); 5548 5549 final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT 5550 ? userHandle.getIdentifier() : mAmi.getCurrentUserId(); 5551 5552 synchronized (mCallNotificationEventCallbacks) { 5553 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 5554 callbacksForPackage = 5555 mCallNotificationEventCallbacks.getOrDefault(packageName, new ArrayMap<>()); 5556 RemoteCallbackList<ICallNotificationEventCallback> callbackList = 5557 callbacksForPackage.getOrDefault(userId, new RemoteCallbackList<>()); 5558 5559 if (callbackList.register(listener)) { 5560 callbacksForPackage.put(userId, callbackList); 5561 mCallNotificationEventCallbacks.put(packageName, callbacksForPackage); 5562 } else { 5563 Log.e(TAG, 5564 "registerCallNotificationEventListener failed to register listener: " 5565 + packageName + " " + userHandle + " " + listener); 5566 return; 5567 } 5568 } 5569 5570 synchronized (mNotificationLock) { 5571 for (NotificationRecord r : mNotificationList) { 5572 if (r.getNotification().isStyle(Notification.CallStyle.class) 5573 && notificationMatchesUserId(r, userId, false) 5574 && r.getSbn().getPackageName().equals(packageName)) { 5575 try { 5576 listener.onCallNotificationPosted(packageName, r.getUser()); 5577 } catch (RemoteException e) { 5578 throw new RuntimeException(e); 5579 } 5580 } 5581 } 5582 } 5583 } 5584 5585 /** 5586 * Unregister a listener that was previously 5587 * registered with {@link #registerCallNotificationEventListener} 5588 * 5589 * @param packageName Which package to stop monitoring 5590 * @param userHandle Which user to stop monitoring 5591 * @param listener Listener to unregister 5592 */ 5593 @Override 5594 @EnforcePermission(allOf = { 5595 android.Manifest.permission.INTERACT_ACROSS_USERS, 5596 android.Manifest.permission.ACCESS_NOTIFICATIONS}) 5597 public void unregisterCallNotificationEventListener(String packageName, 5598 UserHandle userHandle, ICallNotificationEventCallback listener) { 5599 unregisterCallNotificationEventListener_enforcePermission(); 5600 synchronized (mCallNotificationEventCallbacks) { 5601 final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT 5602 ? userHandle.getIdentifier() : mAmi.getCurrentUserId(); 5603 5604 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 5605 callbacksForPackage = mCallNotificationEventCallbacks.get(packageName); 5606 if (callbacksForPackage == null) { 5607 return; 5608 } 5609 RemoteCallbackList<ICallNotificationEventCallback> callbackList = 5610 callbacksForPackage.get(userId); 5611 if (callbackList == null) { 5612 return; 5613 } 5614 if (!callbackList.unregister(listener)) { 5615 Log.e(TAG, 5616 "unregisterCallNotificationEventListener listener not found for: " 5617 + packageName + " " + userHandle + " " + listener); 5618 } 5619 } 5620 } 5621 5622 /** 5623 * Register a listener binder directly with the notification manager. 5624 * 5625 * Only works with system callers. Apps should extend 5626 * {@link NotificationListenerService}. 5627 */ 5628 @Override 5629 public void registerListener(final INotificationListener listener, 5630 final ComponentName component, final int userid) { 5631 enforceSystemOrSystemUI("INotificationManager.registerListener"); 5632 mListeners.registerSystemService(listener, component, userid, Binder.getCallingUid()); 5633 } 5634 5635 /** 5636 * Remove a listener binder directly 5637 */ 5638 @Override 5639 public void unregisterListener(INotificationListener token, int userid) { 5640 mListeners.unregisterService(token, userid); 5641 } 5642 5643 /** 5644 * Allow an INotificationListener to simulate a "clear all" operation. 5645 * 5646 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 5647 * 5648 * @param token The binder for the listener, to check that the caller is allowed 5649 */ 5650 @Override 5651 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 5652 final int callingUid = Binder.getCallingUid(); 5653 final int callingPid = Binder.getCallingPid(); 5654 final long identity = Binder.clearCallingIdentity(); 5655 boolean notificationsRapidlyCleared = false; 5656 final String pkg; 5657 final int packageImportance; 5658 final ManagedServiceInfo info; 5659 try { 5660 synchronized (mNotificationLock) { 5661 info = mListeners.checkServiceTokenLocked(token); 5662 pkg = info.component.getPackageName(); 5663 } 5664 if (lifetimeExtensionRefactor()) { 5665 packageImportance = getPackageImportanceWithIdentity(pkg); 5666 } else { 5667 packageImportance = IMPORTANCE_NONE; 5668 } 5669 synchronized (mNotificationLock) { 5670 // Cancellation reason. If the token comes from assistant, label the 5671 // cancellation as coming from the assistant; default to LISTENER_CANCEL. 5672 int reason = REASON_LISTENER_CANCEL; 5673 if (mAssistants.isServiceTokenValidLocked(token)) { 5674 reason = REASON_ASSISTANT_CANCEL; 5675 } 5676 5677 if (keys != null) { 5678 final int N = keys.length; 5679 for (int i = 0; i < N; i++) { 5680 NotificationRecord r = mNotificationsByKey.get(keys[i]); 5681 if (r == null) continue; 5682 final int userId = r.getSbn().getUserId(); 5683 if (userId != info.userid && userId != USER_ALL && 5684 !mUserProfiles.isCurrentProfile(userId)) { 5685 continue; 5686 } 5687 notificationsRapidlyCleared = notificationsRapidlyCleared 5688 || isNotificationRecent(r.getUpdateTimeMs()); 5689 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 5690 r.getSbn().getPackageName(), r.getSbn().getTag(), 5691 r.getSbn().getId(), userId, reason); 5692 } 5693 } else { 5694 for (NotificationRecord notificationRecord : mNotificationList) { 5695 if (isNotificationRecent(notificationRecord.getUpdateTimeMs())) { 5696 notificationsRapidlyCleared = true; 5697 break; 5698 } 5699 } 5700 if (lifetimeExtensionRefactor()) { 5701 cancelAllLocked(callingUid, callingPid, info.userid, 5702 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(), 5703 FLAG_ONGOING_EVENT | FLAG_NO_CLEAR 5704 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 5705 // If cancellation will be prevented due to lifetime extension, we send 5706 // an update to system UI. 5707 maybeNotifySystemUiListenerLifetimeExtendedListLocked( 5708 mNotificationList, packageImportance); 5709 maybeNotifySystemUiListenerLifetimeExtendedListLocked( 5710 mEnqueuedNotifications, packageImportance); 5711 } else { 5712 cancelAllLocked(callingUid, callingPid, info.userid, 5713 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(), 5714 FLAG_ONGOING_EVENT | FLAG_NO_CLEAR); 5715 } 5716 } 5717 } 5718 if (notificationsRapidlyCleared) { 5719 mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, 5720 callingUid, pkg, /* attributionTag= */ null, /* message= */ null); 5721 } 5722 } finally { 5723 Binder.restoreCallingIdentity(identity); 5724 } 5725 } 5726 5727 /** 5728 * Handle request from an approved listener to re-enable itself. 5729 * 5730 * @param component The componenet to be re-enabled, caller must match package. 5731 */ 5732 @Override 5733 public void requestBindListener(ComponentName component) { 5734 checkCallerIsSystemOrSameApp(component.getPackageName()); 5735 int uid = Binder.getCallingUid(); 5736 int userId = UserHandle.getUserId(uid); 5737 final long identity = Binder.clearCallingIdentity(); 5738 try { 5739 boolean isAssistantEnabled = managedServicesConcurrentMultiuser() 5740 ? mAssistants.isComponentEnabledForUser(component, userId) 5741 : mAssistants.isComponentEnabledForCurrentProfiles(component); 5742 ManagedServices manager = isAssistantEnabled ? mAssistants : mListeners; 5743 manager.setComponentState(component, UserHandle.getUserId(uid), true); 5744 } finally { 5745 Binder.restoreCallingIdentity(identity); 5746 } 5747 } 5748 5749 @Override 5750 public void requestUnbindListener(INotificationListener token) { 5751 int uid = Binder.getCallingUid(); 5752 final long identity = Binder.clearCallingIdentity(); 5753 try { 5754 // allow bound services to disable themselves 5755 synchronized (mNotificationLock) { 5756 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5757 info.getOwner().setComponentState( 5758 info.component, UserHandle.getUserId(uid), false); 5759 } 5760 } finally { 5761 Binder.restoreCallingIdentity(identity); 5762 } 5763 } 5764 5765 @Override 5766 public void requestUnbindListenerComponent(ComponentName component) { 5767 checkCallerIsSameApp(component.getPackageName()); 5768 int uid = Binder.getCallingUid(); 5769 int userId = UserHandle.getUserId(uid); 5770 final long identity = Binder.clearCallingIdentity(); 5771 try { 5772 synchronized (mNotificationLock) { 5773 boolean isAssistantEnabled = managedServicesConcurrentMultiuser() 5774 ? mAssistants.isComponentEnabledForUser(component, userId) 5775 : mAssistants.isComponentEnabledForCurrentProfiles(component); 5776 ManagedServices manager = isAssistantEnabled ? mAssistants : mListeners; 5777 if (manager.isPackageOrComponentAllowed(component.flattenToString(), userId)) { 5778 manager.setComponentState(component, userId, false); 5779 } 5780 } 5781 } finally { 5782 Binder.restoreCallingIdentity(identity); 5783 } 5784 } 5785 5786 @Override 5787 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 5788 final long identity = Binder.clearCallingIdentity(); 5789 try { 5790 synchronized (mNotificationLock) { 5791 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5792 if (keys == null) { 5793 return; 5794 } 5795 ArrayList<NotificationRecord> seen = new ArrayList<>(); 5796 final int n = keys.length; 5797 for (int i = 0; i < n; i++) { 5798 NotificationRecord r = mNotificationsByKey.get(keys[i]); 5799 if (r == null) continue; 5800 final int userId = r.getSbn().getUserId(); 5801 if (userId != info.userid && userId != USER_ALL 5802 && !mUserProfiles.isCurrentProfile(userId)) { 5803 continue; 5804 } 5805 seen.add(r); 5806 if (!r.isSeen()) { 5807 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 5808 reportSeen(r); 5809 r.setSeen(); 5810 maybeRecordInterruptionLocked(r); 5811 } 5812 } 5813 if (!seen.isEmpty()) { 5814 mAssistants.onNotificationsSeenLocked(seen); 5815 } 5816 } 5817 } finally { 5818 Binder.restoreCallingIdentity(identity); 5819 } 5820 } 5821 5822 /** 5823 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 5824 * 5825 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 5826 * 5827 * @param info The binder for the listener, to check that the caller is allowed 5828 */ 5829 @GuardedBy("mNotificationLock") 5830 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 5831 int callingUid, int callingPid, String pkg, String tag, int id, int userId, 5832 int reason) { 5833 int mustNotHaveFlags = FLAG_ONGOING_EVENT; 5834 if (lifetimeExtensionRefactor()) { 5835 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 5836 } 5837 cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */, 5838 mustNotHaveFlags, 5839 true, 5840 userId, reason, info); 5841 } 5842 5843 /** 5844 * Allow an INotificationListener to snooze a single notification until a context. 5845 * 5846 * @param token The binder for the listener, to check that the caller is allowed 5847 */ 5848 @Override 5849 public void snoozeNotificationUntilContextFromListener(INotificationListener token, 5850 String key, String snoozeCriterionId) { 5851 final int callingUid = Binder.getCallingUid(); 5852 final long identity = Binder.clearCallingIdentity(); 5853 try { 5854 snoozeNotificationInt(callingUid, token, key, SNOOZE_UNTIL_UNSPECIFIED, 5855 snoozeCriterionId); 5856 } finally { 5857 Binder.restoreCallingIdentity(identity); 5858 } 5859 } 5860 5861 /** 5862 * Allow an INotificationListener to snooze a single notification until a time. 5863 * 5864 * @param token The binder for the listener, to check that the caller is allowed 5865 */ 5866 @Override 5867 public void snoozeNotificationUntilFromListener(INotificationListener token, String key, 5868 long duration) { 5869 final int callingUid = Binder.getCallingUid(); 5870 final long identity = Binder.clearCallingIdentity(); 5871 try { 5872 snoozeNotificationInt(callingUid, token, key, duration, null); 5873 } finally { 5874 Binder.restoreCallingIdentity(identity); 5875 } 5876 } 5877 5878 /** 5879 * Allows the notification assistant to un-snooze a single notification. 5880 * 5881 * @param token The binder for the assistant, to check that the caller is allowed 5882 */ 5883 @Override 5884 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { 5885 final long identity = Binder.clearCallingIdentity(); 5886 try { 5887 synchronized (mNotificationLock) { 5888 final ManagedServiceInfo info = 5889 mAssistants.checkServiceTokenLocked(token); 5890 unsnoozeNotificationInt(key, info, false); 5891 } 5892 } finally { 5893 Binder.restoreCallingIdentity(identity); 5894 } 5895 } 5896 5897 /** 5898 * Allows the notification assistant to un-snooze a single notification. 5899 * 5900 * @param token The binder for the listener, to check that the caller is allowed 5901 */ 5902 @Override 5903 public void unsnoozeNotificationFromSystemListener(INotificationListener token, 5904 String key) { 5905 final long identity = Binder.clearCallingIdentity(); 5906 try { 5907 synchronized (mNotificationLock) { 5908 final ManagedServiceInfo info = 5909 mListeners.checkServiceTokenLocked(token); 5910 if (!info.isSystem) { 5911 throw new SecurityException("Not allowed to unsnooze before deadline"); 5912 } 5913 unsnoozeNotificationInt(key, info, true); 5914 } 5915 } finally { 5916 Binder.restoreCallingIdentity(identity); 5917 } 5918 } 5919 5920 /** 5921 * Allows an app to set an initial notification listener filter 5922 * 5923 * @param token The binder for the listener, to check that the caller is allowed 5924 */ 5925 @Override 5926 public void migrateNotificationFilter(INotificationListener token, int defaultTypes, 5927 List<String> disallowedApps) { 5928 final long identity = Binder.clearCallingIdentity(); 5929 try { 5930 synchronized (mNotificationLock) { 5931 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5932 5933 Pair key = Pair.create(info.component, info.userid); 5934 5935 NotificationListenerFilter nlf = mListeners.getNotificationListenerFilter(key); 5936 if (nlf == null) { 5937 nlf = new NotificationListenerFilter(); 5938 } 5939 if (nlf.getDisallowedPackages().isEmpty() && disallowedApps != null) { 5940 for (String pkg : disallowedApps) { 5941 // block the current user's version and any work profile versions 5942 for (int userId : mUm.getProfileIds(info.userid, false)) { 5943 try { 5944 int uid = getUidForPackageAndUser(pkg, UserHandle.of(userId)); 5945 if (uid != INVALID_UID) { 5946 VersionedPackage vp = new VersionedPackage(pkg, uid); 5947 nlf.addPackage(vp); 5948 } 5949 } catch (Exception e) { 5950 // pkg doesn't exist on that user; skip 5951 } 5952 } 5953 } 5954 } 5955 if (nlf.areAllTypesAllowed()) { 5956 nlf.setTypes(defaultTypes); 5957 } 5958 mListeners.setNotificationListenerFilter(key, nlf); 5959 } 5960 } finally { 5961 Binder.restoreCallingIdentity(identity); 5962 } 5963 } 5964 5965 /** 5966 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 5967 * 5968 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 5969 * 5970 * @param token The binder for the listener, to check that the caller is allowed 5971 */ 5972 @Override 5973 public void cancelNotificationFromListener(INotificationListener token, String pkg, 5974 String tag, int id) { 5975 Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) use " + 5976 "cancelNotification(key) instead."); 5977 } 5978 5979 /** 5980 * Allow an INotificationListener to request the list of outstanding notifications seen by 5981 * the current user. Useful when starting up, after which point the listener callbacks 5982 * should be used. 5983 * 5984 * @param token The binder for the listener, to check that the caller is allowed 5985 * @param keys An array of notification keys to fetch, or null to fetch everything 5986 * @returns The return value will contain the notifications specified in keys, in that 5987 * order, or if keys is null, all the notifications, in natural order. 5988 */ 5989 @Override 5990 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 5991 INotificationListener token, String[] keys, int trim) { 5992 synchronized (mNotificationLock) { 5993 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5994 final boolean getKeys = keys != null; 5995 final int N = getKeys ? keys.length : mNotificationList.size(); 5996 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 5997 for (int i=0; i<N; i++) { 5998 final NotificationRecord r = getKeys 5999 ? mNotificationsByKey.get(keys[i]) 6000 : mNotificationList.get(i); 6001 addToListIfNeeded(r, info, list, trim); 6002 } 6003 return new ParceledListSlice<>(list); 6004 } 6005 } 6006 6007 /** 6008 * Allow an INotificationListener to request the list of outstanding snoozed notifications 6009 * seen by the current user. Useful when starting up, after which point the listener 6010 * callbacks should be used. 6011 * 6012 * @param token The binder for the listener, to check that the caller is allowed 6013 * @returns The return value will contain the notifications specified in keys, in that 6014 * order, or if keys is null, all the notifications, in natural order. 6015 */ 6016 @Override 6017 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener( 6018 INotificationListener token, int trim) { 6019 synchronized (mNotificationLock) { 6020 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 6021 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed(); 6022 final int N = snoozedRecords.size(); 6023 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 6024 for (int i=0; i < N; i++) { 6025 addToListIfNeeded(snoozedRecords.get(i), info, list, trim); 6026 } 6027 return new ParceledListSlice<>(list); 6028 } 6029 } 6030 6031 private void addToListIfNeeded(NotificationRecord r, ManagedServiceInfo info, 6032 ArrayList<StatusBarNotification> notifications, int trim) { 6033 if (r == null) return; 6034 StatusBarNotification sbn = r.getSbn(); 6035 if (!isVisibleToListener(sbn, r.getNotificationType(), info)) return; 6036 if (mListeners.hasSensitiveContent(r) && !mListeners.isUidTrusted(info.uid)) { 6037 notifications.add(mListeners.redactStatusBarNotification(sbn)); 6038 } else { 6039 notifications.add((trim == TRIM_FULL) ? sbn : sbn.cloneLight()); 6040 } 6041 6042 } 6043 6044 @Override 6045 public void clearRequestedListenerHints(INotificationListener token) { 6046 final long identity = Binder.clearCallingIdentity(); 6047 try { 6048 synchronized (mNotificationLock) { 6049 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 6050 removeDisabledHints(info); 6051 updateListenerHintsLocked(); 6052 updateEffectsSuppressorLocked(); 6053 } 6054 } finally { 6055 Binder.restoreCallingIdentity(identity); 6056 } 6057 } 6058 6059 @Override 6060 public void requestHintsFromListener(INotificationListener token, int hints) { 6061 final long identity = Binder.clearCallingIdentity(); 6062 try { 6063 synchronized (mNotificationLock) { 6064 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 6065 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS 6066 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS 6067 | HINT_HOST_DISABLE_CALL_EFFECTS; 6068 final boolean disableEffects = (hints & disableEffectsMask) != 0; 6069 if (disableEffects) { 6070 addDisabledHints(info, hints); 6071 } else { 6072 removeDisabledHints(info, hints); 6073 } 6074 updateListenerHintsLocked(); 6075 updateEffectsSuppressorLocked(); 6076 } 6077 } finally { 6078 Binder.restoreCallingIdentity(identity); 6079 } 6080 } 6081 6082 @Override 6083 public int getHintsFromListener(INotificationListener token) { 6084 synchronized (mNotificationLock) { 6085 return mListenerHints; 6086 } 6087 } 6088 6089 @Override 6090 public int getHintsFromListenerNoToken() { 6091 synchronized (mNotificationLock) { 6092 return mListenerHints; 6093 } 6094 } 6095 6096 @Override 6097 public void requestInterruptionFilterFromListener(INotificationListener token, 6098 int interruptionFilter) throws RemoteException { 6099 final int callingUid = Binder.getCallingUid(); 6100 ManagedServiceInfo info; 6101 synchronized (mNotificationLock) { 6102 info = mListeners.checkServiceTokenLocked(token); 6103 } 6104 6105 final int zenMode = zenModeFromInterruptionFilter(interruptionFilter, -1); 6106 if (zenMode == -1) return; 6107 6108 UserHandle zenUser = getCallingZenUser(); 6109 if (!canManageGlobalZenPolicy(info.component.getPackageName(), callingUid)) { 6110 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule( 6111 zenUser, info.component.getPackageName(), callingUid, zenMode); 6112 } else { 6113 int origin = computeZenOrigin(/* fromUser= */ false); 6114 Binder.withCleanCallingIdentity(() -> { 6115 mZenModeHelper.setManualZenMode(zenUser, zenMode, /* conditionId= */ null, 6116 origin, "listener:" + info.component.flattenToShortString(), 6117 /* caller= */ info.component.getPackageName(), 6118 callingUid); 6119 }); 6120 } 6121 } 6122 6123 @Override 6124 public int getInterruptionFilterFromListener(INotificationListener token) 6125 throws RemoteException { 6126 synchronized (mNotificationLock) { 6127 return mInterruptionFilter; 6128 } 6129 } 6130 6131 @Override 6132 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 6133 throws RemoteException { 6134 synchronized (mNotificationLock) { 6135 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 6136 if (info == null) return; 6137 mListeners.setOnNotificationPostedTrimLocked(info, trim); 6138 } 6139 } 6140 6141 @Override 6142 public int getZenMode() { 6143 return mZenModeHelper.getZenMode(); 6144 } 6145 6146 @Override 6147 public ZenModeConfig getZenModeConfig() { 6148 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig"); 6149 return mZenModeHelper.getConfig(); 6150 } 6151 6152 @Override 6153 public void setZenMode(int mode, Uri conditionId, String reason, boolean fromUser) { 6154 enforceSystemOrSystemUI("INotificationManager.setZenMode"); 6155 enforceUserOriginOnlyFromSystem(fromUser, "setZenMode"); 6156 UserHandle zenUser = getCallingZenUser(); 6157 6158 final int callingUid = Binder.getCallingUid(); 6159 final long identity = Binder.clearCallingIdentity(); 6160 try { 6161 mZenModeHelper.setManualZenMode(zenUser, mode, conditionId, 6162 computeZenOrigin(fromUser), reason, /* caller= */ null, callingUid); 6163 } finally { 6164 Binder.restoreCallingIdentity(identity); 6165 } 6166 } 6167 6168 @Override 6169 public ParceledListSlice getAutomaticZenRules() { 6170 int callingUid = Binder.getCallingUid(); 6171 enforcePolicyAccess(callingUid, "getAutomaticZenRules"); 6172 List<AutomaticZenRule.AzrWithId> ruleList = new ArrayList<>(); 6173 for (Map.Entry<String, AutomaticZenRule> rule : mZenModeHelper.getAutomaticZenRules( 6174 getCallingZenUser(), callingUid).entrySet()) { 6175 ruleList.add(new AutomaticZenRule.AzrWithId(rule.getKey(), rule.getValue())); 6176 } 6177 return new ParceledListSlice<>(ruleList); 6178 } 6179 6180 @Override 6181 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 6182 Objects.requireNonNull(id, "Id is null"); 6183 int callingUid = Binder.getCallingUid(); 6184 enforcePolicyAccess(callingUid, "getAutomaticZenRule"); 6185 return mZenModeHelper.getAutomaticZenRule(getCallingZenUser(), id, callingUid); 6186 } 6187 6188 @Override 6189 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg, 6190 boolean fromUser) { 6191 validateAutomaticZenRule(/* updateId= */ null, automaticZenRule); 6192 checkCallerIsSameApp(pkg); 6193 if (automaticZenRule.getZenPolicy() != null 6194 && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { 6195 throw new IllegalArgumentException("ZenPolicy is only applicable to " 6196 + "INTERRUPTION_FILTER_PRIORITY filters"); 6197 } 6198 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 6199 enforceUserOriginOnlyFromSystem(fromUser, "addAutomaticZenRule"); 6200 UserHandle zenUser = getCallingZenUser(); 6201 6202 // If the calling app is the system (from any user), take the package name from the 6203 // rule's owner rather than from the caller's package. 6204 String rulePkg = pkg; 6205 if (isCallingAppIdSystem()) { 6206 if (automaticZenRule.getOwner() != null) { 6207 rulePkg = automaticZenRule.getOwner().getPackageName(); 6208 } 6209 } 6210 6211 return mZenModeHelper.addAutomaticZenRule(zenUser, rulePkg, automaticZenRule, 6212 computeZenOrigin(fromUser), "addAutomaticZenRule", Binder.getCallingUid()); 6213 } 6214 6215 @Override 6216 public void setManualZenRuleDeviceEffects(ZenDeviceEffects effects) throws RemoteException { 6217 checkCallerIsSystem(); 6218 UserHandle zenUser = getCallingZenUser(); 6219 6220 mZenModeHelper.setManualZenRuleDeviceEffects(zenUser, effects, 6221 computeZenOrigin(true), "Update manual mode non-policy settings", 6222 Binder.getCallingUid()); 6223 } 6224 6225 @Override 6226 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule, 6227 boolean fromUser) throws RemoteException { 6228 validateAutomaticZenRule(id, automaticZenRule); 6229 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 6230 enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule"); 6231 UserHandle zenUser = getCallingZenUser(); 6232 6233 return mZenModeHelper.updateAutomaticZenRule(zenUser, id, automaticZenRule, 6234 computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid()); 6235 } 6236 6237 private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) { 6238 Objects.requireNonNull(rule, "automaticZenRule is null"); 6239 Objects.requireNonNull(rule.getName(), "Name is null"); 6240 rule.validate(); 6241 6242 // Implicit rules have no ConditionProvider or Activity. We allow the user to customize 6243 // them (via Settings), but not the owner app. Should the app want to start using it as 6244 // a "normal" rule, it must provide a CP/ConfigActivity too. 6245 boolean isImplicitRuleUpdateFromSystem = updateId != null 6246 && ZenModeConfig.isImplicitRuleId(updateId) 6247 && isCallerSystemOrSystemUi(); 6248 if (!isImplicitRuleUpdateFromSystem 6249 && rule.getOwner() == null 6250 && rule.getConfigurationActivity() == null) { 6251 throw new NullPointerException( 6252 "Rule must have a ConditionProviderService and/or configuration " 6253 + "activity"); 6254 } 6255 Objects.requireNonNull(rule.getConditionId(), "ConditionId is null"); 6256 6257 if (isCallerSystemOrSystemUi()) { 6258 return; // System callers can use any type. 6259 } 6260 int uid = Binder.getCallingUid(); 6261 int userId = UserHandle.getUserId(uid); 6262 6263 if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) { 6264 boolean isDeviceOwner = Binder.withCleanCallingIdentity( 6265 () -> mDpm.isActiveDeviceOwner(uid)); 6266 if (!isDeviceOwner) { 6267 throw new IllegalArgumentException( 6268 "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED"); 6269 } 6270 } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) { 6271 String wellbeingPackage = getContext().getResources().getString( 6272 com.android.internal.R.string.config_systemWellbeing); 6273 boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage) 6274 && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId); 6275 if (!isCallerWellbeing) { 6276 throw new IllegalArgumentException( 6277 "Only the 'Wellbeing' package can use AutomaticZenRules with " 6278 + "TYPE_BEDTIME"); 6279 } 6280 } 6281 } 6282 6283 @Override 6284 public boolean removeAutomaticZenRule(String id, boolean fromUser) throws RemoteException { 6285 Objects.requireNonNull(id, "Id is null"); 6286 // Verify that they can modify zen rules. 6287 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 6288 enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRule"); 6289 UserHandle zenUser = getCallingZenUser(); 6290 6291 return mZenModeHelper.removeAutomaticZenRule(zenUser, id, computeZenOrigin(fromUser), 6292 "removeAutomaticZenRule", Binder.getCallingUid()); 6293 } 6294 6295 @Override 6296 public boolean removeAutomaticZenRules(String packageName, boolean fromUser) 6297 throws RemoteException { 6298 Objects.requireNonNull(packageName, "Package name is null"); 6299 enforceSystemOrSystemUI("removeAutomaticZenRules"); 6300 enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRules"); 6301 UserHandle zenUser = getCallingZenUser(); 6302 6303 return mZenModeHelper.removeAutomaticZenRules(zenUser, packageName, 6304 computeZenOrigin(fromUser), packageName + "|removeAutomaticZenRules", 6305 Binder.getCallingUid()); 6306 } 6307 6308 @Override 6309 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 6310 Objects.requireNonNull(owner, "Owner is null"); 6311 enforceSystemOrSystemUI("getRuleInstanceCount"); 6312 6313 return mZenModeHelper.getCurrentInstanceCount(getCallingZenUser(), owner); 6314 } 6315 6316 @Override 6317 @Condition.State 6318 public int getAutomaticZenRuleState(@NonNull String id) { 6319 Objects.requireNonNull(id, "id is null"); 6320 int callingUid = Binder.getCallingUid(); 6321 enforcePolicyAccess(callingUid, "getAutomaticZenRuleState"); 6322 return mZenModeHelper.getAutomaticZenRuleState(getCallingZenUser(), id, callingUid); 6323 } 6324 6325 @Override 6326 public void setAutomaticZenRuleState(String id, Condition condition) { 6327 Objects.requireNonNull(id, "id is null"); 6328 Objects.requireNonNull(condition, "Condition is null"); 6329 condition.validate(); 6330 6331 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState"); 6332 boolean fromUser = (condition.source == Condition.SOURCE_USER_ACTION); 6333 UserHandle zenUser = getCallingZenUser(); 6334 6335 mZenModeHelper.setAutomaticZenRuleState(zenUser, id, condition, 6336 computeZenOrigin(fromUser), Binder.getCallingUid()); 6337 } 6338 6339 /** 6340 * Returns the {@link UserHandle} corresponding to the caller that is performing a 6341 * zen-related operation (such as {@link #setInterruptionFilter}, 6342 * {@link #addAutomaticZenRule}, {@link #setAutomaticZenRuleState}, etc). The user is 6343 * {@link UserHandle#USER_CURRENT} if the caller is the system or SystemUI (assuming 6344 * that all interactions in SystemUI are for the "current" user); otherwise it's the user 6345 * associated to the binder call. 6346 */ 6347 private UserHandle getCallingZenUser() { 6348 if (android.app.Flags.modesMultiuser()) { 6349 if (isCallerSystemOrSystemUiOrShell()) { 6350 return UserHandle.CURRENT; 6351 } else { 6352 return Binder.getCallingUserHandle(); 6353 } 6354 } else { 6355 return UserHandle.CURRENT; 6356 } 6357 } 6358 6359 @ZenModeConfig.ConfigOrigin 6360 private int computeZenOrigin(boolean fromUser) { 6361 if (fromUser) { 6362 if (isCallerSystemOrSystemUi()) { 6363 return ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI; 6364 } else { 6365 return ZenModeConfig.ORIGIN_USER_IN_APP; 6366 } 6367 } else if (isCallerSystemOrSystemUi()) { 6368 return ZenModeConfig.ORIGIN_SYSTEM; 6369 } else { 6370 return ZenModeConfig.ORIGIN_APP; 6371 } 6372 } 6373 6374 private void enforceUserOriginOnlyFromSystem(boolean fromUser, String method) { 6375 if (fromUser && !isCallerSystemOrSystemUiOrShell()) { 6376 throw new SecurityException(TextUtils.formatSimple( 6377 "Calling %s with fromUser == true is only allowed for system", method)); 6378 } 6379 } 6380 6381 @Override 6382 public void setInterruptionFilter(String pkg, int filter, boolean fromUser) { 6383 enforcePolicyAccess(pkg, "setInterruptionFilter"); 6384 final int zen = zenModeFromInterruptionFilter(filter, -1); 6385 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 6386 final int callingUid = Binder.getCallingUid(); 6387 enforceUserOriginOnlyFromSystem(fromUser, "setInterruptionFilter"); 6388 UserHandle zenUser = getCallingZenUser(); 6389 6390 if (!canManageGlobalZenPolicy(pkg, callingUid)) { 6391 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(zenUser, pkg, callingUid, zen); 6392 return; 6393 } 6394 6395 final long identity = Binder.clearCallingIdentity(); 6396 try { 6397 mZenModeHelper.setManualZenMode(zenUser, zen, null, computeZenOrigin(fromUser), 6398 /* reason= */ "setInterruptionFilter", /* caller= */ pkg, 6399 callingUid); 6400 } finally { 6401 Binder.restoreCallingIdentity(identity); 6402 } 6403 } 6404 6405 @Override 6406 public void notifyConditions(final String pkg, IConditionProvider provider, 6407 final Condition[] conditions) { 6408 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 6409 checkCallerIsSystemOrSameApp(pkg); 6410 mHandler.post(new Runnable() { 6411 @Override 6412 public void run() { 6413 mConditionProviders.notifyConditions(pkg, info, conditions); 6414 } 6415 }); 6416 } 6417 6418 @Override 6419 public void requestUnbindProvider(IConditionProvider provider) { 6420 int uid = Binder.getCallingUid(); 6421 final long identity = Binder.clearCallingIdentity(); 6422 try { 6423 // allow bound services to disable themselves 6424 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 6425 info.getOwner().setComponentState(info.component, UserHandle.getUserId(uid), false); 6426 } finally { 6427 Binder.restoreCallingIdentity(identity); 6428 } 6429 } 6430 6431 @Override 6432 public void requestBindProvider(ComponentName component) { 6433 checkCallerIsSystemOrSameApp(component.getPackageName()); 6434 int uid = Binder.getCallingUid(); 6435 final long identity = Binder.clearCallingIdentity(); 6436 try { 6437 mConditionProviders.setComponentState(component, UserHandle.getUserId(uid), true); 6438 } finally { 6439 Binder.restoreCallingIdentity(identity); 6440 } 6441 } 6442 6443 private void enforceSystemOrSystemUI(String message) { 6444 if (isCallerSystemOrPhone()) return; 6445 getContext().enforceCallingPermission(STATUS_BAR_SERVICE, 6446 message); 6447 } 6448 6449 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) { 6450 try { 6451 checkCallerIsSystemOrSameApp(pkg); 6452 } catch (SecurityException e) { 6453 getContext().enforceCallingPermission( 6454 STATUS_BAR_SERVICE, 6455 message); 6456 } 6457 } 6458 6459 private void enforcePolicyAccess(int uid, String method) { 6460 if (PERMISSION_GRANTED == getContext().checkCallingOrSelfPermission( 6461 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 6462 return; 6463 } 6464 boolean accessAllowed = false; 6465 String[] packages = mPackageManagerClient.getPackagesForUid(uid); 6466 final int packageCount = packages.length; 6467 for (int i = 0; i < packageCount; i++) { 6468 if (mConditionProviders.isPackageOrComponentAllowed( 6469 packages[i], UserHandle.getUserId(uid))) { 6470 accessAllowed = true; 6471 } 6472 } 6473 if (!accessAllowed) { 6474 Slog.w(TAG, "Notification policy access denied calling " + method); 6475 throw new SecurityException("Notification policy access denied"); 6476 } 6477 } 6478 6479 private boolean canManageGlobalZenPolicy(String callingPkg, int callingUid) { 6480 boolean isCompatChangeEnabled = Binder.withCleanCallingIdentity( 6481 () -> CompatChanges.isChangeEnabled(MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES, 6482 callingUid)); 6483 return !isCompatChangeEnabled 6484 || isCallerSystemOrSystemUi() 6485 || hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid), 6486 Set.of(AssociationRequest.DEVICE_PROFILE_WATCH, 6487 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)); 6488 } 6489 6490 private void enforcePolicyAccess(String pkg, String method) { 6491 if (PERMISSION_GRANTED == getContext().checkCallingOrSelfPermission( 6492 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 6493 return; 6494 } 6495 checkCallerIsSameApp(pkg); 6496 if (!checkPolicyAccess(pkg)) { 6497 Slog.w(TAG, "Notification policy access denied calling " + method); 6498 throw new SecurityException("Notification policy access denied"); 6499 } 6500 } 6501 6502 private boolean checkPackagePolicyAccess(String pkg) { 6503 return mConditionProviders.isPackageOrComponentAllowed( 6504 pkg, getCallingUserHandle().getIdentifier()); 6505 } 6506 6507 private boolean checkPolicyAccess(String pkg) { 6508 final int uid; 6509 try { 6510 uid = getContext().getPackageManager().getPackageUidAsUser(pkg, 6511 UserHandle.getCallingUserId()); 6512 if (PERMISSION_GRANTED == checkComponentPermission( 6513 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, 6514 -1, true)) { 6515 return true; 6516 } 6517 } catch (NameNotFoundException e) { 6518 return false; 6519 } 6520 if (managedServicesConcurrentMultiuser()) { 6521 return checkPackagePolicyAccess(pkg) 6522 || mListeners.isComponentEnabledForPackage(pkg, 6523 UserHandle.getCallingUserId()) 6524 || (mDpm != null 6525 && (mDpm.isActiveProfileOwner(uid) || mDpm.isActiveDeviceOwner(uid))); 6526 } 6527 //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. 6528 return checkPackagePolicyAccess(pkg) 6529 || mListeners.isComponentEnabledForPackage(pkg) 6530 || (mDpm != null && (mDpm.isActiveProfileOwner(uid) 6531 || mDpm.isActiveDeviceOwner(uid))); 6532 } 6533 6534 @Override 6535 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 6536 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; 6537 final DumpFilter filter = DumpFilter.parseFromArguments(args); 6538 final long token = Binder.clearCallingIdentity(); 6539 try { 6540 final ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions = 6541 getAllUsersNotificationPermissions(); 6542 if (filter.stats) { 6543 dumpJson(pw, filter, pkgPermissions); 6544 } else if (filter.rvStats) { 6545 dumpRemoteViewStats(pw, filter); 6546 } else if (filter.proto) { 6547 dumpProto(fd, filter, pkgPermissions); 6548 } else if (filter.criticalPriority) { 6549 dumpNotificationRecords(pw, filter); 6550 } else { 6551 dumpImpl(pw, filter, pkgPermissions); 6552 } 6553 } finally { 6554 Binder.restoreCallingIdentity(token); 6555 } 6556 } 6557 6558 @Override 6559 public ComponentName getEffectsSuppressor() { 6560 ComponentName suppressor = !mEffectsSuppressors.isEmpty() 6561 ? mEffectsSuppressors.get(0) 6562 : null; 6563 if (isCallerSystemOrSystemUiOrShell() || suppressor == null 6564 || mPackageManagerInternal.isSameApp(suppressor.getPackageName(), 6565 Binder.getCallingUid(), UserHandle.getUserId(Binder.getCallingUid()))) { 6566 return suppressor; 6567 } 6568 6569 return null; 6570 } 6571 6572 @Override 6573 public boolean matchesCallFilter(Bundle extras) { 6574 // Because matchesCallFilter may use contact data to filter calls, the callers of this 6575 // method need to either have notification listener access or permission to read 6576 // contacts. 6577 boolean systemAccess = false; 6578 try { 6579 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 6580 systemAccess = true; 6581 } catch (SecurityException e) { 6582 } 6583 6584 boolean listenerAccess = false; 6585 try { 6586 String[] pkgNames = mPackageManager.getPackagesForUid(Binder.getCallingUid()); 6587 for (int i = 0; i < pkgNames.length; i++) { 6588 // in most cases there should only be one package here 6589 listenerAccess |= mListeners.hasAllowedListener(pkgNames[i], 6590 Binder.getCallingUserHandle().getIdentifier()); 6591 } 6592 } catch (RemoteException e) { 6593 } finally { 6594 if (!systemAccess && !listenerAccess) { 6595 getContext().enforceCallingPermission(Manifest.permission.READ_CONTACTS, 6596 "matchesCallFilter requires listener permission, contacts read access," 6597 + " or system level access"); 6598 } 6599 } 6600 6601 return mZenModeHelper.matchesCallFilter( 6602 Binder.getCallingUserHandle(), 6603 extras, 6604 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 6605 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 6606 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY, 6607 Binder.getCallingUid()); 6608 } 6609 6610 @Override 6611 public void cleanUpCallersAfter(long timeThreshold) { 6612 enforceSystemOrSystemUI("INotificationManager.cleanUpCallersAfter"); 6613 mZenModeHelper.cleanUpCallersAfter(timeThreshold); 6614 } 6615 6616 @Override 6617 public boolean isSystemConditionProviderEnabled(String path) { 6618 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled"); 6619 return mConditionProviders.isSystemProviderEnabled(path); 6620 } 6621 6622 // Backup/restore interface 6623 @Override 6624 public byte[] getBackupPayload(int user) { 6625 checkCallerIsSystem(); 6626 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 6627 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 6628 try { 6629 writePolicyXml(baos, true /*forBackup*/, user, null); 6630 return baos.toByteArray(); 6631 } catch (IOException e) { 6632 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 6633 } 6634 return null; 6635 } 6636 6637 @Override 6638 public void applyRestore(byte[] payload, int user) { 6639 checkCallerIsSystem(); 6640 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 6641 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 6642 if (payload == null) { 6643 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 6644 return; 6645 } 6646 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 6647 try { 6648 readPolicyXml(bais, true /*forRestore*/, user, null); 6649 handleSavePolicyFile(); 6650 } catch (NumberFormatException | XmlPullParserException | IOException e) { 6651 Slog.w(TAG, "applyRestore: error reading payload", e); 6652 } 6653 } 6654 6655 @Override 6656 public boolean isNotificationPolicyAccessGranted(String pkg) { 6657 return checkPolicyAccess(pkg); 6658 } 6659 6660 @Override 6661 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { 6662 enforceSystemOrSystemUIOrSamePackage(pkg, 6663 "request policy access status for another package"); 6664 return checkPolicyAccess(pkg); 6665 } 6666 6667 @Override 6668 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 6669 throws RemoteException { 6670 setNotificationPolicyAccessGrantedForUser( 6671 pkg, getCallingUserHandle().getIdentifier(), granted); 6672 } 6673 6674 @Override 6675 public void setNotificationPolicyAccessGrantedForUser( 6676 String pkg, int userId, boolean granted) { 6677 checkCallerIsSystemOrShell(); 6678 final long identity = Binder.clearCallingIdentity(); 6679 try { 6680 if (mAllowedManagedServicePackages.test( 6681 pkg, userId, mConditionProviders.getRequiredPermission())) { 6682 mConditionProviders.setPackageOrComponentEnabled( 6683 pkg, userId, true, granted); 6684 6685 getContext().sendBroadcastAsUser(new Intent( 6686 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 6687 .setPackage(pkg) 6688 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 6689 UserHandle.of(userId), null); 6690 handleSavePolicyFile(); 6691 } 6692 } finally { 6693 Binder.restoreCallingIdentity(identity); 6694 } 6695 } 6696 6697 @Override 6698 public Policy getNotificationPolicy(String pkg) { 6699 final int callingUid = Binder.getCallingUid(); 6700 UserHandle zenUser = getCallingZenUser(); 6701 if (!canManageGlobalZenPolicy(pkg, callingUid)) { 6702 return mZenModeHelper.getNotificationPolicyFromImplicitZenRule(zenUser, pkg); 6703 } 6704 final long identity = Binder.clearCallingIdentity(); 6705 try { 6706 return mZenModeHelper.getNotificationPolicy(zenUser); 6707 } finally { 6708 Binder.restoreCallingIdentity(identity); 6709 } 6710 } 6711 6712 @Override 6713 public Policy getConsolidatedNotificationPolicy() { 6714 final long identity = Binder.clearCallingIdentity(); 6715 try { 6716 return mZenModeHelper.getConsolidatedNotificationPolicy(); 6717 } finally { 6718 Binder.restoreCallingIdentity(identity); 6719 } 6720 } 6721 6722 /** 6723 * Sets the notification policy. Apps that target API levels below 6724 * {@link Build.VERSION_CODES#P} cannot change user-designated values to 6725 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS}, 6726 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and 6727 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd 6728 */ 6729 @Override 6730 public void setNotificationPolicy(String pkg, Policy policy, boolean fromUser) { 6731 enforcePolicyAccess(pkg, "setNotificationPolicy"); 6732 enforceUserOriginOnlyFromSystem(fromUser, "setNotificationPolicy"); 6733 int callingUid = Binder.getCallingUid(); 6734 @ZenModeConfig.ConfigOrigin int origin = computeZenOrigin(fromUser); 6735 UserHandle zenUser = getCallingZenUser(); 6736 6737 boolean isSystemCaller = isCallerSystemOrSystemUiOrShell(); 6738 boolean shouldApplyAsImplicitRule = !canManageGlobalZenPolicy(pkg, callingUid); 6739 6740 final long identity = Binder.clearCallingIdentity(); 6741 try { 6742 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg, 6743 0, UserHandle.getUserId(callingUid)); 6744 Policy currPolicy = mZenModeHelper.getNotificationPolicy(zenUser); 6745 6746 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) { 6747 int priorityCategories = policy.priorityCategories; 6748 // ignore alarm and media values from new policy 6749 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS; 6750 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA; 6751 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM; 6752 // use user-designated values 6753 priorityCategories |= currPolicy.priorityCategories 6754 & Policy.PRIORITY_CATEGORY_ALARMS; 6755 priorityCategories |= currPolicy.priorityCategories 6756 & Policy.PRIORITY_CATEGORY_MEDIA; 6757 priorityCategories |= currPolicy.priorityCategories 6758 & Policy.PRIORITY_CATEGORY_SYSTEM; 6759 6760 policy = new Policy(priorityCategories, 6761 policy.priorityCallSenders, policy.priorityMessageSenders, 6762 policy.suppressedVisualEffects); 6763 } 6764 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) { 6765 int priorityCategories = correctCategory(policy.priorityCategories, 6766 Policy.PRIORITY_CATEGORY_CONVERSATIONS, 6767 currPolicy.priorityCategories); 6768 6769 policy = new Policy(priorityCategories, 6770 policy.priorityCallSenders, policy.priorityMessageSenders, 6771 policy.suppressedVisualEffects, currPolicy.priorityConversationSenders); 6772 } 6773 6774 int newVisualEffects = calculateSuppressedVisualEffects( 6775 policy, currPolicy, applicationInfo.targetSdkVersion); 6776 6777 if (android.app.Flags.modesUi()) { 6778 // 1. Callers should not modify STATE_CHANNELS_BYPASSING_DND, which is 6779 // internally calculated and only indicates whether channels that want to bypass 6780 // DND _exist_. 6781 // 2. Only system callers should modify STATE_PRIORITY_CHANNELS_BLOCKED because 6782 // it is @hide. 6783 // 3. If the policy has been modified by the targetSdkVersion checks above then 6784 // it has lost its state flags and that's fine (STATE_PRIORITY_CHANNELS_BLOCKED 6785 // didn't exist until V). 6786 int newState = Policy.STATE_UNSET; 6787 if (isSystemCaller && policy.state != Policy.STATE_UNSET) { 6788 newState = Policy.policyState( 6789 currPolicy.hasPriorityChannels(), 6790 policy.allowPriorityChannels()); 6791 } 6792 policy = new Policy(policy.priorityCategories, 6793 policy.priorityCallSenders, policy.priorityMessageSenders, 6794 newVisualEffects, newState, policy.priorityConversationSenders); 6795 } else { 6796 policy = new Policy(policy.priorityCategories, 6797 policy.priorityCallSenders, policy.priorityMessageSenders, 6798 newVisualEffects, policy.priorityConversationSenders); 6799 } 6800 6801 if (shouldApplyAsImplicitRule) { 6802 mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(zenUser, pkg, callingUid, 6803 policy); 6804 } else { 6805 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, 6806 policy); 6807 mZenModeHelper.setNotificationPolicy(zenUser, policy, origin, callingUid); 6808 } 6809 } catch (RemoteException e) { 6810 Slog.e(TAG, "Failed to set notification policy", e); 6811 } finally { 6812 Binder.restoreCallingIdentity(identity); 6813 } 6814 } 6815 6816 /** 6817 * Gets the device-default zen policy as a ZenPolicy. 6818 */ 6819 @Override 6820 public ZenPolicy getDefaultZenPolicy() { 6821 enforceSystemOrSystemUI("INotificationManager.getDefaultZenPolicy"); 6822 final long identity = Binder.clearCallingIdentity(); 6823 try { 6824 return mZenModeHelper.getDefaultZenPolicy(); 6825 } finally { 6826 Binder.restoreCallingIdentity(identity); 6827 } 6828 } 6829 6830 @Override 6831 public List<String> getEnabledNotificationListenerPackages() { 6832 checkCallerIsSystem(); 6833 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier()); 6834 } 6835 6836 @Override 6837 public List<ComponentName> getEnabledNotificationListeners(int userId) { 6838 checkNotificationListenerAccess(); 6839 return mListeners.getAllowedComponents(userId); 6840 } 6841 6842 @Override 6843 public ComponentName getAllowedNotificationAssistantForUser(int userId) { 6844 checkCallerIsSystemOrSystemUiOrShell(); 6845 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 6846 if (allowedComponents.size() > 1) { 6847 throw new IllegalStateException( 6848 "At most one NotificationAssistant: " + allowedComponents.size()); 6849 } 6850 return CollectionUtils.firstOrNull(allowedComponents); 6851 } 6852 6853 @Override 6854 public ComponentName getAllowedNotificationAssistant() { 6855 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier()); 6856 } 6857 6858 @Override 6859 public ComponentName getDefaultNotificationAssistant() { 6860 checkCallerIsSystem(); 6861 return mAssistants.getDefaultFromConfig(); 6862 } 6863 6864 @Override 6865 public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) { 6866 checkCallerIsSystem(); 6867 setNASMigrationDone(userId); 6868 if (loadFromConfig) { 6869 mAssistants.resetDefaultFromConfig(); 6870 } else { 6871 mAssistants.clearDefaults(); 6872 } 6873 } 6874 6875 6876 @Override 6877 public boolean hasEnabledNotificationListener(String packageName, int userId) { 6878 checkCallerIsSystem(); 6879 return mListeners.isPackageAllowed(packageName, userId); 6880 } 6881 6882 @Override 6883 public boolean isNotificationListenerAccessGranted(ComponentName listener) { 6884 Objects.requireNonNull(listener); 6885 checkCallerIsSystemOrSameApp(listener.getPackageName()); 6886 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 6887 getCallingUserHandle().getIdentifier()); 6888 } 6889 6890 @Override 6891 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener, 6892 int userId) { 6893 Objects.requireNonNull(listener); 6894 checkCallerIsSystem(); 6895 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 6896 userId); 6897 } 6898 6899 @Override 6900 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { 6901 Objects.requireNonNull(assistant); 6902 checkCallerIsSystemOrSameApp(assistant.getPackageName()); 6903 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(), 6904 getCallingUserHandle().getIdentifier()); 6905 } 6906 6907 @Override 6908 public void setNotificationListenerAccessGranted(ComponentName listener, 6909 boolean granted, boolean userSet) throws RemoteException { 6910 setNotificationListenerAccessGrantedForUser( 6911 listener, getCallingUserHandle().getIdentifier(), granted, userSet); 6912 } 6913 6914 @Override 6915 public void setNotificationAssistantAccessGranted(ComponentName assistant, 6916 boolean granted) { 6917 setNotificationAssistantAccessGrantedForUser( 6918 assistant, getCallingUserHandle().getIdentifier(), granted); 6919 } 6920 6921 @Override 6922 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, 6923 boolean granted, boolean userSet) { 6924 Objects.requireNonNull(listener); 6925 if (UserHandle.getCallingUserId() != userId) { 6926 getContext().enforceCallingOrSelfPermission( 6927 android.Manifest.permission.INTERACT_ACROSS_USERS, 6928 "setNotificationListenerAccessGrantedForUser for user " + userId); 6929 } 6930 if (!managedServicesConcurrentMultiuser() 6931 && mUmInternal.isVisibleBackgroundFullUser(userId)) { 6932 // The main use case for visible background users is the Automotive multi-display 6933 // configuration where a passenger can use a secondary display while the driver is 6934 // using the main display. NotificationListeners is designed only for the current 6935 // user and work profile. We added a condition to prevent visible background users 6936 // from updating the data managed within the NotificationListeners object. 6937 return; 6938 } 6939 checkNotificationListenerAccess(); 6940 if (granted && listener.flattenToString().length() 6941 > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) { 6942 throw new IllegalArgumentException( 6943 "Component name too long: " + listener.flattenToString()); 6944 } 6945 if (!userSet && isNotificationListenerAccessUserSet(listener, userId)) { 6946 // Don't override user's choice 6947 return; 6948 } 6949 final long identity = Binder.clearCallingIdentity(); 6950 try { 6951 if (mAllowedManagedServicePackages.test( 6952 listener.getPackageName(), userId, mListeners.getRequiredPermission())) { 6953 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(), 6954 userId, false, granted, userSet); 6955 mListeners.setPackageOrComponentEnabled(listener.flattenToString(), 6956 userId, true, granted, userSet); 6957 6958 getContext().sendBroadcastAsUser(new Intent( 6959 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 6960 .setPackage(listener.getPackageName()) 6961 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 6962 UserHandle.of(userId), null); 6963 6964 handleSavePolicyFile(); 6965 } 6966 } finally { 6967 Binder.restoreCallingIdentity(identity); 6968 } 6969 } 6970 6971 private boolean isNotificationListenerAccessUserSet(ComponentName listener, int userId) { 6972 return mListeners.isPackageOrComponentUserSet(listener.flattenToString(), userId); 6973 } 6974 6975 @Override 6976 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, 6977 int userId, boolean granted) { 6978 checkCallerIsSystemOrSystemUiOrShell(); 6979 for (UserInfo ui : mUm.getEnabledProfiles(userId)) { 6980 mAssistants.setUserSet(ui.id, true); 6981 } 6982 final long identity = Binder.clearCallingIdentity(); 6983 try { 6984 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted, 6985 true); 6986 } finally { 6987 Binder.restoreCallingIdentity(identity); 6988 } 6989 } 6990 6991 @Override 6992 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token, 6993 Adjustment adjustment) { 6994 boolean foundEnqueued = false; 6995 final long identity = Binder.clearCallingIdentity(); 6996 try { 6997 synchronized (mNotificationLock) { 6998 ManagedServiceInfo info = mAssistants.checkServiceTokenLocked(token); 6999 int N = mEnqueuedNotifications.size(); 7000 for (int i = 0; i < N; i++) { 7001 final NotificationRecord r = mEnqueuedNotifications.get(i); 7002 if (Objects.equals(adjustment.getKey(), r.getKey()) 7003 && Objects.equals(adjustment.getUser(), r.getUserId()) 7004 && mAssistants.isSameUser(token, r.getUserId())) { 7005 applyAdjustmentLocked(r, adjustment, false); 7006 r.applyAdjustments(); 7007 // importance is checked at the beginning of the 7008 // PostNotificationRunnable, before the signal extractors are run, so 7009 // calculate the final importance here 7010 r.calculateImportance(); 7011 foundEnqueued = true; 7012 } 7013 } 7014 if (!foundEnqueued) { 7015 applyAdjustmentsFromAssistant(token, List.of(adjustment)); 7016 } 7017 } 7018 } finally { 7019 Binder.restoreCallingIdentity(identity); 7020 } 7021 } 7022 7023 @Override 7024 public void applyAdjustmentFromAssistant(INotificationListener token, 7025 Adjustment adjustment) { 7026 List<Adjustment> adjustments = new ArrayList<>(); 7027 adjustments.add(adjustment); 7028 applyAdjustmentsFromAssistant(token, adjustments); 7029 } 7030 7031 @Override 7032 public void applyAdjustmentsFromAssistant(INotificationListener token, 7033 List<Adjustment> adjustments) { 7034 7035 boolean needsSort = false; 7036 final long identity = Binder.clearCallingIdentity(); 7037 try { 7038 synchronized (mNotificationLock) { 7039 mAssistants.checkServiceTokenLocked(token); 7040 for (Adjustment adjustment : adjustments) { 7041 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey()); 7042 if (r != null && mAssistants.isSameUser(token, r.getUserId())) { 7043 applyAdjustmentLocked(r, adjustment, true); 7044 // If the assistant has blocked the notification, cancel it 7045 // This will trigger a sort, so we don't have to explicitly ask for 7046 // one here. 7047 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE) 7048 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE) 7049 == IMPORTANCE_NONE) { 7050 cancelNotificationsFromListener(token, new String[]{r.getKey()}); 7051 } else { 7052 r.setPendingLogUpdate(true); 7053 needsSort = true; 7054 } 7055 } 7056 } 7057 } 7058 if (needsSort) { 7059 mRankingHandler.requestSort(); 7060 } 7061 } finally { 7062 Binder.restoreCallingIdentity(identity); 7063 } 7064 } 7065 7066 @Override 7067 @FlaggedApi(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) 7068 public NotificationChannel createConversationNotificationChannelForPackageFromPrivilegedListener( 7069 INotificationListener token, String pkg, UserHandle user, 7070 String parentId, String conversationId) throws RemoteException { 7071 Objects.requireNonNull(pkg); 7072 Objects.requireNonNull(user); 7073 Objects.requireNonNull(parentId); 7074 Objects.requireNonNull(conversationId); 7075 7076 verifyPrivilegedListener(token, user, true); 7077 7078 int uid = getUidForPackageAndUser(pkg, user); 7079 NotificationChannel conversationChannel = 7080 mPreferencesHelper.getNotificationChannel(pkg, uid, parentId, false).copy(); 7081 String conversationChannelId = String.format( 7082 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId); 7083 conversationChannel.setId(conversationChannelId); 7084 conversationChannel.setConversationId(parentId, conversationId); 7085 createNotificationChannelsImpl( 7086 pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel))); 7087 handleSavePolicyFile(); 7088 7089 return mPreferencesHelper.getConversationNotificationChannel( 7090 pkg, uid, parentId, conversationId, false, false).copy(); 7091 } 7092 7093 @Override 7094 public void updateNotificationChannelGroupFromPrivilegedListener( 7095 INotificationListener token, String pkg, UserHandle user, 7096 NotificationChannelGroup group) throws RemoteException { 7097 Objects.requireNonNull(user); 7098 verifyPrivilegedListener(token, user, false); 7099 createNotificationChannelGroup( 7100 pkg, getUidForPackageAndUser(pkg, user), group, false, true); 7101 handleSavePolicyFile(); 7102 } 7103 7104 @Override 7105 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, 7106 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { 7107 Objects.requireNonNull(channel); 7108 Objects.requireNonNull(pkg); 7109 Objects.requireNonNull(user); 7110 7111 verifyPrivilegedListener(token, user, true); 7112 7113 final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( 7114 pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true); 7115 verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel); 7116 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); 7117 } 7118 7119 @Override 7120 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( 7121 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 7122 Objects.requireNonNull(pkg); 7123 Objects.requireNonNull(user); 7124 verifyPrivilegedListener(token, user, true); 7125 7126 return mPreferencesHelper.getNotificationChannels(pkg, 7127 getUidForPackageAndUser(pkg, user), false /* includeDeleted */, true); 7128 } 7129 7130 @Override 7131 public ParceledListSlice<NotificationChannelGroup> 7132 getNotificationChannelGroupsFromPrivilegedListener( 7133 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 7134 Objects.requireNonNull(pkg); 7135 Objects.requireNonNull(user); 7136 verifyPrivilegedListener(token, user, true); 7137 7138 List<NotificationChannelGroup> groups = new ArrayList<>(); 7139 groups.addAll(mPreferencesHelper.getNotificationChannelGroupsWithoutChannels( 7140 pkg, getUidForPackageAndUser(pkg, user))); 7141 return new ParceledListSlice<>(groups); 7142 } 7143 7144 @Override 7145 public boolean isInCall(String pkg, int uid) { 7146 checkCallerIsSystemOrSystemUiOrShell(); 7147 return isCallNotification(pkg, uid); 7148 } 7149 7150 @Override 7151 public void setPrivateNotificationsAllowed(boolean allow) { 7152 if (PERMISSION_GRANTED 7153 != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 7154 throw new SecurityException( 7155 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 7156 } 7157 if (allow != mLockScreenAllowSecureNotifications) { 7158 mLockScreenAllowSecureNotifications = allow; 7159 if (android.app.Flags.keyguardPrivateNotifications()) { 7160 getContext().sendBroadcast( 7161 new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) 7162 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, 7163 mLockScreenAllowSecureNotifications), 7164 STATUS_BAR_SERVICE); 7165 } 7166 7167 handleSavePolicyFile(); 7168 } 7169 } 7170 7171 @Override 7172 public boolean getPrivateNotificationsAllowed() { 7173 if (PERMISSION_GRANTED 7174 != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 7175 throw new SecurityException( 7176 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 7177 } 7178 return mLockScreenAllowSecureNotifications; 7179 } 7180 7181 @Override 7182 public boolean isPackagePaused(String pkg) { 7183 Objects.requireNonNull(pkg); 7184 checkCallerIsSameApp(pkg); 7185 7186 return isPackagePausedOrSuspended(pkg, Binder.getCallingUid()); 7187 } 7188 7189 @Override 7190 public boolean isPermissionFixed(String pkg, @UserIdInt int userId) { 7191 enforceSystemOrSystemUI("isPermissionFixed"); 7192 return mPermissionHelper.isPermissionFixed(pkg, userId); 7193 } 7194 7195 private void verifyPrivilegedListener(INotificationListener token, UserHandle user, 7196 boolean assistantAllowed) { 7197 ManagedServiceInfo info; 7198 synchronized (mNotificationLock) { 7199 info = mListeners.checkServiceTokenLocked(token); 7200 } 7201 if (!hasCompanionDevice(info)) { 7202 synchronized (mNotificationLock) { 7203 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) { 7204 throw new SecurityException(info + " does not have access"); 7205 } 7206 } 7207 } 7208 if (!info.enabledAndUserMatches(user.getIdentifier())) { 7209 throw new SecurityException(info + " does not have access"); 7210 } 7211 } 7212 7213 private void verifyPrivilegedListenerUriPermission(int sourceUid, 7214 @NonNull NotificationChannel updateChannel, 7215 @Nullable NotificationChannel originalChannel) { 7216 // Check that the NLS has the required permissions to access the channel 7217 final Uri soundUri = updateChannel.getSound(); 7218 final Uri originalSoundUri = 7219 (originalChannel != null) ? originalChannel.getSound() : null; 7220 if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) { 7221 Binder.withCleanCallingIdentity(() -> { 7222 mUgmInternal.checkGrantUriPermission(sourceUid, null, 7223 ContentProvider.getUriWithoutUserId(soundUri), 7224 Intent.FLAG_GRANT_READ_URI_PERMISSION, 7225 ContentProvider.getUserIdFromUri(soundUri, 7226 UserHandle.getUserId(sourceUid))); 7227 }); 7228 } 7229 } 7230 7231 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { 7232 int uid = INVALID_UID; 7233 final long identity = Binder.clearCallingIdentity(); 7234 try { 7235 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); 7236 } finally { 7237 Binder.restoreCallingIdentity(identity); 7238 } 7239 return uid; 7240 } 7241 7242 @Override 7243 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 7244 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 7245 throws RemoteException { 7246 new NotificationShellCmd(NotificationManagerService.this) 7247 .exec(this, in, out, err, args, callback, resultReceiver); 7248 } 7249 7250 /** 7251 * Get stats committed after startNs 7252 * 7253 * @param startNs Report stats committed after this time in nanoseconds. 7254 * @param report Indicatess which section to include in the stats. 7255 * @param doAgg Whether to aggregate the stats or keep them separated. 7256 * @param out List of protos of individual commits or one representing the 7257 * aggregate. 7258 * @return the report time in nanoseconds, or 0 on error. 7259 */ 7260 @Override 7261 public long pullStats(long startNs, int report, boolean doAgg, 7262 List<ParcelFileDescriptor> out) { 7263 checkCallerIsSystemOrShell(); 7264 long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS); 7265 7266 final long identity = Binder.clearCallingIdentity(); 7267 try { 7268 switch (report) { 7269 case REPORT_REMOTE_VIEWS: 7270 Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: " 7271 + startMs + " with " + doAgg); 7272 PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg); 7273 if (stats != null) { 7274 out.add(stats.toParcelFileDescriptor(report)); 7275 Slog.e(TAG, "exiting pullStats with: " + out.size()); 7276 long endNs = TimeUnit.NANOSECONDS 7277 .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS); 7278 return endNs; 7279 } 7280 Slog.e(TAG, "null stats for: " + report); 7281 } 7282 } catch (IOException e) { 7283 7284 Slog.e(TAG, "exiting pullStats: on error", e); 7285 return 0; 7286 } finally { 7287 Binder.restoreCallingIdentity(identity); 7288 } 7289 Slog.e(TAG, "exiting pullStats: bad request"); 7290 return 0; 7291 } 7292 7293 @Override 7294 public void incrementCounter(String metricId) { 7295 if (android.app.Flags.nmBinderPerfLogNmThrottling() && metricId != null) { 7296 Counter.logIncrementWithUid(metricId, Binder.getCallingUid()); 7297 } 7298 } 7299 }; 7300 7301 private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) { 7302 if (!mUmInternal.isUserInitialized(userId)) { 7303 return; // App-op "updates" are sent when starting a new user the first time. 7304 } 7305 int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId); 7306 if (uid == INVALID_UID) { 7307 Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId)); 7308 return; 7309 } 7310 boolean hasPermission = mPermissionHelper.hasPermission(uid); 7311 if (!hasPermission) { 7312 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null, 7313 /* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId, 7314 REASON_PACKAGE_BANNED); 7315 } 7316 } 7317 7318 protected void checkNotificationListenerAccess() { 7319 if (!isCallerSystemOrPhone()) { 7320 // Safe to check calling permission as caller is already not system or phone 7321 getContext().enforceCallingPermission( 7322 permission.MANAGE_NOTIFICATION_LISTENERS, 7323 "Caller must hold " + permission.MANAGE_NOTIFICATION_LISTENERS); 7324 } 7325 } 7326 7327 @VisibleForTesting 7328 protected void setNotificationAssistantAccessGrantedForUserInternal( 7329 ComponentName assistant, int baseUserId, boolean granted, boolean userSet) { 7330 List<UserInfo> users = mUm.getEnabledProfiles(baseUserId); 7331 if (users != null) { 7332 for (UserInfo user : users) { 7333 int userId = user.id; 7334 if (assistant == null) { 7335 ComponentName allowedAssistant = CollectionUtils.firstOrNull( 7336 mAssistants.getAllowedComponents(userId)); 7337 if (allowedAssistant != null) { 7338 setNotificationAssistantAccessGrantedForUserInternal( 7339 allowedAssistant, userId, false, userSet); 7340 } 7341 continue; 7342 } 7343 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), 7344 userId, mAssistants.getRequiredPermission())) { 7345 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(), 7346 userId, false, granted); 7347 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(), 7348 userId, true, granted, userSet); 7349 7350 if (android.service.notification.Flags.notificationClassification()) { 7351 mAssistants.setNasUnsupportedDefaults(userId); 7352 } 7353 7354 getContext().sendBroadcastAsUser( 7355 new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 7356 .setPackage(assistant.getPackageName()) 7357 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 7358 UserHandle.of(userId), null); 7359 7360 handleSavePolicyFile(); 7361 } 7362 } 7363 } 7364 } 7365 7366 @GuardedBy("mNotificationLock") 7367 private void applyAdjustmentLocked(NotificationRecord r, Adjustment adjustment, 7368 boolean isPosted) { 7369 if (r == null) { 7370 return; 7371 } 7372 if (adjustment.getSignals() != null) { 7373 final Bundle adjustments = adjustment.getSignals(); 7374 Bundle.setDefusable(adjustments, true); 7375 // Save classification even if the adjustment is disabled, in case user enables it later 7376 if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) { 7377 r.setBundleType(adjustments.getInt(KEY_TYPE)); 7378 } 7379 List<String> toRemove = new ArrayList<>(); 7380 for (String potentialKey : adjustments.keySet()) { 7381 if (!mAssistants.isAdjustmentAllowed(potentialKey)) { 7382 toRemove.add(potentialKey); 7383 } 7384 if (notificationClassification() && potentialKey.equals(KEY_TYPE)) { 7385 mAssistants.setAdjustmentTypeSupportedState( 7386 r.getSbn().getNormalizedUserId(), potentialKey, true); 7387 if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) { 7388 toRemove.add(potentialKey); 7389 } else if (notificationClassificationUi() 7390 && !mAssistants.isAdjustmentAllowedForPackage(KEY_TYPE, 7391 r.getSbn().getPackageName())) { 7392 toRemove.add(potentialKey); 7393 } 7394 } 7395 if ((nmSummarization() || nmSummarizationUi()) 7396 && potentialKey.equals(KEY_SUMMARIZATION)) { 7397 mAssistants.setAdjustmentTypeSupportedState( 7398 r.getSbn().getNormalizedUserId(), potentialKey, true); 7399 if (!mAssistants.isAdjustmentAllowedForPackage(KEY_SUMMARIZATION, 7400 r.getSbn().getPackageName())) { 7401 toRemove.add(potentialKey); 7402 } 7403 } 7404 } 7405 for (String removeKey : toRemove) { 7406 adjustments.remove(removeKey); 7407 } 7408 if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) { 7409 final NotificationChannel newChannel = getClassificationChannelLocked(r, 7410 adjustments); 7411 if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) { 7412 adjustments.remove(KEY_TYPE); 7413 } else if (android.app.Flags.apiRichOngoing() && hasFlag(r.getNotification().flags, 7414 FLAG_PROMOTED_ONGOING)) { 7415 // Don't bundle any promoted ongoing notifications 7416 adjustments.remove(KEY_TYPE); 7417 } else { 7418 // Save the app-provided type for logging. 7419 int classification = adjustments.getInt(KEY_TYPE); 7420 // swap app provided type with the real thing 7421 adjustments.putParcelable(KEY_TYPE, newChannel); 7422 logClassificationChannelAdjustmentReceived(r, isPosted, classification); 7423 } 7424 } 7425 r.addAdjustment(adjustment); 7426 if (adjustment.getSignals().containsKey(Adjustment.KEY_SENSITIVE_CONTENT)) { 7427 logSensitiveAdjustmentReceived(isPosted, 7428 adjustment.getSignals().getBoolean(Adjustment.KEY_SENSITIVE_CONTENT), 7429 r.getLifespanMs(System.currentTimeMillis())); 7430 } 7431 } 7432 } 7433 7434 @GuardedBy("mNotificationLock") 7435 @Nullable 7436 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 7437 private NotificationChannel getClassificationChannelLocked(NotificationRecord r, 7438 Bundle adjustments) { 7439 int type = adjustments.getInt(KEY_TYPE); 7440 if (type >= TYPE_PROMOTION && type <= TYPE_CONTENT_RECOMMENDATION) { 7441 NotificationChannel channel = mPreferencesHelper.getReservedChannel( 7442 r.getSbn().getPackageName(), r.getUid(), type); 7443 if (channel == null) { 7444 channel = mPreferencesHelper.createReservedChannel( 7445 r.getSbn().getPackageName(), r.getUid(), type); 7446 handleSavePolicyFile(); 7447 } 7448 return channel; 7449 } 7450 return null; 7451 } 7452 7453 @SuppressWarnings("GuardedBy") 7454 @GuardedBy("mNotificationLock") 7455 void addAutogroupKeyLocked(String key, String groupName, boolean requestSort) { 7456 NotificationRecord r = mNotificationsByKey.get(key); 7457 if (r == null) { 7458 return; 7459 } 7460 if (r.getSbn().getOverrideGroupKey() == null) { 7461 if (notificationForceGrouping()) { 7462 if (r.getSbn().isAppGroup()) { 7463 // Override group key early for forced grouped notifications 7464 r.setOverrideGroupKey(groupName); 7465 } 7466 r.getNotification().flags |= Notification.FLAG_SILENT; 7467 } 7468 7469 addAutoGroupAdjustment(r, groupName); 7470 EventLogTags.writeNotificationAutogrouped(key); 7471 7472 if (!android.app.Flags.checkAutogroupBeforePost() || requestSort) { 7473 mRankingHandler.requestSort(); 7474 } 7475 7476 if (notificationForceGrouping()) { 7477 if (r.getSbn().isAppGroup()) { 7478 mListeners.notifyPostedLocked(r, r); 7479 7480 mNotificationRecordLogger.log( 7481 NotificationRecordLogger.NotificationEvent.NOTIFICATION_FORCE_GROUP, r); 7482 } 7483 } 7484 } 7485 } 7486 7487 @GuardedBy("mNotificationLock") 7488 void removeAutogroupKeyLocked(String key) { 7489 NotificationRecord r = mNotificationsByKey.get(key); 7490 if (r == null) { 7491 Slog.w(TAG, "Failed to remove autogroup " + key); 7492 return; 7493 } 7494 if (r.getSbn().getOverrideGroupKey() != null) { 7495 addAutoGroupAdjustment(r, null); 7496 EventLogTags.writeNotificationUnautogrouped(key); 7497 mRankingHandler.requestSort(); 7498 } 7499 } 7500 7501 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) { 7502 Bundle signals = new Bundle(); 7503 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey); 7504 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 7505 r.getSbn().getUserId()); 7506 r.addAdjustment(adjustment); 7507 } 7508 7509 // Clears the 'fake' auto-group summary. 7510 @VisibleForTesting 7511 @GuardedBy("mNotificationLock") 7512 void clearAutogroupSummaryLocked(int userId, String pkg, String groupKey) { 7513 final String autbundledGroupKey; 7514 if (notificationForceGrouping()) { 7515 autbundledGroupKey = groupKey; 7516 } else { 7517 autbundledGroupKey = pkg; 7518 } 7519 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 7520 if (summaries != null && summaries.containsKey(autbundledGroupKey)) { 7521 final NotificationRecord removed = findNotificationByKeyLocked( 7522 summaries.remove(autbundledGroupKey)); 7523 if (removed != null) { 7524 final StatusBarNotification sbn = removed.getSbn(); 7525 cancelNotification(MY_UID, MY_PID, pkg, sbn.getTag(), sbn.getId(), 0, 0, false, 7526 userId, REASON_UNAUTOBUNDLED, null); 7527 } 7528 } 7529 } 7530 7531 @GuardedBy("mNotificationLock") 7532 void removeAppSummaryLocked(String key) { 7533 NotificationRecord r = mNotificationsByKey.get(key); 7534 if (r == null) { 7535 return; 7536 } 7537 if (convertSummaryToNotificationLocked(key)) { 7538 r.isCanceled = true; 7539 cancelNotification(Binder.getCallingUid(), 7540 Binder.getCallingPid(), r.getSbn().getPackageName(), 7541 r.getSbn().getTag(), r.getSbn().getId(), 0, 0, 7542 false, r.getUserId(), 7543 NotificationListenerService.REASON_GROUP_OPTIMIZATION, null); 7544 } 7545 } 7546 7547 @GuardedBy("mNotificationLock") 7548 @Nullable 7549 NotificationRecord removeAppProvidedSummaryOnClassificationLocked(String triggeringKey, 7550 @Nullable String oldGroupKey) { 7551 NotificationRecord canceledSummary = null; 7552 NotificationRecord r = mNotificationsByKey.get(triggeringKey); 7553 if (r == null || oldGroupKey == null) { 7554 return null; 7555 } 7556 7557 if (r.getSbn().isAppGroup() && r.getNotification().isGroupChild()) { 7558 NotificationRecord groupSummary = mSummaryByGroupKey.get(oldGroupKey); 7559 // We only care about app-provided valid groups 7560 if (groupSummary != null && !GroupHelper.isAggregatedGroup(groupSummary)) { 7561 List<NotificationRecord> notificationsInGroup = 7562 findGroupNotificationsLocked(r.getSbn().getPackageName(), 7563 oldGroupKey, r.getUserId()); 7564 // Remove the app-provided summary if only the summary is left in the 7565 // original group, or summary + triggering notification that will be 7566 // regrouped 7567 boolean isOnlySummaryLeft = 7568 (notificationsInGroup.size() <= 1) 7569 || (notificationsInGroup.size() == 2 7570 && notificationsInGroup.contains(r) 7571 && notificationsInGroup.contains(groupSummary)); 7572 if (isOnlySummaryLeft) { 7573 if (DBG) { 7574 Slog.i(TAG, "Removing app summary (all children bundled): " 7575 + groupSummary); 7576 } 7577 if (convertSummaryToNotificationLocked(groupSummary.getKey())) { 7578 groupSummary.isCanceled = true; 7579 canceledSummary = groupSummary; 7580 mSummaryByGroupKey.remove(oldGroupKey); 7581 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), 7582 groupSummary.getSbn().getPackageName(), 7583 groupSummary.getSbn().getTag(), 7584 groupSummary.getSbn().getId(), 0, 0, false, groupSummary.getUserId(), 7585 NotificationListenerService.REASON_GROUP_OPTIMIZATION, null); 7586 } 7587 } 7588 } 7589 } 7590 7591 return canceledSummary; 7592 } 7593 7594 @GuardedBy("mNotificationLock") 7595 private boolean hasAutoGroupSummaryLocked(NotificationRecord record) { 7596 final String autbundledGroupKey; 7597 if (notificationForceGrouping()) { 7598 autbundledGroupKey = GroupHelper.getFullAggregateGroupKey(record); 7599 } else { 7600 autbundledGroupKey = record.getSbn().getPackageName(); 7601 } 7602 7603 ArrayMap<String, String> summaries = mAutobundledSummaries.get(record.getUserId()); 7604 return summaries != null && summaries.containsKey(autbundledGroupKey); 7605 } 7606 7607 // Creates a 'fake' summary for a package that has exceeded the solo-notification limit. 7608 NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey, 7609 String groupKey, int summaryId, NotificationAttributes summaryAttr) { 7610 NotificationRecord summaryRecord = null; 7611 boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId); 7612 synchronized (mNotificationLock) { 7613 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey); 7614 if (notificationRecord == null) { 7615 // The notification could have been cancelled again already. A successive 7616 // adjustment will post a summary if needed. 7617 return null; 7618 } 7619 final StatusBarNotification adjustedSbn = notificationRecord.getSbn(); 7620 userId = adjustedSbn.getUser().getIdentifier(); 7621 int uid = adjustedSbn.getUid(); 7622 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 7623 if (summaries == null) { 7624 summaries = new ArrayMap<>(); 7625 } 7626 mAutobundledSummaries.put(userId, summaries); 7627 7628 boolean hasSummary; 7629 String channelId; 7630 if (notificationForceGrouping()) { 7631 hasSummary = summaries.containsKey(groupKey); 7632 channelId = summaryAttr.channelId; 7633 } else { 7634 hasSummary = summaries.containsKey(pkg); 7635 channelId = notificationRecord.getChannel().getId(); 7636 } 7637 7638 if (!hasSummary) { 7639 // Add summary 7640 final ApplicationInfo appInfo = 7641 adjustedSbn.getNotification().extras.getParcelable( 7642 EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class); 7643 final Bundle extras = new Bundle(); 7644 extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, appInfo); 7645 7646 7647 final Notification summaryNotification = 7648 new Notification.Builder(getContext(), channelId) 7649 .setSmallIcon(summaryAttr.icon) 7650 .setGroupSummary(true) 7651 .setGroupAlertBehavior(summaryAttr.groupAlertBehavior) 7652 .setGroup(groupKey) 7653 .setFlag(summaryAttr.flags, true) 7654 .setColor(summaryAttr.iconColor) 7655 .setVisibility(summaryAttr.visibility) 7656 .build(); 7657 summaryNotification.extras.putAll(extras); 7658 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); 7659 if (appIntent != null) { 7660 summaryNotification.contentIntent = mAmi.getPendingIntentActivityAsApp( 7661 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null, 7662 pkg, appInfo.uid); 7663 } 7664 final StatusBarNotification summarySbn = 7665 new StatusBarNotification(adjustedSbn.getPackageName(), 7666 adjustedSbn.getOpPkg(), 7667 summaryId, 7668 groupKey, adjustedSbn.getUid(), 7669 adjustedSbn.getInitialPid(), summaryNotification, 7670 adjustedSbn.getUser(), groupKey, 7671 System.currentTimeMillis()); 7672 summaryRecord = new NotificationRecord(getContext(), summarySbn, 7673 notificationRecord.getChannel()); 7674 summaryRecord.setImportanceFixed(isPermissionFixed); 7675 summaryRecord.setIsAppImportanceLocked( 7676 notificationRecord.getIsAppImportanceLocked()); 7677 7678 if (notificationForceGrouping()) { 7679 summaries.put(summarySbn.getGroupKey(), summarySbn.getKey()); 7680 } else { 7681 summaries.put(pkg, summarySbn.getKey()); 7682 } 7683 } 7684 if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid, 7685 summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord, 7686 true, false)) { 7687 return summaryRecord; 7688 } 7689 } 7690 return null; 7691 } 7692 7693 @GuardedBy("mNotificationLock") 7694 boolean convertSummaryToNotificationLocked(final String key) { 7695 NotificationRecord r = mNotificationsByKey.get(key); 7696 if (r == null) { 7697 return false; 7698 } 7699 // Convert summary to regular notification 7700 if (r.getSbn().isAppGroup() && r.getNotification().isGroupSummary()) { 7701 String oldGroupKey = r.getGroupKey(); 7702 NotificationRecord groupSummary = mSummaryByGroupKey.get(oldGroupKey); 7703 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { 7704 mSummaryByGroupKey.remove(oldGroupKey); 7705 } 7706 // Clear summary flag 7707 StatusBarNotification sbn = r.getSbn(); 7708 sbn.getNotification().flags = (r.mOriginalFlags & ~FLAG_GROUP_SUMMARY); 7709 7710 EventLogTags.writeNotificationSummaryConverted(key); 7711 mNotificationRecordLogger.log( 7712 NotificationRecordLogger.NotificationEvent.NOTIFICATION_FORCE_GROUP_SUMMARY, r); 7713 return true; 7714 } 7715 return false; 7716 } 7717 7718 // Gets packages that have requested notification permission, and whether that has been 7719 // allowed/denied, for all users on the device. 7720 // Returns a single map containing that info keyed by (uid, package name) for all users. 7721 // Because this calls into mPermissionHelper, this method must never be called with a lock held. 7722 @VisibleForTesting 7723 protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> 7724 getAllUsersNotificationPermissions() { 7725 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>(); 7726 final List<UserInfo> allUsers = mUm.getUsers(); 7727 // for each of these, get the package notification permissions that are associated 7728 // with this user and add it to the map 7729 for (UserInfo ui : allUsers) { 7730 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> userPermissions = 7731 mPermissionHelper.getNotificationPermissionValues( 7732 ui.getUserHandle().getIdentifier()); 7733 for (Pair<Integer, String> pair : userPermissions.keySet()) { 7734 allPermissions.put(pair, userPermissions.get(pair)); 7735 } 7736 } 7737 return allPermissions; 7738 } 7739 7740 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter, 7741 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { 7742 JSONObject dump = new JSONObject(); 7743 try { 7744 dump.put("service", "Notification Manager"); 7745 dump.put("bans", mPreferencesHelper.dumpBansJson(filter, pkgPermissions)); 7746 dump.put("ranking", mPreferencesHelper.dumpJson(filter, pkgPermissions)); 7747 dump.put("stats", mUsageStats.dumpJson(filter)); 7748 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter)); 7749 } catch (JSONException e) { 7750 e.printStackTrace(); 7751 } 7752 pw.println(dump); 7753 } 7754 7755 private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) { 7756 PulledStats stats = mUsageStats.remoteViewStats(filter.since, true); 7757 if (stats == null) { 7758 pw.println("no remote view stats reported."); 7759 return; 7760 } 7761 stats.dump(REPORT_REMOTE_VIEWS, pw, filter); 7762 } 7763 7764 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter, 7765 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { 7766 final ProtoOutputStream proto = new ProtoOutputStream(fd); 7767 synchronized (mNotificationLock) { 7768 int N = mNotificationList.size(); 7769 for (int i = 0; i < N; i++) { 7770 final NotificationRecord nr = mNotificationList.get(i); 7771 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 7772 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 7773 NotificationRecordProto.POSTED); 7774 } 7775 N = mEnqueuedNotifications.size(); 7776 for (int i = 0; i < N; i++) { 7777 final NotificationRecord nr = mEnqueuedNotifications.get(i); 7778 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 7779 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 7780 NotificationRecordProto.ENQUEUED); 7781 } 7782 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed(); 7783 N = snoozed.size(); 7784 for (int i = 0; i < N; i++) { 7785 final NotificationRecord nr = snoozed.get(i); 7786 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 7787 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 7788 NotificationRecordProto.SNOOZED); 7789 } 7790 7791 long zenLog = proto.start(NotificationServiceDumpProto.ZEN); 7792 mZenModeHelper.dump(proto); 7793 for (ComponentName suppressor : mEffectsSuppressors) { 7794 suppressor.dumpDebug(proto, ZenModeProto.SUPPRESSORS); 7795 } 7796 proto.end(zenLog); 7797 7798 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS); 7799 mListeners.dump(proto, filter); 7800 proto.end(listenersToken); 7801 7802 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints); 7803 7804 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) { 7805 long effectsToken = proto.start( 7806 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS); 7807 7808 proto.write( 7809 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i)); 7810 final ArraySet<ComponentName> listeners = 7811 mListenersDisablingEffects.valueAt(i); 7812 for (int j = 0; j < listeners.size(); j++) { 7813 final ComponentName componentName = listeners.valueAt(j); 7814 componentName.dumpDebug(proto, 7815 ListenersDisablingEffectsProto.LISTENER_COMPONENTS); 7816 } 7817 7818 proto.end(effectsToken); 7819 } 7820 7821 long assistantsToken = proto.start( 7822 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS); 7823 mAssistants.dump(proto, filter); 7824 proto.end(assistantsToken); 7825 7826 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS); 7827 mConditionProviders.dump(proto, filter); 7828 proto.end(conditionsToken); 7829 7830 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG); 7831 mRankingHelper.dump(proto, filter); 7832 mPreferencesHelper.dump(proto, filter, pkgPermissions); 7833 proto.end(rankingToken); 7834 } 7835 7836 proto.flush(); 7837 } 7838 7839 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) { 7840 synchronized (mNotificationLock) { 7841 int N; 7842 N = mNotificationList.size(); 7843 if (N > 0) { 7844 pw.println(" Notification List:"); 7845 for (int i = 0; i < N; i++) { 7846 final NotificationRecord nr = mNotificationList.get(i); 7847 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 7848 nr.dump(pw, " ", getContext(), filter.redact); 7849 } 7850 pw.println(" "); 7851 } 7852 } 7853 } 7854 7855 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter, 7856 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { 7857 pw.print("Current Notification Manager state"); 7858 if (filter.filtered) { 7859 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 7860 } 7861 pw.println(':'); 7862 int N; 7863 final boolean zenOnly = filter.filtered && filter.zen; 7864 7865 if (!zenOnly) { 7866 synchronized (mToastQueue) { 7867 N = mToastQueue.size(); 7868 if (N > 0) { 7869 pw.println(" Toast Queue:"); 7870 for (int i=0; i<N; i++) { 7871 mToastQueue.get(i).dump(pw, " ", filter); 7872 } 7873 pw.println(" "); 7874 } 7875 } 7876 } 7877 7878 synchronized (mNotificationLock) { 7879 if (!zenOnly) { 7880 // Priority filters are only set when called via bugreport. If set 7881 // skip sections that are part of the critical section. 7882 if (!filter.normalPriority) { 7883 dumpNotificationRecords(pw, filter); 7884 } 7885 if (!filter.filtered) { 7886 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate); 7887 pw.println(" hideSilentStatusBar=" 7888 + mPreferencesHelper.shouldHideSilentStatusIcons()); 7889 mAttentionHelper.dumpLocked(pw, " ", filter); 7890 } 7891 pw.println(" mArchive=" + mArchive.toString()); 7892 mArchive.dumpImpl(pw, filter); 7893 7894 if (!zenOnly) { 7895 N = mEnqueuedNotifications.size(); 7896 if (N > 0) { 7897 pw.println(" Enqueued Notification List:"); 7898 for (int i = 0; i < N; i++) { 7899 final NotificationRecord nr = mEnqueuedNotifications.get(i); 7900 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 7901 nr.dump(pw, " ", getContext(), filter.redact); 7902 } 7903 pw.println(" "); 7904 } 7905 7906 mSnoozeHelper.dump(pw, filter); 7907 } 7908 } 7909 7910 if (!zenOnly) { 7911 pw.println("\n Ranking Config:"); 7912 mRankingHelper.dump(pw, " ", filter); 7913 7914 pw.println("\n Notification Preferences:"); 7915 mPreferencesHelper.dump(pw, " ", filter, pkgPermissions); 7916 7917 pw.println("\n Notification listeners:"); 7918 mListeners.dump(pw, filter); 7919 pw.print(" mListenerHints: "); pw.println(mListenerHints); 7920 pw.print(" mListenersDisablingEffects: ("); 7921 N = mListenersDisablingEffects.size(); 7922 for (int i = 0; i < N; i++) { 7923 final int hint = mListenersDisablingEffects.keyAt(i); 7924 if (i > 0) pw.print(';'); 7925 pw.print("hint[" + hint + "]:"); 7926 7927 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 7928 final int listenerSize = listeners.size(); 7929 7930 for (int j = 0; j < listenerSize; j++) { 7931 if (j > 0) pw.print(','); 7932 final ComponentName listener = listeners.valueAt(j); 7933 if (listener != null) { 7934 pw.print(listener); 7935 } 7936 } 7937 } 7938 pw.println(')'); 7939 pw.println("\n Notification assistant services:"); 7940 mAssistants.dump(pw, filter); 7941 } 7942 7943 if (!filter.filtered || zenOnly) { 7944 pw.println("\n Zen Mode:"); 7945 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 7946 mZenModeHelper.dump(pw, " "); 7947 7948 pw.println("\n Zen Log:"); 7949 ZenLog.dump(pw, " "); 7950 } 7951 7952 pw.println("\n Condition providers:"); 7953 mConditionProviders.dump(pw, filter); 7954 7955 pw.println("\n Group summaries:"); 7956 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 7957 NotificationRecord r = entry.getValue(); 7958 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 7959 if (mNotificationsByKey.get(r.getKey()) != r) { 7960 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 7961 r.dump(pw, " ", getContext(), filter.redact); 7962 } 7963 } 7964 7965 if (!zenOnly) { 7966 pw.println("\n Usage Stats:"); 7967 mUsageStats.dump(pw, " ", filter); 7968 7969 if (Flags.allNotifsNeedTtl()) { 7970 pw.println("\n TimeToLive alarms:"); 7971 mTtlHelper.dump(pw, " "); 7972 } 7973 } 7974 7975 if (notificationForceGrouping()) { 7976 pw.println("\n GroupHelper:"); 7977 mGroupHelper.dump(pw, " "); 7978 } 7979 } 7980 } 7981 7982 /** 7983 * The private API only accessible to the system process. 7984 */ 7985 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 7986 7987 public byte[] getBackupPayload(int user, BackupRestoreEventLogger logger) { 7988 checkCallerIsSystem(); 7989 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 7990 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7991 try { 7992 writePolicyXml(baos, true /*forBackup*/, user, logger); 7993 return baos.toByteArray(); 7994 } catch (IOException e) { 7995 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 7996 } 7997 return null; 7998 } 7999 8000 @Override 8001 public void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger) { 8002 checkCallerIsSystem(); 8003 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 8004 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 8005 if (payload == null) { 8006 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 8007 return; 8008 } 8009 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 8010 try { 8011 readPolicyXml(bais, true /*forRestore*/, user, logger); 8012 handleSavePolicyFile(); 8013 } catch (NumberFormatException | XmlPullParserException | IOException e) { 8014 Slog.w(TAG, "applyRestore: error reading payload", e); 8015 } 8016 } 8017 8018 @Override 8019 public NotificationChannel getNotificationChannel(String pkg, int uid, String 8020 channelId) { 8021 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false); 8022 } 8023 8024 @Override 8025 public NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String 8026 channelId) { 8027 return mPreferencesHelper.getGroupForChannel(pkg, uid, channelId); 8028 } 8029 8030 @Override 8031 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 8032 String tag, int id, Notification notification, int userId) { 8033 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 8034 userId, /* byForegroundService= */ false , /* isAppProvided= */ true); 8035 } 8036 8037 @Override 8038 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 8039 String tag, int id, Notification notification, int userId, 8040 boolean byForegroundService) { 8041 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 8042 userId, byForegroundService, /* isAppProvided= */ true); 8043 } 8044 8045 @Override 8046 public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid, 8047 String tag, int id, int userId) { 8048 // Don't allow client applications to cancel foreground service notifs, 8049 // user-initiated job notifs or autobundled summaries. 8050 final int mustNotHaveFlags = isCallingUidSystem() ? 0 : 8051 (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY); 8052 cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId, 8053 mustNotHaveFlags); 8054 } 8055 8056 @Override 8057 public boolean isNotificationShown(String pkg, String tag, int notificationId, int userId) { 8058 return isNotificationShownInternal(pkg, tag, notificationId, userId); 8059 } 8060 8061 @Override 8062 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 8063 int userId) { 8064 checkCallerIsSystem(); 8065 mHandler.post(() -> { 8066 synchronized (mNotificationLock) { 8067 removeFlagFromNotificationLocked(pkg, notificationId, userId, 8068 FLAG_FOREGROUND_SERVICE); 8069 } 8070 }); 8071 } 8072 8073 @Override 8074 public void removeUserInitiatedJobFlagFromNotification(String pkg, int notificationId, 8075 int userId) { 8076 checkCallerIsSystem(); 8077 mHandler.post(() -> { 8078 synchronized (mNotificationLock) { 8079 removeFlagFromNotificationLocked(pkg, notificationId, userId, 8080 FLAG_USER_INITIATED_JOB); 8081 } 8082 }); 8083 } 8084 8085 @GuardedBy("mNotificationLock") 8086 private void removeFlagFromNotificationLocked(String pkg, int notificationId, int userId, 8087 int flag) { 8088 int count = getNotificationCount(pkg, userId); 8089 boolean removeFlagFromNotification = false; 8090 if (count > MAX_PACKAGE_NOTIFICATIONS) { 8091 mUsageStats.registerOverCountQuota(pkg); 8092 removeFlagFromNotification = true; 8093 } 8094 if (removeFlagFromNotification) { 8095 NotificationRecord r = findNotificationLocked(pkg, null, notificationId, userId); 8096 if (r != null) { 8097 if (DBG) { 8098 final String type = (flag == FLAG_FOREGROUND_SERVICE) ? "FGS" : "UIJ"; 8099 Slog.d(TAG, "Remove " + type + " flag not allow. " 8100 + "Cancel " + type + " notification"); 8101 } 8102 removeFromNotificationListsLocked(r); 8103 cancelNotificationLocked(r, false, REASON_APP_CANCEL, true, 8104 null, SystemClock.elapsedRealtime()); 8105 } 8106 } else { 8107 List<NotificationRecord> enqueued = findNotificationsByListLocked( 8108 mEnqueuedNotifications, pkg, null, notificationId, userId); 8109 for (int i = 0; i < enqueued.size(); i++) { 8110 final NotificationRecord r = enqueued.get(i); 8111 if (r != null) { 8112 // strip flag from all enqueued notifications. listeners will be informed 8113 // in post runnable. 8114 StatusBarNotification sbn = r.getSbn(); 8115 if (notificationForceGrouping()) { 8116 sbn.getNotification().flags = (r.getFlags() & ~flag); 8117 } else { 8118 sbn.getNotification().flags = (r.mOriginalFlags & ~flag); 8119 } 8120 } 8121 } 8122 8123 NotificationRecord r = findNotificationByListLocked( 8124 mNotificationList, pkg, null, notificationId, userId); 8125 if (r != null) { 8126 // if posted notification exists, strip its flag and tell listeners 8127 StatusBarNotification sbn = r.getSbn(); 8128 if (notificationForceGrouping()) { 8129 sbn.getNotification().flags = (r.getFlags() & ~flag); 8130 } else { 8131 sbn.getNotification().flags = (r.mOriginalFlags & ~flag); 8132 } 8133 mRankingHelper.sort(mNotificationList); 8134 mListeners.notifyPostedLocked(r, r); 8135 } 8136 } 8137 } 8138 8139 @Override 8140 public void onConversationRemoved(String pkg, int uid, Set<String> shortcuts) { 8141 onConversationRemovedInternal(pkg, uid, shortcuts); 8142 } 8143 8144 @Override 8145 public int getNumNotificationChannelsForPackage(String pkg, int uid, 8146 boolean includeDeleted) { 8147 return NotificationManagerService.this 8148 .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted); 8149 } 8150 8151 @Override 8152 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 8153 return areNotificationsEnabledForPackageInt(uid); 8154 } 8155 8156 @Override 8157 public void sendReviewPermissionsNotification() { 8158 if (!mShowReviewPermissionsNotification) { 8159 // don't show if this notification is turned off 8160 return; 8161 } 8162 8163 // This method is meant to be called from the JobService upon running the job for this 8164 // notification having been rescheduled; so without checking any other state, it will 8165 // send the notification. 8166 checkCallerIsSystem(); 8167 NotificationManager nm = getContext().getSystemService(NotificationManager.class); 8168 nm.notify(TAG, 8169 SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS, 8170 createReviewPermissionsNotification()); 8171 Settings.Global.putInt(getContext().getContentResolver(), 8172 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 8173 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 8174 } 8175 8176 @Override 8177 public void cleanupHistoryFiles() { 8178 checkCallerIsSystem(); 8179 mHistoryManager.cleanupHistoryFiles(); 8180 } 8181 8182 @Override 8183 public void removeBitmaps() { 8184 // Check all NotificationRecords, remove expired bitmaps and icon URIs, repost silently. 8185 synchronized (mNotificationLock) { 8186 for (NotificationRecord r: mNotificationList) { 8187 8188 // System#currentTimeMillis when posted 8189 final long timePostedMs = r.getSbn().getPostTime(); 8190 final long timeNowMs = System.currentTimeMillis(); 8191 8192 final long bitmapDuration; 8193 if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) { 8194 bitmapDuration = Duration.ofSeconds(5).toMillis(); 8195 } else { 8196 bitmapDuration = BITMAP_DURATION.toMillis(); 8197 } 8198 8199 if (isBitmapExpired(timePostedMs, timeNowMs, bitmapDuration)) { 8200 removeBitmapAndRepost(r); 8201 } 8202 } 8203 } 8204 } 8205 8206 @Override 8207 public void setDeviceEffectsApplier(DeviceEffectsApplier applier) { 8208 if (mZenModeHelper == null) { 8209 throw new IllegalStateException("ZenModeHelper is not yet ready!"); 8210 } 8211 // This can also throw IllegalStateException if called too late. 8212 mZenModeHelper.setDeviceEffectsApplier(applier); 8213 } 8214 8215 @Override 8216 public void onDisplayRemoveSystemDecorations(int displayId) { 8217 synchronized (mToastQueue) { 8218 for (int i = mToastQueue.size() - 1; i >= 0; i--) { 8219 final ToastRecord toast = mToastQueue.get(i); 8220 if (toast.displayId == displayId) { 8221 cancelToastLocked(i); 8222 } 8223 } 8224 } 8225 } 8226 }; 8227 8228 private static boolean isBigPictureWithBitmapOrIcon(Notification n) { 8229 final boolean isBigPicture = n.isStyle(Notification.BigPictureStyle.class); 8230 if (!isBigPicture) { 8231 return false; 8232 } 8233 8234 final boolean hasBitmap = n.extras.containsKey(Notification.EXTRA_PICTURE) 8235 && n.extras.getParcelable(Notification.EXTRA_PICTURE) != null; 8236 if (hasBitmap) { 8237 return true; 8238 } 8239 8240 final boolean hasIcon = n.extras.containsKey(Notification.EXTRA_PICTURE_ICON) 8241 && n.extras.getParcelable(Notification.EXTRA_PICTURE_ICON) != null; 8242 if (hasIcon) { 8243 return true; 8244 } 8245 return false; 8246 } 8247 8248 private static boolean isBitmapExpired(long timePostedMs, long timeNowMs, long timeToLiveMs) { 8249 final long timeDiff = timeNowMs - timePostedMs; 8250 return timeDiff > timeToLiveMs; 8251 } 8252 8253 private void removeBitmapAndRepost(NotificationRecord r) { 8254 if (!isBigPictureWithBitmapOrIcon(r.getNotification())) { 8255 return; 8256 } 8257 // Remove Notification object's reference to picture bitmap or URI. Leave the extras set to 8258 // null to avoid crashing apps that came to expect them to be present but null. 8259 r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE, null); 8260 r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE_ICON, null); 8261 8262 // Make Notification silent 8263 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 8264 8265 // Repost as the original app (even if it was posted by a delegate originally 8266 // because the delegate may now be revoked) 8267 enqueueNotificationInternal(r.getSbn().getPackageName(), 8268 r.getSbn().getPackageName(), r.getSbn().getUid(), 8269 MY_PID, r.getSbn().getTag(), 8270 r.getSbn().getId(), r.getNotification(), 8271 r.getSbn().getUserId(), /* postSilently= */ true, 8272 /* byForegroundService= */ false, 8273 /* isAppProvided= */ false); 8274 } 8275 8276 int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) { 8277 // don't show perm prompt if the only channels are bundle channels 8278 return mPreferencesHelper.getNotificationChannels( 8279 pkg, uid, includeDeleted, false).getList().size(); 8280 } 8281 8282 void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid, 8283 String tag, int id, int userId, int mustNotHaveFlags) { 8284 userId = ActivityManager.handleIncomingUser(callingPid, 8285 callingUid, userId, true, false, "cancelNotificationWithTag", pkg); 8286 8287 // ensure opPkg is delegate if does not match pkg 8288 8289 int uid = INVALID_UID; 8290 8291 try { 8292 uid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 8293 } catch (NameNotFoundException e) { 8294 // package either never existed so there's no posted notification or it's being 8295 // uninstalled so we'll be cleaning it up soon. log and return immediately below. 8296 } 8297 8298 if (uid == INVALID_UID) { 8299 Slog.w(TAG, opPkg + ":" + callingUid + " trying to cancel notification " 8300 + "for nonexistent pkg " + pkg + " in user " + userId); 8301 return; 8302 } 8303 8304 // if opPkg is not the same as pkg, make sure the notification given was posted 8305 // by opPkg 8306 if (!Objects.equals(pkg, opPkg)) { 8307 synchronized (mNotificationLock) { 8308 // Look for the notification, searching both the posted and enqueued lists. 8309 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 8310 if (r != null) { 8311 if (!Objects.equals(opPkg, r.getSbn().getOpPkg())) { 8312 throw new SecurityException(opPkg + " does not have permission to " 8313 + "cancel a notification they did not post " + tag + " " + id); 8314 } 8315 } 8316 } 8317 } 8318 if (Flags.traceCancelEvents()) { 8319 Trace.instant(Trace.TRACE_TAG_SYSTEM_SERVER, "cancelNotificationInternal: " + 8320 SmallHash.hash(Objects.hashCode(tag) ^ id)); 8321 } 8322 8323 cancelNotification(uid, callingPid, pkg, tag, id, 0, 8324 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); 8325 } 8326 8327 boolean isNotificationShownInternal(String pkg, String tag, int notificationId, int userId) { 8328 synchronized (mNotificationLock) { 8329 return findNotificationLocked(pkg, tag, notificationId, userId) != null; 8330 } 8331 } 8332 8333 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 8334 final int callingPid, final String tag, final int id, final Notification notification, 8335 int incomingUserId, boolean byForegroundService, boolean isAppProvided) { 8336 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 8337 incomingUserId, false /* postSilently */, byForegroundService, isAppProvided); 8338 } 8339 8340 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 8341 final int callingPid, final String tag, final int id, final Notification notification, 8342 int incomingUserId, boolean postSilently, boolean byForegroundService, 8343 boolean isAppProvided) { 8344 PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid); 8345 boolean enqueued = false; 8346 try { 8347 enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, 8348 notification, incomingUserId, postSilently, tracker, byForegroundService, 8349 isAppProvided); 8350 } finally { 8351 if (!enqueued) { 8352 tracker.cancel(); 8353 } 8354 } 8355 } 8356 8357 private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) { 8358 // The package probably doesn't have WAKE_LOCK permission and should not require it. 8359 return Binder.withCleanCallingIdentity(() -> { 8360 WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 8361 "NotificationManagerService:post:" + pkg); 8362 wakeLock.setWorkSource(new WorkSource(uid, pkg)); 8363 wakeLock.acquire(POST_WAKE_LOCK_TIMEOUT.toMillis()); 8364 return mPostNotificationTrackerFactory.newTracker(wakeLock); 8365 }); 8366 } 8367 8368 /** 8369 * @return True if we successfully processed the notification and handed off the task of 8370 * enqueueing it to a background thread; false otherwise. 8371 */ 8372 private boolean enqueueNotificationInternal(final String pkg, final String opPkg, //HUI 8373 final int callingUid, final int callingPid, final String tag, final int id, 8374 final Notification notification, int incomingUserId, boolean postSilently, 8375 PostNotificationTracker tracker, boolean byForegroundService, boolean isAppProvided) { 8376 if (DBG) { 8377 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 8378 + " notification=" + notification); 8379 } 8380 8381 if (pkg == null || notification == null) { 8382 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 8383 + " id=" + id + " notification=" + notification); 8384 } 8385 8386 final int userId = ActivityManager.handleIncomingUser(callingPid, 8387 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 8388 final UserHandle user = UserHandle.of(userId); 8389 8390 // Can throw a SecurityException if the calling uid doesn't have permission to post 8391 // as "pkg" 8392 int notificationUid = INVALID_UID; 8393 8394 try { 8395 notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 8396 } catch (NameNotFoundException e) { 8397 // not great - throw immediately below 8398 } 8399 8400 if (notificationUid == INVALID_UID) { 8401 throw new SecurityException("Caller " + opPkg + ":" + callingUid 8402 + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId); 8403 } 8404 8405 IBinder allowlistToken = notification.getAllowlistToken(); 8406 if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) { 8407 throw new SecurityException( 8408 "Unexpected allowlist token received from " + callingUid); 8409 } 8410 // allowlistToken is populated by unparceling, so it can be null if the notification was 8411 // posted from inside system_server. Ensure it's the expected value. 8412 notification.overrideAllowlistToken(ALLOWLIST_TOKEN); 8413 8414 checkRestrictedCategories(notification); 8415 8416 // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE, 8417 // but it's also possible that the app has called notify() with an update to an 8418 // FGS notification that hasn't yet been displayed. Make sure we check for any 8419 // FGS-related situation up front, outside of any locks so it's safe to call into 8420 // the Activity Manager. 8421 final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification( 8422 notification, tag, id, pkg, userId); 8423 8424 boolean stripUijFlag = true; 8425 final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); 8426 if (js != null) { 8427 stripUijFlag = !js.isNotificationAssociatedWithAnyUserInitiatedJobs(id, userId, pkg); 8428 } 8429 8430 // Fix the notification as best we can. 8431 try { 8432 fixNotification(notification, pkg, tag, id, userId, notificationUid, 8433 policy, stripUijFlag); 8434 } catch (Exception e) { 8435 if (notification.isForegroundService()) { 8436 throw new SecurityException("Invalid FGS notification", e); 8437 } 8438 Slog.e(TAG, "Cannot fix notification", e); 8439 return false; 8440 } 8441 8442 if (policy == ServiceNotificationPolicy.UPDATE_ONLY) { 8443 // Proceed if the notification is already showing/known, otherwise ignore 8444 // because the service lifecycle logic has retained responsibility for its 8445 // handling. 8446 if (!isNotificationShownInternal(pkg, tag, id, userId)) { 8447 reportForegroundServiceUpdate(false, notification, id, pkg, userId); 8448 return false; 8449 } 8450 } 8451 8452 mUsageStats.registerEnqueuedByApp(pkg); 8453 8454 final StatusBarNotification n = new StatusBarNotification( 8455 pkg, opPkg, id, tag, notificationUid, callingPid, notification, 8456 user, null, System.currentTimeMillis()); 8457 8458 // setup local book-keeping 8459 String channelId = notification.getChannelId(); 8460 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) { 8461 channelId = (new Notification.TvExtender(notification)).getChannelId(); 8462 } 8463 String shortcutId = n.getShortcutId(); 8464 final NotificationChannel channel = getNotificationChannelRestoreDeleted(pkg, 8465 callingUid, notificationUid, channelId, shortcutId); 8466 if (channel == null) { 8467 final String noChannelStr = "No Channel found for " 8468 + "pkg=" + pkg 8469 + ", channelId=" + channelId 8470 + ", id=" + id 8471 + ", tag=" + tag 8472 + ", opPkg=" + opPkg 8473 + ", callingUid=" + callingUid 8474 + ", userId=" + userId 8475 + ", incomingUserId=" + incomingUserId 8476 + ", notificationUid=" + notificationUid 8477 + ", notification=" + notification; 8478 Slog.e(TAG, noChannelStr); 8479 boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid); 8480 8481 8482 if (!appNotificationsOff) { 8483 doChannelWarningToast(notificationUid, 8484 "Developer warning for package \"" + pkg + "\"\n" + 8485 "Failed to post notification on channel \"" + channelId + "\"\n" + 8486 "See log for more details"); 8487 } 8488 return false; 8489 } 8490 8491 if (android.app.Flags.apiRichOngoing()) { 8492 // This would normally be done in fixNotification(), but we need the channel info so 8493 // it's done a little late 8494 if (mPreferencesHelper.canBePromoted(pkg, notificationUid) 8495 && notification.hasPromotableCharacteristics() 8496 && channel.getImportance() > IMPORTANCE_MIN) { 8497 notification.flags |= FLAG_PROMOTED_ONGOING; 8498 } 8499 } 8500 8501 final NotificationRecord r = new NotificationRecord(getContext(), n, channel); 8502 r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId)); 8503 r.setPostSilently(postSilently); 8504 r.setFlagBubbleRemoved(false); 8505 r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg)); 8506 boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId); 8507 r.setImportanceFixed(isImportanceFixed); 8508 if (notification.isFgsOrUij()) { 8509 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0 8510 || !channel.isUserVisibleTaskShown()) 8511 && (r.getImportance() == IMPORTANCE_MIN 8512 || r.getImportance() == IMPORTANCE_NONE)) { 8513 // Increase the importance of fgs/uij notifications unless the user had 8514 // an opinion otherwise (and the channel hasn't yet shown a fgs/uij). 8515 channel.setImportance(IMPORTANCE_LOW); 8516 r.setSystemImportance(IMPORTANCE_LOW); 8517 if (!channel.isUserVisibleTaskShown()) { 8518 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); 8519 channel.setUserVisibleTaskShown(true); 8520 } 8521 mPreferencesHelper.updateNotificationChannel( 8522 pkg, notificationUid, channel, false, callingUid, 8523 isCallerSystemOrSystemUi()); 8524 r.updateNotificationChannel(channel); 8525 } else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId) 8526 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 8527 channel.setUserVisibleTaskShown(true); 8528 r.updateNotificationChannel(channel); 8529 } 8530 } 8531 8532 ShortcutInfo info = mShortcutHelper != null 8533 ? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user) 8534 : null; 8535 if (notification.getShortcutId() != null && info == null) { 8536 Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut"); 8537 } 8538 r.setShortcutInfo(info); 8539 r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid)); 8540 r.userDemotedAppFromConvoSpace( 8541 mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid)); 8542 8543 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, 8544 r.getSbn().getOverrideGroupKey() != null, byForegroundService)) { 8545 return false; 8546 } 8547 8548 mUsageStats.registerEnqueuedByAppAndAccepted(pkg); 8549 8550 if (info != null) { 8551 // Cache the shortcut synchronously after the associated notification is posted in case 8552 // the app unpublishes this shortcut immediately after posting the notification. If the 8553 // user does not modify the notification settings on this conversation, the shortcut 8554 // will be uncached by People Service when all the associated notifications are removed. 8555 mShortcutHelper.cacheShortcut(info, user); 8556 } 8557 8558 // temporarily allow apps to perform extra work when their pending intents are launched 8559 if (notification.allPendingIntents != null) { 8560 final int intentCount = notification.allPendingIntents.size(); 8561 if (intentCount > 0) { 8562 final long duration = LocalServices.getService( 8563 DeviceIdleInternal.class).getNotificationAllowlistDuration(); 8564 for (int i = 0; i < intentCount; i++) { 8565 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); 8566 if (pendingIntent != null) { 8567 mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(), 8568 ALLOWLIST_TOKEN, duration, 8569 TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, 8570 REASON_NOTIFICATION_SERVICE, 8571 "NotificationManagerService"); 8572 mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(), 8573 ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER 8574 | FLAG_SERVICE_SENDER)); 8575 } 8576 } 8577 } 8578 } 8579 8580 // Need escalated privileges to get package importance. 8581 final int packageImportance = getPackageImportanceWithIdentity(pkg); 8582 boolean isAppForeground = packageImportance == IMPORTANCE_FOREGROUND; 8583 mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, 8584 /* isAppProvided= */ isAppProvided, tracker)); 8585 return true; 8586 } 8587 8588 /** 8589 * Returns a channel, if exists and is not a bundle channel, and restores deleted 8590 * conversation channels. 8591 */ 8592 @Nullable 8593 private NotificationChannel getNotificationChannelRestoreDeleted(String pkg, 8594 int callingUid, int notificationUid, String channelId, String conversationId) { 8595 if (SYSTEM_RESERVED_IDS.contains(channelId)) { 8596 // apps cannot post to these channels directly, in case they post incorrect content 8597 return null; 8598 } 8599 // Restore a deleted conversation channel, if exists. Otherwise use the parent channel. 8600 NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel( 8601 pkg, notificationUid, channelId, conversationId, 8602 true /* parent ok */, !TextUtils.isEmpty(conversationId) /* includeDeleted */); 8603 // Restore deleted conversation channel 8604 if (channel != null && channel.isDeleted()) { 8605 if (Objects.equals(conversationId, channel.getConversationId())) { 8606 boolean needsPolicyFileChange = mPreferencesHelper.createNotificationChannel( 8607 pkg, notificationUid, channel, true /* fromTargetApp */, 8608 mConditionProviders.isPackageOrComponentAllowed(pkg, 8609 UserHandle.getUserId(notificationUid)), callingUid, true); 8610 // Update policy file if the conversation channel was restored 8611 if (needsPolicyFileChange) { 8612 handleSavePolicyFile(); 8613 } 8614 } else { 8615 // Do not restore parent channel 8616 channel = null; 8617 } 8618 } 8619 return channel; 8620 } 8621 8622 private void onConversationRemovedInternal(String pkg, int uid, Set<String> shortcuts) { 8623 checkCallerIsSystem(); 8624 Preconditions.checkStringNotEmpty(pkg); 8625 8626 mHistoryManager.deleteConversations(pkg, uid, shortcuts); 8627 List<String> deletedChannelIds = 8628 mPreferencesHelper.deleteConversations(pkg, uid, shortcuts, 8629 /* callingUid */ Process.SYSTEM_UID, /* is system */ true); 8630 for (String channelId : deletedChannelIds) { 8631 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, 8632 UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED 8633 ); 8634 } 8635 handleSavePolicyFile(); 8636 } 8637 8638 private void makeStickyHun(Notification notification, String pkg, @UserIdInt int userId) { 8639 if (mPermissionHelper.hasRequestedPermission( 8640 Manifest.permission.USE_FULL_SCREEN_INTENT, pkg, userId)) { 8641 notification.flags |= FLAG_FSI_REQUESTED_BUT_DENIED; 8642 } 8643 if (notification.contentIntent == null) { 8644 // On notification click, if contentIntent is null, SystemUI launches the 8645 // fullScreenIntent instead. 8646 notification.contentIntent = notification.fullScreenIntent; 8647 } 8648 notification.fullScreenIntent = null; 8649 } 8650 8651 @VisibleForTesting 8652 protected void fixNotification(Notification notification, String pkg, String tag, int id, 8653 @UserIdInt int userId, int notificationUid, 8654 ServiceNotificationPolicy fgsPolicy, boolean stripUijFlag) 8655 throws NameNotFoundException, RemoteException { 8656 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( 8657 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 8658 (userId == USER_ALL) ? USER_SYSTEM : userId); 8659 Notification.addFieldsFromContext(ai, notification); 8660 8661 // can't be set by an app 8662 notification.extras.remove(Notification.EXTRA_SUMMARIZED_CONTENT); 8663 8664 if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) { 8665 notification.flags &= ~FLAG_FOREGROUND_SERVICE; 8666 } 8667 if (notification.isUserInitiatedJob() && stripUijFlag) { 8668 notification.flags &= ~FLAG_USER_INITIATED_JOB; 8669 } 8670 8671 // Remove FLAG_AUTO_CANCEL from notifications that are associated with a FGS or UIJ. 8672 if (notification.isFgsOrUij()) { 8673 notification.flags &= ~FLAG_AUTO_CANCEL; 8674 } 8675 8676 // Only notifications that can be non-dismissible can have the flag FLAG_NO_DISMISS 8677 if (((notification.flags & FLAG_ONGOING_EVENT) > 0) 8678 && canBeNonDismissible(ai, notification)) { 8679 notification.flags |= FLAG_NO_DISMISS; 8680 } else { 8681 notification.flags &= ~FLAG_NO_DISMISS; 8682 } 8683 8684 int canColorize = getContext().checkPermission( 8685 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, -1, notificationUid); 8686 8687 if (canColorize == PERMISSION_GRANTED) { 8688 notification.flags |= Notification.FLAG_CAN_COLORIZE; 8689 } else { 8690 notification.flags &= ~Notification.FLAG_CAN_COLORIZE; 8691 } 8692 8693 if (notification.extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, false)) { 8694 int hasShowDuringSetupPerm = getContext().checkPermission( 8695 android.Manifest.permission.NOTIFICATION_DURING_SETUP, -1, notificationUid); 8696 if (hasShowDuringSetupPerm != PERMISSION_GRANTED) { 8697 notification.extras.remove(Notification.EXTRA_ALLOW_DURING_SETUP); 8698 if (DBG) { 8699 Slog.w(TAG, "warning: pkg " + pkg + " attempting to show during setup" 8700 + " without holding perm " 8701 + Manifest.permission.NOTIFICATION_DURING_SETUP); 8702 } 8703 } 8704 } 8705 8706 notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED; 8707 8708 // Apps cannot post notifications that are lifetime extended. 8709 if (lifetimeExtensionRefactor()) { 8710 notification.flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 8711 } 8712 8713 if (notification.fullScreenIntent != null) { 8714 final AttributionSource attributionSource = 8715 new AttributionSource.Builder(notificationUid).setPackageName(pkg).build(); 8716 final boolean canUseFullScreenIntent = checkUseFullScreenIntentPermission( 8717 attributionSource, ai, true /* forDataDelivery */); 8718 if (!canUseFullScreenIntent) { 8719 makeStickyHun(notification, pkg, userId); 8720 } 8721 } 8722 8723 // Ensure all actions are present 8724 if (notification.actions != null) { 8725 boolean hasNullActions = false; 8726 int nActions = notification.actions.length; 8727 for (int i = 0; i < nActions; i++) { 8728 if (notification.actions[i] == null) { 8729 hasNullActions = true; 8730 break; 8731 } 8732 } 8733 if (hasNullActions) { 8734 ArrayList<Notification.Action> nonNullActions = new ArrayList<>(); 8735 for (int i = 0; i < nActions; i++) { 8736 if (notification.actions[i] != null) { 8737 nonNullActions.add(notification.actions[i]); 8738 } 8739 } 8740 if (nonNullActions.size() != 0) { 8741 notification.actions = nonNullActions.toArray(new Notification.Action[0]); 8742 } else { 8743 notification.actions = null; 8744 } 8745 } 8746 } 8747 8748 // Apps cannot set this flag 8749 notification.flags &= ~FLAG_PROMOTED_ONGOING; 8750 8751 // Ensure CallStyle has all the correct actions 8752 if (notification.isStyle(Notification.CallStyle.class)) { 8753 Notification.Builder builder = 8754 Notification.Builder.recoverBuilder(getContext(), notification); 8755 Notification.CallStyle style = (Notification.CallStyle) builder.getStyle(); 8756 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 8757 notification.actions = new Notification.Action[actions.size()]; 8758 actions.toArray(notification.actions); 8759 } 8760 8761 // Ensure MediaStyle has correct permissions for remote device extras 8762 if (notification.isStyle(Notification.MediaStyle.class) 8763 || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) { 8764 int hasMediaContentControlPermission = getContext().checkPermission( 8765 android.Manifest.permission.MEDIA_CONTENT_CONTROL, -1, notificationUid); 8766 if (hasMediaContentControlPermission != PERMISSION_GRANTED) { 8767 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE); 8768 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON); 8769 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT); 8770 if (DBG) { 8771 Slog.w(TAG, "Package " + pkg + ": Use of setRemotePlayback requires the " 8772 + "MEDIA_CONTENT_CONTROL permission"); 8773 } 8774 } 8775 8776 // Enforce NO_CLEAR flag on MediaStyle notification for apps with targetSdk >= V. 8777 if (CompatChanges.isChangeEnabled(ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION, 8778 notificationUid)) { 8779 notification.flags |= FLAG_NO_CLEAR; 8780 } 8781 } 8782 8783 // Ensure only allowed packages have a substitute app name 8784 if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { 8785 int hasSubstituteAppNamePermission = getContext().checkPermission( 8786 permission.SUBSTITUTE_NOTIFICATION_APP_NAME, -1, notificationUid); 8787 if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) { 8788 notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME); 8789 if (DBG) { 8790 Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name" 8791 + " without holding perm " 8792 + Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME); 8793 } 8794 } 8795 } 8796 8797 // Remote views? Are they too big? 8798 checkRemoteViews(pkg, tag, id, notification); 8799 8800 if (Flags.allNotifsNeedTtl()) { 8801 if (notification.getTimeoutAfter() == 0) { 8802 notification.setTimeoutAfter(NOTIFICATION_TTL); 8803 } 8804 } 8805 8806 if (notificationForceGrouping()) { 8807 notification.fixSilentGroup(); 8808 } 8809 } 8810 8811 /** 8812 * Whether a notification can be non-dismissible. 8813 * A notification should be dismissible, unless it's exempted for some reason. 8814 */ 8815 private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) { 8816 return notification.isMediaNotification() || isEnterpriseExempted(ai) 8817 || notification.isStyle(Notification.CallStyle.class) 8818 || isDefaultSearchSelectorPackage(ai.packageName) 8819 || isDefaultAdservicesPackage(ai.packageName); 8820 } 8821 8822 private boolean isDefaultSearchSelectorPackage(String pkg) { 8823 return Objects.equals(mDefaultSearchSelectorPkg, pkg); 8824 } 8825 8826 private boolean isDefaultAdservicesPackage(String pkg) { 8827 if (mAdservicesModuleInfo == null) { 8828 return false; 8829 } 8830 // Handles the special package structure for mainline modules 8831 for (String apkName : mAdservicesModuleInfo.getApkInApexPackageNames()) { 8832 if (Objects.equals(apkName, pkg)) { 8833 return true; 8834 } 8835 } 8836 return false; 8837 } 8838 8839 private boolean isEnterpriseExempted(ApplicationInfo ai) { 8840 // Check if the app is an organization admin app 8841 // TODO(b/234609037): Replace with new DPM APIs to check if organization admin 8842 if (mDpm != null && (mDpm.isActiveProfileOwner(ai.uid) 8843 || mDpm.isActiveDeviceOwner(ai.uid))) { 8844 return true; 8845 } 8846 // Check if an app has been given system exemption 8847 if (ai.uid == Process.SYSTEM_UID) { 8848 return false; 8849 } 8850 return mAppOps.checkOpNoThrow( 8851 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 8852 ai.packageName) == MODE_ALLOWED; 8853 } 8854 8855 private boolean checkUseFullScreenIntentPermission(@NonNull AttributionSource attributionSource, 8856 @NonNull ApplicationInfo applicationInfo, 8857 boolean forDataDelivery) { 8858 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) { 8859 return true; 8860 } 8861 final int permissionResult; 8862 if (forDataDelivery) { 8863 permissionResult = mPermissionManager.checkPermissionForDataDelivery( 8864 permission.USE_FULL_SCREEN_INTENT, attributionSource, /* message= */ null); 8865 } else { 8866 permissionResult = mPermissionManager.checkPermissionForPreflight( 8867 permission.USE_FULL_SCREEN_INTENT, attributionSource); 8868 } 8869 return permissionResult == PermissionManager.PERMISSION_GRANTED; 8870 } 8871 8872 private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { 8873 if (android.app.Flags.removeRemoteViews()) { 8874 if (notification.containsCustomViews()) { 8875 Slog.i(TAG, "Removed customViews for " + pkg); 8876 mUsageStats.registerImageRemoved(pkg); 8877 } 8878 notification.contentView = null; 8879 notification.bigContentView = null; 8880 notification.headsUpContentView = null; 8881 if (notification.publicVersion != null) { 8882 notification.publicVersion.contentView = null; 8883 notification.publicVersion.bigContentView = null; 8884 notification.publicVersion.headsUpContentView = null; 8885 } 8886 } else { 8887 if (removeRemoteView(pkg, tag, id, notification.contentView)) { 8888 notification.contentView = null; 8889 } 8890 if (removeRemoteView(pkg, tag, id, notification.bigContentView)) { 8891 notification.bigContentView = null; 8892 } 8893 if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) { 8894 notification.headsUpContentView = null; 8895 } 8896 if (notification.publicVersion != null) { 8897 if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) { 8898 notification.publicVersion.contentView = null; 8899 } 8900 if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) { 8901 notification.publicVersion.bigContentView = null; 8902 } 8903 if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) { 8904 notification.publicVersion.headsUpContentView = null; 8905 } 8906 } 8907 } 8908 } 8909 8910 private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) { 8911 if (contentView == null) { 8912 return false; 8913 } 8914 final long contentViewSize = contentView.estimateMemoryUsage(); 8915 if (contentViewSize > mWarnRemoteViewsSizeBytes 8916 && contentViewSize < mStripRemoteViewsSizeBytes) { 8917 Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id 8918 + " this might be stripped in a future release"); 8919 } 8920 if (contentViewSize >= mStripRemoteViewsSizeBytes) { 8921 mUsageStats.registerImageRemoved(pkg); 8922 Slog.w(TAG, "Removed too large RemoteViews (" + contentViewSize + " bytes) on pkg: " 8923 + pkg + " tag: " + tag + " id: " + id); 8924 return true; 8925 } 8926 return false; 8927 } 8928 8929 /** 8930 * Strips any flags from BubbleMetadata that wouldn't apply (e.g. app not foreground). 8931 */ 8932 private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) { 8933 Notification notification = r.getNotification(); 8934 Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); 8935 if (metadata == null) { 8936 // Nothing to update 8937 return; 8938 } 8939 if (!isAppForeground) { 8940 // Auto expand only works if foreground 8941 int flags = metadata.getFlags(); 8942 flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 8943 metadata.setFlags(flags); 8944 } 8945 if (!metadata.isBubbleSuppressable()) { 8946 // If it's not suppressable remove the suppress flag 8947 int flags = metadata.getFlags(); 8948 flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; 8949 metadata.setFlags(flags); 8950 } 8951 } 8952 8953 private ShortcutHelper.ShortcutListener mShortcutListener = 8954 new ShortcutHelper.ShortcutListener() { 8955 @Override 8956 public void onShortcutRemoved(String key) { 8957 String packageName; 8958 synchronized (mNotificationLock) { 8959 NotificationRecord r = mNotificationsByKey.get(key); 8960 packageName = r != null ? r.getSbn().getPackageName() : null; 8961 } 8962 final int packageImportance = getPackageImportanceWithIdentity(packageName); 8963 boolean isAppForeground = packageName != null 8964 && packageImportance == IMPORTANCE_FOREGROUND; 8965 synchronized (mNotificationLock) { 8966 NotificationRecord r = mNotificationsByKey.get(key); 8967 if (r != null) { 8968 r.setShortcutInfo(null); 8969 // Enqueue will trigger resort & flag is updated that way. 8970 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 8971 mHandler.post( 8972 new EnqueueNotificationRunnable( 8973 r.getUser().getIdentifier(), r, isAppForeground, 8974 /* isAppProvided= */ false, 8975 mPostNotificationTrackerFactory.newTracker(null))); 8976 } 8977 } 8978 } 8979 }; 8980 8981 protected void doChannelWarningToast(int forUid, CharSequence toastText) { 8982 Binder.withCleanCallingIdentity(() -> { 8983 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(), 8984 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0) != 0; 8985 if (warningEnabled) { 8986 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText, 8987 Toast.LENGTH_SHORT); 8988 toast.show(); 8989 } 8990 }); 8991 } 8992 8993 @VisibleForTesting 8994 int resolveNotificationUid(String callingPkg, String targetPkg, int callingUid, int userId) 8995 throws NameNotFoundException { 8996 if (userId == USER_ALL) { 8997 userId = USER_SYSTEM; 8998 } 8999 // posted from app A on behalf of app A 9000 if (isCallerSameApp(targetPkg, callingUid, userId) 9001 && (TextUtils.equals(callingPkg, targetPkg) 9002 || isCallerSameApp(callingPkg, callingUid, userId))) { 9003 return callingUid; 9004 } 9005 9006 int targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 9007 9008 // posted from app A on behalf of app B 9009 if (isCallerAndroid(callingPkg, callingUid) 9010 || mPreferencesHelper.isDelegateAllowed( 9011 targetPkg, targetUid, callingPkg, callingUid)) { 9012 return targetUid; 9013 } 9014 9015 throw new SecurityException("Caller " + callingPkg + ":" + callingUid 9016 + " cannot post for pkg " + targetPkg + " in user " + userId); 9017 } 9018 9019 public boolean hasFlag(final int flags, final int flag) { 9020 return (flags & flag) != 0; 9021 } 9022 /** 9023 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking. 9024 * 9025 * Has side effects. 9026 */ 9027 boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag, 9028 NotificationRecord r, boolean isAutogroup, boolean byForegroundService) { 9029 Notification n = r.getNotification(); 9030 final String pkg = r.getSbn().getPackageName(); 9031 final boolean isSystemNotification = 9032 isUidSystemOrPhone(uid) || ("android".equals(pkg)); 9033 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 9034 9035 // Limit the number of notifications that any given package except the android 9036 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 9037 if (!isSystemNotification && !isNotificationFromListener) { 9038 final int callingUid = Binder.getCallingUid(); 9039 synchronized (mNotificationLock) { 9040 if (mNotificationsByKey.get(r.getSbn().getKey()) == null 9041 && isCallerInstantApp(callingUid, userId)) { 9042 // Ephemeral apps have some special constraints for notifications. 9043 // They are not allowed to create new notifications however they are allowed to 9044 // update notifications created by the system (e.g. a foreground service 9045 // notification). 9046 throw new SecurityException("Instant app " + pkg 9047 + " cannot create notifications"); 9048 } 9049 9050 // Rate limit updates that aren't completed progress notifications 9051 // Search for the original one in the posted and not-yet-posted (enqueued) lists. 9052 boolean isUpdate = mNotificationsByKey.get(r.getSbn().getKey()) != null 9053 || findNotificationByListLocked(mEnqueuedNotifications, r.getSbn().getKey()) 9054 != null; 9055 if (isUpdate && !r.getNotification().hasCompletedProgress() && !isAutogroup) { 9056 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); 9057 if (appEnqueueRate > mMaxPackageEnqueueRate) { 9058 mUsageStats.registerOverRateQuota(pkg); 9059 final long now = SystemClock.elapsedRealtime(); 9060 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { 9061 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate 9062 + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg); 9063 mLastOverRateLogTime = now; 9064 } 9065 return false; 9066 } 9067 } 9068 } 9069 9070 // limit the number of non-fgs/uij outstanding notificationrecords an app can have 9071 if (!n.isFgsOrUij()) { 9072 int count = getNotificationCount(pkg, userId, id, tag); 9073 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 9074 mUsageStats.registerOverCountQuota(pkg); 9075 Slog.e(TAG, "Package has already posted or enqueued " + count 9076 + " notifications. Not showing more. package=" + pkg); 9077 return false; 9078 } 9079 } 9080 } 9081 9082 // bubble or inline reply that's immutable? 9083 if (n.getBubbleMetadata() != null 9084 && n.getBubbleMetadata().getIntent() != null 9085 && hasFlag(mAmi.getPendingIntentFlags( 9086 n.getBubbleMetadata().getIntent().getTarget()), 9087 PendingIntent.FLAG_IMMUTABLE)) { 9088 throw new IllegalArgumentException(r.getKey() + " Not posted." 9089 + " PendingIntents attached to bubbles must be mutable"); 9090 } 9091 9092 if (n.actions != null) { 9093 for (Notification.Action action : n.actions) { 9094 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null) 9095 && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()), 9096 PendingIntent.FLAG_IMMUTABLE)) { 9097 throw new IllegalArgumentException(r.getKey() + " Not posted." 9098 + " PendingIntents attached to actions with remote" 9099 + " inputs must be mutable"); 9100 } 9101 } 9102 } 9103 9104 if (r.getSystemGeneratedSmartActions() != null) { 9105 for (Notification.Action action : r.getSystemGeneratedSmartActions()) { 9106 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null) 9107 && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()), 9108 PendingIntent.FLAG_IMMUTABLE)) { 9109 throw new IllegalArgumentException(r.getKey() + " Not posted." 9110 + " PendingIntents attached to contextual actions with remote inputs" 9111 + " must be mutable"); 9112 } 9113 } 9114 } 9115 9116 if (n.isStyle(Notification.CallStyle.class)) { 9117 boolean hasFullScreenIntent = n.fullScreenIntent != null; 9118 boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0; 9119 if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent 9120 && !byForegroundService) { 9121 throw new IllegalArgumentException(r.getKey() + " Not posted." 9122 + " CallStyle notifications must be for a foreground service or" 9123 + " user initated job or use a fullScreenIntent."); 9124 } 9125 } 9126 9127 // snoozed apps 9128 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) { 9129 MetricsLogger.action(r.getLogMaker() 9130 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE) 9131 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)); 9132 mNotificationRecordLogger.log( 9133 NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED, 9134 r); 9135 if (DBG) { 9136 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); 9137 } 9138 mSnoozeHelper.update(userId, r); 9139 handleSavePolicyFile(); 9140 return false; 9141 } 9142 9143 // blocked apps 9144 boolean isBlocked = !areNotificationsEnabledForPackageInt(uid); 9145 synchronized (mNotificationLock) { 9146 isBlocked |= isRecordBlockedLocked(r); 9147 } 9148 if (isBlocked && !(n.isMediaNotification() || isCallNotification(pkg, uid, n))) { 9149 if (DBG) { 9150 Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName() 9151 + " by user request."); 9152 } 9153 mUsageStats.registerBlocked(r); 9154 return false; 9155 } 9156 9157 if (Flags.rejectOldNotifications() && n.hasAppProvidedWhen() && n.getWhen() > 0 9158 && (System.currentTimeMillis() - n.getWhen()) > NOTIFICATION_MAX_AGE_AT_POST) { 9159 Slog.d(TAG, "Ignored enqueue for old " + n.getWhen() + " notification " + r.getKey()); 9160 mUsageStats.registerTooOldBlocked(r); 9161 return false; 9162 } 9163 9164 return true; 9165 } 9166 9167 private boolean isCallNotification(String pkg, int uid, Notification n) { 9168 if (n.isStyle(Notification.CallStyle.class)) { 9169 return isCallNotification(pkg, uid); 9170 } 9171 return false; 9172 } 9173 9174 private boolean isCallNotification(String pkg, int uid) { 9175 final long identity = Binder.clearCallingIdentity(); 9176 try { 9177 if (mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM) 9178 && mTelecomManager != null) { 9179 try { 9180 return mTelecomManager.isInManagedCall() 9181 || mTelecomManager.isInSelfManagedCall(pkg, 9182 UserHandle.ALL); 9183 } catch (IllegalStateException ise) { 9184 // Telecom is not ready (this is likely early boot), so there are no calls. 9185 return false; 9186 } 9187 } 9188 return false; 9189 } finally { 9190 Binder.restoreCallingIdentity(identity); 9191 } 9192 } 9193 9194 private boolean areNotificationsEnabledForPackageInt(int uid) { 9195 return mPermissionHelper.hasPermission(uid); 9196 } 9197 9198 private int getNotificationCount(String pkg, int userId) { 9199 int count = 0; 9200 synchronized (mNotificationLock) { 9201 final int numListSize = mNotificationList.size(); 9202 for (int i = 0; i < numListSize; i++) { 9203 final NotificationRecord existing = mNotificationList.get(i); 9204 if (existing.getSbn().getPackageName().equals(pkg) 9205 && existing.getSbn().getUserId() == userId) { 9206 count++; 9207 } 9208 } 9209 final int numEnqSize = mEnqueuedNotifications.size(); 9210 for (int i = 0; i < numEnqSize; i++) { 9211 final NotificationRecord existing = mEnqueuedNotifications.get(i); 9212 if (existing.getSbn().getPackageName().equals(pkg) 9213 && existing.getSbn().getUserId() == userId) { 9214 count++; 9215 } 9216 } 9217 } 9218 return count; 9219 } 9220 9221 protected int getNotificationCount(String pkg, int userId, int excludedId, 9222 String excludedTag) { 9223 int count = 0; 9224 synchronized (mNotificationLock) { 9225 final int N = mNotificationList.size(); 9226 for (int i = 0; i < N; i++) { 9227 final NotificationRecord existing = mNotificationList.get(i); 9228 if (existing.getSbn().getPackageName().equals(pkg) 9229 && existing.getSbn().getUserId() == userId) { 9230 if (existing.getSbn().getId() == excludedId 9231 && TextUtils.equals(existing.getSbn().getTag(), excludedTag)) { 9232 continue; 9233 } 9234 count++; 9235 } 9236 } 9237 final int M = mEnqueuedNotifications.size(); 9238 for (int i = 0; i < M; i++) { 9239 final NotificationRecord existing = mEnqueuedNotifications.get(i); 9240 if (existing.getSbn().getPackageName().equals(pkg) 9241 && existing.getSbn().getUserId() == userId) { 9242 count++; 9243 } 9244 } 9245 } 9246 return count; 9247 } 9248 9249 /** 9250 * Checks whether a notification is banned at a group or channel level or if the NAS or system 9251 * has blocked the notification. 9252 */ 9253 @GuardedBy("mNotificationLock") 9254 boolean isRecordBlockedLocked(NotificationRecord r) { 9255 final String pkg = r.getSbn().getPackageName(); 9256 final int callingUid = r.getSbn().getUid(); 9257 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup()) 9258 || r.getImportance() == IMPORTANCE_NONE; 9259 } 9260 9261 protected class SnoozeNotificationRunnable implements Runnable { 9262 private final String mKey; 9263 private final long mDuration; 9264 private final String mSnoozeCriterionId; 9265 9266 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) { 9267 mKey = key; 9268 mDuration = duration; 9269 mSnoozeCriterionId = snoozeCriterionId; 9270 } 9271 9272 @Override 9273 public void run() { 9274 synchronized (mNotificationLock) { 9275 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey); 9276 if (r != null) { 9277 snoozeLocked(r); 9278 } 9279 } 9280 } 9281 9282 @GuardedBy("mNotificationLock") 9283 void snoozeLocked(NotificationRecord r) { 9284 final List<NotificationRecord> recordsToSnooze = new ArrayList<>(); 9285 if (r.getSbn().isGroup()) { 9286 final List<NotificationRecord> groupNotifications = 9287 findCurrentAndSnoozedGroupNotificationsLocked( 9288 r.getSbn().getPackageName(), 9289 r.getSbn().getGroupKey(), r.getSbn().getUserId()); 9290 if (r.getNotification().isGroupSummary()) { 9291 // snooze all children 9292 for (int i = 0; i < groupNotifications.size(); i++) { 9293 if (!mKey.equals(groupNotifications.get(i).getKey())) { 9294 recordsToSnooze.add(groupNotifications.get(i)); 9295 } 9296 } 9297 } else { 9298 // if there is a valid summary for this group, and we are snoozing the only 9299 // child, also snooze the summary 9300 if (mSummaryByGroupKey.containsKey(r.getSbn().getGroupKey())) { 9301 if (groupNotifications.size() == 2) { 9302 // snooze summary and the one child 9303 for (int i = 0; i < groupNotifications.size(); i++) { 9304 if (!mKey.equals(groupNotifications.get(i).getKey())) { 9305 recordsToSnooze.add(groupNotifications.get(i)); 9306 } 9307 } 9308 } 9309 } 9310 } 9311 } 9312 // snooze the notification 9313 recordsToSnooze.add(r); 9314 9315 if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) { 9316 for (int i = 0; i < recordsToSnooze.size(); i++) { 9317 snoozeNotificationLocked(recordsToSnooze.get(i)); 9318 } 9319 } else { 9320 Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications"); 9321 } 9322 } 9323 9324 @GuardedBy("mNotificationLock") 9325 void snoozeNotificationLocked(NotificationRecord r) { 9326 MetricsLogger.action(r.getLogMaker() 9327 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED) 9328 .setType(MetricsEvent.TYPE_CLOSE) 9329 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, 9330 mDuration) 9331 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA, 9332 mSnoozeCriterionId == null ? 0 : 1)); 9333 mNotificationRecordLogger.log( 9334 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, r); 9335 reportUserInteraction(r); 9336 boolean wasPosted = removeFromNotificationListsLocked(r); 9337 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null, 9338 SystemClock.elapsedRealtime()); 9339 mAttentionHelper.updateLightsLocked(); 9340 if (isSnoozable(r)) { 9341 if (mSnoozeCriterionId != null) { 9342 mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId); 9343 mSnoozeHelper.snooze(r, mSnoozeCriterionId); 9344 } else { 9345 mSnoozeHelper.snooze(r, mDuration); 9346 } 9347 r.recordSnoozed(); 9348 handleSavePolicyFile(); 9349 } 9350 } 9351 9352 /** 9353 * Autogroup summaries are not snoozable 9354 * They will be recreated as needed when the group children are unsnoozed 9355 */ 9356 private boolean isSnoozable(NotificationRecord record) { 9357 if (notificationForceGrouping()) { 9358 boolean isExemptedSummary = 9359 ((record.getFlags() & FLAG_AUTOGROUP_SUMMARY) != 0 9360 || GroupHelper.isAggregatedGroup(record)); 9361 return !(record.getNotification().isGroupSummary() && isExemptedSummary); 9362 } else { 9363 return !(record.getNotification().isGroupSummary() 9364 && GroupHelper.AUTOGROUP_KEY.equals(record.getNotification().getGroup())); 9365 } 9366 } 9367 } 9368 9369 private void unsnoozeAll() { 9370 synchronized (mNotificationLock) { 9371 mSnoozeHelper.repostAll(mUserProfiles.getCurrentProfileIds()); 9372 handleSavePolicyFile(); 9373 } 9374 } 9375 9376 protected class CancelNotificationRunnable implements Runnable { 9377 private final int mCallingUid; 9378 private final int mCallingPid; 9379 private final String mPkg; 9380 private final String mTag; 9381 private final int mId; 9382 private final int mMustHaveFlags; 9383 private final int mMustNotHaveFlags; 9384 private final boolean mSendDelete; 9385 private final int mUserId; 9386 private final int mReason; 9387 private final int mRank; 9388 private final int mCount; 9389 private final ManagedServiceInfo mListener; 9390 private final long mCancellationElapsedTimeMs; 9391 9392 CancelNotificationRunnable(final int callingUid, final int callingPid, 9393 final String pkg, final String tag, final int id, 9394 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 9395 final int userId, final int reason, int rank, int count, 9396 final ManagedServiceInfo listener, 9397 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 9398 this.mCallingUid = callingUid; 9399 this.mCallingPid = callingPid; 9400 this.mPkg = pkg; 9401 this.mTag = tag; 9402 this.mId = id; 9403 this.mMustHaveFlags = mustHaveFlags; 9404 this.mMustNotHaveFlags = mustNotHaveFlags; 9405 this.mSendDelete = sendDelete; 9406 this.mUserId = userId; 9407 this.mReason = reason; 9408 this.mRank = rank; 9409 this.mCount = count; 9410 this.mListener = listener; 9411 this.mCancellationElapsedTimeMs = cancellationElapsedTimeMs; 9412 } 9413 9414 @Override 9415 public void run() { 9416 String listenerName = mListener == null ? null : mListener.component.toShortString(); 9417 if (DBG) { 9418 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag, 9419 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName); 9420 } 9421 int packageImportance = IMPORTANCE_NONE; 9422 if (lifetimeExtensionRefactor()) { 9423 packageImportance = getPackageImportanceWithIdentity(mPkg); 9424 } 9425 synchronized (mNotificationLock) { 9426 // Look for the notification, searching both the posted and enqueued lists. 9427 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId); 9428 9429 if (r != null) { 9430 // The notification was found, check if it should be removed. 9431 // Ideally we'd do this in the caller of this method. However, that would 9432 // require the caller to also find the notification. 9433 if (mReason == REASON_CLICK) { 9434 mUsageStats.registerClickedByUser(r); 9435 } 9436 9437 if ((mReason == REASON_LISTENER_CANCEL 9438 && r.getNotification().isBubbleNotification()) 9439 || (mReason == REASON_CLICK && r.canBubble() 9440 && r.isFlagBubbleRemoved())) { 9441 int flags = 0; 9442 if (r.getNotification().getBubbleMetadata() != null) { 9443 flags = r.getNotification().getBubbleMetadata().getFlags(); 9444 } 9445 flags |= FLAG_SUPPRESS_NOTIFICATION; 9446 mNotificationDelegate.onBubbleMetadataFlagChanged(r.getKey(), flags); 9447 return; 9448 } 9449 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { 9450 return; 9451 } 9452 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { 9453 if (lifetimeExtensionRefactor()) { 9454 // If cancellation will be prevented due to lifetime extension, 9455 // we need to send an update to system UI first. 9456 maybeNotifySystemUiListenerLifetimeExtendedLocked(r, mPkg, 9457 packageImportance); 9458 } 9459 return; 9460 } 9461 9462 FlagChecker childrenFlagChecker = (flags) -> { 9463 if (mReason == REASON_CANCEL 9464 || mReason == REASON_CLICK 9465 || mReason == REASON_CANCEL_ALL) { 9466 // Bubbled children get to stick around if the summary was manually 9467 // cancelled (user removed) from systemui. 9468 if ((flags & FLAG_BUBBLE) != 0) { 9469 return false; 9470 } 9471 } else if (mReason == REASON_APP_CANCEL) { 9472 if ((flags & FLAG_FOREGROUND_SERVICE) != 0 9473 || (flags & FLAG_USER_INITIATED_JOB) != 0) { 9474 return false; 9475 } 9476 } 9477 if ((flags & mMustNotHaveFlags) != 0) { 9478 return false; 9479 } 9480 return true; 9481 }; 9482 9483 // Cancel the notification. 9484 boolean wasPosted = removeFromNotificationListsLocked(r); 9485 cancelNotificationLocked( 9486 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName, 9487 mCancellationElapsedTimeMs); 9488 if (r.getNotification().isGroupSummary()) { 9489 cancelGroupChildrenLocked(mUserId, mPkg, mCallingUid, mCallingPid, 9490 listenerName, mSendDelete, childrenFlagChecker, 9491 NotificationManagerService::isChildOfCurrentGroupChecker, 9492 r.getGroupKey(), mReason, mCancellationElapsedTimeMs); 9493 } 9494 mAttentionHelper.updateLightsLocked(); 9495 if (mShortcutHelper != null) { 9496 mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, 9497 true /* isRemoved */); 9498 } 9499 } else { 9500 if (notificationForceGrouping()) { 9501 // No notification was found => maybe it was canceled by forced grouping 9502 if (Flags.notificationForceGroupSingletons()) { 9503 mGroupHelper.maybeCancelGroupChildrenForCanceledSummary(mPkg, mTag, 9504 mId, mUserId, mReason); 9505 } 9506 } 9507 9508 // No notification was found, assume that it is snoozed and cancel it. 9509 if (mReason != REASON_SNOOZED) { 9510 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId); 9511 if (wasSnoozed) { 9512 handleSavePolicyFile(); 9513 } 9514 } 9515 } 9516 } 9517 } 9518 } 9519 9520 protected static class ShowNotificationPermissionPromptRunnable implements Runnable { 9521 private final String mPkgName; 9522 private final int mUserId; 9523 private final int mTaskId; 9524 private final PermissionPolicyInternal mPpi; 9525 9526 ShowNotificationPermissionPromptRunnable(String pkg, int user, int task, 9527 PermissionPolicyInternal pPi) { 9528 mPkgName = pkg; 9529 mUserId = user; 9530 mTaskId = task; 9531 mPpi = pPi; 9532 } 9533 9534 @Override 9535 public boolean equals(Object o) { 9536 if (!(o instanceof ShowNotificationPermissionPromptRunnable)) { 9537 return false; 9538 } 9539 9540 ShowNotificationPermissionPromptRunnable other = 9541 (ShowNotificationPermissionPromptRunnable) o; 9542 9543 return Objects.equals(mPkgName, other.mPkgName) && mUserId == other.mUserId 9544 && mTaskId == other.mTaskId; 9545 } 9546 9547 @Override 9548 public int hashCode() { 9549 return Objects.hash(mPkgName, mUserId, mTaskId); 9550 } 9551 9552 @Override 9553 public void run() { 9554 mPpi.showNotificationPromptIfNeeded(mPkgName, mUserId, mTaskId); 9555 } 9556 } 9557 9558 protected class EnqueueNotificationRunnable implements Runnable { 9559 private final NotificationRecord r; 9560 private final int userId; 9561 private final boolean isAppForeground; 9562 private final boolean isAppProvided; 9563 private final PostNotificationTracker mTracker; 9564 9565 EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground, 9566 boolean isAppProvided, PostNotificationTracker tracker) { 9567 this.userId = userId; 9568 this.r = r; 9569 this.isAppForeground = foreground; 9570 this.isAppProvided = isAppProvided; 9571 this.mTracker = checkNotNull(tracker); 9572 } 9573 9574 @Override 9575 public void run() { 9576 boolean enqueued = false; 9577 try { 9578 enqueued = enqueueNotification(); 9579 } finally { 9580 if (!enqueued) { 9581 mTracker.cancel(); 9582 } 9583 } 9584 } 9585 9586 /** 9587 * @return True if we successfully enqueued the notification and handed off the task of 9588 * posting it to a background thread; false otherwise. 9589 */ 9590 private boolean enqueueNotification() { 9591 synchronized (mNotificationLock) { 9592 // allowlistToken is populated by unparceling, so it will be absent if the 9593 // EnqueueNotificationRunnable is created directly by NMS (as we do for group 9594 // summaries) instead of via notify(). Fix that. 9595 r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN); 9596 9597 final long snoozeAt = 9598 mSnoozeHelper.getSnoozeTimeForUnpostedNotification( 9599 r.getUser().getIdentifier(), 9600 r.getSbn().getPackageName(), r.getSbn().getKey()); 9601 final long currentTime = System.currentTimeMillis(); 9602 if (snoozeAt > currentTime) { 9603 (new SnoozeNotificationRunnable(r.getSbn().getKey(), 9604 snoozeAt - currentTime, null)).snoozeLocked(r); 9605 return false; 9606 } 9607 9608 final String contextId = 9609 mSnoozeHelper.getSnoozeContextForUnpostedNotification( 9610 r.getUser().getIdentifier(), 9611 r.getSbn().getPackageName(), r.getSbn().getKey()); 9612 if (contextId != null) { 9613 (new SnoozeNotificationRunnable(r.getSbn().getKey(), 9614 0, contextId)).snoozeLocked(r); 9615 return false; 9616 } 9617 9618 mEnqueuedNotifications.add(r); 9619 if (Flags.allNotifsNeedTtl()) { 9620 mTtlHelper.scheduleTimeoutLocked(r, SystemClock.elapsedRealtime()); 9621 } else { 9622 scheduleTimeoutLocked(r); 9623 } 9624 9625 final StatusBarNotification n = r.getSbn(); 9626 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 9627 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 9628 if (old != null) { 9629 // Retain ranking information from previous record 9630 r.copyRankingInformation(old); 9631 } 9632 9633 final int callingUid = n.getUid(); 9634 final int callingPid = n.getInitialPid(); 9635 final Notification notification = n.getNotification(); 9636 final String pkg = n.getPackageName(); 9637 final int id = n.getId(); 9638 final String tag = n.getTag(); 9639 9640 // We need to fix the notification up a little for bubbles 9641 updateNotificationBubbleFlags(r, isAppForeground); 9642 9643 // Handle grouped notifications and bail out early if we 9644 // can to avoid extracting signals. 9645 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 9646 9647 // if this is a group child, unsnooze parent summary 9648 if (n.isGroup() && notification.isGroupChild()) { 9649 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey()); 9650 } 9651 9652 // This conditional is a dirty hack to limit the logging done on 9653 // behalf of the download manager without affecting other apps. 9654 if (!pkg.equals("com.android.providers.downloads") 9655 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 9656 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 9657 if (old != null) { 9658 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 9659 } 9660 int appProvided = isAppProvided ? 1 : 0; 9661 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 9662 pkg, id, tag, userId, notification.toString(), 9663 enqueueStatus, appProvided); 9664 } 9665 9666 // tell the assistant service about the notification 9667 if (mAssistants.isEnabled()) { 9668 mAssistants.onNotificationEnqueuedLocked(r); 9669 mHandler.postDelayed( 9670 new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 9671 r.getUid(), mTracker), 9672 DELAY_FOR_ASSISTANT_TIME); 9673 } else { 9674 mHandler.post( 9675 new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 9676 r.getUid(), mTracker)); 9677 } 9678 return true; 9679 } 9680 } 9681 } 9682 9683 @GuardedBy("mNotificationLock") 9684 boolean isPackagePausedOrSuspended(String pkg, int uid) { 9685 boolean isPaused; 9686 9687 final PackageManagerInternal pmi = LocalServices.getService( 9688 PackageManagerInternal.class); 9689 int flags = pmi.getDistractingPackageRestrictions( 9690 pkg, Binder.getCallingUserHandle().getIdentifier()); 9691 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0); 9692 9693 isPaused |= isPackageSuspendedForUser(pkg, uid); 9694 9695 return isPaused; 9696 } 9697 9698 protected class PostNotificationRunnable implements Runnable { 9699 private final String key; 9700 private final String pkg; 9701 private final int uid; 9702 private final PostNotificationTracker mTracker; 9703 9704 PostNotificationRunnable(String key, String pkg, int uid, PostNotificationTracker tracker) { 9705 this.key = key; 9706 this.pkg = pkg; 9707 this.uid = uid; 9708 this.mTracker = checkNotNull(tracker); 9709 } 9710 9711 @Override 9712 public void run() { 9713 boolean posted = false; 9714 try { 9715 posted = postNotification(); 9716 } catch (Exception e) { 9717 Slog.e(TAG, "Error posting", e); 9718 } finally { 9719 if (!posted) { 9720 mTracker.cancel(); 9721 } 9722 } 9723 } 9724 9725 /** 9726 * @return True if we successfully processed the notification and handed off the task of 9727 * notifying all listeners to a background thread; false otherwise. 9728 */ 9729 private boolean postNotification() { 9730 boolean appBanned = !areNotificationsEnabledForPackageInt(uid); 9731 boolean isCallNotification = isCallNotification(pkg, uid); 9732 boolean posted = false; 9733 synchronized (NotificationManagerService.this.mNotificationLock) { 9734 try { 9735 NotificationRecord r = findNotificationByListLocked(mEnqueuedNotifications, 9736 key); 9737 if (r == null) { 9738 Slog.i(TAG, "Cannot find enqueued record for key: " + key); 9739 return false; 9740 } 9741 9742 final StatusBarNotification n = r.getSbn(); 9743 final Notification notification = n.getNotification(); 9744 boolean isCallNotificationAndCorrectStyle = isCallNotification 9745 && notification.isStyle(Notification.CallStyle.class); 9746 9747 if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle) 9748 && (appBanned || isRecordBlockedLocked(r))) { 9749 mUsageStats.registerBlocked(r); 9750 if (DBG) { 9751 Slog.e(TAG, "Suppressing notification from package " + pkg); 9752 } 9753 return false; 9754 } 9755 9756 if (notificationForceGrouping()) { 9757 if (Flags.notificationForceGroupSingletons()) { 9758 // Check if this is an updated for a summary for an aggregated sparse 9759 // group and remove it because that summary has been canceled 9760 if (mGroupHelper.isUpdateForCanceledSummary(r)) { 9761 if (DBG) { 9762 Log.w(TAG, 9763 "Suppressing notification because summary was canceled: " 9764 + r); 9765 } 9766 9767 String groupKey = r.getGroupKey(); 9768 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 9769 if (groupSummary != null && groupSummary.getKey() 9770 .equals(r.getKey())) { 9771 mSummaryByGroupKey.remove(groupKey); 9772 } 9773 return false; 9774 } 9775 } 9776 } 9777 9778 9779 final boolean isPackageSuspended = 9780 isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid()); 9781 r.setHidden(isPackageSuspended); 9782 if (isPackageSuspended) { 9783 mUsageStats.registerSuspendedByAdmin(r); 9784 } 9785 NotificationRecord old = mNotificationsByKey.get(key); 9786 9787 // Make sure the SBN has an instance ID for statsd logging. 9788 if (old == null || old.getSbn().getInstanceId() == null) { 9789 n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 9790 } else { 9791 n.setInstanceId(old.getSbn().getInstanceId()); 9792 } 9793 9794 int index = indexOfNotificationLocked(n.getKey()); 9795 if (index < 0) { 9796 mNotificationList.add(r); 9797 mUsageStats.registerPostedByApp(r); 9798 mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(), 9799 r.getSbn().getUser(), mTracker.getStartTime()); 9800 final boolean isInterruptive = isVisuallyInterruptive(null, r); 9801 r.setInterruptive(isInterruptive); 9802 r.setTextChanged(isInterruptive); 9803 } else { 9804 old = mNotificationList.get(index); // Potentially *changes* old 9805 mNotificationList.set(index, r); 9806 mUsageStats.registerUpdatedByApp(r, old); 9807 mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(), 9808 r.getSbn().getUser(), mTracker.getStartTime()); 9809 // Make sure we don't lose the foreground service state. 9810 notification.flags |= 9811 old.getNotification().flags & FLAG_FOREGROUND_SERVICE; 9812 r.isUpdate = true; 9813 final boolean isInterruptive = isVisuallyInterruptive(old, r); 9814 r.setTextChanged(isInterruptive); 9815 if (sortSectionByTime()) { 9816 if (isInterruptive) { 9817 r.resetRankingTime(); 9818 } 9819 } 9820 } 9821 9822 mNotificationsByKey.put(n.getKey(), r); 9823 9824 // Ensure if this is a foreground service that the proper additional 9825 // flags are set. 9826 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) { 9827 notification.flags |= FLAG_NO_CLEAR; 9828 } 9829 9830 // Posts the notification if it has a small icon, and potentially autogroup 9831 // the new notification. 9832 if (android.app.Flags.checkAutogroupBeforePost()) { 9833 if (notification.getSmallIcon() != null && !isCritical(r)) { 9834 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 9835 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()) 9836 || !Objects.equals(oldSbn.getNotification().getGroup(), 9837 n.getNotification().getGroup()) 9838 || oldSbn.getNotification().flags 9839 != n.getNotification().flags 9840 || !old.getChannel().getId().equals(r.getChannel().getId())) { 9841 synchronized (mNotificationLock) { 9842 final String autogroupName = 9843 notificationForceGrouping() ? 9844 GroupHelper.getFullAggregateGroupKey(r) 9845 : GroupHelper.AUTOGROUP_KEY; 9846 boolean willBeAutogrouped = 9847 mGroupHelper.onNotificationPosted(r, 9848 hasAutoGroupSummaryLocked(r)); 9849 if (willBeAutogrouped) { 9850 // The newly posted notification will be autogrouped, but 9851 // was not autogrouped onPost, to avoid an unnecessary sort. 9852 // We add the autogroup key to the notification without a 9853 // sort here, and it'll be sorted below with extractSignals. 9854 addAutogroupKeyLocked(key, 9855 autogroupName, /*requestSort=*/false); 9856 } else { 9857 if (notificationForceGrouping()) { 9858 // Wait 3 seconds so that the app has a chance to post 9859 // a group summary or children (complete a group) 9860 mHandler.postDelayed(() -> { 9861 synchronized (mNotificationLock) { 9862 NotificationRecord record = 9863 mNotificationsByKey.get(key); 9864 if (record != null) { 9865 mGroupHelper.onNotificationPostedWithDelay( 9866 record, mNotificationList, 9867 mSummaryByGroupKey); 9868 } 9869 } 9870 }, key, DELAY_FORCE_REGROUP_TIME); 9871 } 9872 } 9873 9874 } 9875 } 9876 } 9877 } 9878 9879 mRankingHelper.extractSignals(r); 9880 mRankingHelper.sort(mNotificationList); 9881 final int position = mRankingHelper.indexOf(mNotificationList, r); 9882 9883 int buzzBeepBlinkLoggingCode = 0; 9884 if (!r.isHidden()) { 9885 buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r, 9886 new NotificationAttentionHelper.Signals( 9887 mUserProfiles.isCurrentProfile(r.getUserId()), 9888 mListenerHints)); 9889 } 9890 9891 if (notification.getSmallIcon() != null) { 9892 NotificationRecordLogger.NotificationReported maybeReport = 9893 mNotificationRecordLogger.prepareToLogNotificationPosted(r, old, 9894 position, buzzBeepBlinkLoggingCode, 9895 getGroupInstanceId(r.getSbn().getGroupKey())); 9896 notifyListenersPostedAndLogLocked(r, old, mTracker, maybeReport); 9897 posted = true; 9898 9899 if (!android.app.Flags.checkAutogroupBeforePost()) { 9900 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 9901 if (oldSbn == null 9902 || !Objects.equals(oldSbn.getGroup(), n.getGroup()) 9903 || oldSbn.getNotification().flags 9904 != n.getNotification().flags) { 9905 if (!isCritical(r)) { 9906 mHandler.post(() -> { 9907 synchronized (mNotificationLock) { 9908 mGroupHelper.onNotificationPosted( 9909 r, hasAutoGroupSummaryLocked(r)); 9910 } 9911 }); 9912 9913 if (notificationForceGrouping()) { 9914 mHandler.postDelayed(() -> { 9915 synchronized (mNotificationLock) { 9916 NotificationRecord record = 9917 mNotificationsByKey.get(key); 9918 if (record != null) { 9919 mGroupHelper.onNotificationPostedWithDelay( 9920 record, mNotificationList, 9921 mSummaryByGroupKey); 9922 } 9923 } 9924 }, key, DELAY_FORCE_REGROUP_TIME); 9925 } 9926 } 9927 } 9928 } 9929 } else { 9930 Slog.e(TAG, "Not posting notification without small icon: " + notification); 9931 if (old != null && !old.isCanceled) { 9932 mListeners.notifyRemovedLocked(r, 9933 REASON_ERROR, r.getStats()); 9934 if (notificationForceGrouping()) { 9935 mHandler.post(() -> { 9936 synchronized (mNotificationLock) { 9937 mGroupHelper.onNotificationRemoved(r, mNotificationList, 9938 /* sendingDelete= */ false); 9939 } 9940 }); 9941 } else { 9942 mHandler.post(new Runnable() { 9943 @Override 9944 public void run() { 9945 mGroupHelper.onNotificationRemoved(r); 9946 } 9947 }); 9948 } 9949 } 9950 9951 if (callstyleCallbackApi()) { 9952 notifyCallNotificationEventListenerOnRemoved(r); 9953 } 9954 9955 // ATTENTION: in a future release we will bail out here 9956 // so that we do not play sounds, show lights, etc. for invalid 9957 // notifications 9958 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 9959 + n.getPackageName()); 9960 } 9961 9962 if (mShortcutHelper != null) { 9963 mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, 9964 false /* isRemoved */); 9965 } 9966 9967 maybeRecordInterruptionLocked(r); 9968 maybeRegisterMessageSent(r); 9969 maybeReportForegroundServiceUpdate(r, true); 9970 } finally { 9971 int N = mEnqueuedNotifications.size(); 9972 for (int i = 0; i < N; i++) { 9973 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 9974 if (Objects.equals(key, enqueued.getKey())) { 9975 mEnqueuedNotifications.remove(i); 9976 break; 9977 } 9978 } 9979 } 9980 } 9981 return posted; 9982 } 9983 } 9984 9985 /** 9986 * 9987 */ 9988 @GuardedBy("mNotificationLock") 9989 InstanceId getGroupInstanceId(String groupKey) { 9990 if (groupKey == null) { 9991 return null; 9992 } 9993 NotificationRecord group = mSummaryByGroupKey.get(groupKey); 9994 if (group == null) { 9995 return null; 9996 } 9997 return group.getSbn().getInstanceId(); 9998 } 9999 10000 /** 10001 * If the notification differs enough visually, consider it a new interruptive notification. 10002 */ 10003 @GuardedBy("mNotificationLock") 10004 @VisibleForTesting 10005 protected boolean isVisuallyInterruptive(@Nullable NotificationRecord old, 10006 @NonNull NotificationRecord r) { 10007 // Ignore summary updates because we don't display most of the information. 10008 if (r.getSbn().isGroup() && r.getSbn().getNotification().isGroupSummary()) { 10009 if (DEBUG_INTERRUPTIVENESS) { 10010 Slog.v(TAG, "INTERRUPTIVENESS: " 10011 + r.getKey() + " is not interruptive: summary"); 10012 } 10013 return false; 10014 } 10015 10016 if (old == null) { 10017 if (DEBUG_INTERRUPTIVENESS) { 10018 Slog.v(TAG, "INTERRUPTIVENESS: " 10019 + r.getKey() + " is interruptive: new notification"); 10020 } 10021 return true; 10022 } 10023 10024 Notification oldN = old.getSbn().getNotification(); 10025 Notification newN = r.getSbn().getNotification(); 10026 if (oldN.extras == null || newN.extras == null) { 10027 if (DEBUG_INTERRUPTIVENESS) { 10028 Slog.v(TAG, "INTERRUPTIVENESS: " 10029 + r.getKey() + " is not interruptive: no extras"); 10030 } 10031 return false; 10032 } 10033 10034 if (sortSectionByTime()) { 10035 // Ignore visual interruptions from FGS/UIJs because users 10036 // consider them one 'session'. Count them for everything else. 10037 if (r.getSbn().getNotification().isFgsOrUij()) { 10038 if (DEBUG_INTERRUPTIVENESS) { 10039 Slog.v(TAG, "INTERRUPTIVENESS: " 10040 + r.getKey() + " is not interruptive: FGS/UIJ"); 10041 } 10042 return false; 10043 } 10044 } else { 10045 // Ignore visual interruptions from foreground services because users 10046 // consider them one 'session'. Count them for everything else. 10047 if ((r.getSbn().getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { 10048 if (DEBUG_INTERRUPTIVENESS) { 10049 Slog.v(TAG, "INTERRUPTIVENESS: " 10050 + r.getKey() + " is not interruptive: foreground service"); 10051 } 10052 return false; 10053 } 10054 } 10055 10056 final String oldTitle = String.valueOf(oldN.extras.get(EXTRA_TITLE)); 10057 final String newTitle = String.valueOf(newN.extras.get(EXTRA_TITLE)); 10058 if (!Objects.equals(oldTitle, newTitle)) { 10059 if (DEBUG_INTERRUPTIVENESS) { 10060 Slog.v(TAG, "INTERRUPTIVENESS: " 10061 + r.getKey() + " is interruptive: changed title"); 10062 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)", 10063 oldTitle, oldTitle.getClass(), oldTitle.hashCode())); 10064 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)", 10065 newTitle, newTitle.getClass(), newTitle.hashCode())); 10066 } 10067 return true; 10068 } 10069 10070 // Do not compare Spannables (will always return false); compare unstyled Strings 10071 final String oldText = String.valueOf(oldN.extras.get(EXTRA_TEXT)); 10072 final String newText = String.valueOf(newN.extras.get(EXTRA_TEXT)); 10073 if (!Objects.equals(oldText, newText)) { 10074 if (DEBUG_INTERRUPTIVENESS) { 10075 Slog.v(TAG, "INTERRUPTIVENESS: " 10076 + r.getKey() + " is interruptive: changed text"); 10077 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)", 10078 oldText, oldText.getClass(), oldText.hashCode())); 10079 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)", 10080 newText, newText.getClass(), newText.hashCode())); 10081 } 10082 return true; 10083 } 10084 10085 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) { 10086 if (DEBUG_INTERRUPTIVENESS) { 10087 Slog.v(TAG, "INTERRUPTIVENESS: " 10088 + r.getKey() + " is interruptive: completed progress"); 10089 } 10090 return true; 10091 } 10092 10093 if (Notification.areIconsDifferent(oldN, newN)) { 10094 if (DEBUG_INTERRUPTIVENESS) { 10095 Slog.v(TAG, "INTERRUPTIVENESS: " 10096 + r.getKey() + " is interruptive: icons differ"); 10097 } 10098 return true; 10099 } 10100 10101 // Fields below are invisible to bubbles. 10102 if (r.canBubble()) { 10103 if (DEBUG_INTERRUPTIVENESS) { 10104 Slog.v(TAG, "INTERRUPTIVENESS: " 10105 + r.getKey() + " is not interruptive: bubble"); 10106 } 10107 return false; 10108 } 10109 10110 // Actions 10111 if (Notification.areActionsVisiblyDifferent(oldN, newN)) { 10112 if (DEBUG_INTERRUPTIVENESS) { 10113 Slog.v(TAG, "INTERRUPTIVENESS: " 10114 + r.getKey() + " is interruptive: changed actions"); 10115 } 10116 return true; 10117 } 10118 10119 try { 10120 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN); 10121 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN); 10122 10123 // Style based comparisons 10124 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) { 10125 if (DEBUG_INTERRUPTIVENESS) { 10126 Slog.v(TAG, "INTERRUPTIVENESS: " 10127 + r.getKey() + " is interruptive: styles differ"); 10128 } 10129 return true; 10130 } 10131 10132 // Remote views 10133 if (Notification.areRemoteViewsChanged(oldB, newB)) { 10134 if (DEBUG_INTERRUPTIVENESS) { 10135 Slog.v(TAG, "INTERRUPTIVENESS: " 10136 + r.getKey() + " is interruptive: remoteviews differ"); 10137 } 10138 return true; 10139 } 10140 } catch (Exception e) { 10141 Slog.w(TAG, "error recovering builder", e); 10142 } 10143 return false; 10144 } 10145 10146 /** 10147 * Check if the notification is classified as critical. 10148 * 10149 * @param record the record to test for criticality 10150 * @return {@code true} if notification is considered critical 10151 * 10152 * @see CriticalNotificationExtractor for criteria 10153 */ 10154 private boolean isCritical(NotificationRecord record) { 10155 // 0 is the most critical 10156 return record.getCriticality() < CriticalNotificationExtractor.NORMAL; 10157 } 10158 10159 /** 10160 * Check if the notification was a summary that has been auto-grouped 10161 * @param r the current notification record 10162 * @param old the previous notification record 10163 * @return true if the notification record was a summary that was auto-grouped 10164 */ 10165 @GuardedBy("mNotificationLock") 10166 private boolean wasSummaryAutogrouped(NotificationRecord r, NotificationRecord old) { 10167 boolean wasAutogrouped = false; 10168 if (old != null) { 10169 boolean wasSummary = (old.mOriginalFlags & FLAG_GROUP_SUMMARY) != 0; 10170 boolean wasForcedGrouped = (old.getFlags() & FLAG_GROUP_SUMMARY) == 0 10171 && old.getSbn().getOverrideGroupKey() != null; 10172 boolean isNotAutogroupSummary = (r.getFlags() & FLAG_AUTOGROUP_SUMMARY) == 0 10173 && (r.getFlags() & FLAG_GROUP_SUMMARY) != 0; 10174 if ((wasSummary && wasForcedGrouped) || (wasForcedGrouped && isNotAutogroupSummary)) { 10175 wasAutogrouped = true; 10176 } 10177 } 10178 return wasAutogrouped; 10179 } 10180 10181 /** 10182 * Ensures that grouped notification receive their special treatment. 10183 * 10184 * <p>Cancels group children if the new notification causes a group to lose 10185 * its summary.</p> 10186 * 10187 * <p>Updates mSummaryByGroupKey.</p> 10188 */ 10189 @GuardedBy("mNotificationLock") 10190 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 10191 int callingUid, int callingPid) { 10192 StatusBarNotification sbn = r.getSbn(); 10193 Notification n = sbn.getNotification(); 10194 if (n.isGroupSummary() && !sbn.isAppGroup()) { 10195 // notifications without a group shouldn't be a summary, otherwise autobundling can 10196 // lead to bugs 10197 n.flags &= ~Notification.FLAG_GROUP_SUMMARY; 10198 } 10199 10200 if (notificationForceGrouping()) { 10201 // If this is an update to a summary that was forced grouped => remove summary flag 10202 if (wasSummaryAutogrouped(r, old)) { 10203 n.flags &= ~FLAG_GROUP_SUMMARY; 10204 } 10205 } 10206 10207 String group = sbn.getGroupKey(); 10208 boolean isSummary = n.isGroupSummary(); 10209 10210 Notification oldN = old != null ? old.getSbn().getNotification() : null; 10211 String oldGroup = old != null ? old.getSbn().getGroupKey() : null; 10212 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 10213 10214 if (oldIsSummary) { 10215 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 10216 if (removedSummary != old) { 10217 String removedKey = 10218 removedSummary != null ? removedSummary.getKey() : "<null>"; 10219 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 10220 ", removed=" + removedKey); 10221 } 10222 } 10223 if (isSummary) { 10224 mSummaryByGroupKey.put(group, r); 10225 10226 if (notificationForceGrouping()) { 10227 // If any formerly-ungrouped notifications will be grouped by this summary, update 10228 // accordingly. 10229 mGroupHelper.onGroupSummaryAdded(r, mNotificationList); 10230 } 10231 } 10232 10233 FlagChecker childrenFlagChecker = (flags) -> { 10234 if ((flags & FLAG_FOREGROUND_SERVICE) != 0 || (flags & FLAG_USER_INITIATED_JOB) != 0) { 10235 return false; 10236 } 10237 return true; 10238 }; 10239 10240 // Clear out group children of the old notification if the update 10241 // causes the group summary to go away. This happens when the old 10242 // notification was a summary and the new one isn't, or when the old 10243 // notification was a summary and its group key changed. 10244 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 10245 cancelGroupChildrenLocked(old.getUserId(), old.getSbn().getPackageName(), callingUid, 10246 callingPid, null, false /* sendDelete */, childrenFlagChecker, 10247 NotificationManagerService::isChildOfCurrentGroupChecker, old.getGroupKey(), 10248 REASON_APP_CANCEL, SystemClock.elapsedRealtime()); 10249 } 10250 } 10251 10252 private PendingIntent getNotificationTimeoutPendingIntent(NotificationRecord record, 10253 int flags) { 10254 flags |= PendingIntent.FLAG_IMMUTABLE; 10255 return PendingIntent.getBroadcast(getContext(), 10256 REQUEST_CODE_TIMEOUT, 10257 new Intent(ACTION_NOTIFICATION_TIMEOUT) 10258 .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME) 10259 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT) 10260 .appendPath(record.getKey()).build()) 10261 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 10262 .putExtra(EXTRA_KEY, record.getKey()), 10263 flags); 10264 } 10265 10266 @VisibleForTesting 10267 @GuardedBy("mNotificationLock") 10268 void scheduleTimeoutLocked(NotificationRecord record) { 10269 if (record.getNotification().getTimeoutAfter() > 0) { 10270 final PendingIntent pi = getNotificationTimeoutPendingIntent( 10271 record, PendingIntent.FLAG_UPDATE_CURRENT); 10272 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 10273 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi); 10274 } 10275 } 10276 10277 @VisibleForTesting 10278 @GuardedBy("mNotificationLock") 10279 void cancelScheduledTimeoutLocked(NotificationRecord record) { 10280 final PendingIntent pi = getNotificationTimeoutPendingIntent( 10281 record, PendingIntent.FLAG_CANCEL_CURRENT); 10282 if (pi != null) { 10283 mAlarmManager.cancel(pi); 10284 } 10285 } 10286 10287 @GuardedBy("mToastQueue") 10288 void showNextToastLocked(boolean lastToastWasTextRecord) { 10289 if (mIsCurrentToastShown) { 10290 return; // Don't show the same toast twice. 10291 } 10292 10293 ToastRecord record = mToastQueue.get(0); 10294 while (record != null) { 10295 int userId = UserHandle.getUserId(record.uid); 10296 boolean rateLimitingEnabled = 10297 !mToastRateLimitingDisabledUids.contains(record.uid); 10298 boolean isWithinQuota = 10299 mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG) 10300 || isExemptFromRateLimiting(record.pkg, userId); 10301 boolean isPackageInForeground = isPackageInForegroundForToast(record.uid); 10302 10303 if (tryShowToast( 10304 record, rateLimitingEnabled, isWithinQuota, isPackageInForeground)) { 10305 scheduleDurationReachedLocked(record, lastToastWasTextRecord); 10306 mIsCurrentToastShown = true; 10307 if (rateLimitingEnabled && !isPackageInForeground) { 10308 mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG); 10309 } 10310 return; 10311 } 10312 10313 int index = mToastQueue.indexOf(record); 10314 if (index >= 0) { 10315 ToastRecord toast = mToastQueue.remove(index); 10316 mWindowManagerInternal.removeWindowToken( 10317 toast.windowToken, true /* removeWindows */, toast.displayId); 10318 } 10319 record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null; 10320 } 10321 } 10322 10323 /** Returns true if it successfully showed the toast. */ 10324 private boolean tryShowToast(ToastRecord record, boolean rateLimitingEnabled, 10325 boolean isWithinQuota, boolean isPackageInForeground) { 10326 if (rateLimitingEnabled && !isWithinQuota && !isPackageInForeground) { 10327 reportCompatRateLimitingToastsChange(record.uid); 10328 Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the " 10329 + "following toast was blocked and discarded: " + record); 10330 return false; 10331 } 10332 if (blockToast(record.uid, record.isSystemToast, record.isAppRendered(), 10333 isPackageInForeground)) { 10334 Slog.w(TAG, "Blocking custom toast from package " + record.pkg 10335 + " due to package not in the foreground at the time of showing the toast"); 10336 return false; 10337 } 10338 return record.show(); 10339 } 10340 10341 private boolean isExemptFromRateLimiting(String pkg, int userId) { 10342 boolean isExemptFromRateLimiting = false; 10343 try { 10344 isExemptFromRateLimiting = mPackageManager.checkPermission( 10345 android.Manifest.permission.UNLIMITED_TOASTS, pkg, userId) 10346 == PERMISSION_GRANTED; 10347 } catch (RemoteException e) { 10348 Slog.e(TAG, "Failed to connect with package manager"); 10349 } 10350 return isExemptFromRateLimiting; 10351 } 10352 10353 /** Reports rate limiting toasts compat change (used when the toast was blocked). */ 10354 private void reportCompatRateLimitingToastsChange(int uid) { 10355 final long id = Binder.clearCallingIdentity(); 10356 try { 10357 mPlatformCompat.reportChangeByUid(RATE_LIMIT_TOASTS, uid); 10358 } catch (RemoteException e) { 10359 Slog.e(TAG, "Unexpected exception while reporting toast was blocked due to rate" 10360 + " limiting", e); 10361 } finally { 10362 Binder.restoreCallingIdentity(id); 10363 } 10364 } 10365 10366 @GuardedBy("mToastQueue") 10367 void cancelToastLocked(int index) { 10368 ToastRecord record = mToastQueue.get(index); 10369 record.hide(); 10370 10371 if (index == 0) { 10372 mIsCurrentToastShown = false; 10373 } 10374 10375 ToastRecord lastToast = mToastQueue.remove(index); 10376 10377 // We need to schedule a timeout to make sure the token is eventually killed 10378 scheduleKillTokenTimeout(lastToast); 10379 10380 keepProcessAliveForToastIfNeededLocked(record.pid); 10381 if (mToastQueue.size() > 0) { 10382 // Show the next one. If the callback fails, this will remove 10383 // it from the list, so don't assume that the list hasn't changed 10384 // after this point. 10385 showNextToastLocked(lastToast instanceof TextToastRecord); 10386 } 10387 } 10388 10389 void finishWindowTokenLocked(IBinder t, int displayId) { 10390 mHandler.removeCallbacksAndMessages(t); 10391 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any 10392 // remaining surfaces as either the client has called finishToken indicating 10393 // it has successfully removed the views, or the client has timed out 10394 // at which point anything goes. 10395 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId); 10396 } 10397 10398 @GuardedBy("mToastQueue") 10399 private void scheduleDurationReachedLocked(ToastRecord r, boolean lastToastWasTextRecord) 10400 { 10401 mHandler.removeCallbacksAndMessages(r); 10402 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r); 10403 int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 10404 // Accessibility users may need longer timeout duration. This api compares original delay 10405 // with user's preference and return longer one. It returns original delay if there's no 10406 // preference. 10407 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay, 10408 AccessibilityManager.FLAG_CONTENT_TEXT); 10409 10410 if (lastToastWasTextRecord) { 10411 delay += 250; // delay to account for previous toast's "out" animation 10412 } 10413 if (r instanceof TextToastRecord) { 10414 delay += 333; // delay to account for this toast's "in" animation 10415 } 10416 10417 mHandler.sendMessageDelayed(m, delay); 10418 } 10419 10420 private void handleDurationReached(ToastRecord record) 10421 { 10422 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " token=" + record.token); 10423 synchronized (mToastQueue) { 10424 int index = indexOfToastLocked(record.pkg, record.token); 10425 if (index >= 0) { 10426 cancelToastLocked(index); 10427 } 10428 } 10429 } 10430 10431 @GuardedBy("mToastQueue") 10432 private void scheduleKillTokenTimeout(ToastRecord r) 10433 { 10434 mHandler.removeCallbacksAndMessages(r); 10435 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r); 10436 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT); 10437 } 10438 10439 private void handleKillTokenTimeout(ToastRecord record) 10440 { 10441 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.windowToken); 10442 synchronized (mToastQueue) { 10443 finishWindowTokenLocked(record.windowToken, record.displayId); 10444 } 10445 } 10446 10447 @GuardedBy("mToastQueue") 10448 int indexOfToastLocked(String pkg, IBinder token) { 10449 ArrayList<ToastRecord> list = mToastQueue; 10450 int len = list.size(); 10451 for (int i=0; i<len; i++) { 10452 ToastRecord r = list.get(i); 10453 if (r.pkg.equals(pkg) && r.token == token) { 10454 return i; 10455 } 10456 } 10457 return -1; 10458 } 10459 10460 /** 10461 * Adjust process {@code pid} importance according to whether it has toasts in the queue or not. 10462 */ 10463 public void keepProcessAliveForToastIfNeeded(int pid) { 10464 synchronized (mToastQueue) { 10465 keepProcessAliveForToastIfNeededLocked(pid); 10466 } 10467 } 10468 10469 @GuardedBy("mToastQueue") 10470 private void keepProcessAliveForToastIfNeededLocked(int pid) { 10471 int toastCount = 0; // toasts from this pid, rendered by the app 10472 ArrayList<ToastRecord> list = mToastQueue; 10473 int n = list.size(); 10474 for (int i = 0; i < n; i++) { 10475 ToastRecord r = list.get(i); 10476 if (r.pid == pid && r.keepProcessAlive()) { 10477 toastCount++; 10478 } 10479 } 10480 try { 10481 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast"); 10482 } catch (RemoteException e) { 10483 // Shouldn't happen. 10484 } 10485 } 10486 10487 /** 10488 * Implementation note: Our definition of foreground for toasts is an implementation matter 10489 * and should strike a balance between functionality and anti-abuse effectiveness. We 10490 * currently worry about the following cases: 10491 * <ol> 10492 * <li>App with fullscreen activity: Allow toasts 10493 * <li>App behind translucent activity from other app: Block toasts 10494 * <li>App in multi-window: Allow toasts 10495 * <li>App with expanded bubble: Allow toasts 10496 * <li>App posting toasts on onCreate(), onStart(), onResume(): Allow toasts 10497 * <li>App posting toasts on onPause(), onStop(), onDestroy(): Block toasts 10498 * </ol> 10499 * Checking if the UID has any resumed activities satisfy use-cases above. 10500 * 10501 * <p>Checking if {@code mActivityManager.getUidImportance(callingUid) == 10502 * IMPORTANCE_FOREGROUND} does not work because it considers the app in foreground if it has 10503 * any visible activities, failing case 2 in list above. 10504 */ 10505 private boolean isPackageInForegroundForToast(int callingUid) { 10506 return mAtm.hasResumedActivity(callingUid); 10507 } 10508 10509 /** 10510 * True if the toast should be blocked. It will return true if all of the following conditions 10511 * apply: it's a custom toast, it's not a system toast, the package that sent the toast is in 10512 * the background and CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is enabled. 10513 * 10514 * CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so it will return false for apps 10515 * with targetSdk < R. For apps with targetSdk R+, text toasts are not app-rendered, so 10516 * isAppRenderedToast == true means it's a custom toast. 10517 */ 10518 private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast, 10519 boolean isPackageInForeground) { 10520 return isAppRenderedToast 10521 && !isSystemToast 10522 && !isPackageInForeground 10523 && CompatChanges.isChangeEnabled(CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, uid); 10524 } 10525 10526 private void handleRankingReconsideration(Message message) { 10527 if (!(message.obj instanceof RankingReconsideration)) return; 10528 RankingReconsideration recon = (RankingReconsideration) message.obj; 10529 recon.run(); 10530 boolean changed; 10531 synchronized (mNotificationLock) { 10532 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 10533 if (record == null) { 10534 return; 10535 } 10536 int indexBefore = findNotificationRecordIndexLocked(record); 10537 boolean interceptBefore = record.isIntercepted(); 10538 int visibilityBefore = record.getPackageVisibilityOverride(); 10539 boolean interruptiveBefore = record.isInterruptive(); 10540 10541 recon.applyChangesLocked(record); 10542 applyZenModeLocked(record); 10543 mRankingHelper.sort(mNotificationList); 10544 boolean indexChanged = indexBefore != findNotificationRecordIndexLocked(record); 10545 boolean interceptChanged = interceptBefore != record.isIntercepted(); 10546 boolean visibilityChanged = visibilityBefore != record.getPackageVisibilityOverride(); 10547 10548 // Broadcast isInterruptive changes for bubbles. 10549 boolean interruptiveChanged = 10550 record.canBubble() && (interruptiveBefore != record.isInterruptive()); 10551 10552 changed = indexChanged 10553 || interceptChanged 10554 || visibilityChanged 10555 || interruptiveChanged; 10556 if (interceptBefore && !record.isIntercepted() 10557 && record.isNewEnoughForAlerting(System.currentTimeMillis())) { 10558 10559 mAttentionHelper.buzzBeepBlinkLocked(record, 10560 new NotificationAttentionHelper.Signals(mUserProfiles.isCurrentProfile( 10561 record.getUserId()), mListenerHints)); 10562 10563 // Log alert after change in intercepted state to Zen Log as well 10564 ZenLog.traceAlertOnUpdatedIntercept(record); 10565 } 10566 } 10567 if (changed) { 10568 mHandler.scheduleSendRankingUpdate(); 10569 } 10570 } 10571 10572 void handleRankingSort() { 10573 if (mRankingHelper == null) return; 10574 synchronized (mNotificationLock) { 10575 final int N = mNotificationList.size(); 10576 // Any field that can change via one of the extractors needs to be added here. 10577 ArrayMap<String, NotificationRecordExtractorData> extractorDataBefore = 10578 new ArrayMap<>(N); 10579 for (int i = 0; i < N; i++) { 10580 final NotificationRecord r = mNotificationList.get(i); 10581 NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData( 10582 i, 10583 r.getPackageVisibilityOverride(), 10584 r.canShowBadge(), 10585 r.canBubble(), 10586 r.getNotification().isBubbleNotification(), 10587 r.getChannel(), 10588 r.getGroupKey(), 10589 r.getPeopleOverride(), 10590 r.getSnoozeCriteria(), 10591 r.getUserSentiment(), 10592 r.getSuppressedVisualEffects(), 10593 r.getSystemGeneratedSmartActions(), 10594 r.getSmartReplies(), 10595 r.getImportance(), 10596 r.getRankingScore(), 10597 r.isConversation(), 10598 r.getProposedImportance(), 10599 r.hasSensitiveContent(), 10600 r.getSummarization()); 10601 extractorDataBefore.put(r.getKey(), extractorData); 10602 mRankingHelper.extractSignals(r); 10603 } 10604 mRankingHelper.sort(mNotificationList); 10605 for (int i = 0; i < N; i++) { 10606 final NotificationRecord r = mNotificationList.get(i); 10607 if (!extractorDataBefore.containsKey(r.getKey())) { 10608 // This shouldn't happen given that we just built this with all the 10609 // notifications, but check just to be safe. 10610 continue; 10611 } 10612 if (extractorDataBefore.get(r.getKey()).hasDiffForRankingLocked(r, i)) { 10613 mHandler.scheduleSendRankingUpdate(); 10614 } 10615 10616 // If this notification is one for which we wanted to log an update, and 10617 // sufficient relevant bits are different, log update. 10618 if (r.hasPendingLogUpdate()) { 10619 // We need to acquire the previous data associated with this specific 10620 // notification, as the one at the current index may be unrelated if 10621 // notification order has changed. 10622 NotificationRecordExtractorData prevData = extractorDataBefore.get(r.getKey()); 10623 if (prevData.hasDiffForLoggingLocked(r, i)) { 10624 mNotificationRecordLogger.logNotificationAdjusted(r, i, 0, 10625 getGroupInstanceId(r.getSbn().getGroupKey())); 10626 } 10627 10628 // Remove whether there was a diff or not; we've sorted the key, so if it 10629 // turns out there was nothing to log, that's fine too. 10630 r.setPendingLogUpdate(false); 10631 } 10632 } 10633 } 10634 } 10635 10636 @GuardedBy("mNotificationLock") 10637 private void recordCallerLocked(NotificationRecord record) { 10638 if (mZenModeHelper.isCall(record)) { 10639 mZenModeHelper.recordCaller(record); 10640 } 10641 } 10642 10643 // let zen mode evaluate this record 10644 @GuardedBy("mNotificationLock") 10645 private void applyZenModeLocked(NotificationRecord record) { 10646 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 10647 if (record.isIntercepted()) { 10648 record.setSuppressedVisualEffects( 10649 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects); 10650 } else { 10651 record.setSuppressedVisualEffects(0); 10652 } 10653 } 10654 10655 @GuardedBy("mNotificationLock") 10656 private int findNotificationRecordIndexLocked(NotificationRecord target) { 10657 return mRankingHelper.indexOf(mNotificationList, target); 10658 } 10659 10660 private void handleSendRankingUpdate() { 10661 synchronized (mNotificationLock) { 10662 mListeners.notifyRankingUpdateLocked(null); 10663 } 10664 } 10665 10666 private void scheduleListenerHintsChanged(int state) { 10667 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 10668 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 10669 } 10670 10671 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 10672 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 10673 mHandler.obtainMessage( 10674 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 10675 listenerInterruptionFilter, 10676 0).sendToTarget(); 10677 } 10678 10679 private void handleListenerHintsChanged(int hints) { 10680 synchronized (mNotificationLock) { 10681 mListeners.notifyListenerHintsChangedLocked(hints); 10682 } 10683 } 10684 10685 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 10686 synchronized (mNotificationLock) { 10687 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 10688 } 10689 } 10690 10691 void handleOnPackageChanged(boolean removingPackage, int changeUserId, 10692 String[] pkgList, int[] uidList) { 10693 boolean preferencesChanged = removingPackage; 10694 mListeners.onPackagesChanged(removingPackage, pkgList, uidList); 10695 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList); 10696 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); 10697 preferencesChanged |= mPreferencesHelper.onPackagesChanged( 10698 removingPackage, changeUserId, pkgList, uidList); 10699 if (removingPackage) { 10700 int size = Math.min(pkgList.length, uidList.length); 10701 for (int i = 0; i < size; i++) { 10702 final String pkg = pkgList[i]; 10703 final int uid = uidList[i]; 10704 final int userHandle = UserHandle.getUserId(uid); 10705 // Removes this package's notifications from both recent notification archive 10706 // (recently dismissed notifications) and notification history. 10707 mArchive.removePackageNotifications(pkg, userHandle); 10708 mHistoryManager.onPackageRemoved(userHandle, pkg); 10709 } 10710 } 10711 if (preferencesChanged) { 10712 handleSavePolicyFile(); 10713 } 10714 } 10715 10716 protected class WorkerHandler extends Handler 10717 { 10718 public WorkerHandler(Looper looper) { 10719 super(looper); 10720 } 10721 10722 @Override 10723 public void handleMessage(Message msg) 10724 { 10725 switch (msg.what) 10726 { 10727 case MESSAGE_DURATION_REACHED: 10728 handleDurationReached((ToastRecord) msg.obj); 10729 break; 10730 case MESSAGE_FINISH_TOKEN_TIMEOUT: 10731 handleKillTokenTimeout((ToastRecord) msg.obj); 10732 break; 10733 case MESSAGE_SEND_RANKING_UPDATE: 10734 handleSendRankingUpdate(); 10735 break; 10736 case MESSAGE_LISTENER_HINTS_CHANGED: 10737 handleListenerHintsChanged(msg.arg1); 10738 break; 10739 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 10740 handleListenerInterruptionFilterChanged(msg.arg1); 10741 break; 10742 case MESSAGE_ON_PACKAGE_CHANGED: 10743 SomeArgs args = (SomeArgs) msg.obj; 10744 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2, 10745 (int[]) args.arg3); 10746 args.recycle(); 10747 break; 10748 } 10749 } 10750 10751 protected void scheduleSendRankingUpdate() { 10752 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 10753 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); 10754 sendMessage(m); 10755 } 10756 } 10757 10758 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable, 10759 int delay) { 10760 if (lifetimeExtensionRefactor()) { 10761 sendMessageDelayed(Message.obtain(this, cancelRunnable), delay); 10762 } else { 10763 if (!hasCallbacks(cancelRunnable)) { 10764 sendMessage(Message.obtain(this, cancelRunnable)); 10765 } 10766 } 10767 } 10768 10769 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId, 10770 String[] pkgList, int[] uidList) { 10771 SomeArgs args = SomeArgs.obtain(); 10772 args.arg1 = removingPackage; 10773 args.argi1 = changeUserId; 10774 args.arg2 = pkgList; 10775 args.arg3 = uidList; 10776 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args)); 10777 } 10778 } 10779 10780 private final class RankingHandlerWorker extends Handler implements RankingHandler 10781 { 10782 public RankingHandlerWorker(Looper looper) { 10783 super(looper); 10784 } 10785 10786 @Override 10787 public void handleMessage(Message msg) { 10788 switch (msg.what) { 10789 case MESSAGE_RECONSIDER_RANKING: 10790 handleRankingReconsideration(msg); 10791 break; 10792 case MESSAGE_RANKING_SORT: 10793 handleRankingSort(); 10794 break; 10795 } 10796 } 10797 10798 public void requestSort() { 10799 removeMessages(MESSAGE_RANKING_SORT); 10800 Message msg = Message.obtain(); 10801 msg.what = MESSAGE_RANKING_SORT; 10802 sendMessage(msg); 10803 } 10804 10805 public void requestReconsideration(RankingReconsideration recon) { 10806 Message m = Message.obtain(this, 10807 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 10808 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 10809 sendMessageDelayed(m, delay); 10810 } 10811 } 10812 10813 // Notifications 10814 // ============================================================================ 10815 static int clamp(int x, int low, int high) { 10816 return (x < low) ? low : ((x > high) ? high : x); 10817 } 10818 10819 /** 10820 * Removes all NotificationsRecords with the same key as the given notification record 10821 * from both lists. Do not call this method while iterating over either list. 10822 */ 10823 @GuardedBy("mNotificationLock") 10824 private boolean removeFromNotificationListsLocked(NotificationRecord r) { 10825 // Remove from both lists, either list could have a separate Record for what is 10826 // effectively the same notification. 10827 boolean wasPosted = false; 10828 NotificationRecord recordInList = null; 10829 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) 10830 != null) { 10831 mNotificationList.remove(recordInList); 10832 mNotificationsByKey.remove(recordInList.getSbn().getKey()); 10833 wasPosted = true; 10834 } 10835 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) 10836 != null) { 10837 mEnqueuedNotifications.remove(recordInList); 10838 } 10839 return wasPosted; 10840 } 10841 10842 @GuardedBy("mNotificationLock") 10843 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, 10844 @NotificationListenerService.NotificationCancelReason int reason, 10845 boolean wasPosted, String listenerName, 10846 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 10847 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName, 10848 cancellationElapsedTimeMs); 10849 } 10850 10851 @GuardedBy("mNotificationLock") 10852 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, 10853 @NotificationListenerService.NotificationCancelReason int reason, 10854 int rank, int count, boolean wasPosted, String listenerName, 10855 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 10856 final String canceledKey = r.getKey(); 10857 if (Flags.allNotifsNeedTtl()) { 10858 mTtlHelper.cancelScheduledTimeoutLocked(r); 10859 } else { 10860 cancelScheduledTimeoutLocked(r); 10861 } 10862 10863 // Record caller. 10864 recordCallerLocked(r); 10865 10866 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) { 10867 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER); 10868 } 10869 10870 // tell the app 10871 if (sendDelete) { 10872 sendDeleteIntent(r.getNotification().deleteIntent, r.getSbn().getPackageName()); 10873 } 10874 10875 // Only cancel these if this notification actually got to be posted. 10876 if (wasPosted) { 10877 // status bar 10878 if (r.getNotification().getSmallIcon() != null) { 10879 if (reason != REASON_SNOOZED) { 10880 r.isCanceled = true; 10881 } 10882 mListeners.notifyRemovedLocked(r, reason, r.getStats()); 10883 if (notificationForceGrouping()) { 10884 mHandler.removeCallbacksAndEqualMessages(r.getKey()); 10885 mHandler.post(() -> { 10886 synchronized (NotificationManagerService.this.mNotificationLock) { 10887 mGroupHelper.onNotificationRemoved(r, mNotificationList, sendDelete); 10888 } 10889 }); 10890 10891 // Wait 3 seconds so that the app has a chance to cancel/post 10892 // a group summary or children 10893 final NotificationRecord groupSummary = mSummaryByGroupKey.get(r.getGroupKey()); 10894 if (groupSummary != null 10895 && !GroupHelper.isAggregatedGroup(groupSummary) 10896 && !groupSummary.getKey().equals(canceledKey)) { 10897 // We only care about app-provided valid group summaries 10898 final String summaryKey = groupSummary.getKey(); 10899 mHandler.removeCallbacksAndEqualMessages(summaryKey); 10900 mHandler.postDelayed(() -> { 10901 synchronized (mNotificationLock) { 10902 NotificationRecord summaryRecord = mNotificationsByKey.get( 10903 summaryKey); 10904 if (summaryRecord != null) { 10905 mGroupHelper.onGroupedNotificationRemovedWithDelay( 10906 summaryRecord, mNotificationList, mSummaryByGroupKey); 10907 } 10908 } 10909 }, summaryKey, DELAY_FORCE_REGROUP_TIME); 10910 } 10911 } else { 10912 mHandler.post(new Runnable() { 10913 @Override 10914 public void run() { 10915 mGroupHelper.onNotificationRemoved(r); 10916 } 10917 }); 10918 } 10919 if (callstyleCallbackApi()) { 10920 notifyCallNotificationEventListenerOnRemoved(r); 10921 } 10922 } 10923 10924 mAttentionHelper.clearEffectsLocked(canceledKey); 10925 } 10926 10927 // Record usage stats 10928 // TODO: add unbundling stats? 10929 switch (reason) { 10930 case REASON_CANCEL: 10931 case REASON_CANCEL_ALL: 10932 case REASON_LISTENER_CANCEL: 10933 case REASON_LISTENER_CANCEL_ALL: 10934 mUsageStats.registerDismissedByUser(r); 10935 break; 10936 case REASON_APP_CANCEL: 10937 case REASON_APP_CANCEL_ALL: 10938 mUsageStats.registerRemovedByApp(r); 10939 mUsageStatsManagerInternal.reportNotificationRemoved(r.getSbn().getOpPkg(), 10940 r.getUser(), cancellationElapsedTimeMs); 10941 break; 10942 } 10943 10944 String groupKey = r.getGroupKey(); 10945 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 10946 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) { 10947 mSummaryByGroupKey.remove(groupKey); 10948 } 10949 final ArrayMap<String, String> summaries = 10950 mAutobundledSummaries.get(r.getSbn().getUserId()); 10951 final String autbundledGroupKey; 10952 if (notificationForceGrouping()) { 10953 autbundledGroupKey = groupKey; 10954 } else { 10955 autbundledGroupKey = r.getSbn().getPackageName(); 10956 } 10957 if (summaries != null && r.getSbn().getKey().equals( 10958 summaries.get(autbundledGroupKey))) { 10959 summaries.remove(autbundledGroupKey); 10960 } 10961 10962 // Save it for users of getHistoricalNotifications(), unless the whole channel was deleted 10963 if (reason != REASON_CHANNEL_REMOVED) { 10964 mArchive.record(r.getSbn(), reason); 10965 } 10966 10967 final long now = System.currentTimeMillis(); 10968 final LogMaker logMaker = r.getItemLogMaker() 10969 .setType(MetricsEvent.TYPE_DISMISS) 10970 .setSubtype(reason); 10971 if (rank != -1 && count != -1) { 10972 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank) 10973 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count); 10974 } 10975 MetricsLogger.action(logMaker); 10976 EventLogTags.writeNotificationCanceled(canceledKey, reason, 10977 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 10978 rank, count, listenerName); 10979 if (wasPosted) { 10980 mNotificationRecordLogger.logNotificationCancelled(r, reason, 10981 r.getStats().getDismissalSurface()); 10982 } 10983 } 10984 10985 private static void sendDeleteIntent(@Nullable PendingIntent deleteIntent, String fromPkg) { 10986 if (deleteIntent != null) { 10987 try { 10988 // make sure deleteIntent cannot be used to start activities from background 10989 LocalServices.getService(ActivityManagerInternal.class) 10990 .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(), 10991 ALLOWLIST_TOKEN); 10992 deleteIntent.send(); 10993 } catch (PendingIntent.CanceledException ex) { 10994 // There's no relevant way to recover, and no reason to let this propagate 10995 Slog.w(TAG, "canceled PendingIntent for " + fromPkg, ex); 10996 } 10997 } 10998 } 10999 11000 @VisibleForTesting 11001 void updateUriPermissions(@Nullable NotificationRecord newRecord, 11002 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) { 11003 updateUriPermissions(newRecord, oldRecord, targetPkg, targetUserId, false); 11004 } 11005 11006 @VisibleForTesting 11007 void updateUriPermissions(@Nullable NotificationRecord newRecord, 11008 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId, 11009 boolean onlyRevokeCurrentTarget) { 11010 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey(); 11011 if (DBG) Slog.d(TAG, key + ": updating permissions"); 11012 11013 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null; 11014 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null; 11015 11016 // Shortcut when no Uris involved 11017 if (newUris == null && oldUris == null) { 11018 return; 11019 } 11020 11021 // Inherit any existing owner 11022 IBinder permissionOwner = null; 11023 if (newRecord != null && permissionOwner == null) { 11024 permissionOwner = newRecord.permissionOwner; 11025 } 11026 if (oldRecord != null && permissionOwner == null) { 11027 permissionOwner = oldRecord.permissionOwner; 11028 } 11029 11030 // If we have Uris to grant, but no owner yet, go create one 11031 if (newUris != null && permissionOwner == null) { 11032 if (DBG) Slog.d(TAG, key + ": creating owner"); 11033 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key); 11034 } 11035 11036 // If we have no Uris to grant, but an existing owner, go destroy it 11037 // When revoking permissions of a single listener, destroying the owner will revoke 11038 // permissions of other listeners who need to keep access. 11039 if (newUris == null && permissionOwner != null && !onlyRevokeCurrentTarget) { 11040 destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key); 11041 permissionOwner = null; 11042 } 11043 11044 // Grant access to new Uris 11045 if (newUris != null && permissionOwner != null) { 11046 for (int i = 0; i < newUris.size(); i++) { 11047 final Uri uri = newUris.valueAt(i); 11048 if (oldUris == null || !oldUris.contains(uri)) { 11049 if (DBG) { 11050 Slog.d(TAG, key + ": granting " + uri); 11051 } 11052 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg, 11053 targetUserId); 11054 } 11055 } 11056 } 11057 11058 // Revoke access to old Uris 11059 if (oldUris != null && permissionOwner != null) { 11060 for (int i = 0; i < oldUris.size(); i++) { 11061 final Uri uri = oldUris.valueAt(i); 11062 if (newUris == null || !newUris.contains(uri)) { 11063 if (DBG) Slog.d(TAG, key + ": revoking " + uri); 11064 if (onlyRevokeCurrentTarget) { 11065 // We're revoking permission from one listener only; other listeners may 11066 // still need access because the notification may still exist 11067 revokeUriPermission(permissionOwner, uri, 11068 UserHandle.getUserId(oldRecord.getUid()), targetPkg, targetUserId); 11069 } else { 11070 // This is broad to unilaterally revoke permissions to this Uri as granted 11071 // by this notification. But this code-path can only be used when the 11072 // reason for revoking is that the notification posted again without this 11073 // Uri, not when removing an individual listener. 11074 revokeUriPermission(permissionOwner, uri, 11075 UserHandle.getUserId(oldRecord.getUid()), 11076 null, USER_ALL); 11077 } 11078 } 11079 } 11080 } 11081 11082 if (newRecord != null) { 11083 newRecord.permissionOwner = permissionOwner; 11084 } 11085 } 11086 11087 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg, 11088 int targetUserId) { 11089 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 11090 final long ident = Binder.clearCallingIdentity(); 11091 try { 11092 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg, 11093 ContentProvider.getUriWithoutUserId(uri), 11094 Intent.FLAG_GRANT_READ_URI_PERMISSION, 11095 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)), 11096 targetUserId); 11097 } catch (RemoteException ignored) { 11098 // Ignored because we're in same process 11099 } catch (SecurityException e) { 11100 Slog.e(TAG, "Cannot grant uri access; " + sourceUid + " does not own " + uri); 11101 } finally { 11102 Binder.restoreCallingIdentity(ident); 11103 } 11104 } 11105 11106 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUserId, String targetPkg, 11107 int targetUserId) { 11108 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 11109 int userId = ContentProvider.getUserIdFromUri(uri, sourceUserId); 11110 11111 final long ident = Binder.clearCallingIdentity(); 11112 try { 11113 mUgmInternal.revokeUriPermissionFromOwner( 11114 owner, 11115 ContentProvider.getUriWithoutUserId(uri), 11116 Intent.FLAG_GRANT_READ_URI_PERMISSION, 11117 userId, targetPkg, targetUserId); 11118 } finally { 11119 Binder.restoreCallingIdentity(ident); 11120 } 11121 } 11122 11123 private void destroyPermissionOwner(IBinder owner, int userId, String logKey) { 11124 final long ident = Binder.clearCallingIdentity(); 11125 try { 11126 if (DBG) Slog.d(TAG, logKey + ": destroying owner"); 11127 mUgmInternal.revokeUriPermissionFromOwner(owner, null, ~0, userId); 11128 } finally { 11129 Binder.restoreCallingIdentity(ident); 11130 } 11131 } 11132 11133 /** 11134 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 11135 * and none of the {@code mustNotHaveFlags}. 11136 */ 11137 void cancelNotification(final int callingUid, final int callingPid, 11138 final String pkg, final String tag, int id, 11139 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 11140 final int userId, final int reason, final ManagedServiceInfo listener) { 11141 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags, 11142 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener); 11143 } 11144 11145 /** 11146 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 11147 * and none of the {@code mustNotHaveFlags}. 11148 */ 11149 void cancelNotification(final int callingUid, final int callingPid, 11150 final String pkg, final String tag, final int id, 11151 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 11152 final int userId, final int reason, int rank, int count, 11153 final ManagedServiceInfo listener) { 11154 // In enqueueNotificationInternal notifications are added by scheduling the 11155 // work on the worker handler. Hence, we also schedule the cancel on this 11156 // handler to avoid a scenario where an add notification call followed by a 11157 // remove notification call ends up in not removing the notification. 11158 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid, 11159 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank, 11160 count, listener, SystemClock.elapsedRealtime()), 0); 11161 } 11162 11163 /** 11164 * Determine whether the userId applies to the notification in question, either because 11165 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 11166 */ 11167 private static boolean notificationMatchesUserId(NotificationRecord r, int userId, 11168 boolean isAutogroupSummary) { 11169 if (isAutogroupSummary) { 11170 return r.getUserId() == userId; 11171 } else { 11172 return 11173 // looking for USER_ALL notifications? match everything 11174 userId == USER_ALL 11175 // a notification sent to USER_ALL matches any query 11176 || r.getUserId() == USER_ALL 11177 // an exact user match 11178 || r.getUserId() == userId; 11179 } 11180 } 11181 11182 /** 11183 * Determine whether the userId applies to the notification in question, either because 11184 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 11185 * because it matches one of the users profiles. 11186 */ 11187 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 11188 return notificationMatchesUserId(r, userId, false) 11189 || mUserProfiles.isCurrentProfile(r.getUserId()); 11190 } 11191 11192 /** 11193 * Cancels all notifications from a given package that have all of the 11194 * {@code mustHaveFlags} and none of the {@code mustNotHaveFlags}. 11195 */ 11196 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, 11197 @Nullable String channelId, int mustHaveFlags, int mustNotHaveFlags, int userId, 11198 int reason) { 11199 final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime(); 11200 mHandler.post(new Runnable() { 11201 @Override 11202 public void run() { 11203 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 11204 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 11205 /* listener= */ null); 11206 11207 synchronized (mNotificationLock) { 11208 FlagChecker flagChecker = (int flags) -> { 11209 if ((flags & mustHaveFlags) != mustHaveFlags) { 11210 return false; 11211 } 11212 if ((flags & mustNotHaveFlags) != 0) { 11213 return false; 11214 } 11215 return true; 11216 }; 11217 cancelAllNotificationsByListLocked(mNotificationList, pkg, 11218 true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 11219 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 11220 null /* listenerName */, true /* wasPosted */, 11221 cancellationElapsedTimeMs); 11222 cancelAllNotificationsByListLocked(mEnqueuedNotifications, pkg, 11223 true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 11224 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 11225 null /* listenerName */, false /* wasPosted */, 11226 cancellationElapsedTimeMs); 11227 mSnoozeHelper.cancel(userId, pkg); 11228 } 11229 } 11230 }); 11231 } 11232 11233 private interface FlagChecker { 11234 // Returns false if these flags do not pass the defined flag test. 11235 public boolean apply(int flags); 11236 } 11237 11238 @FunctionalInterface 11239 private interface GroupChildChecker { 11240 // Returns true if the childRecord is a child of the group defined 11241 // by the rest of the parameters 11242 boolean apply(NotificationRecord childRecord, int userId, String pkg, String groupKey); 11243 } 11244 11245 /** 11246 * Checks that the notification is currently a child of the group 11247 * @param childRecord the notification to check 11248 * @param userId userId of the group 11249 * @param pkg package name of the group 11250 * @param groupKey group key for a current group 11251 * @return true if the childRecord is currently a child of the group 11252 */ 11253 private static boolean isChildOfCurrentGroupChecker(NotificationRecord childRecord, int userId, 11254 String pkg, String groupKey) { 11255 return (childRecord.getUser().getIdentifier() == userId 11256 && childRecord.getSbn().getPackageName().equals(pkg) 11257 && childRecord.getSbn().isGroup() 11258 && !childRecord.getNotification().isGroupSummary() 11259 && TextUtils.equals(groupKey, childRecord.getGroupKey())); 11260 } 11261 11262 /** 11263 * Checks that the notification was originally a child of the group 11264 * @param childRecord the notification to check 11265 * @param userId userId of the group 11266 * @param pkg package name of the group 11267 * @param groupKey original/initial group key for a group that was force grouped 11268 * @return true if the childRecord was originally a child of the group 11269 */ 11270 private static boolean wasChildOfForceRegroupedGroupChecker(NotificationRecord childRecord, 11271 int userId, String pkg, String groupKey) { 11272 return (childRecord.getUser().getIdentifier() == userId 11273 && childRecord.getSbn().getPackageName().equals(pkg) 11274 && childRecord.getSbn().isGroup() 11275 && !childRecord.getNotification().isGroupSummary() 11276 && TextUtils.equals(groupKey, childRecord.getOriginalGroupKey())); 11277 } 11278 11279 @GuardedBy("mNotificationLock") 11280 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList, 11281 @Nullable String pkg, boolean nullPkgIndicatesUserSwitch, @Nullable String channelId, 11282 FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, boolean sendDelete, 11283 int reason, String listenerName, boolean wasPosted, 11284 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 11285 Set<String> childNotifications = null; 11286 for (int i = notificationList.size() - 1; i >= 0; --i) { 11287 NotificationRecord r = notificationList.get(i); 11288 if (includeCurrentProfiles) { 11289 if (!notificationMatchesCurrentProfiles(r, userId)) { 11290 continue; 11291 } 11292 } else if (!notificationMatchesUserId(r, userId, false)) { 11293 continue; 11294 } 11295 // Don't remove notifications to all, if there's no package name specified 11296 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == USER_ALL) { 11297 continue; 11298 } 11299 if (!flagChecker.apply(r.getFlags())) { 11300 continue; 11301 } 11302 if (pkg != null && !r.getSbn().getPackageName().equals(pkg)) { 11303 continue; 11304 } 11305 if (channelId != null && !channelId.equals(r.getChannel().getId())) { 11306 continue; 11307 } 11308 if (r.getSbn().isGroup() && r.getNotification().isGroupChild()) { 11309 if (childNotifications == null) { 11310 childNotifications = new HashSet<>(); 11311 } 11312 childNotifications.add(r.getKey()); 11313 continue; 11314 } 11315 notificationList.remove(i); 11316 mNotificationsByKey.remove(r.getKey()); 11317 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); 11318 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName, 11319 cancellationElapsedTimeMs); 11320 } 11321 if (childNotifications != null) { 11322 final int M = notificationList.size(); 11323 for (int i = M - 1; i >= 0; i--) { 11324 NotificationRecord r = notificationList.get(i); 11325 if (childNotifications.contains(r.getKey())) { 11326 // dismiss conditions were checked in the first loop and so don't need to be 11327 // checked again 11328 notificationList.remove(i); 11329 mNotificationsByKey.remove(r.getKey()); 11330 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); 11331 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName, 11332 cancellationElapsedTimeMs); 11333 } 11334 } 11335 mAttentionHelper.updateLightsLocked(); 11336 } 11337 } 11338 11339 void snoozeNotificationInt(int callingUid, INotificationListener token, String key, 11340 long duration, String snoozeCriterionId) { 11341 final String packageName; 11342 final long notificationUpdateTimeMs; 11343 11344 synchronized (mNotificationLock) { 11345 final ManagedServiceInfo listener = mListeners.checkServiceTokenLocked(token); 11346 if (listener == null) { 11347 return; 11348 } 11349 packageName = listener.component.getPackageName(); 11350 String listenerName = listener.component.toShortString(); 11351 if ((duration <= 0 && snoozeCriterionId == null) || key == null) { 11352 return; 11353 } 11354 11355 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key); 11356 if (r == null) { 11357 return; 11358 } 11359 if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){ 11360 return; 11361 } 11362 notificationUpdateTimeMs = r.getUpdateTimeMs(); 11363 11364 if (DBG) { 11365 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration, 11366 snoozeCriterionId, listenerName)); 11367 } 11368 // Needs to post so that it can cancel notifications not yet enqueued. 11369 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); 11370 } 11371 11372 if (isNotificationRecent(notificationUpdateTimeMs)) { 11373 mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, 11374 callingUid, packageName, /* attributionTag= */ null, /* message= */ null); 11375 } 11376 } 11377 11378 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) { 11379 String listenerName = listener == null ? null : listener.component.toShortString(); 11380 if (DBG) { 11381 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); 11382 } 11383 mSnoozeHelper.repost(key, muteOnReturn); 11384 handleSavePolicyFile(); 11385 } 11386 11387 private boolean isNotificationRecent(long notificationUpdateTimeMs) { 11388 if (!rapidClearNotificationsByListenerAppOpEnabled()) { 11389 return false; 11390 } 11391 return System.currentTimeMillis() - notificationUpdateTimeMs 11392 < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS; 11393 } 11394 11395 @GuardedBy("mNotificationLock") 11396 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 11397 ManagedServiceInfo listener, boolean includeCurrentProfiles, int mustNotHaveFlags) { 11398 final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime(); 11399 mHandler.post(new Runnable() { 11400 @Override 11401 public void run() { 11402 synchronized (mNotificationLock) { 11403 String listenerName = 11404 listener == null ? null : listener.component.toShortString(); 11405 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 11406 null, userId, 0, 0, reason, listenerName); 11407 11408 FlagChecker flagChecker = (int flags) -> { 11409 int flagsToCheck = mustNotHaveFlags; 11410 if (REASON_LISTENER_CANCEL_ALL == reason 11411 || REASON_CANCEL_ALL == reason) { 11412 flagsToCheck |= FLAG_BUBBLE; 11413 } 11414 if ((flags & flagsToCheck) != 0) { 11415 return false; 11416 } 11417 return true; 11418 }; 11419 11420 cancelAllNotificationsByListLocked(mNotificationList, 11421 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker, 11422 includeCurrentProfiles, userId, true /*sendDelete*/, reason, 11423 listenerName, true, cancellationElapsedTimeMs); 11424 cancelAllNotificationsByListLocked(mEnqueuedNotifications, 11425 null, false /*nullPkgIndicatesUserSwitch*/, null, 11426 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/, 11427 reason, listenerName, false, cancellationElapsedTimeMs); 11428 mSnoozeHelper.cancel(userId, includeCurrentProfiles); 11429 } 11430 } 11431 }); 11432 } 11433 11434 // Warning: The caller is responsible for invoking updateLightsLocked(). 11435 @GuardedBy("mNotificationLock") 11436 private void cancelGroupChildrenLocked(int userId, String pkg, int callingUid, int callingPid, 11437 String listenerName, boolean sendDelete, FlagChecker flagChecker, 11438 GroupChildChecker groupChildChecker, String groupKey, int reason, 11439 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 11440 if (pkg == null) { 11441 if (DBG) Slog.e(TAG, "No package for group summary"); 11442 return; 11443 } 11444 11445 cancelGroupChildrenByListLocked(mNotificationList, userId, pkg, callingUid, callingPid, 11446 listenerName, sendDelete, true, flagChecker, groupChildChecker, groupKey, 11447 reason, cancellationElapsedTimeMs); 11448 cancelGroupChildrenByListLocked(mEnqueuedNotifications, userId, pkg, callingUid, callingPid, 11449 listenerName, sendDelete, false, flagChecker, groupChildChecker, groupKey, 11450 reason, cancellationElapsedTimeMs); 11451 } 11452 11453 @GuardedBy("mNotificationLock") 11454 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList, 11455 int userId, String pkg, int callingUid, int callingPid, 11456 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker, 11457 GroupChildChecker grouChildChecker, String groupKey, int reason, 11458 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 11459 final int childReason = REASON_GROUP_SUMMARY_CANCELED; 11460 for (int i = notificationList.size() - 1; i >= 0; i--) { 11461 final NotificationRecord childR = notificationList.get(i); 11462 final StatusBarNotification childSbn = childR.getSbn(); 11463 if (grouChildChecker.apply(childR, userId, pkg, groupKey) 11464 && (flagChecker == null || flagChecker.apply(childR.getFlags())) 11465 && (!childR.getChannel().isImportantConversation() || reason != REASON_CANCEL)) { 11466 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 11467 childSbn.getTag(), userId, 0, 0, childReason, listenerName); 11468 notificationList.remove(i); 11469 mNotificationsByKey.remove(childR.getKey()); 11470 cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName, 11471 cancellationElapsedTimeMs); 11472 } 11473 } 11474 } 11475 11476 @GuardedBy("mNotificationLock") 11477 @NonNull 11478 List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg, 11479 String groupKey, int userId) { 11480 List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId); 11481 records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId)); 11482 return records; 11483 } 11484 11485 @GuardedBy("mNotificationLock") 11486 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg, 11487 String groupKey, int userId) { 11488 List<NotificationRecord> records = new ArrayList<>(); 11489 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId)); 11490 records.addAll( 11491 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId)); 11492 return records; 11493 } 11494 11495 @GuardedBy("mNotificationLock") 11496 private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) { 11497 NotificationRecord r = findNotificationByKeyLocked(key); 11498 if (r == null) { 11499 r = mSnoozeHelper.getNotification(key); 11500 } 11501 return r; 11502 11503 } 11504 11505 @GuardedBy("mNotificationLock") 11506 @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) 11507 private @NonNull List<NotificationRecord> findAppNotificationByListLocked( 11508 ArrayList<NotificationRecord> list, String pkg, int userId) { 11509 List<NotificationRecord> records = new ArrayList<>(); 11510 final int len = list.size(); 11511 for (int i = 0; i < len; i++) { 11512 NotificationRecord r = list.get(i); 11513 if (notificationMatchesUserId(r, userId, false) 11514 && r.getSbn().getPackageName().equals(pkg)) { 11515 records.add(r); 11516 } 11517 } 11518 return records; 11519 } 11520 11521 @GuardedBy("mNotificationLock") 11522 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( 11523 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) { 11524 List<NotificationRecord> records = new ArrayList<>(); 11525 final int len = list.size(); 11526 for (int i = 0; i < len; i++) { 11527 NotificationRecord r = list.get(i); 11528 if (notificationMatchesUserId(r, userId, false) && r.getGroupKey().equals(groupKey) 11529 && r.getSbn().getPackageName().equals(pkg)) { 11530 records.add(r); 11531 } 11532 } 11533 return records; 11534 } 11535 11536 // Searches both enqueued and posted notifications by key. 11537 // TODO: need to combine a bunch of these getters with slightly different behavior. 11538 // TODO: Should enqueuing just add to mNotificationsByKey instead? 11539 @GuardedBy("mNotificationLock") 11540 private NotificationRecord findNotificationByKeyLocked(String key) { 11541 NotificationRecord r; 11542 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) { 11543 return r; 11544 } 11545 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) { 11546 return r; 11547 } 11548 return null; 11549 } 11550 11551 @GuardedBy("mNotificationLock") 11552 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) { 11553 NotificationRecord r; 11554 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) { 11555 return r; 11556 } 11557 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId)) 11558 != null) { 11559 return r; 11560 } 11561 11562 return null; 11563 } 11564 11565 @Nullable 11566 private static NotificationRecord findNotificationByListLocked( 11567 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { 11568 final int len = list.size(); 11569 for (int i = 0; i < len; i++) { 11570 NotificationRecord r = list.get(i); 11571 if (notificationMatchesUserId(r, userId, (r.getFlags() & GroupHelper.BASE_FLAGS) != 0) 11572 && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag) 11573 && r.getSbn().getPackageName().equals(pkg)) { 11574 return r; 11575 } 11576 } 11577 return null; 11578 } 11579 11580 private static List<NotificationRecord> findNotificationsByListLocked( 11581 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { 11582 List<NotificationRecord> matching = new ArrayList<>(); 11583 final int len = list.size(); 11584 for (int i = 0; i < len; i++) { 11585 NotificationRecord r = list.get(i); 11586 if (notificationMatchesUserId(r, userId, false) && r.getSbn().getId() == id 11587 && TextUtils.equals(r.getSbn().getTag(), tag) 11588 && r.getSbn().getPackageName().equals(pkg)) { 11589 matching.add(r); 11590 } 11591 } 11592 return matching; 11593 } 11594 11595 @Nullable 11596 private static NotificationRecord findNotificationByListLocked( 11597 ArrayList<NotificationRecord> list, String key) { 11598 final int N = list.size(); 11599 for (int i = 0; i < N; i++) { 11600 if (key.equals(list.get(i).getKey())) { 11601 return list.get(i); 11602 } 11603 } 11604 return null; 11605 } 11606 11607 @GuardedBy("mNotificationLock") 11608 int indexOfNotificationLocked(String key) { 11609 final int N = mNotificationList.size(); 11610 for (int i = 0; i < N; i++) { 11611 if (key.equals(mNotificationList.get(i).getKey())) { 11612 return i; 11613 } 11614 } 11615 return -1; 11616 } 11617 11618 private void hideNotificationsForPackages(@NonNull String[] pkgs, @NonNull int[] uidList) { 11619 synchronized (mNotificationLock) { 11620 Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet()); 11621 List<String> pkgList = Arrays.asList(pkgs); 11622 List<NotificationRecord> changedNotifications = new ArrayList<>(); 11623 int numNotifications = mNotificationList.size(); 11624 for (int i = 0; i < numNotifications; i++) { 11625 NotificationRecord rec = mNotificationList.get(i); 11626 if (pkgList.contains(rec.getSbn().getPackageName()) 11627 && uidSet.contains(rec.getUid())) { 11628 rec.setHidden(true); 11629 changedNotifications.add(rec); 11630 } 11631 } 11632 11633 mListeners.notifyHiddenLocked(changedNotifications); 11634 } 11635 } 11636 11637 private void unhideNotificationsForPackages(@NonNull String[] pkgs, 11638 @NonNull int[] uidList) { 11639 synchronized (mNotificationLock) { 11640 Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet()); 11641 List<String> pkgList = Arrays.asList(pkgs); 11642 List<NotificationRecord> changedNotifications = new ArrayList<>(); 11643 int numNotifications = mNotificationList.size(); 11644 for (int i = 0; i < numNotifications; i++) { 11645 NotificationRecord rec = mNotificationList.get(i); 11646 if (pkgList.contains(rec.getSbn().getPackageName()) 11647 && uidSet.contains(rec.getUid())) { 11648 rec.setHidden(false); 11649 changedNotifications.add(rec); 11650 } 11651 } 11652 11653 mListeners.notifyUnhiddenLocked(changedNotifications); 11654 } 11655 } 11656 11657 private void cancelNotificationsWhenEnterLockDownMode(int userId) { 11658 synchronized (mNotificationLock) { 11659 int numNotifications = mNotificationList.size(); 11660 for (int i = 0; i < numNotifications; i++) { 11661 NotificationRecord rec = mNotificationList.get(i); 11662 if (rec.getUser().getIdentifier() != userId) { 11663 continue; 11664 } 11665 mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN, 11666 rec.getStats()); 11667 } 11668 11669 } 11670 } 11671 11672 private void postNotificationsWhenExitLockDownMode(int userId) { 11673 synchronized (mNotificationLock) { 11674 int numNotifications = mNotificationList.size(); 11675 // Set the delay to spread out the burst of notifications. 11676 long delay = 0; 11677 for (int i = 0; i < numNotifications; i++) { 11678 NotificationRecord rec = mNotificationList.get(i); 11679 if (rec.getUser().getIdentifier() != userId) { 11680 continue; 11681 } 11682 mHandler.postDelayed(() -> { 11683 synchronized (mNotificationLock) { 11684 mListeners.notifyPostedLocked(rec, rec); 11685 } 11686 }, delay); 11687 delay += 20; 11688 } 11689 } 11690 } 11691 11692 protected boolean isCallingUidSystem() { 11693 final int uid = Binder.getCallingUid(); 11694 return uid == Process.SYSTEM_UID; 11695 } 11696 11697 protected boolean isCallingAppIdSystem() { 11698 final int uid = Binder.getCallingUid(); 11699 final int appid = UserHandle.getAppId(uid); 11700 return appid == Process.SYSTEM_UID; 11701 } 11702 11703 protected boolean isUidSystemOrPhone(int uid) { 11704 final int appid = UserHandle.getAppId(uid); 11705 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID 11706 || uid == Process.ROOT_UID); 11707 } 11708 11709 // TODO: Most calls should probably move to isCallerSystem. 11710 protected boolean isCallerSystemOrPhone() { 11711 return isUidSystemOrPhone(Binder.getCallingUid()); 11712 } 11713 11714 @VisibleForTesting 11715 protected boolean isCallerSystemOrSystemUi() { 11716 if (isCallerSystemOrPhone()) { 11717 return true; 11718 } 11719 return getContext().checkCallingPermission(STATUS_BAR_SERVICE) 11720 == PERMISSION_GRANTED; 11721 } 11722 11723 private boolean isCallerSystemOrSystemUiOrShell() { 11724 int callingUid = Binder.getCallingUid(); 11725 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 11726 return true; 11727 } 11728 return isCallerSystemOrSystemUi(); 11729 } 11730 11731 private void checkCallerIsSystemOrShell() { 11732 int callingUid = Binder.getCallingUid(); 11733 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 11734 return; 11735 } 11736 checkCallerIsSystem(); 11737 } 11738 11739 private void checkCallerIsSystem() { 11740 if (isCallerSystemOrPhone()) { 11741 return; 11742 } 11743 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 11744 } 11745 11746 private void checkCallerIsSystemOrSystemUiOrShell() { 11747 checkCallerIsSystemOrSystemUiOrShell(null); 11748 } 11749 11750 private void checkCallerIsSystemOrSystemUiOrShell(String message) { 11751 int callingUid = Binder.getCallingUid(); 11752 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 11753 return; 11754 } 11755 if (isCallerSystemOrPhone()) { 11756 return; 11757 } 11758 getContext().enforceCallingPermission(STATUS_BAR_SERVICE, 11759 message); 11760 } 11761 11762 private void checkCallerIsSystemOrSameApp(String pkg) { 11763 if (isCallerSystemOrPhone()) { 11764 return; 11765 } 11766 checkCallerIsSameApp(pkg); 11767 } 11768 11769 private boolean isCallerAndroid(String callingPkg, int uid) { 11770 return isUidSystemOrPhone(uid) && callingPkg != null 11771 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg); 11772 } 11773 11774 /** 11775 * Check if the notification is of a category type that is restricted to system use only, 11776 * if so throw SecurityException 11777 */ 11778 private void checkRestrictedCategories(final Notification notification) { 11779 try { 11780 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) { 11781 return; 11782 } 11783 } catch (RemoteException re) { 11784 if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category " 11785 + "restrictions check thus the check will be done anyway"); 11786 } 11787 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category) 11788 || Notification.CATEGORY_CAR_WARNING.equals(notification.category) 11789 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) { 11790 getContext().enforceCallingPermission( 11791 android.Manifest.permission.SEND_CATEGORY_CAR_NOTIFICATIONS, 11792 String.format("Notification category %s restricted", 11793 notification.category)); 11794 } 11795 } 11796 11797 @VisibleForTesting 11798 boolean isCallerInstantApp(int callingUid, int userId) { 11799 // System is always allowed to act for ephemeral apps. 11800 if (isUidSystemOrPhone(callingUid)) { 11801 return false; 11802 } 11803 11804 if (userId == USER_ALL) { 11805 userId = USER_SYSTEM; 11806 } 11807 11808 try { 11809 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 11810 if (pkgs == null) { 11811 throw new SecurityException("Unknown uid " + callingUid); 11812 } 11813 final String pkg = pkgs[0]; 11814 mAppOps.checkPackage(callingUid, pkg); 11815 11816 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId); 11817 if (ai == null) { 11818 throw new SecurityException("Unknown package " + pkg); 11819 } 11820 return ai.isInstantApp(); 11821 } catch (RemoteException re) { 11822 throw new SecurityException("Unknown uid " + callingUid, re); 11823 } 11824 } 11825 11826 private void checkCallerIsSameApp(String pkg) { 11827 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId()); 11828 } 11829 11830 private void checkCallerIsSameApp(String pkg, int uid, int userId) { 11831 if (uid == Process.ROOT_UID && ROOT_PKG.equals(pkg)) { 11832 return; 11833 } 11834 if (!mPackageManagerInternal.isSameApp(pkg, uid, userId)) { 11835 throw new SecurityException("Package " + pkg + " is not owned by uid " + uid); 11836 } 11837 } 11838 11839 private boolean isCallerSameApp(String pkg, int uid, int userId) { 11840 try { 11841 checkCallerIsSameApp(pkg, uid, userId); 11842 return true; 11843 } catch (SecurityException e) { 11844 return false; 11845 } 11846 } 11847 11848 private static String callStateToString(int state) { 11849 switch (state) { 11850 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 11851 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 11852 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 11853 default: return "CALL_STATE_UNKNOWN_" + state; 11854 } 11855 } 11856 11857 /** 11858 * Generates a NotificationRankingUpdate from 'sbns', considering only 11859 * notifications visible to the given listener. 11860 */ 11861 @GuardedBy("mNotificationLock") 11862 NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 11863 final int N = mNotificationList.size(); 11864 final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>(); 11865 11866 for (int i = 0; i < N; i++) { 11867 NotificationRecord record = mNotificationList.get(i); 11868 if (isInLockDownMode(record.getUser().getIdentifier())) { 11869 continue; 11870 } 11871 if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) { 11872 continue; 11873 } 11874 final String key = record.getSbn().getKey(); 11875 final NotificationListenerService.Ranking ranking = 11876 new NotificationListenerService.Ranking(); 11877 ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions(); 11878 ArrayList<CharSequence> smartReplies = record.getSmartReplies(); 11879 boolean hasSensitiveContent = record.hasSensitiveContent(); 11880 if (redactSensitiveNotificationsFromUntrustedListeners()) { 11881 if (!mListeners.isUidTrusted(info.uid) && mListeners.hasSensitiveContent(record)) { 11882 smartActions = null; 11883 smartReplies = null; 11884 } 11885 } 11886 ranking.populate( 11887 key, 11888 rankings.size(), 11889 !record.isIntercepted(), 11890 record.getPackageVisibilityOverride(), 11891 record.getSuppressedVisualEffects(), 11892 record.getImportance(), 11893 record.getImportanceExplanation(), 11894 record.getSbn().getOverrideGroupKey(), 11895 record.getChannel(), 11896 record.getPeopleOverride(), 11897 record.getSnoozeCriteria(), 11898 record.canShowBadge(), 11899 record.getUserSentiment(), 11900 record.isHidden(), 11901 record.getLastAudiblyAlertedMs(), 11902 record.getSound() != null || record.getVibration() != null, 11903 smartActions, 11904 smartReplies, 11905 record.canBubble(), 11906 record.isTextChanged(), 11907 record.isConversation(), 11908 record.getShortcutInfo(), 11909 record.getRankingScore() == 0 11910 ? RANKING_UNCHANGED 11911 : (record.getRankingScore() > 0 ? RANKING_PROMOTED : RANKING_DEMOTED), 11912 record.getNotification().isBubbleNotification(), 11913 record.getProposedImportance(), 11914 hasSensitiveContent, 11915 record.getSummarization() 11916 ); 11917 rankings.add(ranking); 11918 } 11919 11920 return new NotificationRankingUpdate( 11921 rankings.toArray(new NotificationListenerService.Ranking[0])); 11922 } 11923 11924 boolean isInLockDownMode(int userId) { 11925 return mStrongAuthTracker.isInLockDownMode(userId); 11926 } 11927 11928 boolean hasCompanionDevice(ManagedServiceInfo info) { 11929 return hasCompanionDevice(info.component.getPackageName(), 11930 info.userid, /* withDeviceProfile= */ null); 11931 } 11932 11933 private boolean hasCompanionDevice(String pkg, @UserIdInt int userId, 11934 @Nullable Set</* @AssociationRequest.DeviceProfile */ String> withDeviceProfiles) { 11935 if (mCompanionManager == null) { 11936 mCompanionManager = getCompanionManager(); 11937 } 11938 // Companion mgr doesn't exist on all device types 11939 if (mCompanionManager == null) { 11940 return false; 11941 } 11942 final long identity = Binder.clearCallingIdentity(); 11943 try { 11944 List<AssociationInfo> associations = mCompanionManager.getAssociations(pkg, userId); 11945 for (AssociationInfo association : associations) { 11946 if (withDeviceProfiles == null || withDeviceProfiles.contains( 11947 association.getDeviceProfile())) { 11948 return true; 11949 } 11950 } 11951 } catch (SecurityException se) { 11952 // Not a privileged listener 11953 } catch (RemoteException re) { 11954 Slog.e(TAG, "Cannot reach companion device service", re); 11955 } catch (Exception e) { 11956 Slog.e(TAG, "Cannot verify caller pkg=" + pkg + ", userId=" + userId, e); 11957 } finally { 11958 Binder.restoreCallingIdentity(identity); 11959 } 11960 return false; 11961 } 11962 11963 protected ICompanionDeviceManager getCompanionManager() { 11964 return ICompanionDeviceManager.Stub.asInterface( 11965 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); 11966 } 11967 11968 @VisibleForTesting 11969 boolean isVisibleToListener(StatusBarNotification sbn, int notificationType, 11970 ManagedServiceInfo listener) { 11971 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 11972 return false; 11973 } 11974 if (!isInteractionVisibleToListener(listener, sbn.getUserId())) { 11975 return false; 11976 } 11977 NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey); 11978 if (nls != null 11979 && (!nls.isTypeAllowed(notificationType) 11980 || !nls.isPackageAllowed( 11981 new VersionedPackage(sbn.getPackageName(), sbn.getUid())))) { 11982 return false; 11983 } 11984 return true; 11985 } 11986 11987 /** 11988 * Returns whether the given assistant should be informed about interactions on the given user. 11989 * 11990 * Normally an assistant would be able to see all interactions on the current user and any 11991 * associated profiles because they are notification listeners, but since NASes have one 11992 * instance per user, we want to filter out interactions that are not for the user that the 11993 * given NAS is bound in. 11994 */ 11995 @VisibleForTesting 11996 boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) { 11997 boolean isAssistantService = isServiceTokenValid(info.getService()); 11998 return !isAssistantService || info.isSameUser(userId); 11999 } 12000 12001 private boolean isServiceTokenValid(IInterface service) { 12002 synchronized (mNotificationLock) { 12003 return mAssistants.isServiceTokenValidLocked(service); 12004 } 12005 } 12006 12007 private boolean isPackageSuspendedForUser(String pkg, int uid) { 12008 final long identity = Binder.clearCallingIdentity(); 12009 int userId = UserHandle.getUserId(uid); 12010 try { 12011 return mPackageManager.isPackageSuspendedForUser(pkg, userId); 12012 } catch (RemoteException re) { 12013 throw new SecurityException("Could not talk to package manager service"); 12014 } catch (IllegalArgumentException ex) { 12015 // Package not found. 12016 return false; 12017 } finally { 12018 Binder.restoreCallingIdentity(identity); 12019 } 12020 } 12021 12022 @VisibleForTesting 12023 boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) { 12024 boolean canUseManagedServices = true; 12025 if (requiredPermission != null) { 12026 try { 12027 if (mPackageManager.checkPermission(requiredPermission, pkg, userId) 12028 != PERMISSION_GRANTED) { 12029 canUseManagedServices = false; 12030 } 12031 } catch (RemoteException e) { 12032 Slog.e(TAG, "can't talk to pm", e); 12033 } 12034 } 12035 12036 return canUseManagedServices; 12037 } 12038 12039 private class TrimCache { 12040 StatusBarNotification heavy; 12041 StatusBarNotification sbnClone; 12042 StatusBarNotification sbnCloneLight; 12043 12044 TrimCache(StatusBarNotification sbn) { 12045 heavy = sbn; 12046 } 12047 12048 StatusBarNotification ForListener(ManagedServiceInfo info) { 12049 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 12050 if (sbnCloneLight == null) { 12051 sbnCloneLight = heavy.cloneLight(); 12052 } 12053 return sbnCloneLight; 12054 } else { 12055 if (sbnClone == null) { 12056 sbnClone = heavy.clone(); 12057 } 12058 return sbnClone; 12059 } 12060 } 12061 } 12062 12063 public class NotificationAssistants extends ManagedServices { 12064 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants"; 12065 12066 private static final String ATT_TYPES = "types"; 12067 private static final String TAG_DENIED = "user_denied_adjustments"; 12068 private static final String TAG_DENIED_KEY = "adjustment"; 12069 private static final String ATT_DENIED_KEY = "key"; 12070 private static final String ATT_DENIED_KEY_APPS = "denied_apps"; 12071 private static final String TAG_ENABLED_TYPES = "enabled_classification_types"; 12072 private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments"; 12073 12074 private final Object mLock = new Object(); 12075 12076 @GuardedBy("mLock") 12077 private Set<Integer> mAllowedClassificationTypes = new ArraySet<>(); 12078 12079 @GuardedBy("mLock") 12080 private Set<String> mAllowedAdjustments = new ArraySet<>(); 12081 12082 @GuardedBy("mLock") 12083 private Set<String> mDeniedAdjustments = new ArraySet<>(); 12084 12085 @GuardedBy("mLock") 12086 private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>(); 12087 12088 // key: Adjustment key. value - list of pkgs that we shouldn't apply adjustments with that 12089 // key to 12090 @GuardedBy("mLock") 12091 private Map<String, Set<String>> mAdjustmentKeyDeniedPackages = new ArrayMap<>(); 12092 12093 protected ComponentName mDefaultFromConfig = null; 12094 12095 @Override 12096 protected void loadDefaultsFromConfig() { 12097 loadDefaultsFromConfig(true); 12098 } 12099 12100 protected void loadDefaultsFromConfig(boolean addToDefault) { 12101 ArraySet<String> assistants = new ArraySet<>(); 12102 assistants.addAll(Arrays.asList(mContext.getResources().getString( 12103 com.android.internal.R.string.config_defaultAssistantAccessComponent) 12104 .split(ManagedServices.ENABLED_SERVICES_SEPARATOR))); 12105 for (int i = 0; i < assistants.size(); i++) { 12106 ComponentName assistantCn = ComponentName 12107 .unflattenFromString(assistants.valueAt(i)); 12108 String packageName = assistants.valueAt(i); 12109 if (assistantCn != null) { 12110 packageName = assistantCn.getPackageName(); 12111 } 12112 if (TextUtils.isEmpty(packageName)) { 12113 continue; 12114 } 12115 ArraySet<ComponentName> approved = queryPackageForServices(packageName, 12116 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM); 12117 if (approved.contains(assistantCn)) { 12118 if (addToDefault) { 12119 // add the default loaded from config file to mDefaultComponents and 12120 // mDefaultPackages 12121 addDefaultComponentOrPackage(assistantCn.flattenToString()); 12122 } else { 12123 // otherwise, store in the mDefaultFromConfig for NAS settings migration 12124 mDefaultFromConfig = assistantCn; 12125 } 12126 } 12127 } 12128 } 12129 12130 ComponentName getDefaultFromConfig() { 12131 if (mDefaultFromConfig == null) { 12132 loadDefaultsFromConfig(false); 12133 } 12134 return mDefaultFromConfig; 12135 } 12136 12137 @Override 12138 protected void upgradeUserSet() { 12139 for (int userId: mApproved.keySet()) { 12140 ArraySet<String> userSetServices = mUserSetServices.get(userId); 12141 mIsUserChanged.put(userId, (userSetServices != null && userSetServices.size() > 0)); 12142 } 12143 } 12144 12145 @Override 12146 protected void addApprovedList(String approved, int userId, boolean isPrimary, 12147 String userSet) { 12148 if (!TextUtils.isEmpty(approved)) { 12149 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR); 12150 if (approvedArray.length > 1) { 12151 Slog.d(TAG, "More than one approved assistants"); 12152 approved = approvedArray[0]; 12153 } 12154 } 12155 super.addApprovedList(approved, userId, isPrimary, userSet); 12156 } 12157 12158 public NotificationAssistants(Context context, Object lock, UserProfiles up, 12159 IPackageManager pm) { 12160 super(context, lock, up, pm); 12161 12162 if (!notificationClassification()) { 12163 // Add all default allowed adjustment types. 12164 for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) { 12165 mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]); 12166 } 12167 } else { 12168 mAllowedClassificationTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES)); 12169 } 12170 } 12171 12172 @Override 12173 protected Config getConfig() { 12174 Config c = new Config(); 12175 c.caption = "notification assistant"; 12176 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; 12177 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS; 12178 c.secureSettingName = Secure.ENABLED_NOTIFICATION_ASSISTANT; 12179 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; 12180 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 12181 c.clientLabel = R.string.notification_ranker_binding_label; 12182 return c; 12183 } 12184 12185 @Override 12186 protected IInterface asInterface(IBinder binder) { 12187 return INotificationListener.Stub.asInterface(binder); 12188 } 12189 12190 @Override 12191 protected boolean checkType(IInterface service) { 12192 return service instanceof INotificationListener; 12193 } 12194 12195 @Override 12196 protected void onServiceAdded(ManagedServiceInfo info) { 12197 mListeners.registerGuestService(info); 12198 } 12199 12200 @Override 12201 protected void ensureFilters(ServiceInfo si, int userId) { 12202 // nothing to filter; no user visible settings for types/packages like other 12203 // listeners 12204 } 12205 12206 @Override 12207 @GuardedBy("mNotificationLock") 12208 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 12209 mListeners.unregisterService(removed.service, removed.userid); 12210 } 12211 12212 @Override 12213 public void onUserUnlocked(int user) { 12214 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); 12215 // force rebind the assistant, as it might be keeping its own state in user locked 12216 // storage 12217 rebindServices(true, user); 12218 } 12219 12220 @Override 12221 protected boolean allowRebindForParentUser() { 12222 return false; 12223 } 12224 12225 @Override 12226 protected String getRequiredPermission() { 12227 // only signature/privileged apps can be bound. 12228 return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE; 12229 } 12230 12231 protected Set<String> getAllowedAssistantAdjustments() { 12232 synchronized (mLock) { 12233 if (notificationClassification()) { 12234 Set<String> types = new HashSet<>(Set.of(DEFAULT_ALLOWED_ADJUSTMENTS)); 12235 types.removeAll(mDeniedAdjustments); 12236 return types; 12237 } else { 12238 Set<String> types = new HashSet<>(); 12239 types.addAll(mAllowedAdjustments); 12240 return types; 12241 } 12242 } 12243 } 12244 12245 protected boolean isAdjustmentAllowed(String type) { 12246 synchronized (mLock) { 12247 if (notificationClassification()) { 12248 return List.of(DEFAULT_ALLOWED_ADJUSTMENTS).contains(type) 12249 && !mDeniedAdjustments.contains(type); 12250 } else { 12251 return mAllowedAdjustments.contains(type); 12252 } 12253 } 12254 } 12255 12256 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 12257 protected @NonNull boolean isAdjustmentKeyTypeAllowed(@Adjustment.Types int type) { 12258 synchronized (mLock) { 12259 if (notificationClassification()) { 12260 return mAllowedClassificationTypes.contains(type); 12261 } 12262 } 12263 return false; 12264 } 12265 12266 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 12267 protected @NonNull int[] getAllowedClassificationTypes() { 12268 synchronized (mLock) { 12269 if (notificationClassification()) { 12270 return mAllowedClassificationTypes.stream() 12271 .mapToInt(Integer::intValue).toArray(); 12272 } 12273 } 12274 return new int[]{}; 12275 } 12276 12277 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 12278 public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type, 12279 boolean enabled) { 12280 if (!android.service.notification.Flags.notificationClassification()) { 12281 return; 12282 } 12283 synchronized (mLock) { 12284 if (enabled) { 12285 mAllowedClassificationTypes.add(type); 12286 } else { 12287 mAllowedClassificationTypes.remove(type); 12288 } 12289 } 12290 } 12291 12292 protected @NonNull String[] getAdjustmentDeniedPackages(@Adjustment.Keys String key) { 12293 synchronized (mLock) { 12294 if (notificationClassificationUi() || nmSummarization() | nmSummarizationUi()) { 12295 return mAdjustmentKeyDeniedPackages.getOrDefault( 12296 key, new ArraySet<>()).toArray(new String[0]); 12297 } 12298 } 12299 return new String[]{}; 12300 } 12301 12302 protected @NonNull boolean isAdjustmentAllowedForPackage(@Adjustment.Keys String key, 12303 String pkg) { 12304 synchronized (mLock) { 12305 if (notificationClassificationUi() || nmSummarization() | nmSummarizationUi()) { 12306 return !mAdjustmentKeyDeniedPackages.getOrDefault( 12307 key, new ArraySet<>()).contains(pkg); 12308 } 12309 } 12310 return true; 12311 } 12312 12313 public void setAdjustmentSupportedForPackage(@Adjustment.Keys String key, String pkg, 12314 boolean enabled) { 12315 if (!(notificationClassificationUi() || nmSummarization() | nmSummarizationUi())) { 12316 return; 12317 } 12318 synchronized (mLock) { 12319 mAdjustmentKeyDeniedPackages.putIfAbsent(key, new ArraySet<>()); 12320 if (enabled) { 12321 mAdjustmentKeyDeniedPackages.get(key).remove(pkg); 12322 } else { 12323 mAdjustmentKeyDeniedPackages.get(key).add(pkg); 12324 } 12325 } 12326 } 12327 12328 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) { 12329 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12330 ArrayList<String> keys = new ArrayList<>(records.size()); 12331 for (NotificationRecord r : records) { 12332 boolean sbnVisible = isVisibleToListener( 12333 r.getSbn(), r.getNotificationType(), info) 12334 && info.isSameUser(r.getUserId()); 12335 if (sbnVisible) { 12336 keys.add(r.getKey()); 12337 } 12338 } 12339 12340 if (!keys.isEmpty()) { 12341 mHandler.post(() -> notifySeen(info, keys)); 12342 } 12343 } 12344 } 12345 12346 protected void onPanelRevealed(int items) { 12347 // send to all currently bounds NASes since notifications from both users will appear in 12348 // the panel 12349 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12350 mHandler.post(() -> { 12351 final INotificationListener assistant = (INotificationListener) info.service; 12352 try { 12353 assistant.onPanelRevealed(items); 12354 } catch (RemoteException ex) { 12355 Slog.e(TAG, "unable to notify assistant (panel revealed): " + info, ex); 12356 } 12357 }); 12358 } 12359 } 12360 12361 protected void onPanelHidden() { 12362 // send to all currently bounds NASes since notifications from both users will appear in 12363 // the panel 12364 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12365 mHandler.post(() -> { 12366 final INotificationListener assistant = (INotificationListener) info.service; 12367 try { 12368 assistant.onPanelHidden(); 12369 } catch (RemoteException ex) { 12370 Slog.e(TAG, "unable to notify assistant (panel hidden): " + info, ex); 12371 } 12372 }); 12373 } 12374 } 12375 12376 boolean hasUserSet(int userId) { 12377 Boolean userSet = mIsUserChanged.get(userId); 12378 return (userSet != null && userSet); 12379 } 12380 12381 void setUserSet(int userId, boolean set) { 12382 mIsUserChanged.put(userId, set); 12383 } 12384 12385 private void notifySeen(final ManagedServiceInfo info, 12386 final ArrayList<String> keys) { 12387 final INotificationListener assistant = (INotificationListener) info.service; 12388 try { 12389 assistant.onNotificationsSeen(keys); 12390 } catch (RemoteException ex) { 12391 Slog.e(TAG, "unable to notify assistant (seen): " + info, ex); 12392 } 12393 } 12394 12395 @GuardedBy("mNotificationLock") 12396 private void onNotificationEnqueuedLocked(final NotificationRecord r) { 12397 final boolean debug = isVerboseLogEnabled(); 12398 if (debug) { 12399 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]"); 12400 } 12401 final StatusBarNotification sbn = r.getSbn(); 12402 12403 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12404 boolean sbnVisible = isVisibleToListener( 12405 sbn, r.getNotificationType(), info) 12406 && info.isSameUser(r.getUserId()); 12407 if (sbnVisible) { 12408 TrimCache trimCache = new TrimCache(sbn); 12409 final INotificationListener assistant = (INotificationListener) info.service; 12410 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 12411 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 12412 12413 try { 12414 if (android.app.Flags.noSbnholder()) { 12415 assistant.onNotificationEnqueuedWithChannelFull(sbnToPost, 12416 r.getChannel(), update); 12417 } else { 12418 final StatusBarNotificationHolder sbnHolder = 12419 new StatusBarNotificationHolder(sbnToPost); 12420 12421 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(), 12422 update); 12423 } 12424 } catch (DeadObjectException ex) { 12425 Slog.wtf(TAG, "unable to notify assistant (enqueued): " + info, ex); 12426 } catch (RemoteException ex) { 12427 Slog.e(TAG, "unable to notify assistant (enqueued): " + info, ex); 12428 } 12429 } 12430 } 12431 } 12432 12433 @GuardedBy("mNotificationLock") 12434 void notifyAssistantVisibilityChangedLocked( 12435 final NotificationRecord r, 12436 final boolean isVisible) { 12437 final String key = r.getSbn().getKey(); 12438 if (DBG) { 12439 Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key); 12440 } 12441 notifyAssistantLocked( 12442 r.getSbn(), 12443 r.getNotificationType(), 12444 true /* sameUserOnly */, 12445 (assistant, unused) -> { 12446 try { 12447 assistant.onNotificationVisibilityChanged(key, isVisible); 12448 } catch (RemoteException ex) { 12449 Slog.e(TAG, "unable to notify assistant (visible): " + assistant, ex); 12450 } 12451 }); 12452 } 12453 12454 @GuardedBy("mNotificationLock") 12455 void notifyAssistantExpansionChangedLocked( 12456 final StatusBarNotification sbn, 12457 final int notificationType, 12458 final boolean isUserAction, 12459 final boolean isExpanded) { 12460 final String key = sbn.getKey(); 12461 notifyAssistantLocked( 12462 sbn, 12463 notificationType, 12464 true /* sameUserOnly */, 12465 (assistant, unused) -> { 12466 try { 12467 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded); 12468 } catch (RemoteException ex) { 12469 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 12470 } 12471 }); 12472 } 12473 12474 @GuardedBy("mNotificationLock") 12475 void notifyAssistantNotificationDirectReplyLocked( 12476 final NotificationRecord r) { 12477 final String key = r.getKey(); 12478 notifyAssistantLocked( 12479 r.getSbn(), 12480 r.getNotificationType(), 12481 true /* sameUserOnly */, 12482 (assistant, unused) -> { 12483 try { 12484 assistant.onNotificationDirectReply(key); 12485 } catch (RemoteException ex) { 12486 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 12487 } 12488 }); 12489 } 12490 12491 @GuardedBy("mNotificationLock") 12492 void notifyAssistantSuggestedReplySent( 12493 final StatusBarNotification sbn, int notificationType, 12494 CharSequence reply, boolean generatedByAssistant) { 12495 final String key = sbn.getKey(); 12496 notifyAssistantLocked( 12497 sbn, 12498 notificationType, 12499 true /* sameUserOnly */, 12500 (assistant, unused) -> { 12501 try { 12502 assistant.onSuggestedReplySent( 12503 key, 12504 reply, 12505 generatedByAssistant 12506 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 12507 : NotificationAssistantService.SOURCE_FROM_APP); 12508 } catch (RemoteException ex) { 12509 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 12510 } 12511 }); 12512 } 12513 12514 @GuardedBy("mNotificationLock") 12515 void notifyAssistantActionClicked( 12516 final NotificationRecord r, Notification.Action action, 12517 boolean generatedByAssistant) { 12518 final String key = r.getSbn().getKey(); 12519 notifyAssistantLocked( 12520 r.getSbn(), 12521 r.getNotificationType(), 12522 true /* sameUserOnly */, 12523 (assistant, unused) -> { 12524 try { 12525 assistant.onActionClicked( 12526 key, 12527 action, 12528 generatedByAssistant 12529 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 12530 : NotificationAssistantService.SOURCE_FROM_APP); 12531 } catch (RemoteException ex) { 12532 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 12533 } 12534 }); 12535 } 12536 12537 /** 12538 * asynchronously notify the assistant that a notification has been snoozed until a 12539 * context 12540 */ 12541 @GuardedBy("mNotificationLock") 12542 private void notifyAssistantSnoozedLocked( 12543 final NotificationRecord r, final String snoozeCriterionId) { 12544 notifyAssistantLocked( 12545 r.getSbn(), 12546 r.getNotificationType(), 12547 true /* sameUserOnly */, 12548 (info, sbnToPost) -> { 12549 try { 12550 if (android.app.Flags.noSbnholder()) { 12551 info.onNotificationSnoozedUntilContextFull( 12552 sbnToPost, snoozeCriterionId); 12553 } else { 12554 final StatusBarNotificationHolder sbnHolder = 12555 new StatusBarNotificationHolder(sbnToPost); 12556 info.onNotificationSnoozedUntilContext( 12557 sbnHolder, snoozeCriterionId); 12558 } 12559 } catch (DeadObjectException ex) { 12560 Slog.wtf(TAG, "unable to notify assistant (snoozed): " + info, ex); 12561 } catch (RemoteException ex) { 12562 Slog.e(TAG, "unable to notify assistant (snoozed): " + info, ex); 12563 } 12564 }); 12565 } 12566 12567 @GuardedBy("mNotificationLock") 12568 void notifyAssistantNotificationClicked(final NotificationRecord r) { 12569 final String key = r.getSbn().getKey(); 12570 notifyAssistantLocked( 12571 r.getSbn(), 12572 r.getNotificationType(), 12573 true /* sameUserOnly */, 12574 (assistant, unused) -> { 12575 try { 12576 assistant.onNotificationClicked(key); 12577 } catch (RemoteException ex) { 12578 Slog.e(TAG, "unable to notify assistant (clicked): " + assistant, ex); 12579 } 12580 }); 12581 } 12582 12583 @GuardedBy("mNotificationLock") 12584 void notifyAssistantFeedbackReceived(final NotificationRecord r, Bundle feedback) { 12585 final StatusBarNotification sbn = r.getSbn(); 12586 12587 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12588 boolean sbnVisible = isVisibleToListener( 12589 sbn, r.getNotificationType(), info) 12590 && info.isSameUser(r.getUserId()); 12591 if (sbnVisible) { 12592 final INotificationListener assistant = (INotificationListener) info.service; 12593 try { 12594 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 12595 assistant.onNotificationFeedbackReceived(sbn.getKey(), update, feedback); 12596 } catch (RemoteException ex) { 12597 Slog.e(TAG, "unable to notify assistant (feedback): " + assistant, ex); 12598 } 12599 } 12600 } 12601 } 12602 12603 /** 12604 * Notifies the assistant something about the specified notification, only assistant 12605 * that is visible to the notification will be notified. 12606 * 12607 * @param sbn the notification object that the update is about. 12608 * @param sameUserOnly should the update be sent to the assistant in the same user only. 12609 * @param callback the callback that provides the assistant to be notified, executed 12610 * in WorkerHandler. 12611 */ 12612 @GuardedBy("mNotificationLock") 12613 private void notifyAssistantLocked( 12614 final StatusBarNotification sbn, 12615 int notificationType, 12616 boolean sameUserOnly, 12617 BiConsumer<INotificationListener, StatusBarNotification> callback) { 12618 TrimCache trimCache = new TrimCache(sbn); 12619 // There should be only one, but it's a list, so while we enforce 12620 // singularity elsewhere, we keep it general here, to avoid surprises. 12621 12622 final boolean debug = isVerboseLogEnabled(); 12623 if (debug) { 12624 Slog.v(TAG, 12625 "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = [" 12626 + sameUserOnly + "], callback = [" + callback + "]"); 12627 } 12628 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12629 boolean sbnVisible = isVisibleToListener(sbn, notificationType, info) 12630 && (!sameUserOnly || info.isSameUser(sbn.getUserId())); 12631 if (debug) { 12632 Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible); 12633 } 12634 if (!sbnVisible) { 12635 continue; 12636 } 12637 final INotificationListener assistant = (INotificationListener) info.service; 12638 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 12639 mHandler.post(() -> callback.accept(assistant, sbnToPost)); 12640 } 12641 } 12642 12643 public boolean isEnabled() { 12644 return !getServices().isEmpty(); 12645 } 12646 12647 protected void resetDefaultAssistantsIfNecessary() { 12648 final List<UserInfo> activeUsers = mUm.getAliveUsers(); 12649 for (UserInfo userInfo : activeUsers) { 12650 int userId = userInfo.getUserHandle().getIdentifier(); 12651 if (!hasUserSet(userId)) { 12652 if (!isNASMigrationDone(userId)) { 12653 resetDefaultFromConfig(); 12654 setNASMigrationDone(userId); 12655 } 12656 Slog.d(TAG, "Approving default notification assistant for user " + userId); 12657 setDefaultAssistantForUser(userId); 12658 } 12659 } 12660 } 12661 12662 protected void resetDefaultFromConfig() { 12663 clearDefaults(); 12664 loadDefaultsFromConfig(); 12665 } 12666 12667 protected void clearDefaults() { 12668 mDefaultComponents.clear(); 12669 mDefaultPackages.clear(); 12670 } 12671 12672 @Override 12673 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, 12674 boolean isPrimary, boolean enabled, boolean userSet) { 12675 // Ensures that only one component is enabled at a time 12676 if (enabled) { 12677 List<ComponentName> allowedComponents = getAllowedComponents(userId); 12678 if (!allowedComponents.isEmpty()) { 12679 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents); 12680 if (currentComponent.flattenToString().equals(pkgOrComponent)) return; 12681 setNotificationAssistantAccessGrantedForUserInternal( 12682 currentComponent, userId, false, userSet); 12683 } 12684 } 12685 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet); 12686 } 12687 12688 private boolean isVerboseLogEnabled() { 12689 return Log.isLoggable("notification_assistant", Log.VERBOSE); 12690 } 12691 12692 private void addDefaultClassificationTypes() { 12693 // Add the default classification types if the list is empty 12694 synchronized (mLock) { 12695 if (mAllowedClassificationTypes.isEmpty()) { 12696 mAllowedClassificationTypes.addAll( 12697 List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES)); 12698 } 12699 } 12700 } 12701 12702 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 12703 @GuardedBy("mNotificationLock") 12704 public void allowAdjustmentType(@Adjustment.Keys String key) { 12705 if (!android.service.notification.Flags.notificationClassification()) { 12706 return; 12707 } 12708 mDeniedAdjustments.remove(key); 12709 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12710 mHandler.post(() -> notifyCapabilitiesChanged(info)); 12711 } 12712 if (KEY_TYPE.equals(key)) { 12713 addDefaultClassificationTypes(); 12714 } 12715 } 12716 12717 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 12718 @GuardedBy("mNotificationLock") 12719 public void disallowAdjustmentType(@Adjustment.Keys String key) { 12720 if (!android.service.notification.Flags.notificationClassification()) { 12721 return; 12722 } 12723 mDeniedAdjustments.add(key); 12724 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 12725 mHandler.post(() -> notifyCapabilitiesChanged(info)); 12726 } 12727 } 12728 12729 @GuardedBy("mNotificationLock") 12730 public void setAdjustmentTypeSupportedState(@UserIdInt int userId, 12731 @Adjustment.Keys String key, boolean supported) { 12732 if (!(android.service.notification.Flags.notificationClassification() 12733 || android.app.Flags.nmSummarizationUi() 12734 || android.app.Flags.nmSummarization())) { 12735 return; 12736 } 12737 HashSet<String> disabledAdjustments = 12738 mNasUnsupported.getOrDefault(userId, new HashSet<>()); 12739 if (supported) { 12740 disabledAdjustments.remove(key); 12741 } else { 12742 disabledAdjustments.add(key); 12743 } 12744 mNasUnsupported.put(userId, disabledAdjustments); 12745 handleSavePolicyFile(); 12746 } 12747 12748 @GuardedBy("mNotificationLock") 12749 public @NonNull Set<String> getUnsupportedAdjustments(@UserIdInt int userId) { 12750 if (!(android.service.notification.Flags.notificationClassification() 12751 || android.app.Flags.nmSummarizationUi() 12752 || android.app.Flags.nmSummarization())) { 12753 return new HashSet<>(); 12754 } 12755 return mNasUnsupported.getOrDefault(userId, new HashSet<>()); 12756 } 12757 12758 private void setNasUnsupportedDefaults(@UserIdInt int userId) { 12759 if (mNasUnsupported != null) { 12760 mNasUnsupported.put(userId, new HashSet(List.of(mDefaultUnsupportedAdjustments))); 12761 handleSavePolicyFile(); 12762 } 12763 } 12764 12765 @Override 12766 protected void writeExtraAttributes(TypedXmlSerializer out, @UserIdInt int approvedUserId) 12767 throws IOException { 12768 if (!android.service.notification.Flags.notificationClassification()) { 12769 return; 12770 } 12771 synchronized (mLock) { 12772 out.attribute(null, ATT_NAS_UNSUPPORTED, TextUtils.join(",", 12773 mNasUnsupported.getOrDefault(approvedUserId, new HashSet<>()))); 12774 } 12775 } 12776 12777 @Override 12778 protected void readExtraAttributes(String tag, TypedXmlPullParser parser, 12779 @UserIdInt int approvedUserId) throws IOException { 12780 if (!android.service.notification.Flags.notificationClassification()) { 12781 return; 12782 } 12783 if (ManagedServices.TAG_MANAGED_SERVICES.equals(tag)) { 12784 final String types = XmlUtils.readStringAttribute(parser, ATT_NAS_UNSUPPORTED); 12785 synchronized (mLock) { 12786 if (types == null) { 12787 setNasUnsupportedDefaults(approvedUserId); 12788 } else { 12789 if (!TextUtils.isEmpty(types)) { 12790 mNasUnsupported.put(approvedUserId, 12791 new HashSet(List.of(types.split(",")))); 12792 } else { 12793 mNasUnsupported.put(approvedUserId, new HashSet()); 12794 } 12795 } 12796 } 12797 } 12798 } 12799 12800 @Override 12801 protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException { 12802 if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())) { 12803 return; 12804 } 12805 synchronized (mLock) { 12806 out.startTag(null, TAG_DENIED); 12807 out.attribute(null, ATT_TYPES, TextUtils.join(",", mDeniedAdjustments)); 12808 for (String key : mAdjustmentKeyDeniedPackages.keySet()) { 12809 Set<String> pkgs = mAdjustmentKeyDeniedPackages.get(key); 12810 if (pkgs != null && !pkgs.isEmpty()) { 12811 out.startTag(null, TAG_DENIED_KEY); 12812 out.attribute(null, ATT_DENIED_KEY, key); 12813 out.attribute(null, ATT_DENIED_KEY_APPS, TextUtils.join(",", pkgs)); 12814 out.endTag(null, TAG_DENIED_KEY); 12815 } 12816 } 12817 out.endTag(null, TAG_DENIED); 12818 out.startTag(null, TAG_ENABLED_TYPES); 12819 out.attribute(null, ATT_TYPES, 12820 TextUtils.join(",", mAllowedClassificationTypes)); 12821 out.endTag(null, TAG_ENABLED_TYPES); 12822 } 12823 } 12824 12825 @Override 12826 protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException { 12827 if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())) { 12828 return; 12829 } 12830 if (TAG_DENIED.equals(tag)) { 12831 final String keys = XmlUtils.readStringAttribute(parser, ATT_TYPES); 12832 synchronized (mLock) { 12833 mDeniedAdjustments.clear(); 12834 if (!TextUtils.isEmpty(keys)) { 12835 mDeniedAdjustments.addAll(Arrays.asList(keys.split(","))); 12836 } 12837 } 12838 } else if (TAG_ENABLED_TYPES.equals(tag)) { 12839 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES); 12840 synchronized (mLock) { 12841 mAllowedClassificationTypes.clear(); 12842 if (!TextUtils.isEmpty(types)) { 12843 List<String> typeList = Arrays.asList(types.split(",")); 12844 for (String type : typeList) { 12845 try { 12846 mAllowedClassificationTypes.add(Integer.parseInt(type)); 12847 } catch (NumberFormatException e) { 12848 Slog.wtf(TAG, "Bad type specified", e); 12849 } 12850 } 12851 } 12852 } 12853 } else if (TAG_DENIED_KEY.equals(tag)) { 12854 final String key = XmlUtils.readStringAttribute(parser, ATT_DENIED_KEY); 12855 final String pkgs = XmlUtils.readStringAttribute(parser, ATT_DENIED_KEY_APPS); 12856 if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(pkgs)) { 12857 List<String> pkgList = Arrays.asList(pkgs.split(",")); 12858 mAdjustmentKeyDeniedPackages.put(key, new ArraySet<>(pkgList)); 12859 } 12860 } 12861 } 12862 12863 private void notifyCapabilitiesChanged(final ManagedServiceInfo info) { 12864 final INotificationListener assistant = (INotificationListener) info.service; 12865 try { 12866 assistant.onAllowedAdjustmentsChanged(); 12867 } catch (RemoteException ex) { 12868 Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex); 12869 } 12870 } 12871 12872 /** 12873 * Fills out {@link BundlePreferences} proto and wraps it in a {@link StatsEvent}. 12874 */ 12875 @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 12876 protected void pullBundlePreferencesStats(List<StatsEvent> events) { 12877 boolean bundlesAllowed = true; 12878 synchronized (mLock) { 12879 List<String> unsupportedAdjustments = new ArrayList( 12880 mNasUnsupported.getOrDefault( 12881 UserHandle.getUserId(Binder.getCallingUid()), 12882 new HashSet(List.of(mDefaultUnsupportedAdjustments))) 12883 ); 12884 bundlesAllowed = !unsupportedAdjustments.contains(Adjustment.KEY_TYPE); 12885 } 12886 12887 int[] allowedBundleTypes = getAllowedClassificationTypes(); 12888 12889 events.add(FrameworkStatsLog.buildStatsEvent( 12890 NOTIFICATION_BUNDLE_PREFERENCES, 12891 /* optional int32 event_id = 1 */ 12892 NotificationPullStatsEvent.NOTIFICATION_BUNDLE_PREFERENCES_PULLED.getId(), 12893 /* optional bool bundles_allowed = 2 */ bundlesAllowed, 12894 /* repeated android.stats.notification.BundleTypes allowed_bundle_types = 3 */ 12895 allowedBundleTypes)); 12896 } 12897 } 12898 12899 /** 12900 * Asynchronously notify all listeners about a posted (new or updated) notification. This 12901 * should be called from {@link PostNotificationRunnable} to "complete" the post (since SysUI is 12902 * one of the NLSes, and will display it to the user). 12903 * 12904 * <p>This method will call {@link PostNotificationTracker#finish} on the supplied tracker 12905 * when every {@link NotificationListenerService} has received the news. 12906 * 12907 * <p>Also takes care of removing a notification that has been visible to a listener before, 12908 * but isn't anymore. 12909 */ 12910 @GuardedBy("mNotificationLock") 12911 private void notifyListenersPostedAndLogLocked(NotificationRecord r, NotificationRecord old, 12912 @NonNull PostNotificationTracker tracker, 12913 @Nullable NotificationRecordLogger.NotificationReported report) { 12914 List<Runnable> listenerCalls = mListeners.prepareNotifyPostedLocked(r, old, true); 12915 mHandler.post(() -> { 12916 for (Runnable listenerCall : listenerCalls) { 12917 listenerCall.run(); 12918 } 12919 12920 long postDurationMillis = tracker.finish(); 12921 if (report != null) { 12922 report.post_duration_millis = postDurationMillis; 12923 mNotificationRecordLogger.logNotificationPosted(report); 12924 } 12925 }); 12926 12927 if (callstyleCallbackApi()) { 12928 notifyCallNotificationEventListenerOnPosted(r); 12929 } 12930 } 12931 12932 @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR) 12933 @GuardedBy("mNotificationLock") 12934 private void maybeNotifySystemUiListenerLifetimeExtendedListLocked( 12935 List<NotificationRecord> notificationList, int packageImportance) { 12936 for (int i = notificationList.size() - 1; i >= 0; --i) { 12937 NotificationRecord record = notificationList.get(i); 12938 maybeNotifySystemUiListenerLifetimeExtendedLocked(record, 12939 record.getSbn().getPackageName(), packageImportance); 12940 } 12941 } 12942 12943 @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR) 12944 @GuardedBy("mNotificationLock") 12945 private void maybeNotifySystemUiListenerLifetimeExtendedLocked(NotificationRecord record, 12946 String pkg, int packageImportance) { 12947 if (record != null && (record.getSbn().getNotification().flags 12948 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0 12949 && !record.isCanceledAfterLifetimeExtension()) { 12950 // Mark that the notification is being updated due to cancelation, so it won't 12951 // be updated again if the app cancels multiple times. 12952 record.setCanceledAfterLifetimeExtension(true); 12953 12954 boolean isAppForeground = pkg != null && packageImportance == IMPORTANCE_FOREGROUND; 12955 12956 // Save the original Record's post silently value, so we can restore it after we send 12957 // the SystemUI specific silent update. 12958 boolean savedPostSilentlyState = record.shouldPostSilently(); 12959 boolean savedOnlyAlertOnceState = (record.getNotification().flags 12960 & FLAG_ONLY_ALERT_ONCE) > 0; 12961 // Lifetime extended notifications don't need to alert on new state change. 12962 record.setPostSilently(true); 12963 // We also set FLAG_ONLY_ALERT_ONCE to avoid the notification from HUN-ing again. 12964 record.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 12965 12966 PostNotificationTracker tracker = mPostNotificationTrackerFactory.newTracker(null); 12967 tracker.addCleanupRunnable(() -> { 12968 synchronized (mNotificationLock) { 12969 // Set the post silently status to the record's previous value. 12970 record.setPostSilently(savedPostSilentlyState); 12971 // Remove FLAG_ONLY_ALERT_ONCE if the notification did not previously have it. 12972 if (!savedOnlyAlertOnceState) { 12973 record.getNotification().flags &= ~FLAG_ONLY_ALERT_ONCE; 12974 } 12975 } 12976 }); 12977 12978 mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(), 12979 record, isAppForeground, /* isAppProvided= */ false, tracker)); 12980 12981 EventLogTags.writeNotificationCancelPrevented(record.getKey()); 12982 } 12983 } 12984 12985 @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR) 12986 private int getPackageImportanceWithIdentity(String pkg) { 12987 final long token = Binder.clearCallingIdentity(); 12988 final int packageImportance; 12989 try { 12990 packageImportance = mActivityManager.getPackageImportance(pkg); 12991 } finally { 12992 Binder.restoreCallingIdentity(token); 12993 } 12994 return packageImportance; 12995 } 12996 12997 public class NotificationListeners extends ManagedServices { 12998 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners"; 12999 static final String TAG_REQUESTED_LISTENERS = "request_listeners"; 13000 static final String TAG_REQUESTED_LISTENER = "listener"; 13001 static final String ATT_COMPONENT = "component"; 13002 static final String ATT_TYPES = "types"; 13003 static final String ATT_PKG = "pkg"; 13004 static final String ATT_UID = "uid"; 13005 static final String TAG_APPROVED = "allowed"; 13006 static final String TAG_DISALLOWED= "disallowed"; 13007 static final String XML_SEPARATOR = ","; 13008 static final String FLAG_SEPARATOR = "\\|"; 13009 13010 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 13011 13012 @GuardedBy("mTrustedListenerUids") 13013 private final ArraySet<Integer> mTrustedListenerUids = new ArraySet<>(); 13014 @GuardedBy("mRequestedNotificationListeners") 13015 private final ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter> 13016 mRequestedNotificationListeners = new ArrayMap<>(); 13017 private final boolean mIsHeadlessSystemUserMode; 13018 13019 public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, 13020 IPackageManager pm) { 13021 this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode()); 13022 } 13023 13024 @VisibleForTesting 13025 public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, 13026 IPackageManager pm, boolean isHeadlessSystemUserMode) { 13027 super(context, lock, userProfiles, pm); 13028 this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode; 13029 } 13030 13031 @Override 13032 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, 13033 boolean isPrimary, boolean enabled, boolean userSet) { 13034 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet); 13035 String pkgName = getPackageName(pkgOrComponent); 13036 if (redactSensitiveNotificationsFromUntrustedListeners()) { 13037 int uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId); 13038 if (!enabled && uid >= 0) { 13039 synchronized (mTrustedListenerUids) { 13040 mTrustedListenerUids.remove(uid); 13041 } 13042 } 13043 if (enabled && uid >= 0 && isAppTrustedNotificationListenerService(uid, pkgName)) { 13044 synchronized (mTrustedListenerUids) { 13045 mTrustedListenerUids.add(uid); 13046 } 13047 } 13048 } 13049 13050 mContext.sendBroadcastAsUser( 13051 new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED) 13052 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 13053 UserHandle.of(userId), null); 13054 } 13055 13056 @Override 13057 protected void loadDefaultsFromConfig() { 13058 String defaultListenerAccess = mContext.getResources().getString( 13059 R.string.config_defaultListenerAccessPackages); 13060 if (defaultListenerAccess != null) { 13061 String[] listeners = 13062 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR); 13063 for (int i = 0; i < listeners.length; i++) { 13064 if (TextUtils.isEmpty(listeners[i])) { 13065 continue; 13066 } 13067 int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; 13068 // In the headless system user mode, packages might not be installed for the 13069 // system user. Match packages for any user since apps can be installed only for 13070 // non-system users and would be considering uninstalled for the system user. 13071 if (mIsHeadlessSystemUserMode) { 13072 packageQueryFlags += MATCH_ANY_USER; 13073 } 13074 ArraySet<ComponentName> approvedListeners = 13075 this.queryPackageForServices(listeners[i], packageQueryFlags, 13076 USER_SYSTEM); 13077 for (int k = 0; k < approvedListeners.size(); k++) { 13078 ComponentName cn = approvedListeners.valueAt(k); 13079 addDefaultComponentOrPackage(cn.flattenToString()); 13080 } 13081 } 13082 } 13083 } 13084 13085 @Override 13086 protected int getBindFlags() { 13087 // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE 13088 // because too many 3P apps could be kept in memory as notification listeners and 13089 // cause extreme memory pressure. 13090 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation. 13091 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE 13092 | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT; 13093 } 13094 13095 @Override 13096 protected Config getConfig() { 13097 Config c = new Config(); 13098 c.caption = "notification listener"; 13099 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 13100 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS; 13101 c.secureSettingName = Secure.ENABLED_NOTIFICATION_LISTENERS; 13102 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 13103 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 13104 c.clientLabel = R.string.notification_listener_binding_label; 13105 return c; 13106 } 13107 13108 @Override 13109 protected IInterface asInterface(IBinder binder) { 13110 return INotificationListener.Stub.asInterface(binder); 13111 } 13112 13113 @Override 13114 protected boolean checkType(IInterface service) { 13115 return service instanceof INotificationListener; 13116 } 13117 13118 @Override 13119 public void onServiceAdded(ManagedServiceInfo info) { 13120 if (lifetimeExtensionRefactor()) { 13121 // Generally, only System or System UI should have the permissions to call 13122 // registerSystemService. 13123 // isCallerSystemOrPhone tells us whether the caller is System. We negate this, 13124 // to eliminate cases where the service was added by the system. This leaves 13125 // services registered by system server. 13126 // To identify system UI, we explicitly check the status bar permission for the 13127 // uid in the info object. 13128 // We can't use the calling uid here because it belongs to system server. 13129 // Note that this will also return true for the shell, but we deem this 13130 // acceptable, for the purposes of testing. 13131 info.isSystemUi = !isCallerSystemOrPhone() && getContext().checkPermission( 13132 android.Manifest.permission.STATUS_BAR_SERVICE, -1, info.uid) 13133 == PERMISSION_GRANTED; 13134 } 13135 final INotificationListener listener = (INotificationListener) info.service; 13136 final NotificationRankingUpdate update; 13137 synchronized (mNotificationLock) { 13138 update = makeRankingUpdateLocked(info); 13139 updateUriPermissionsForActiveNotificationsLocked(info, true); 13140 } 13141 if (redactSensitiveNotificationsFromUntrustedListeners() 13142 && isAppTrustedNotificationListenerService( 13143 info.uid, info.component.getPackageName())) { 13144 synchronized (mTrustedListenerUids) { 13145 mTrustedListenerUids.add(info.uid); 13146 } 13147 } 13148 try { 13149 listener.onListenerConnected(update); 13150 } catch (RemoteException e) { 13151 // we tried 13152 } 13153 } 13154 13155 @Override 13156 @GuardedBy("mNotificationLock") 13157 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 13158 updateUriPermissionsForActiveNotificationsLocked(removed, false); 13159 if (removeDisabledHints(removed)) { 13160 updateListenerHintsLocked(); 13161 updateEffectsSuppressorLocked(); 13162 } 13163 if (redactSensitiveNotificationsFromUntrustedListeners()) { 13164 synchronized (mTrustedListenerUids) { 13165 mTrustedListenerUids.remove(removed.uid); 13166 } 13167 } 13168 mLightTrimListeners.remove(removed); 13169 } 13170 13171 @Override 13172 public void onUserRemoved(int user) { 13173 super.onUserRemoved(user); 13174 synchronized (mRequestedNotificationListeners) { 13175 for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) { 13176 if (mRequestedNotificationListeners.keyAt(i).second == user) { 13177 mRequestedNotificationListeners.removeAt(i); 13178 } 13179 } 13180 } 13181 } 13182 13183 @Override 13184 public void onUserUnlocked(int user) { 13185 if (!managedServicesConcurrentMultiuser() 13186 && mUmInternal.isVisibleBackgroundFullUser(user)) { 13187 // The main use case for visible background users is the Automotive 13188 // multi-display configuration where a passenger can use a secondary 13189 // display while the driver is using the main display. 13190 // NotificationListeners is designed only for the current user and work 13191 // profile. We added a condition to prevent visible background users from 13192 // updating the data managed within the NotificationListeners object. 13193 return; 13194 } 13195 super.onUserUnlocked(user); 13196 } 13197 13198 @Override 13199 protected boolean allowRebindForParentUser() { 13200 return true; 13201 } 13202 13203 @Override 13204 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) { 13205 super.onPackagesChanged(removingPackage, pkgList, uidList); 13206 13207 synchronized (mRequestedNotificationListeners) { 13208 // Since the default behavior is to allow everything, we don't need to explicitly 13209 // handle package add or update. they will be added to the xml file on next boot or 13210 // when the user tries to change the settings. 13211 if (removingPackage) { 13212 for (int i = 0; i < pkgList.length; i++) { 13213 String pkg = pkgList[i]; 13214 int userId = UserHandle.getUserId(uidList[i]); 13215 for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { 13216 Pair<ComponentName, Integer> key = 13217 mRequestedNotificationListeners.keyAt(j); 13218 if (key.second == userId && key.first.getPackageName().equals(pkg)) { 13219 mRequestedNotificationListeners.removeAt(j); 13220 } 13221 } 13222 } 13223 13224 // Clean up removed package from the disallowed packages list 13225 for (int i = 0; i < pkgList.length; i++) { 13226 String pkg = pkgList[i]; 13227 for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { 13228 NotificationListenerFilter nlf = 13229 mRequestedNotificationListeners.valueAt(j); 13230 VersionedPackage ai = new VersionedPackage(pkg, uidList[i]); 13231 nlf.removePackage(ai); 13232 } 13233 } 13234 } 13235 } 13236 } 13237 13238 @Override 13239 protected String getRequiredPermission() { 13240 return null; 13241 } 13242 13243 @Override 13244 protected boolean shouldReflectToSettings() { 13245 // androidx has a public method that reads the approved set of listeners from 13246 // Settings so we have to continue writing this list for this type of service 13247 return true; 13248 } 13249 13250 @Override 13251 protected void readExtraTag(String tag, TypedXmlPullParser parser) 13252 throws IOException, XmlPullParserException { 13253 if (TAG_REQUESTED_LISTENERS.equals(tag)) { 13254 final int listenersOuterDepth = parser.getDepth(); 13255 while (XmlUtils.nextElementWithin(parser, listenersOuterDepth)) { 13256 if (!TAG_REQUESTED_LISTENER.equals(parser.getName())) { 13257 continue; 13258 } 13259 final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID); 13260 final ComponentName cn = ComponentName.unflattenFromString( 13261 XmlUtils.readStringAttribute(parser, ATT_COMPONENT)); 13262 int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING 13263 | FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING; 13264 13265 ArraySet<VersionedPackage> disallowedPkgs = new ArraySet<>(); 13266 final int listenerOuterDepth = parser.getDepth(); 13267 while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) { 13268 if (TAG_APPROVED.equals(parser.getName())) { 13269 approved = XmlUtils.readIntAttribute(parser, ATT_TYPES); 13270 } else if (TAG_DISALLOWED.equals(parser.getName())) { 13271 String pkg = XmlUtils.readStringAttribute(parser, ATT_PKG); 13272 int uid = XmlUtils.readIntAttribute(parser, ATT_UID); 13273 if (!TextUtils.isEmpty(pkg)) { 13274 VersionedPackage ai = new VersionedPackage(pkg, uid); 13275 disallowedPkgs.add(ai); 13276 } 13277 } 13278 } 13279 NotificationListenerFilter nlf = 13280 new NotificationListenerFilter(approved, disallowedPkgs); 13281 synchronized (mRequestedNotificationListeners) { 13282 mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf); 13283 } 13284 } 13285 } 13286 } 13287 13288 @Override 13289 protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException { 13290 out.startTag(null, TAG_REQUESTED_LISTENERS); 13291 synchronized (mRequestedNotificationListeners) { 13292 for (Pair<ComponentName, Integer> listener : 13293 mRequestedNotificationListeners.keySet()) { 13294 NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener); 13295 out.startTag(null, TAG_REQUESTED_LISTENER); 13296 XmlUtils.writeStringAttribute( 13297 out, ATT_COMPONENT, listener.first.flattenToString()); 13298 XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second); 13299 13300 out.startTag(null, TAG_APPROVED); 13301 XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes()); 13302 out.endTag(null, TAG_APPROVED); 13303 13304 for (VersionedPackage ai : nlf.getDisallowedPackages()) { 13305 if (!TextUtils.isEmpty(ai.getPackageName())) { 13306 out.startTag(null, TAG_DISALLOWED); 13307 XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName()); 13308 XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode()); 13309 out.endTag(null, TAG_DISALLOWED); 13310 } 13311 } 13312 13313 out.endTag(null, TAG_REQUESTED_LISTENER); 13314 } 13315 } 13316 13317 out.endTag(null, TAG_REQUESTED_LISTENERS); 13318 } 13319 13320 @Nullable protected NotificationListenerFilter getNotificationListenerFilter( 13321 Pair<ComponentName, Integer> pair) { 13322 synchronized (mRequestedNotificationListeners) { 13323 return mRequestedNotificationListeners.get(pair); 13324 } 13325 } 13326 13327 protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair, 13328 NotificationListenerFilter nlf) { 13329 synchronized (mRequestedNotificationListeners) { 13330 mRequestedNotificationListeners.put(pair, nlf); 13331 } 13332 } 13333 13334 @Override 13335 protected void ensureFilters(ServiceInfo si, int userId) { 13336 Pair<ComponentName, Integer> listener = Pair.create(si.getComponentName(), userId); 13337 synchronized (mRequestedNotificationListeners) { 13338 NotificationListenerFilter existingNlf = 13339 mRequestedNotificationListeners.get(listener); 13340 if (si.metaData != null) { 13341 if (existingNlf == null) { 13342 // no stored filters for this listener; see if they provided a default 13343 if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) { 13344 String typeList = 13345 si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString(); 13346 if (typeList != null) { 13347 int types = getTypesFromStringList(typeList); 13348 NotificationListenerFilter nlf = 13349 new NotificationListenerFilter(types, new ArraySet<>()); 13350 mRequestedNotificationListeners.put(listener, nlf); 13351 } 13352 } 13353 } 13354 13355 // also check the types they never want bridged 13356 if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) { 13357 int neverBridge = getTypesFromStringList(si.metaData.get( 13358 META_DATA_DISABLED_FILTER_TYPES).toString()); 13359 if (neverBridge != 0) { 13360 NotificationListenerFilter nlf = 13361 mRequestedNotificationListeners.getOrDefault( 13362 listener, new NotificationListenerFilter()); 13363 nlf.setTypes(nlf.getTypes() & ~neverBridge); 13364 mRequestedNotificationListeners.put(listener, nlf); 13365 } 13366 } 13367 } 13368 } 13369 } 13370 13371 private int getTypesFromStringList(String typeList) { 13372 int types = 0; 13373 if (typeList != null) { 13374 String[] typeStrings = typeList.split(FLAG_SEPARATOR); 13375 for (int i = 0; i < typeStrings.length; i++) { 13376 final String typeString = typeStrings[i]; 13377 if (TextUtils.isEmpty(typeString)) { 13378 continue; 13379 } 13380 if (typeString.equalsIgnoreCase("ONGOING")) { 13381 types |= FLAG_FILTER_TYPE_ONGOING; 13382 } else if (typeString.equalsIgnoreCase("CONVERSATIONS")) { 13383 types |= FLAG_FILTER_TYPE_CONVERSATIONS; 13384 } else if (typeString.equalsIgnoreCase("SILENT")) { 13385 types |= FLAG_FILTER_TYPE_SILENT; 13386 } else if (typeString.equalsIgnoreCase("ALERTING")) { 13387 types |= FLAG_FILTER_TYPE_ALERTING; 13388 } else { 13389 try { 13390 types |= Integer.parseInt(typeString); 13391 } catch (NumberFormatException e) { 13392 // skip 13393 } 13394 } 13395 } 13396 } 13397 return types; 13398 } 13399 13400 @GuardedBy("mNotificationLock") 13401 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 13402 if (trim == TRIM_LIGHT) { 13403 mLightTrimListeners.add(info); 13404 } else { 13405 mLightTrimListeners.remove(info); 13406 } 13407 } 13408 13409 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 13410 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 13411 } 13412 13413 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { 13414 // send to all currently bounds NASes since notifications from both users will appear in 13415 // the status bar 13416 for (final ManagedServiceInfo info : getServices()) { 13417 mHandler.post(() -> { 13418 final INotificationListener listener = (INotificationListener) info.service; 13419 try { 13420 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons); 13421 } catch (RemoteException ex) { 13422 Slog.e(TAG, "unable to notify listener " 13423 + "(hideSilentStatusIcons): " + info, ex); 13424 } 13425 }); 13426 } 13427 } 13428 13429 /** 13430 * Asynchronously notify all listeners about a new or updated notification. Note that the 13431 * notification is new or updated from the point of view of the NLS, but might not be 13432 * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method 13433 * is also invoked after exiting lockdown mode. 13434 * 13435 * <p> 13436 * Also takes care of removing a notification that has been visible to a listener before, 13437 * but isn't anymore. 13438 */ 13439 @VisibleForTesting 13440 @GuardedBy("mNotificationLock") 13441 void notifyPostedLocked(NotificationRecord r, NotificationRecord old) { 13442 notifyPostedLocked(r, old, true); 13443 } 13444 13445 /** 13446 * Asynchronously notify all listeners about a new or updated notification. Note that the 13447 * notification is new or updated from the point of view of the NLS, but might not be 13448 * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method 13449 * is invoked after exiting lockdown mode. 13450 * 13451 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners 13452 * targeting <= O_MR1 13453 */ 13454 @VisibleForTesting 13455 @GuardedBy("mNotificationLock") 13456 void notifyPostedLocked(NotificationRecord r, NotificationRecord old, 13457 boolean notifyAllListeners) { 13458 for (Runnable listenerCall : prepareNotifyPostedLocked(r, old, notifyAllListeners)) { 13459 mHandler.post(listenerCall); 13460 } 13461 } 13462 13463 /** 13464 * "Prepares" to notify all listeners about the posted notification. 13465 * 13466 * <p>This method <em>does not invoke</em> the listeners; the caller should post each 13467 * returned {@link Runnable} on a suitable thread to do so. 13468 * 13469 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners 13470 * targeting <= O_MR1 13471 * @return A list of {@link Runnable} operations to notify all listeners about the posted 13472 * notification. 13473 */ 13474 @VisibleForTesting 13475 @GuardedBy("mNotificationLock") 13476 List<Runnable> prepareNotifyPostedLocked(NotificationRecord r, 13477 NotificationRecord old, boolean notifyAllListeners) { 13478 if (isInLockDownMode(r.getUser().getIdentifier())) { 13479 return new ArrayList<>(); 13480 } 13481 13482 ArrayList<Runnable> listenerCalls = new ArrayList<>(); 13483 try { 13484 // Lazily initialized snapshots of the notification. 13485 StatusBarNotification sbn = r.getSbn(); 13486 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 13487 TrimCache trimCache = new TrimCache(sbn); 13488 TrimCache redactedCache = null; 13489 StatusBarNotification redactedSbn = null; 13490 StatusBarNotification oldRedactedSbn = null; 13491 boolean isNewSensitive = hasSensitiveContent(r); 13492 boolean isOldSensitive = hasSensitiveContent(old); 13493 boolean redactionEnabled = redactSensitiveNotificationsFromUntrustedListeners() 13494 && mRedactOtpNotifications; 13495 13496 for (final ManagedServiceInfo info : getServices()) { 13497 boolean isTrusted = isUidTrusted(info.uid); 13498 boolean sendRedacted = redactionEnabled && isNewSensitive && !isTrusted; 13499 boolean sendOldRedacted = redactionEnabled && isOldSensitive && !isTrusted; 13500 boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info); 13501 boolean oldSbnVisible = (oldSbn != null) 13502 && isVisibleToListener(oldSbn, old.getNotificationType(), info); 13503 // This notification hasn't been and still isn't visible -> ignore. 13504 if (!oldSbnVisible && !sbnVisible) { 13505 continue; 13506 } 13507 // If the notification is hidden, don't notifyPosted listeners targeting < P. 13508 // Instead, those listeners will receive notifyPosted when the notification is 13509 // unhidden. 13510 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 13511 continue; 13512 } 13513 13514 if (lifetimeExtensionRefactor()) { 13515 if (sendRedacted && redactedSbn == null) { 13516 redactedSbn = redactStatusBarNotification(sbn); 13517 redactedCache = new TrimCache(redactedSbn); 13518 } 13519 final StatusBarNotification sbnToPost = sendRedacted 13520 ? redactedCache.ForListener(info) : trimCache.ForListener(info); 13521 13522 // Checks if this is a request to notify system UI about a notification that 13523 // has been lifetime extended. 13524 // We check both old and new for the flag, to avoid catching updates 13525 // (where new will not have the flag). 13526 // If it is such a request, and this is the system UI listener, we send 13527 // the post request. If it's any other listener, we skip it. 13528 if (old != null && old.getNotification() != null 13529 && (old.getNotification().flags 13530 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0 13531 && sbn != null && sbn.getNotification() != null 13532 && (sbn.getNotification().flags 13533 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) { 13534 if (info.isSystemUi()) { 13535 final NotificationRankingUpdate update = 13536 makeRankingUpdateLocked(info); 13537 listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); 13538 break; 13539 } else { 13540 // Skipping because this is the direct-reply "update" and we only 13541 // need to send it to sysui, so we immediately continue, before it 13542 // can get sent to other listeners below. 13543 if (DBG) { 13544 Slog.d(TAG, "prepareNotifyPostedLocked: direct reply update, " 13545 + "skipping post to " + info.toString()); 13546 } 13547 continue; 13548 } 13549 } 13550 } 13551 13552 // If we shouldn't notify all listeners, this means the hidden state of 13553 // a notification was changed. Don't notifyPosted listeners targeting >= P. 13554 // Instead, those listeners will receive notifyRankingUpdate. 13555 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) { 13556 continue; 13557 } 13558 13559 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 13560 13561 // This notification became invisible -> remove the old one. 13562 if (oldSbnVisible && !sbnVisible) { 13563 if (sendOldRedacted && oldRedactedSbn == null) { 13564 oldRedactedSbn = redactStatusBarNotification(oldSbn); 13565 } 13566 final StatusBarNotification oldSbnLightClone = 13567 sendOldRedacted ? oldRedactedSbn.cloneLight() : oldSbn.cloneLight(); 13568 listenerCalls.add(() -> notifyRemoved( 13569 info, oldSbnLightClone, update, null, REASON_USER_STOPPED)); 13570 13571 continue; 13572 } 13573 // Grant access before listener is notified 13574 final int targetUserId = (info.userid == USER_ALL) 13575 ? USER_SYSTEM : info.userid; 13576 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId); 13577 13578 mPackageManagerInternal.grantImplicitAccess( 13579 targetUserId, null /* intent */, 13580 UserHandle.getAppId(info.uid), 13581 sbn.getUid(), 13582 false /* direct */, false /* retainOnUpdate */); 13583 13584 if (sendRedacted && redactedSbn == null) { 13585 redactedSbn = redactStatusBarNotification(sbn); 13586 redactedCache = new TrimCache(redactedSbn); 13587 } 13588 13589 final StatusBarNotification sbnToPost = sendRedacted 13590 ? redactedCache.ForListener(info) : trimCache.ForListener(info); 13591 listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); 13592 } 13593 } catch (Exception e) { 13594 Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e); 13595 } 13596 return listenerCalls; 13597 } 13598 13599 boolean isAppTrustedNotificationListenerService(int uid, String pkg) { 13600 if (!redactSensitiveNotificationsFromUntrustedListeners()) { 13601 return true; 13602 } 13603 13604 long token = Binder.clearCallingIdentity(); 13605 try { 13606 if (mPackageManager.checkUidPermission(RECEIVE_SENSITIVE_NOTIFICATIONS, uid) 13607 == PERMISSION_GRANTED || mPackageManagerInternal.isPlatformSigned(pkg) 13608 || mAppOps 13609 .noteOpNoThrow(OP_RECEIVE_SENSITIVE_NOTIFICATIONS, uid, pkg, null, null) 13610 == MODE_ALLOWED) { 13611 return true; 13612 } 13613 13614 // check if there is a CDM association with the listener 13615 // We don't listen for changes because if an association is lost, the app loses 13616 // NLS access 13617 List<AssociationInfo> cdmAssocs = new ArrayList<>(); 13618 if (mCompanionManager == null) { 13619 mCompanionManager = getCompanionManager(); 13620 } 13621 if (mCompanionManager != null) { 13622 cdmAssocs = 13623 mCompanionManager.getAllAssociationsForUser(UserHandle.getUserId(uid)); 13624 } 13625 for (int i = 0; i < cdmAssocs.size(); i++) { 13626 AssociationInfo assocInfo = cdmAssocs.get(i); 13627 if (!assocInfo.isRevoked() && pkg.equals(assocInfo.getPackageName()) 13628 && assocInfo.getUserId() == UserHandle.getUserId(uid)) { 13629 return true; 13630 } 13631 } 13632 } catch (RemoteException e) { 13633 Slog.e(TAG, "Failed to check trusted status of listener", e); 13634 } finally { 13635 Binder.restoreCallingIdentity(token); 13636 } 13637 return false; 13638 } 13639 13640 StatusBarNotification redactStatusBarNotification(StatusBarNotification sbn) { 13641 if (!redactSensitiveNotificationsFromUntrustedListeners()) { 13642 throw new RuntimeException("redactStatusBarNotification called while flag is off"); 13643 } 13644 13645 ApplicationInfo appInfo = sbn.getNotification().extras.getParcelable( 13646 EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class); 13647 String pkgLabel; 13648 if (appInfo != null) { 13649 pkgLabel = appInfo.loadLabel(mPackageManagerClient).toString(); 13650 } else { 13651 Slog.w(TAG, "StatusBarNotification " + sbn + " does not have ApplicationInfo." 13652 + " Did you pass in a 'cloneLight' notification?"); 13653 pkgLabel = sbn.getPackageName(); 13654 } 13655 String redactedText = mContext.getString(R.string.redacted_notification_message); 13656 Notification oldNotif = sbn.getNotification(); 13657 Notification oldClone = new Notification(); 13658 oldNotif.cloneInto(oldClone, false); 13659 Notification.Builder redactedNotifBuilder = 13660 new Notification.Builder(getContext(), oldClone); 13661 redactedNotifBuilder.setContentTitle(pkgLabel); 13662 redactedNotifBuilder.setContentText(redactedText); 13663 redactedNotifBuilder.setSubText(null); 13664 redactedNotifBuilder.setActions(); 13665 if (oldNotif.actions != null) { 13666 for (int i = 0; i < oldNotif.actions.length; i++) { 13667 Notification.Action act = 13668 new Notification.Action.Builder(oldNotif.actions[i]).build(); 13669 act.title = mContext.getString(R.string.redacted_notification_action_title); 13670 redactedNotifBuilder.addAction(act); 13671 } 13672 } 13673 13674 if (oldNotif.isStyle(MessagingStyle.class)) { 13675 Person empty = new Person.Builder().setName("").build(); 13676 MessagingStyle messageStyle = new MessagingStyle(empty); 13677 messageStyle.addMessage(new MessagingStyle.Message( 13678 redactedText, System.currentTimeMillis(), empty)); 13679 redactedNotifBuilder.setStyle(messageStyle); 13680 } 13681 if (redactSensitiveNotificationsBigTextStyle() 13682 && oldNotif.isStyle(Notification.BigTextStyle.class)) { 13683 Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(); 13684 bigTextStyle.bigText(mContext.getString(R.string.redacted_notification_message)); 13685 bigTextStyle.setBigContentTitle(""); 13686 bigTextStyle.setSummaryText(""); 13687 redactedNotifBuilder.setStyle(bigTextStyle); 13688 } 13689 13690 Notification redacted = redactedNotifBuilder.build(); 13691 // Notification extras can't always be overridden by a builder (configured by a system 13692 // property), so set them after building 13693 if (redacted.extras.containsKey(EXTRA_TITLE_BIG)) { 13694 redacted.extras.putString(EXTRA_TITLE_BIG, pkgLabel); 13695 } 13696 redacted.extras.remove(EXTRA_SUB_TEXT); 13697 redacted.extras.remove(EXTRA_TEXT_LINES); 13698 redacted.extras.remove(EXTRA_LARGE_ICON_BIG); 13699 return sbn.cloneShallow(redacted); 13700 } 13701 13702 boolean hasSensitiveContent(NotificationRecord r) { 13703 if (r == null || !redactSensitiveNotificationsFromUntrustedListeners()) { 13704 return false; 13705 } 13706 return r.hasSensitiveContent(); 13707 } 13708 13709 boolean isUidTrusted(int uid) { 13710 synchronized (mTrustedListenerUids) { 13711 return !redactSensitiveNotificationsFromUntrustedListeners() 13712 || mTrustedListenerUids.contains(uid); 13713 } 13714 } 13715 13716 /** 13717 * Synchronously grant or revoke permissions to Uris for all active and visible 13718 * notifications to just the NotificationListenerService provided. 13719 */ 13720 @GuardedBy("mNotificationLock") 13721 private void updateUriPermissionsForActiveNotificationsLocked( 13722 ManagedServiceInfo info, boolean grant) { 13723 try { 13724 for (final NotificationRecord r : mNotificationList) { 13725 // When granting permissions, ignore notifications which are invisible. 13726 // When revoking permissions, all notifications are invisible, so process all. 13727 if (grant && !isVisibleToListener(r.getSbn(), r.getNotificationType(), info)) { 13728 continue; 13729 } 13730 // If the notification is hidden, permissions are not required by the listener. 13731 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 13732 continue; 13733 } 13734 // Grant or revoke access synchronously 13735 final int targetUserId = (info.userid == USER_ALL) 13736 ? USER_SYSTEM : info.userid; 13737 if (grant) { 13738 // Grant permissions by passing arguments as if the notification is new. 13739 updateUriPermissions(/* newRecord */ r, /* oldRecord */ null, 13740 info.component.getPackageName(), targetUserId); 13741 } else { 13742 // Revoke permissions by passing arguments as if the notification was 13743 // removed, but set `onlyRevokeCurrentTarget` to avoid revoking permissions 13744 // granted to *other* targets by this notification's URIs. 13745 updateUriPermissions(/* newRecord */ null, /* oldRecord */ r, 13746 info.component.getPackageName(), targetUserId, 13747 /* onlyRevokeCurrentTarget */ true); 13748 } 13749 } 13750 } catch (Exception e) { 13751 Slog.e(TAG, "Could not " + (grant ? "grant" : "revoke") + " Uri permissions to " 13752 + info.component, e); 13753 } 13754 } 13755 13756 /** 13757 * asynchronously notify all listeners about a removed notification 13758 */ 13759 @GuardedBy("mNotificationLock") 13760 public void notifyRemovedLocked(NotificationRecord r, int reason, 13761 NotificationStats notificationStats) { 13762 if (isInLockDownMode(r.getUser().getIdentifier())) { 13763 return; 13764 } 13765 13766 final StatusBarNotification sbn = r.getSbn(); 13767 13768 // make a copy in case changes are made to the underlying Notification object 13769 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 13770 // notification 13771 final StatusBarNotification sbnLight = sbn.cloneLight(); 13772 StatusBarNotification redactedSbn = null; 13773 boolean hasSensitiveContent = hasSensitiveContent(r); 13774 for (final ManagedServiceInfo info : getServices()) { 13775 if (!isVisibleToListener(sbn, r.getNotificationType(), info)) { 13776 continue; 13777 } 13778 13779 // don't notifyRemoved for listeners targeting < P 13780 // if not for reason package suspended 13781 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED 13782 && info.targetSdkVersion < Build.VERSION_CODES.P) { 13783 continue; 13784 } 13785 13786 // don't notifyRemoved for listeners targeting >= P 13787 // if the reason is package suspended 13788 if (reason == REASON_PACKAGE_SUSPENDED 13789 && info.targetSdkVersion >= Build.VERSION_CODES.P) { 13790 continue; 13791 } 13792 13793 boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners() 13794 && hasSensitiveContent && !isUidTrusted(info.uid); 13795 if (sendRedacted && redactedSbn == null) { 13796 redactedSbn = redactStatusBarNotification(sbn); 13797 } 13798 13799 // Only assistants can get stats 13800 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service) 13801 ? notificationStats : null; 13802 final StatusBarNotification sbnToSend = sendRedacted ? redactedSbn : sbnLight; 13803 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 13804 mHandler.post(() -> notifyRemoved(info, sbnToSend, update, stats, reason)); 13805 } 13806 13807 // Revoke access after all listeners have been updated 13808 mHandler.post(() -> updateUriPermissions(null, r, null, USER_SYSTEM)); 13809 } 13810 13811 /** 13812 * Asynchronously notify all listeners about a reordering of notifications 13813 * unless changedHiddenNotifications is populated. 13814 * If changedHiddenNotifications is populated, there was a change in the hidden state 13815 * of the notifications. In this case, we only send updates to listeners that 13816 * target >= P. 13817 */ 13818 @GuardedBy("mNotificationLock") 13819 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { 13820 boolean isHiddenRankingUpdate = changedHiddenNotifications != null 13821 && changedHiddenNotifications.size() > 0; 13822 13823 // TODO (b/73052211): if the ranking update changed the notification type, 13824 // cancel notifications for NLSes that can't see them anymore 13825 for (final ManagedServiceInfo serviceInfo : getServices()) { 13826 if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener( 13827 serviceInfo, ActivityManager.getCurrentUser())) { 13828 continue; 13829 } 13830 13831 boolean notifyThisListener = false; 13832 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >= 13833 Build.VERSION_CODES.P) { 13834 for (NotificationRecord rec : changedHiddenNotifications) { 13835 if (isVisibleToListener( 13836 rec.getSbn(), rec.getNotificationType(), serviceInfo)) { 13837 notifyThisListener = true; 13838 break; 13839 } 13840 } 13841 } 13842 13843 if (notifyThisListener || !isHiddenRankingUpdate) { 13844 final NotificationRankingUpdate update = makeRankingUpdateLocked( 13845 serviceInfo); 13846 mHandler.post(() -> notifyRankingUpdate(serviceInfo, update)); 13847 } 13848 } 13849 } 13850 13851 @GuardedBy("mNotificationLock") 13852 public void notifyListenerHintsChangedLocked(final int hints) { 13853 for (final ManagedServiceInfo serviceInfo : getServices()) { 13854 if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener( 13855 serviceInfo, ActivityManager.getCurrentUser())) { 13856 continue; 13857 } 13858 mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints)); 13859 } 13860 } 13861 13862 /** 13863 * asynchronously notify relevant listeners their notification is hidden 13864 * NotificationListenerServices that target P+: 13865 * NotificationListenerService#notifyRankingUpdateLocked() 13866 * NotificationListenerServices that target <= P: 13867 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED. 13868 */ 13869 @GuardedBy("mNotificationLock") 13870 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) { 13871 if (changedNotifications == null || changedNotifications.size() == 0) { 13872 return; 13873 } 13874 13875 notifyRankingUpdateLocked(changedNotifications); 13876 13877 // for listeners that target < P, notifyRemoveLocked 13878 int numChangedNotifications = changedNotifications.size(); 13879 for (int i = 0; i < numChangedNotifications; i++) { 13880 NotificationRecord rec = changedNotifications.get(i); 13881 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats()); 13882 } 13883 } 13884 13885 /** 13886 * asynchronously notify relevant listeners their notification is unhidden 13887 * NotificationListenerServices that target P+: 13888 * NotificationListenerService#notifyRankingUpdateLocked() 13889 * NotificationListenerServices that target <= P: 13890 * NotificationListeners#notifyPostedLocked() 13891 */ 13892 @GuardedBy("mNotificationLock") 13893 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) { 13894 if (changedNotifications == null || changedNotifications.size() == 0) { 13895 return; 13896 } 13897 13898 notifyRankingUpdateLocked(changedNotifications); 13899 13900 // for listeners that target < P, notifyPostedLocked 13901 int numChangedNotifications = changedNotifications.size(); 13902 for (int i = 0; i < numChangedNotifications; i++) { 13903 NotificationRecord rec = changedNotifications.get(i); 13904 notifyPostedLocked(rec, rec, false); 13905 } 13906 } 13907 13908 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 13909 for (final ManagedServiceInfo serviceInfo : getServices()) { 13910 if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener( 13911 serviceInfo, ActivityManager.getCurrentUser())) { 13912 continue; 13913 } 13914 mHandler.post( 13915 () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter)); 13916 } 13917 } 13918 13919 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, 13920 final NotificationChannel channel, final int modificationType) { 13921 if (channel == null) { 13922 return; 13923 } 13924 for (final ManagedServiceInfo info : getServices()) { 13925 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId()) 13926 || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) { 13927 continue; 13928 } 13929 13930 BackgroundThread.getHandler().post(() -> { 13931 if (info.isSystem 13932 || hasCompanionDevice(info) 13933 || isServiceTokenValid(info.service)) { 13934 notifyNotificationChannelChanged( 13935 info, pkg, user, channel, modificationType); 13936 } 13937 }); 13938 } 13939 } 13940 13941 protected void notifyNotificationChannelGroupChanged( 13942 final String pkg, final UserHandle user, final NotificationChannelGroup group, 13943 final int modificationType) { 13944 if (group == null) { 13945 return; 13946 } 13947 for (final ManagedServiceInfo info : getServices()) { 13948 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId()) 13949 || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) { 13950 continue; 13951 } 13952 13953 BackgroundThread.getHandler().post(() -> { 13954 if (info.isSystem() || hasCompanionDevice(info)) { 13955 notifyNotificationChannelGroupChanged( 13956 info, pkg, user, group, modificationType); 13957 } 13958 }); 13959 } 13960 } 13961 13962 private void notifyPosted(final ManagedServiceInfo info, 13963 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 13964 final INotificationListener listener = (INotificationListener) info.service; 13965 try { 13966 if (android.app.Flags.noSbnholder()) { 13967 listener.onNotificationPostedFull(sbn, rankingUpdate); 13968 } else { 13969 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 13970 listener.onNotificationPosted(sbnHolder, rankingUpdate); 13971 } 13972 } catch (DeadObjectException ex) { 13973 Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex); 13974 } catch (RemoteException ex) { 13975 Slog.e(TAG, "unable to notify listener (posted): " + info, ex); 13976 } 13977 } 13978 13979 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 13980 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) { 13981 final INotificationListener listener = (INotificationListener) info.service; 13982 try { 13983 if (!CompatChanges.isChangeEnabled(NOTIFICATION_CANCELLATION_REASONS, info.uid) 13984 && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) { 13985 reason = REASON_CHANNEL_BANNED; 13986 } 13987 // apps before T don't know about REASON_ASSISTANT, so replace it with the 13988 // previously-used case, REASON_LISTENER_CANCEL 13989 if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid) 13990 && reason == REASON_ASSISTANT_CANCEL) { 13991 reason = REASON_LISTENER_CANCEL; 13992 } 13993 if (android.app.Flags.noSbnholder()) { 13994 listener.onNotificationRemovedFull(sbn, rankingUpdate, stats, reason); 13995 } else { 13996 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 13997 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason); 13998 } 13999 } catch (DeadObjectException ex) { 14000 Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex); 14001 } catch (RemoteException ex) { 14002 Slog.e(TAG, "unable to notify listener (removed): " + info, ex); 14003 } 14004 } 14005 14006 private void notifyRankingUpdate(ManagedServiceInfo info, 14007 NotificationRankingUpdate rankingUpdate) { 14008 final INotificationListener listener = (INotificationListener) info.service; 14009 try { 14010 listener.onNotificationRankingUpdate(rankingUpdate); 14011 } catch (DeadObjectException ex) { 14012 Slog.wtf(TAG, "unable to notify listener (ranking update): " + info, ex); 14013 } catch (RemoteException ex) { 14014 Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex); 14015 } 14016 } 14017 14018 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 14019 final INotificationListener listener = (INotificationListener) info.service; 14020 try { 14021 listener.onListenerHintsChanged(hints); 14022 } catch (RemoteException ex) { 14023 Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex); 14024 } 14025 } 14026 14027 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 14028 int interruptionFilter) { 14029 final INotificationListener listener = (INotificationListener) info.service; 14030 try { 14031 listener.onInterruptionFilterChanged(interruptionFilter); 14032 } catch (RemoteException ex) { 14033 Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex); 14034 } 14035 } 14036 14037 void notifyNotificationChannelChanged(ManagedServiceInfo info, 14038 final String pkg, final UserHandle user, final NotificationChannel channel, 14039 final int modificationType) { 14040 final INotificationListener listener = (INotificationListener) info.service; 14041 try { 14042 listener.onNotificationChannelModification(pkg, user, channel, modificationType); 14043 } catch (RemoteException ex) { 14044 Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex); 14045 } 14046 } 14047 14048 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, 14049 final String pkg, final UserHandle user, final NotificationChannelGroup group, 14050 final int modificationType) { 14051 final INotificationListener listener = (INotificationListener) info.getService(); 14052 try { 14053 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); 14054 } catch (RemoteException ex) { 14055 Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex); 14056 } 14057 } 14058 14059 public boolean isListenerPackage(String packageName) { 14060 if (packageName == null) { 14061 return false; 14062 } 14063 // TODO: clean up locking object later 14064 synchronized (mNotificationLock) { 14065 for (final ManagedServiceInfo serviceInfo : getServices()) { 14066 if (packageName.equals(serviceInfo.component.getPackageName())) { 14067 return true; 14068 } 14069 } 14070 } 14071 return false; 14072 } 14073 14074 // Returns whether there is a component with listener access granted that is associated 14075 // with the given package name / user ID. 14076 boolean hasAllowedListener(String packageName, int userId) { 14077 if (packageName == null) { 14078 return false; 14079 } 14080 14081 // Loop through allowed components to compare package names 14082 List<ComponentName> allowedComponents = getAllowedComponents(userId); 14083 for (int i = 0; i < allowedComponents.size(); i++) { 14084 if (allowedComponents.get(i).getPackageName().equals(packageName)) { 14085 return true; 14086 } 14087 } 14088 return false; 14089 } 14090 } 14091 14092 @GuardedBy("mNotificationLock") 14093 private void broadcastToCallNotificationEventCallbacks( 14094 final RemoteCallbackList<ICallNotificationEventCallback> callbackList, 14095 final NotificationRecord r, 14096 boolean isPosted) { 14097 if (callbackList != null) { 14098 int numCallbacks = callbackList.beginBroadcast(); 14099 try { 14100 for (int i = 0; i < numCallbacks; i++) { 14101 if (isPosted) { 14102 callbackList.getBroadcastItem(i) 14103 .onCallNotificationPosted(r.getSbn().getPackageName(), r.getUser()); 14104 } else { 14105 callbackList.getBroadcastItem(i) 14106 .onCallNotificationRemoved(r.getSbn().getPackageName(), 14107 r.getUser()); 14108 } 14109 } 14110 } catch (RemoteException e) { 14111 throw new RuntimeException(e); 14112 } 14113 callbackList.finishBroadcast(); 14114 } 14115 } 14116 14117 @GuardedBy("mNotificationLock") 14118 void notifyCallNotificationEventListenerOnPosted(final NotificationRecord r) { 14119 if (!r.getNotification().isStyle(Notification.CallStyle.class)) { 14120 return; 14121 } 14122 14123 synchronized (mCallNotificationEventCallbacks) { 14124 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 14125 callbacksForPackage = 14126 mCallNotificationEventCallbacks.get(r.getSbn().getPackageName()); 14127 if (callbacksForPackage == null) { 14128 return; 14129 } 14130 14131 if (!r.getUser().equals(UserHandle.ALL)) { 14132 broadcastToCallNotificationEventCallbacks( 14133 callbacksForPackage.get(r.getUser().getIdentifier()), r, true); 14134 // Also notify the listeners registered for USER_ALL 14135 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r, 14136 true); 14137 } else { 14138 // Notify listeners registered for any userId 14139 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList 14140 : callbacksForPackage.values()) { 14141 broadcastToCallNotificationEventCallbacks(callbackList, r, true); 14142 } 14143 } 14144 } 14145 } 14146 14147 @GuardedBy("mNotificationLock") 14148 void notifyCallNotificationEventListenerOnRemoved(final NotificationRecord r) { 14149 if (!r.getNotification().isStyle(Notification.CallStyle.class)) { 14150 return; 14151 } 14152 14153 synchronized (mCallNotificationEventCallbacks) { 14154 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 14155 callbacksForPackage = 14156 mCallNotificationEventCallbacks.get(r.getSbn().getPackageName()); 14157 if (callbacksForPackage == null) { 14158 return; 14159 } 14160 14161 if (!r.getUser().equals(UserHandle.ALL)) { 14162 broadcastToCallNotificationEventCallbacks( 14163 callbacksForPackage.get(r.getUser().getIdentifier()), r, false); 14164 // Also notify the listeners registered for USER_ALL 14165 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r, 14166 false); 14167 } else { 14168 // Notify listeners registered for any userId 14169 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList 14170 : callbacksForPackage.values()) { 14171 broadcastToCallNotificationEventCallbacks(callbackList, r, false); 14172 } 14173 } 14174 } 14175 } 14176 14177 // TODO (b/194833441): remove when we've fully migrated to a permission 14178 class RoleObserver implements OnRoleHoldersChangedListener { 14179 // Role name : user id : list of approved packages 14180 private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps; 14181 14182 /** 14183 * Writes should be pretty rare (only when default browser changes) and reads are done 14184 * during activity start code-path, so we're optimizing for reads. This means this set is 14185 * immutable once written and we'll recreate the set every time there is a role change and 14186 * then assign that new set to the volatile below, so reads can be done without needing to 14187 * hold a lock. Every write is done on the main-thread, so write atomicity is guaranteed. 14188 * 14189 * Didn't use unmodifiable set to enforce immutability to avoid iterating via iterators. 14190 */ 14191 private volatile ArraySet<Integer> mTrampolineExemptUids = new ArraySet<>(); 14192 14193 private final RoleManager mRm; 14194 private final IPackageManager mPm; 14195 private final Executor mExecutor; 14196 private final Looper mMainLooper; 14197 14198 RoleObserver(Context context, @NonNull RoleManager roleManager, 14199 @NonNull IPackageManager pkgMgr, @NonNull Looper mainLooper) { 14200 mRm = roleManager; 14201 mPm = pkgMgr; 14202 mExecutor = context.getMainExecutor(); 14203 mMainLooper = mainLooper; 14204 } 14205 14206 /** Should be called from the main-thread. */ 14207 @MainThread 14208 public void init() { 14209 List<UserHandle> users = mUm.getUserHandles(/* excludeDying */ true); 14210 mNonBlockableDefaultApps = new ArrayMap<>(); 14211 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 14212 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>(); 14213 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList); 14214 for (int j = 0; j < users.size(); j++) { 14215 Integer userId = users.get(j).getIdentifier(); 14216 ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser( 14217 NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId))); 14218 ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>(); 14219 for (String pkg : approvedForUserId) { 14220 approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId))); 14221 } 14222 userToApprovedList.put(userId, approvedForUserId); 14223 mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids); 14224 } 14225 } 14226 updateTrampolineExemptUidsForUsers(users.toArray(new UserHandle[0])); 14227 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); 14228 } 14229 14230 void destroy() { 14231 mRm.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.ALL); 14232 } 14233 14234 @VisibleForTesting 14235 public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) { 14236 return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg); 14237 } 14238 14239 @VisibleForTesting 14240 public boolean isUidExemptFromTrampolineRestrictions(int uid) { 14241 return mTrampolineExemptUids.contains(uid); 14242 } 14243 14244 /** 14245 * Convert the assistant-role holder into settings. The rest of the system uses the 14246 * settings. 14247 * 14248 * @param roleName the name of the role whose holders are changed 14249 * @param user the user for this role holder change 14250 */ 14251 @Override 14252 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { 14253 onRoleHoldersChangedForNonBlockableDefaultApps(roleName, user); 14254 onRoleHoldersChangedForTrampolines(roleName, user); 14255 } 14256 14257 private void onRoleHoldersChangedForNonBlockableDefaultApps(@NonNull String roleName, 14258 @NonNull UserHandle user) { 14259 // we only care about a couple of the roles they'll tell us about 14260 boolean relevantChange = false; 14261 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 14262 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) { 14263 relevantChange = true; 14264 break; 14265 } 14266 } 14267 14268 if (!relevantChange) { 14269 return; 14270 } 14271 14272 ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user)); 14273 14274 // find the diff 14275 ArrayMap<Integer, ArraySet<String>> prevApprovedForRole = 14276 mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>()); 14277 ArraySet<String> previouslyApproved = 14278 prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>()); 14279 14280 ArraySet<String> toRemove = new ArraySet<>(); 14281 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 14282 14283 for (String previous : previouslyApproved) { 14284 if (!roleHolders.contains(previous)) { 14285 toRemove.add(previous); 14286 } 14287 } 14288 for (String nowApproved : roleHolders) { 14289 if (!previouslyApproved.contains(nowApproved)) { 14290 toAdd.add(new Pair(nowApproved, 14291 getUidForPackage(nowApproved, user.getIdentifier()))); 14292 } 14293 } 14294 14295 // store newly approved apps 14296 prevApprovedForRole.put(user.getIdentifier(), roleHolders); 14297 mNonBlockableDefaultApps.put(roleName, prevApprovedForRole); 14298 14299 // update what apps can be blocked 14300 mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd); 14301 14302 // RoleManager is the source of truth for this data so we don't need to trigger a 14303 // write of the notification policy xml for this change 14304 } 14305 14306 private void onRoleHoldersChangedForTrampolines(@NonNull String roleName, 14307 @NonNull UserHandle user) { 14308 if (!RoleManager.ROLE_BROWSER.equals(roleName)) { 14309 return; 14310 } 14311 updateTrampolineExemptUidsForUsers(user); 14312 } 14313 14314 private void updateTrampolineExemptUidsForUsers(UserHandle... users) { 14315 Preconditions.checkState(mMainLooper.isCurrentThread()); 14316 ArraySet<Integer> oldUids = mTrampolineExemptUids; 14317 ArraySet<Integer> newUids = new ArraySet<>(); 14318 // Add the uids from previous set for the users that we won't update. 14319 for (int i = 0, n = oldUids.size(); i < n; i++) { 14320 int uid = oldUids.valueAt(i); 14321 UserHandle user = UserHandle.of(UserHandle.getUserId(uid)); 14322 if (!ArrayUtils.contains(users, user)) { 14323 newUids.add(uid); 14324 } 14325 } 14326 // Now lookup the new uids for the users that we want to update. 14327 for (int i = 0, n = users.length; i < n; i++) { 14328 UserHandle user = users[i]; 14329 for (String pkg : mRm.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, user)) { 14330 int uid = getUidForPackage(pkg, user.getIdentifier()); 14331 if (uid != -1) { 14332 newUids.add(uid); 14333 } else { 14334 Slog.e(TAG, "Bad uid (-1) for browser package " + pkg); 14335 } 14336 } 14337 } 14338 mTrampolineExemptUids = newUids; 14339 } 14340 14341 private int getUidForPackage(String pkg, int userId) { 14342 try { 14343 return mPm.getPackageUid(pkg, MATCH_ALL, userId); 14344 } catch (RemoteException e) { 14345 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId); 14346 } 14347 return -1; 14348 } 14349 } 14350 14351 public static final class DumpFilter { 14352 public boolean filtered = false; 14353 public String pkgFilter; 14354 public boolean zen; 14355 public long since; 14356 public boolean stats; 14357 public boolean rvStats; 14358 public boolean redact = true; 14359 public boolean proto = false; 14360 public boolean criticalPriority = false; 14361 public boolean normalPriority = false; 14362 14363 @NonNull 14364 public static DumpFilter parseFromArguments(String[] args) { 14365 final DumpFilter filter = new DumpFilter(); 14366 for (int ai = 0; ai < args.length; ai++) { 14367 final String a = args[ai]; 14368 if ("--proto".equals(a)) { 14369 filter.proto = true; 14370 } else if ("--noredact".equals(a) || "--reveal".equals(a)) { 14371 filter.redact = false; 14372 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 14373 if (ai < args.length-1) { 14374 ai++; 14375 filter.pkgFilter = args[ai].trim().toLowerCase(); 14376 if (filter.pkgFilter.isEmpty()) { 14377 filter.pkgFilter = null; 14378 } else { 14379 filter.filtered = true; 14380 } 14381 } 14382 } else if ("--zen".equals(a) || "zen".equals(a)) { 14383 filter.filtered = true; 14384 filter.zen = true; 14385 } else if ("--stats".equals(a)) { 14386 filter.stats = true; 14387 if (ai < args.length-1) { 14388 ai++; 14389 filter.since = Long.parseLong(args[ai]); 14390 } else { 14391 filter.since = 0; 14392 } 14393 } else if ("--remote-view-stats".equals(a)) { 14394 filter.rvStats = true; 14395 if (ai < args.length-1) { 14396 ai++; 14397 filter.since = Long.parseLong(args[ai]); 14398 } else { 14399 filter.since = 0; 14400 } 14401 } else if (PRIORITY_ARG.equals(a)) { 14402 // Bugreport will call the service twice with priority arguments, first to dump 14403 // critical sections and then non critical ones. Set appropriate filters 14404 // to generate the desired data. 14405 if (ai < args.length - 1) { 14406 ai++; 14407 switch (args[ai]) { 14408 case PRIORITY_ARG_CRITICAL: 14409 filter.criticalPriority = true; 14410 break; 14411 case PRIORITY_ARG_NORMAL: 14412 filter.normalPriority = true; 14413 break; 14414 } 14415 } 14416 } 14417 } 14418 return filter; 14419 } 14420 14421 public boolean matches(StatusBarNotification sbn) { 14422 if (!filtered) return true; 14423 return zen ? true : sbn != null 14424 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 14425 } 14426 14427 public boolean matches(ComponentName component) { 14428 if (!filtered) return true; 14429 return zen ? true : component != null && matches(component.getPackageName()); 14430 } 14431 14432 public boolean matches(String pkg) { 14433 if (!filtered) return true; 14434 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 14435 } 14436 14437 @Override 14438 public String toString() { 14439 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 14440 } 14441 } 14442 14443 @VisibleForTesting 14444 void resetAssistantUserSet(int userId) { 14445 checkCallerIsSystemOrShell(); 14446 mAssistants.setUserSet(userId, false); 14447 handleSavePolicyFile(); 14448 } 14449 14450 @VisibleForTesting 14451 @Nullable 14452 ComponentName getApprovedAssistant(int userId) { 14453 checkCallerIsSystemOrShell(); 14454 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 14455 return CollectionUtils.firstOrNull(allowedComponents); 14456 } 14457 14458 /** 14459 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 14460 * binder without sending large amounts of data over a oneway transaction. 14461 */ 14462 private static final class StatusBarNotificationHolder 14463 extends IStatusBarNotificationHolder.Stub { 14464 private StatusBarNotification mValue; 14465 14466 public StatusBarNotificationHolder(StatusBarNotification value) { 14467 mValue = value; 14468 } 14469 14470 /** Get the held value and clear it. This function should only be called once per holder */ 14471 @Override 14472 public StatusBarNotification get() { 14473 StatusBarNotification value = mValue; 14474 mValue = null; 14475 return value; 14476 } 14477 } 14478 14479 private void writeSecureNotificationsPolicy(TypedXmlSerializer out) throws IOException { 14480 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 14481 out.attributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, 14482 mLockScreenAllowSecureNotifications); 14483 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 14484 } 14485 14486 // Creates a notification that informs the user about changes due to the migration to 14487 // use permissions for notifications. 14488 protected Notification createReviewPermissionsNotification() { 14489 int title = R.string.review_notification_settings_title; 14490 int content = R.string.review_notification_settings_text; 14491 14492 // Tapping on the notification leads to the settings screen for managing app notifications, 14493 // using the intent reserved for system services to indicate it comes from this notification 14494 Intent tapIntent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS_FOR_REVIEW); 14495 Intent remindIntent = new Intent(REVIEW_NOTIF_ACTION_REMIND); 14496 Intent dismissIntent = new Intent(REVIEW_NOTIF_ACTION_DISMISS); 14497 Intent swipeIntent = new Intent(REVIEW_NOTIF_ACTION_CANCELED); 14498 14499 // Both "remind me" and "dismiss" actions will be actions received by the BroadcastReceiver 14500 final Notification.Action remindMe = new Notification.Action.Builder(null, 14501 getContext().getResources().getString( 14502 R.string.review_notification_settings_remind_me_action), 14503 PendingIntent.getBroadcast( 14504 getContext(), 0, remindIntent, 14505 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 14506 .build(); 14507 final Notification.Action dismiss = new Notification.Action.Builder(null, 14508 getContext().getResources().getString( 14509 R.string.review_notification_settings_dismiss), 14510 PendingIntent.getBroadcast( 14511 getContext(), 0, dismissIntent, 14512 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 14513 .build(); 14514 14515 return new Notification.Builder(getContext(), SystemNotificationChannels.SYSTEM_CHANGES) 14516 .setSmallIcon(R.drawable.stat_sys_adb) 14517 .setContentTitle(getContext().getResources().getString(title)) 14518 .setContentText(getContext().getResources().getString(content)) 14519 .setContentIntent(PendingIntent.getActivity(getContext(), 0, tapIntent, 14520 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 14521 .setStyle(new Notification.BigTextStyle()) 14522 .setFlag(FLAG_NO_CLEAR, true) 14523 .setAutoCancel(true) 14524 .addAction(remindMe) 14525 .addAction(dismiss) 14526 .setDeleteIntent(PendingIntent.getBroadcast(getContext(), 0, swipeIntent, 14527 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 14528 .build(); 14529 } 14530 14531 protected void maybeShowInitialReviewPermissionsNotification() { 14532 if (!mShowReviewPermissionsNotification) { 14533 // if this notification is disabled by settings do not ever show it 14534 return; 14535 } 14536 14537 int currentState = Settings.Global.getInt(getContext().getContentResolver(), 14538 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14539 REVIEW_NOTIF_STATE_UNKNOWN); 14540 14541 // now check the last known state of the notification -- this determination of whether the 14542 // user is in the correct target audience occurs elsewhere, and will have written the 14543 // REVIEW_NOTIF_STATE_SHOULD_SHOW to indicate it should be shown in the future. 14544 // 14545 // alternatively, if the user has rescheduled the notification (so it has been shown 14546 // again) but not yet interacted with the new notification, then show it again on boot, 14547 // as this state indicates that the user had the notification open before rebooting. 14548 // 14549 // sending the notification here does not record a new state for the notification; 14550 // that will be written by parts of the system further down the line if at any point 14551 // the user interacts with the notification. 14552 if (currentState == REVIEW_NOTIF_STATE_SHOULD_SHOW 14553 || currentState == REVIEW_NOTIF_STATE_RESHOWN) { 14554 NotificationManager nm = getContext().getSystemService(NotificationManager.class); 14555 nm.notify(TAG, 14556 SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS, 14557 createReviewPermissionsNotification()); 14558 } 14559 } 14560 14561 /** 14562 * Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too 14563 * aggressive and annoying the user. 14564 * 14565 * TODO(b/161957908): Remove dogfooder toast. 14566 */ 14567 private class NotificationTrampolineCallback implements BackgroundActivityStartCallback { 14568 @Override 14569 public BackgroundActivityStartCallbackResult isActivityStartAllowed( 14570 Collection<IBinder> tokens, int uid, String packageName) { 14571 checkArgument(!tokens.isEmpty()); 14572 for (IBinder token : tokens) { 14573 if (token != ALLOWLIST_TOKEN) { 14574 // We only block or warn if the start is exclusively due to notification 14575 return RESULT_TRUE; 14576 } 14577 } 14578 String logcatMessage = 14579 "Indirect notification activity start (trampoline) from " + packageName; 14580 if (blockTrampoline(uid)) { 14581 Slog.e(TAG, logcatMessage + " blocked"); 14582 return RESULT_FALSE; 14583 } else { 14584 Slog.w(TAG, logcatMessage + ", this should be avoided for performance reasons"); 14585 return new BackgroundActivityStartCallbackResult(true, ALLOWLIST_TOKEN); 14586 } 14587 } 14588 14589 private boolean blockTrampoline(int uid) { 14590 if (mRoleObserver != null && mRoleObserver.isUidExemptFromTrampolineRestrictions(uid)) { 14591 return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES, 14592 uid); 14593 } 14594 return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); 14595 } 14596 14597 @Override 14598 public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) { 14599 // If the start is allowed via notification, we allow the app to close system dialogs 14600 // only if their targetSdk < S, otherwise they have no valid reason to do this since 14601 // trampolines are blocked. 14602 return tokens.contains(ALLOWLIST_TOKEN) 14603 && !CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); 14604 } 14605 } 14606 14607 interface PostNotificationTrackerFactory { 14608 default PostNotificationTracker newTracker(@Nullable WakeLock optionalWakelock) { 14609 return new PostNotificationTracker(optionalWakelock); 14610 } 14611 } 14612 14613 static class PostNotificationTracker { 14614 @ElapsedRealtimeLong private final long mStartTime; 14615 @Nullable private final WakeLock mWakeLock; 14616 private boolean mOngoing; 14617 private final List<Runnable> mCleanupRunnables; 14618 14619 @VisibleForTesting 14620 PostNotificationTracker(@Nullable WakeLock wakeLock) { 14621 mStartTime = SystemClock.elapsedRealtime(); 14622 mWakeLock = wakeLock; 14623 mOngoing = true; 14624 mCleanupRunnables = new ArrayList<Runnable>(); 14625 if (DBG) { 14626 Slog.d(TAG, "PostNotification: Started"); 14627 } 14628 } 14629 14630 void addCleanupRunnable(Runnable runnable) { 14631 mCleanupRunnables.add(runnable); 14632 } 14633 14634 @ElapsedRealtimeLong 14635 long getStartTime() { 14636 return mStartTime; 14637 } 14638 14639 @VisibleForTesting 14640 boolean isOngoing() { 14641 return mOngoing; 14642 } 14643 14644 /** 14645 * Cancels the tracker (releasing the acquired WakeLock) and runs any set cleanup runnables. 14646 * Either {@link #finish} or {@link #cancel} (exclusively) should be called on this object 14647 * before it's discarded. 14648 */ 14649 void cancel() { 14650 if (!isOngoing()) { 14651 Log.wtfStack(TAG, "cancel() called on already-finished tracker"); 14652 return; 14653 } 14654 mOngoing = false; 14655 if (mWakeLock != null) { 14656 Binder.withCleanCallingIdentity(() -> mWakeLock.release()); 14657 } 14658 for (Runnable r : mCleanupRunnables) { 14659 r.run(); 14660 } 14661 if (DBG) { 14662 long elapsedTime = SystemClock.elapsedRealtime() - mStartTime; 14663 Slog.d(TAG, TextUtils.formatSimple("PostNotification: Abandoned after %d ms", 14664 elapsedTime)); 14665 } 14666 } 14667 14668 /** 14669 * Finishes the tracker (releasing the acquired WakeLock), runs any set cleanup runnables, 14670 * and returns the time elapsed since the operation started, in milliseconds. 14671 * Either {@link #finish} or {@link #cancel} (exclusively) should be called on this object 14672 * before it's discarded. 14673 */ 14674 @DurationMillisLong 14675 long finish() { 14676 long elapsedTime = SystemClock.elapsedRealtime() - mStartTime; 14677 if (!isOngoing()) { 14678 Log.wtfStack(TAG, "finish() called on already-finished tracker"); 14679 return elapsedTime; 14680 } 14681 mOngoing = false; 14682 if (mWakeLock != null) { 14683 Binder.withCleanCallingIdentity(() -> mWakeLock.release()); 14684 } 14685 for (Runnable r : mCleanupRunnables) { 14686 r.run(); 14687 } 14688 if (DBG) { 14689 Slog.d(TAG, 14690 TextUtils.formatSimple("PostNotification: Finished in %d ms", elapsedTime)); 14691 } 14692 return elapsedTime; 14693 } 14694 } 14695 } 14696