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.sortSectionByTime; 30 import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 31 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO; 32 import static android.app.Notification.EXTRA_LARGE_ICON_BIG; 33 import static android.app.Notification.EXTRA_SUB_TEXT; 34 import static android.app.Notification.EXTRA_TEXT; 35 import static android.app.Notification.EXTRA_TEXT_LINES; 36 import static android.app.Notification.EXTRA_TITLE_BIG; 37 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; 38 import static android.app.Notification.FLAG_AUTO_CANCEL; 39 import static android.app.Notification.FLAG_BUBBLE; 40 import static android.app.Notification.FLAG_FOREGROUND_SERVICE; 41 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED; 42 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 43 import static android.app.Notification.FLAG_NO_CLEAR; 44 import static android.app.Notification.FLAG_NO_DISMISS; 45 import static android.app.Notification.FLAG_ONGOING_EVENT; 46 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; 47 import static android.app.Notification.FLAG_USER_INITIATED_JOB; 48 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; 49 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED; 50 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; 51 import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED; 52 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; 53 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL; 54 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED; 55 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED; 56 import static android.app.NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED; 57 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED; 58 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED; 59 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 60 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; 61 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; 62 import static android.app.NotificationManager.EXTRA_NOTIFICATION_POLICY; 63 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 64 import static android.app.NotificationManager.IMPORTANCE_LOW; 65 import static android.app.NotificationManager.IMPORTANCE_MIN; 66 import static android.app.NotificationManager.IMPORTANCE_NONE; 67 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 68 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET; 69 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 70 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 71 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 72 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 73 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 74 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 78 import static android.app.NotificationManager.zenModeFromInterruptionFilter; 79 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; 80 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; 81 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; 82 import static android.content.Context.BIND_AUTO_CREATE; 83 import static android.content.Context.BIND_FOREGROUND_SERVICE; 84 import static android.content.Context.BIND_NOT_PERCEPTIBLE; 85 import static android.content.pm.PackageManager.FEATURE_LEANBACK; 86 import static android.content.pm.PackageManager.FEATURE_TELECOM; 87 import static android.content.pm.PackageManager.FEATURE_TELEVISION; 88 import static android.content.pm.PackageManager.MATCH_ALL; 89 import static android.content.pm.PackageManager.MATCH_ANY_USER; 90 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; 91 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 92 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 93 import static android.os.Flags.allowPrivateProfile; 94 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; 95 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; 96 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; 97 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 98 import static android.os.UserHandle.USER_ALL; 99 import static android.os.UserHandle.USER_NULL; 100 import static android.os.UserHandle.USER_SYSTEM; 101 import static android.service.notification.Flags.callstyleCallbackApi; 102 import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners; 103 import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle; 104 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; 105 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; 106 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; 107 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; 108 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 109 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 110 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 111 import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES; 112 import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES; 113 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; 114 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; 115 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; 116 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 117 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; 118 import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL; 119 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 120 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; 121 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; 122 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_REMOVED; 123 import static android.service.notification.NotificationListenerService.REASON_CLEAR_DATA; 124 import static android.service.notification.NotificationListenerService.REASON_CLICK; 125 import static android.service.notification.NotificationListenerService.REASON_ERROR; 126 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; 127 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; 128 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; 129 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; 130 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; 131 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; 132 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; 133 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF; 134 import static android.service.notification.NotificationListenerService.REASON_SNOOZED; 135 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; 136 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; 137 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; 138 import static android.service.notification.NotificationListenerService.Ranking.RANKING_DEMOTED; 139 import static android.service.notification.NotificationListenerService.Ranking.RANKING_PROMOTED; 140 import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED; 141 import static android.service.notification.NotificationListenerService.TRIM_FULL; 142 import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 143 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 144 import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled; 145 146 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; 147 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES; 148 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES; 149 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES; 150 import static com.android.internal.util.Preconditions.checkArgument; 151 import static com.android.internal.util.Preconditions.checkNotNull; 152 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 153 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 154 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 155 import static com.android.server.notification.Flags.expireBitmaps; 156 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER; 157 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 158 import static com.android.server.utils.PriorityDump.PRIORITY_ARG; 159 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; 160 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; 161 162 import android.Manifest; 163 import android.Manifest.permission; 164 import android.annotation.DurationMillisLong; 165 import android.annotation.ElapsedRealtimeLong; 166 import android.annotation.EnforcePermission; 167 import android.annotation.FlaggedApi; 168 import android.annotation.MainThread; 169 import android.annotation.NonNull; 170 import android.annotation.Nullable; 171 import android.annotation.RequiresPermission; 172 import android.annotation.UserIdInt; 173 import android.annotation.WorkerThread; 174 import android.app.ActivityManager; 175 import android.app.ActivityManagerInternal; 176 import android.app.ActivityManagerInternal.ServiceNotificationPolicy; 177 import android.app.ActivityTaskManager; 178 import android.app.AlarmManager; 179 import android.app.AppGlobals; 180 import android.app.AppOpsManager; 181 import android.app.AutomaticZenRule; 182 import android.app.IActivityManager; 183 import android.app.ICallNotificationEventCallback; 184 import android.app.INotificationManager; 185 import android.app.ITransientNotification; 186 import android.app.ITransientNotificationCallback; 187 import android.app.IUriGrantsManager; 188 import android.app.Notification; 189 import android.app.Notification.MessagingStyle; 190 import android.app.NotificationChannel; 191 import android.app.NotificationChannelGroup; 192 import android.app.NotificationHistory; 193 import android.app.NotificationHistory.HistoricalNotification; 194 import android.app.NotificationManager; 195 import android.app.NotificationManager.Policy; 196 import android.app.PendingIntent; 197 import android.app.Person; 198 import android.app.RemoteServiceException.BadForegroundServiceNotificationException; 199 import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException; 200 import android.app.StatsManager; 201 import android.app.UriGrantsManager; 202 import android.app.admin.DevicePolicyManagerInternal; 203 import android.app.backup.BackupManager; 204 import android.app.compat.CompatChanges; 205 import android.app.role.OnRoleHoldersChangedListener; 206 import android.app.role.RoleManager; 207 import android.app.usage.UsageEvents; 208 import android.app.usage.UsageStatsManagerInternal; 209 import android.companion.AssociationInfo; 210 import android.companion.AssociationRequest; 211 import android.companion.ICompanionDeviceManager; 212 import android.compat.annotation.ChangeId; 213 import android.compat.annotation.EnabledAfter; 214 import android.compat.annotation.EnabledSince; 215 import android.compat.annotation.LoggingOnly; 216 import android.content.AttributionSource; 217 import android.content.BroadcastReceiver; 218 import android.content.ComponentName; 219 import android.content.ContentProvider; 220 import android.content.ContentResolver; 221 import android.content.Context; 222 import android.content.Intent; 223 import android.content.IntentFilter; 224 import android.content.pm.ApplicationInfo; 225 import android.content.pm.IPackageManager; 226 import android.content.pm.LauncherApps; 227 import android.content.pm.ModuleInfo; 228 import android.content.pm.PackageInfo; 229 import android.content.pm.PackageManager; 230 import android.content.pm.PackageManager.NameNotFoundException; 231 import android.content.pm.PackageManagerInternal; 232 import android.content.pm.ParceledListSlice; 233 import android.content.pm.ServiceInfo; 234 import android.content.pm.ShortcutInfo; 235 import android.content.pm.ShortcutServiceInternal; 236 import android.content.pm.UserInfo; 237 import android.content.pm.VersionedPackage; 238 import android.content.res.Resources; 239 import android.database.ContentObserver; 240 import android.graphics.drawable.Icon; 241 import android.metrics.LogMaker; 242 import android.net.Uri; 243 import android.os.Binder; 244 import android.os.Build; 245 import android.os.Bundle; 246 import android.os.DeadObjectException; 247 import android.os.DeviceIdleManager; 248 import android.os.Environment; 249 import android.os.Handler; 250 import android.os.HandlerThread; 251 import android.os.IBinder; 252 import android.os.IInterface; 253 import android.os.Looper; 254 import android.os.Message; 255 import android.os.ParcelFileDescriptor; 256 import android.os.PowerManager; 257 import android.os.PowerManager.WakeLock; 258 import android.os.Process; 259 import android.os.RemoteCallbackList; 260 import android.os.RemoteException; 261 import android.os.ResultReceiver; 262 import android.os.ServiceManager; 263 import android.os.ShellCallback; 264 import android.os.SystemClock; 265 import android.os.SystemProperties; 266 import android.os.Trace; 267 import android.os.UserHandle; 268 import android.os.UserManager; 269 import android.os.WorkSource; 270 import android.permission.PermissionManager; 271 import android.provider.Settings; 272 import android.provider.Settings.Secure; 273 import android.service.notification.Adjustment; 274 import android.service.notification.Condition; 275 import android.service.notification.ConversationChannelWrapper; 276 import android.service.notification.DeviceEffectsApplier; 277 import android.service.notification.IConditionProvider; 278 import android.service.notification.INotificationListener; 279 import android.service.notification.IStatusBarNotificationHolder; 280 import android.service.notification.ListenersDisablingEffectsProto; 281 import android.service.notification.NotificationAssistantService; 282 import android.service.notification.NotificationListenerFilter; 283 import android.service.notification.NotificationListenerService; 284 import android.service.notification.NotificationRankingUpdate; 285 import android.service.notification.NotificationRecordProto; 286 import android.service.notification.NotificationServiceDumpProto; 287 import android.service.notification.NotificationStats; 288 import android.service.notification.StatusBarNotification; 289 import android.service.notification.ZenDeviceEffects; 290 import android.service.notification.ZenModeConfig; 291 import android.service.notification.ZenModeProto; 292 import android.service.notification.ZenPolicy; 293 import android.telecom.TelecomManager; 294 import android.telephony.TelephonyManager; 295 import android.text.TextUtils; 296 import android.text.format.DateUtils; 297 import android.util.ArrayMap; 298 import android.util.ArraySet; 299 import android.util.AtomicFile; 300 import android.util.IntArray; 301 import android.util.Log; 302 import android.util.Pair; 303 import android.util.Slog; 304 import android.util.SparseArray; 305 import android.util.SparseBooleanArray; 306 import android.util.StatsEvent; 307 import android.util.Xml; 308 import android.util.proto.ProtoOutputStream; 309 import android.view.Display; 310 import android.view.accessibility.AccessibilityManager; 311 import android.widget.RemoteViews; 312 import android.widget.Toast; 313 314 import com.android.internal.R; 315 import com.android.internal.annotations.GuardedBy; 316 import com.android.internal.annotations.VisibleForTesting; 317 import com.android.internal.compat.IPlatformCompat; 318 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; 319 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags; 320 import com.android.internal.logging.InstanceId; 321 import com.android.internal.logging.InstanceIdSequence; 322 import com.android.internal.logging.MetricsLogger; 323 import com.android.internal.logging.nano.MetricsProto; 324 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 325 import com.android.internal.messages.nano.SystemMessageProto; 326 import com.android.internal.notification.SystemNotificationChannels; 327 import com.android.internal.os.BackgroundThread; 328 import com.android.internal.os.SomeArgs; 329 import com.android.internal.statusbar.NotificationVisibility; 330 import com.android.internal.util.ArrayUtils; 331 import com.android.internal.util.CollectionUtils; 332 import com.android.internal.util.ConcurrentUtils; 333 import com.android.internal.util.DumpUtils; 334 import com.android.internal.util.FrameworkStatsLog; 335 import com.android.internal.util.Preconditions; 336 import com.android.internal.util.XmlUtils; 337 import com.android.internal.util.function.TriPredicate; 338 import com.android.internal.widget.LockPatternUtils; 339 import com.android.modules.utils.TypedXmlPullParser; 340 import com.android.modules.utils.TypedXmlSerializer; 341 import com.android.server.DeviceIdleInternal; 342 import com.android.server.EventLogTags; 343 import com.android.server.IoThread; 344 import com.android.server.LocalServices; 345 import com.android.server.SystemService; 346 import com.android.server.job.JobSchedulerInternal; 347 import com.android.server.lights.LightsManager; 348 import com.android.server.notification.GroupHelper.NotificationAttributes; 349 import com.android.server.notification.ManagedServices.ManagedServiceInfo; 350 import com.android.server.notification.ManagedServices.UserProfiles; 351 import com.android.server.notification.toast.CustomToastRecord; 352 import com.android.server.notification.toast.TextToastRecord; 353 import com.android.server.notification.toast.ToastRecord; 354 import com.android.server.pm.PackageManagerService; 355 import com.android.server.pm.UserManagerInternal; 356 import com.android.server.policy.PermissionPolicyInternal; 357 import com.android.server.statusbar.StatusBarManagerInternal; 358 import com.android.server.uri.UriGrantsManagerInternal; 359 import com.android.server.utils.Slogf; 360 import com.android.server.utils.quota.MultiRateLimiter; 361 import com.android.server.wm.ActivityTaskManagerInternal; 362 import com.android.server.wm.BackgroundActivityStartCallback; 363 import com.android.server.wm.WindowManagerInternal; 364 365 import libcore.io.IoUtils; 366 367 import org.json.JSONException; 368 import org.json.JSONObject; 369 import org.xmlpull.v1.XmlPullParserException; 370 371 import java.io.ByteArrayInputStream; 372 import java.io.ByteArrayOutputStream; 373 import java.io.File; 374 import java.io.FileDescriptor; 375 import java.io.FileNotFoundException; 376 import java.io.FileOutputStream; 377 import java.io.IOException; 378 import java.io.InputStream; 379 import java.io.OutputStream; 380 import java.io.PrintWriter; 381 import java.nio.charset.StandardCharsets; 382 import java.time.Clock; 383 import java.time.Duration; 384 import java.util.ArrayList; 385 import java.util.Arrays; 386 import java.util.Collection; 387 import java.util.HashSet; 388 import java.util.Iterator; 389 import java.util.LinkedList; 390 import java.util.List; 391 import java.util.Map; 392 import java.util.Map.Entry; 393 import java.util.Objects; 394 import java.util.Set; 395 import java.util.concurrent.Executor; 396 import java.util.concurrent.TimeUnit; 397 import java.util.function.BiConsumer; 398 import java.util.stream.Collectors; 399 400 /** {@hide} */ 401 public class NotificationManagerService extends SystemService { 402 public static final String TAG = "NotificationService"; 403 public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 404 public static final boolean ENABLE_CHILD_NOTIFICATIONS 405 = SystemProperties.getBoolean("debug.child_notifs", true); 406 407 // pullStats report request: undecorated remote view stats 408 public static final int REPORT_REMOTE_VIEWS = 0x01; 409 410 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean( 411 "debug.notification.interruptiveness", false); 412 413 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 414 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f; 415 416 // To limit bad UX of seeing a toast many seconds after if was triggered. 417 static final int MAX_PACKAGE_TOASTS = 5; 418 419 // message codes 420 static final int MESSAGE_DURATION_REACHED = 2; 421 // 3: removed to a different handler 422 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 423 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 424 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 425 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7; 426 static final int MESSAGE_ON_PACKAGE_CHANGED = 8; 427 428 static final Duration BITMAP_DURATION = Duration.ofHours(24); 429 430 // ranking thread messages 431 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 432 private static final int MESSAGE_RANKING_SORT = 1001; 433 434 static final int LONG_DELAY = TOAST_WINDOW_TIMEOUT - TOAST_WINDOW_ANIM_BUFFER; // 3.5 seconds 435 static final int SHORT_DELAY = 2000; // 2 seconds 436 437 // 1 second past the ANR timeout. 438 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000; 439 440 static final long SNOOZE_UNTIL_UNSPECIFIED = -1; 441 442 /** 443 * The threshold, in milliseconds, to determine whether a notification has been 444 * cleared too quickly. 445 */ 446 private static final int NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS = 5000; 447 448 static final int INVALID_UID = -1; 449 static final String ROOT_PKG = "root"; 450 451 static final String[] ALLOWED_ADJUSTMENTS = new String[] { 452 Adjustment.KEY_PEOPLE, 453 Adjustment.KEY_SNOOZE_CRITERIA, 454 Adjustment.KEY_USER_SENTIMENT, 455 Adjustment.KEY_CONTEXTUAL_ACTIONS, 456 Adjustment.KEY_TEXT_REPLIES, 457 Adjustment.KEY_IMPORTANCE, 458 Adjustment.KEY_IMPORTANCE_PROPOSAL, 459 Adjustment.KEY_SENSITIVE_CONTENT, 460 Adjustment.KEY_RANKING_SCORE, 461 Adjustment.KEY_NOT_CONVERSATION 462 }; 463 464 static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] { 465 RoleManager.ROLE_DIALER, 466 RoleManager.ROLE_EMERGENCY 467 }; 468 469 // Used for rate limiting toasts by package. 470 static final String TOAST_QUOTA_TAG = "toast_quota_tag"; 471 472 // This constant defines rate limits applied to showing toasts. The numbers are set in a way 473 // such that an aggressive toast showing strategy would result in a roughly 1.5x longer wait 474 // time (before the package is allowed to show toasts again) each time the toast rate limit is 475 // reached. It's meant to protect the user against apps spamming them with toasts (either 476 // accidentally or on purpose). 477 private static final MultiRateLimiter.RateLimit[] TOAST_RATE_LIMITS = { 478 MultiRateLimiter.RateLimit.create(3, Duration.ofSeconds(20)), 479 MultiRateLimiter.RateLimit.create(5, Duration.ofSeconds(42)), 480 MultiRateLimiter.RateLimit.create(6, Duration.ofSeconds(68)), 481 }; 482 483 // When #matchesCallFilter is called from the ringer, wait at most 484 // 3s to resolve the contacts. This timeout is required since 485 // ContactsProvider might take a long time to start up. 486 // 487 // Return STARRED_CONTACT when the timeout is hit in order to avoid 488 // missed calls in ZEN mode "Important". 489 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 490 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 491 ValidateNotificationPeople.STARRED_CONTACT; 492 493 /** notification_enqueue status value for a newly enqueued notification. */ 494 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 495 496 /** notification_enqueue status value for an existing notification. */ 497 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 498 499 /** notification_enqueue status value for an ignored notification. */ 500 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 501 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds 502 503 private static final long DELAY_FOR_ASSISTANT_TIME = 200; 504 505 private static final String ACTION_NOTIFICATION_TIMEOUT = 506 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 507 private static final int REQUEST_CODE_TIMEOUT = 1; 508 private static final String SCHEME_TIMEOUT = "timeout"; 509 private static final String EXTRA_KEY = "key"; 510 511 private static final int NOTIFICATION_INSTANCE_ID_MAX = (1 << 13); 512 513 // States for the review permissions notification 514 static final int REVIEW_NOTIF_STATE_UNKNOWN = -1; 515 static final int REVIEW_NOTIF_STATE_SHOULD_SHOW = 0; 516 static final int REVIEW_NOTIF_STATE_USER_INTERACTED = 1; 517 static final int REVIEW_NOTIF_STATE_DISMISSED = 2; 518 static final int REVIEW_NOTIF_STATE_RESHOWN = 3; 519 520 // Action strings for review permissions notification 521 static final String REVIEW_NOTIF_ACTION_REMIND = "REVIEW_NOTIF_ACTION_REMIND"; 522 static final String REVIEW_NOTIF_ACTION_DISMISS = "REVIEW_NOTIF_ACTION_DISMISS"; 523 static final String REVIEW_NOTIF_ACTION_CANCELED = "REVIEW_NOTIF_ACTION_CANCELED"; 524 525 /** 526 * Apps that post custom toasts in the background will have those blocked. Apps can 527 * still post toasts created with 528 * {@link Toast#makeText(Context, CharSequence, int)} and its variants while 529 * in the background. 530 */ 531 @ChangeId 532 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) 533 private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; 534 535 /** 536 * Activity starts coming from broadcast receivers or services in response to notification and 537 * notification action clicks will be blocked for UX and performance reasons. Instead start the 538 * activity directly from the PendingIntent. 539 */ 540 @ChangeId 541 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) 542 private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L; 543 544 /** 545 * Activity starts coming from broadcast receivers or services in response to notification and 546 * notification action clicks will be blocked for UX and performance reasons for previously 547 * exempt role holders (browser). 548 */ 549 @ChangeId 550 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) 551 private static final long NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES = 227752274L; 552 553 /** 554 * Whether a notification listeners can understand new, more specific, cancellation reasons. 555 */ 556 @ChangeId 557 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) 558 private static final long NOTIFICATION_CANCELLATION_REASONS = 175319604L; 559 560 /** 561 * Rate limit showing toasts, on a per package basis. 562 * 563 * It limits the number of {@link Toast#show()} calls to prevent overburdening 564 * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed 565 * in a certain time frame will result in the toast being discarded. 566 */ 567 @ChangeId 568 @LoggingOnly 569 private static final long RATE_LIMIT_TOASTS = 174840628L; 570 571 /** 572 * Whether listeners understand the more specific reason provided for notification 573 * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL. 574 */ 575 @ChangeId 576 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) 577 private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L; 578 579 /** 580 * NO_CLEAR flag will be set for any media notification. 581 */ 582 @ChangeId 583 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 584 static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L; 585 586 /** 587 * App calls to {@link NotificationManager#setInterruptionFilter} and 588 * {@link NotificationManager#setNotificationPolicy} manage DND through the 589 * creation and activation of an implicit {@link AutomaticZenRule}. 590 */ 591 @ChangeId 592 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 593 static final long MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES = 308670109L; 594 595 private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30); 596 597 static final long NOTIFICATION_TTL = Duration.ofDays(3).toMillis(); 598 599 static final long NOTIFICATION_MAX_AGE_AT_POST = Duration.ofDays(14).toMillis(); 600 601 private IActivityManager mAm; 602 private ActivityTaskManagerInternal mAtm; 603 private ActivityManager mActivityManager; 604 private ActivityManagerInternal mAmi; 605 @VisibleForTesting 606 IPackageManager mPackageManager; 607 private PackageManager mPackageManagerClient; 608 PackageManagerInternal mPackageManagerInternal; 609 private PermissionManager mPermissionManager; 610 private PermissionPolicyInternal mPermissionPolicyInternal; 611 612 // Can be null for wear 613 @Nullable StatusBarManagerInternal mStatusBar; 614 private WindowManagerInternal mWindowManagerInternal; 615 private AlarmManager mAlarmManager; 616 @VisibleForTesting 617 ICompanionDeviceManager mCompanionManager; 618 private AccessibilityManager mAccessibilityManager; 619 private DeviceIdleManager mDeviceIdleManager; 620 private IUriGrantsManager mUgm; 621 private UriGrantsManagerInternal mUgmInternal; 622 private volatile RoleObserver mRoleObserver; 623 private UserManager mUm; 624 private UserManagerInternal mUmInternal; 625 private IPlatformCompat mPlatformCompat; 626 private ShortcutHelper mShortcutHelper; 627 private PermissionHelper mPermissionHelper; 628 private UsageStatsManagerInternal mUsageStatsManagerInternal; 629 private TelecomManager mTelecomManager; 630 private PowerManager mPowerManager; 631 private PostNotificationTrackerFactory mPostNotificationTrackerFactory; 632 633 private LockPatternUtils mLockUtils; 634 635 final IBinder mForegroundToken = new Binder(); 636 @VisibleForTesting 637 WorkerHandler mHandler; 638 private final HandlerThread mRankingThread = new HandlerThread("ranker", 639 Process.THREAD_PRIORITY_BACKGROUND); 640 641 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects = 642 new SparseArray<>(); 643 private List<ComponentName> mEffectsSuppressors = new ArrayList<>(); 644 private int mListenerHints; // right now, all hints are global 645 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 646 647 private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver; 648 649 // used as a mutex for access to all active notifications & listeners 650 final Object mNotificationLock = new Object(); 651 @GuardedBy("mNotificationLock") 652 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>(); 653 @GuardedBy("mNotificationLock") 654 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>(); 655 @GuardedBy("mNotificationLock") 656 final ArrayMap<String, InlineReplyUriRecord> mInlineReplyRecordsByKey = new ArrayMap<>(); 657 @GuardedBy("mNotificationLock") 658 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>(); 659 @GuardedBy("mNotificationLock") 660 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); 661 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>(); 662 // set of uids for which toast rate limiting is disabled 663 @GuardedBy("mToastQueue") 664 private final Set<Integer> mToastRateLimitingDisabledUids = new ArraySet<>(); 665 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 666 667 // True if the toast that's on top of the queue is being shown at the moment. 668 @GuardedBy("mToastQueue") 669 private boolean mIsCurrentToastShown = false; 670 671 // Used for rate limiting toasts by package. 672 private MultiRateLimiter mToastRateLimiter; 673 674 private AppOpsManager mAppOps; 675 private UsageStatsManagerInternal mAppUsageStats; 676 private DevicePolicyManagerInternal mDpm; 677 private StatsManager mStatsManager; 678 private StatsPullAtomCallbackImpl mPullAtomCallback; 679 680 private Archive mArchive; 681 682 // Persistent storage for notification policy 683 private AtomicFile mPolicyFile; 684 685 private static final int DB_VERSION = 1; 686 687 688 private static final String ADSERVICES_MODULE_PKG_NAME = 689 "com.android.adservices"; 690 691 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 692 private static final String ATTR_VERSION = "version"; 693 694 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG = 695 "allow-secure-notifications-on-lockscreen"; 696 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value"; 697 698 @VisibleForTesting 699 RankingHelper mRankingHelper; 700 @VisibleForTesting 701 PreferencesHelper mPreferencesHelper; 702 703 private final UserProfiles mUserProfiles = new UserProfiles(); 704 private NotificationListeners mListeners; 705 @VisibleForTesting 706 NotificationAssistants mAssistants; 707 private ConditionProviders mConditionProviders; 708 private NotificationUsageStats mUsageStats; 709 private boolean mLockScreenAllowSecureNotifications = true; 710 final ArrayMap<String, ArrayMap<Integer, 711 RemoteCallbackList<ICallNotificationEventCallback>>> 712 mCallNotificationEventCallbacks = new ArrayMap<>(); 713 714 private static final int MY_UID = Process.myUid(); 715 private static final int MY_PID = Process.myPid(); 716 static final IBinder ALLOWLIST_TOKEN = new Binder(); 717 protected RankingHandler mRankingHandler; 718 private long mLastOverRateLogTime; 719 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 720 721 private NotificationHistoryManager mHistoryManager; 722 protected SnoozeHelper mSnoozeHelper; 723 private TimeToLiveHelper mTtlHelper; 724 private GroupHelper mGroupHelper; 725 private int mAutoGroupAtCount; 726 private boolean mIsTelevision; 727 protected NotificationAttentionHelper mAttentionHelper; 728 729 private int mWarnRemoteViewsSizeBytes; 730 private int mStripRemoteViewsSizeBytes; 731 732 @VisibleForTesting 733 protected boolean mShowReviewPermissionsNotification; 734 735 private MetricsLogger mMetricsLogger; 736 private NotificationChannelLogger mNotificationChannelLogger; 737 private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; 738 739 private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); 740 private NotificationRecordLogger mNotificationRecordLogger; 741 private InstanceIdSequence mNotificationInstanceIdSequence; 742 private Set<String> mMsgPkgsAllowedAsConvos = new HashSet(); 743 private String mDefaultSearchSelectorPkg; 744 745 // Broadcast intent receiver for notification permissions review-related intents 746 private ReviewNotificationPermissionsReceiver mReviewNotificationPermissionsReceiver; 747 748 private AppOpsManager.OnOpChangedListener mAppOpsListener; 749 750 private ModuleInfo mAdservicesModuleInfo; 751 752 static class Archive { 753 final SparseArray<Boolean> mEnabled; 754 final int mBufferSize; 755 final Object mBufferLock = new Object(); 756 @GuardedBy("mBufferLock") 757 final LinkedList<Pair<StatusBarNotification, Integer>> mBuffer; 758 Archive(int size)759 public Archive(int size) { 760 mBufferSize = size; 761 mBuffer = new LinkedList<>(); 762 mEnabled = new SparseArray<>(); 763 } 764 toString()765 public String toString() { 766 final StringBuilder sb = new StringBuilder(); 767 final int N = mBuffer.size(); 768 sb.append("Archive ("); 769 sb.append(N); 770 sb.append(" notification"); 771 sb.append((N == 1) ? ")" : "s)"); 772 return sb.toString(); 773 } 774 record(StatusBarNotification sbn, int reason)775 public void record(StatusBarNotification sbn, int reason) { 776 if (!mEnabled.get(sbn.getNormalizedUserId(), false)) { 777 return; 778 } 779 synchronized (mBufferLock) { 780 if (mBuffer.size() == mBufferSize) { 781 mBuffer.removeFirst(); 782 } 783 784 // We don't want to store the heavy bits of the notification in the archive, 785 // but other clients in the system process might be using the object, so we 786 // store a (lightened) copy. 787 mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason)); 788 } 789 } 790 descendingIterator()791 public Iterator<Pair<StatusBarNotification, Integer>> descendingIterator() { 792 return mBuffer.descendingIterator(); 793 } 794 getArray(UserManager um, int count, boolean includeSnoozed)795 public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) { 796 ArrayList<Integer> currentUsers = new ArrayList<>(); 797 currentUsers.add(USER_ALL); 798 Binder.withCleanCallingIdentity(() -> { 799 for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) { 800 currentUsers.add(user); 801 } 802 }); 803 synchronized (mBufferLock) { 804 if (count == 0) count = mBufferSize; 805 List<StatusBarNotification> a = new ArrayList(); 806 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); 807 int i = 0; 808 while (iter.hasNext() && i < count) { 809 Pair<StatusBarNotification, Integer> pair = iter.next(); 810 if (pair.second != REASON_SNOOZED || includeSnoozed) { 811 if (currentUsers.contains(pair.first.getUserId())) { 812 i++; 813 a.add(pair.first); 814 } 815 } 816 } 817 return a.toArray(new StatusBarNotification[a.size()]); 818 } 819 } 820 updateHistoryEnabled(@serIdInt int userId, boolean enabled)821 public void updateHistoryEnabled(@UserIdInt int userId, boolean enabled) { 822 mEnabled.put(userId, enabled); 823 824 if (!enabled) { 825 synchronized (mBufferLock) { 826 for (int i = mBuffer.size() - 1; i >= 0; i--) { 827 if (userId == mBuffer.get(i).first.getNormalizedUserId()) { 828 mBuffer.remove(i); 829 } 830 } 831 } 832 } 833 } 834 835 // Remove notifications with the specified user & channel ID. removeChannelNotifications(String pkg, @UserIdInt int userId, String channelId)836 public void removeChannelNotifications(String pkg, @UserIdInt int userId, 837 String channelId) { 838 synchronized (mBufferLock) { 839 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); 840 while (bufferIter.hasNext()) { 841 final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); 842 if (pair.first != null 843 && userId == pair.first.getNormalizedUserId() 844 && pkg != null && pkg.equals(pair.first.getPackageName()) 845 && pair.first.getNotification() != null 846 && Objects.equals(channelId, 847 pair.first.getNotification().getChannelId())) { 848 bufferIter.remove(); 849 } 850 } 851 } 852 } 853 854 // Removes all notifications with the specified user & package. removePackageNotifications(String pkg, @UserIdInt int userId)855 public void removePackageNotifications(String pkg, @UserIdInt int userId) { 856 synchronized (mBufferLock) { 857 Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); 858 while (bufferIter.hasNext()) { 859 final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); 860 if (pair.first != null 861 && userId == pair.first.getNormalizedUserId() 862 && pkg != null && pkg.equals(pair.first.getPackageName()) 863 && pair.first.getNotification() != null) { 864 bufferIter.remove(); 865 } 866 } 867 } 868 } 869 dumpImpl(PrintWriter pw, @NonNull DumpFilter filter)870 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) { 871 synchronized (mBufferLock) { 872 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); 873 int i = 0; 874 while (iter.hasNext()) { 875 final StatusBarNotification sbn = iter.next().first; 876 if (filter != null && !filter.matches(sbn)) continue; 877 pw.println(" " + sbn); 878 if (++i >= 5) { 879 if (iter.hasNext()) pw.println(" ..."); 880 break; 881 } 882 } 883 } 884 } 885 } 886 loadDefaultApprovedServices(int userId)887 void loadDefaultApprovedServices(int userId) { 888 mListeners.loadDefaultsFromConfig(); 889 890 mConditionProviders.loadDefaultsFromConfig(); 891 892 mAssistants.loadDefaultsFromConfig(); 893 } 894 allowDefaultApprovedServices(int userId)895 protected void allowDefaultApprovedServices(int userId) { 896 ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents(); 897 for (int i = 0; i < defaultListeners.size(); i++) { 898 ComponentName cn = defaultListeners.valueAt(i); 899 allowNotificationListener(userId, cn); 900 } 901 902 allowDndPackages(userId); 903 904 setDefaultAssistantForUser(userId); 905 } 906 907 @VisibleForTesting allowDndPackages(int userId)908 void allowDndPackages(int userId) { 909 ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages(); 910 for (int i = 0; i < defaultDnds.size(); i++) { 911 allowDndPackage(userId, defaultDnds.valueAt(i)); 912 } 913 if (!isDNDMigrationDone(userId)) { 914 setDNDMigrationDone(userId); 915 } 916 } 917 918 @VisibleForTesting isDNDMigrationDone(int userId)919 boolean isDNDMigrationDone(int userId) { 920 return Secure.getIntForUser(getContext().getContentResolver(), 921 Secure.DND_CONFIGS_MIGRATED, 0, userId) == 1; 922 } 923 924 @VisibleForTesting setDNDMigrationDone(int userId)925 void setDNDMigrationDone(int userId) { 926 Secure.putIntForUser(getContext().getContentResolver(), 927 Secure.DND_CONFIGS_MIGRATED, 1, userId); 928 } 929 migrateDefaultNAS()930 protected void migrateDefaultNAS() { 931 final List<UserInfo> activeUsers = mUm.getUsers(); 932 for (UserInfo userInfo : activeUsers) { 933 int userId = userInfo.getUserHandle().getIdentifier(); 934 if (isNASMigrationDone(userId) || isProfileUser(userInfo)) { 935 continue; 936 } 937 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 938 if (allowedComponents.size() == 0) { // user set to none 939 Slog.d(TAG, "NAS Migration: user set to none, disable new NAS setting"); 940 setNASMigrationDone(userId); 941 mAssistants.clearDefaults(); 942 } else { 943 Slog.d(TAG, "Reset NAS setting and migrate to new default"); 944 resetAssistantUserSet(userId); 945 // migrate to new default and set migration done 946 mAssistants.resetDefaultAssistantsIfNecessary(); 947 } 948 } 949 } 950 951 @VisibleForTesting setNASMigrationDone(int baseUserId)952 void setNASMigrationDone(int baseUserId) { 953 for (int profileId : mUm.getProfileIds(baseUserId, false)) { 954 Secure.putIntForUser(getContext().getContentResolver(), 955 Secure.NAS_SETTINGS_UPDATED, 1, profileId); 956 } 957 } 958 959 @VisibleForTesting isNASMigrationDone(int userId)960 boolean isNASMigrationDone(int userId) { 961 return (Secure.getIntForUser(getContext().getContentResolver(), 962 Secure.NAS_SETTINGS_UPDATED, 0, userId) == 1); 963 } 964 isProfileUser(UserInfo userInfo)965 boolean isProfileUser(UserInfo userInfo) { 966 if (privateSpaceFlagsEnabled()) { 967 return userInfo.isProfile() && hasParent(userInfo); 968 } 969 return userInfo.isManagedProfile() || userInfo.isCloneProfile(); 970 } 971 hasParent(UserInfo profile)972 boolean hasParent(UserInfo profile) { 973 return mUmInternal.getProfileParentId(profile.id) != profile.id; 974 } 975 setDefaultAssistantForUser(int userId)976 protected void setDefaultAssistantForUser(int userId) { 977 ArraySet<ComponentName> defaults = mAssistants.getDefaultComponents(); 978 // We should have only one default assistant by default 979 // allowAssistant should execute once in practice 980 for (int i = 0; i < defaults.size(); i++) { 981 ComponentName cn = defaults.valueAt(i); 982 if (allowAssistant(userId, cn)) return; 983 } 984 } 985 986 /** 987 * This method will update the flags and/or the icon of the summary. 988 * It will set it to FLAG_ONGOING_EVENT if any of its group members 989 * has the same flag. It will delete the flag otherwise. 990 * It will update the summary notification icon if the group children's 991 * icons are different. 992 * @param userId user id of the autogroup summary 993 * @param pkg package of the autogroup summary 994 * @param summaryAttr the new flags and/or icon & color for this summary 995 * @param isAppForeground true if the app is currently in the foreground. 996 */ 997 @GuardedBy("mNotificationLock") updateAutobundledSummaryLocked(int userId, String pkg, NotificationAttributes summaryAttr, boolean isAppForeground)998 protected void updateAutobundledSummaryLocked(int userId, String pkg, 999 NotificationAttributes summaryAttr, boolean isAppForeground) { 1000 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 1001 if (summaries == null) { 1002 return; 1003 } 1004 String summaryKey = summaries.get(pkg); 1005 if (summaryKey == null) { 1006 return; 1007 } 1008 NotificationRecord summary = mNotificationsByKey.get(summaryKey); 1009 if (summary == null) { 1010 return; 1011 } 1012 int oldFlags = summary.getSbn().getNotification().flags; 1013 1014 boolean attributesUpdated = 1015 !summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon()) 1016 || summaryAttr.iconColor != summary.getSbn().getNotification().color 1017 || summaryAttr.visibility != summary.getSbn().getNotification().visibility; 1018 1019 if (oldFlags != summaryAttr.flags || attributesUpdated) { 1020 summary.getSbn().getNotification().flags = 1021 summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags; 1022 summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon); 1023 summary.getSbn().getNotification().color = summaryAttr.iconColor; 1024 summary.getSbn().getNotification().visibility = summaryAttr.visibility; 1025 mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground, 1026 mPostNotificationTrackerFactory.newTracker(null))); 1027 } 1028 } 1029 allowDndPackage(int userId, String packageName)1030 private void allowDndPackage(int userId, String packageName) { 1031 try { 1032 getBinderService().setNotificationPolicyAccessGrantedForUser(packageName, userId, true); 1033 } catch (RemoteException e) { 1034 e.printStackTrace(); 1035 } 1036 } 1037 allowNotificationListener(int userId, ComponentName cn)1038 private void allowNotificationListener(int userId, ComponentName cn) { 1039 1040 try { 1041 getBinderService().setNotificationListenerAccessGrantedForUser(cn, 1042 userId, true, true); 1043 } catch (RemoteException e) { 1044 e.printStackTrace(); 1045 } 1046 } 1047 allowAssistant(int userId, ComponentName candidate)1048 private boolean allowAssistant(int userId, ComponentName candidate) { 1049 Set<ComponentName> validAssistants = 1050 mAssistants.queryPackageForServices( 1051 null, 1052 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); 1053 if (candidate != null && validAssistants.contains(candidate)) { 1054 setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true, false); 1055 return true; 1056 } 1057 return false; 1058 } 1059 readPolicyXml(InputStream stream, boolean forRestore, int userId)1060 void readPolicyXml(InputStream stream, boolean forRestore, int userId) 1061 throws XmlPullParserException, NumberFormatException, IOException { 1062 final TypedXmlPullParser parser; 1063 if (forRestore) { 1064 parser = Xml.newFastPullParser(); 1065 parser.setInput(stream, StandardCharsets.UTF_8.name()); 1066 } else { 1067 parser = Xml.resolvePullParser(stream); 1068 } 1069 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY); 1070 boolean migratedManagedServices = false; 1071 UserInfo userInfo = mUmInternal.getUserInfo(userId); 1072 boolean ineligibleForManagedServices = forRestore && isProfileUser(userInfo); 1073 int outerDepth = parser.getDepth(); 1074 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 1075 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) { 1076 mZenModeHelper.readXml(parser, forRestore, userId); 1077 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){ 1078 mPreferencesHelper.readXml(parser, forRestore, userId); 1079 } 1080 if (mListeners.getConfig().xmlTag.equals(parser.getName())) { 1081 if (ineligibleForManagedServices) { 1082 continue; 1083 } 1084 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 1085 migratedManagedServices = true; 1086 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) { 1087 if (ineligibleForManagedServices) { 1088 continue; 1089 } 1090 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 1091 migratedManagedServices = true; 1092 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) { 1093 if (ineligibleForManagedServices) { 1094 continue; 1095 } 1096 mConditionProviders.readXml( 1097 parser, mAllowedManagedServicePackages, forRestore, userId); 1098 migratedManagedServices = true; 1099 } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) { 1100 mSnoozeHelper.readXml(parser, System.currentTimeMillis()); 1101 } 1102 if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) { 1103 if (forRestore && userId != USER_SYSTEM) { 1104 continue; 1105 } 1106 mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null, 1107 LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true); 1108 } 1109 } 1110 1111 if (!migratedManagedServices) { 1112 mListeners.migrateToXml(); 1113 mAssistants.migrateToXml(); 1114 mConditionProviders.migrateToXml(); 1115 handleSavePolicyFile(); 1116 } 1117 1118 mAssistants.resetDefaultAssistantsIfNecessary(); 1119 mPreferencesHelper.syncChannelsBypassingDnd(); 1120 } 1121 1122 @VisibleForTesting resetDefaultDndIfNecessary()1123 void resetDefaultDndIfNecessary() { 1124 boolean removed = false; 1125 final List<UserInfo> activeUsers = mUm.getAliveUsers(); 1126 for (UserInfo userInfo : activeUsers) { 1127 int userId = userInfo.getUserHandle().getIdentifier(); 1128 if (isDNDMigrationDone(userId)) { 1129 continue; 1130 } 1131 removed |= mConditionProviders.removeDefaultFromConfig(userId); 1132 mConditionProviders.resetDefaultFromConfig(); 1133 allowDndPackages(userId); 1134 } 1135 if (removed) { 1136 handleSavePolicyFile(); 1137 } 1138 } 1139 1140 @VisibleForTesting loadPolicyFile()1141 protected void loadPolicyFile() { 1142 if (DBG) Slog.d(TAG, "loadPolicyFile"); 1143 synchronized (mPolicyFile) { 1144 InputStream infile = null; 1145 try { 1146 infile = mPolicyFile.openRead(); 1147 readPolicyXml(infile, false /*forRestore*/, USER_ALL); 1148 1149 // We re-load the default dnd packages to allow the newly added and denined. 1150 final boolean isWatch = mPackageManagerClient.hasSystemFeature( 1151 PackageManager.FEATURE_WATCH); 1152 if (isWatch) { 1153 resetDefaultDndIfNecessary(); 1154 } 1155 } catch (FileNotFoundException e) { 1156 // No data yet 1157 // Load default managed services approvals 1158 loadDefaultApprovedServices(USER_SYSTEM); 1159 allowDefaultApprovedServices(USER_SYSTEM); 1160 } catch (IOException e) { 1161 Log.wtf(TAG, "Unable to read notification policy", e); 1162 } catch (NumberFormatException e) { 1163 Log.wtf(TAG, "Unable to parse notification policy", e); 1164 } catch (XmlPullParserException e) { 1165 Log.wtf(TAG, "Unable to parse notification policy", e); 1166 } finally { 1167 IoUtils.closeQuietly(infile); 1168 } 1169 } 1170 } 1171 1172 @VisibleForTesting handleSavePolicyFile()1173 protected void handleSavePolicyFile() { 1174 if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) { 1175 IoThread.getHandler().postDelayed(mSavePolicyFile, 250); 1176 } 1177 } 1178 privateSpaceFlagsEnabled()1179 protected static boolean privateSpaceFlagsEnabled() { 1180 return allowPrivateProfile() && android.multiuser.Flags.enablePrivateSpaceFeatures(); 1181 } 1182 1183 private final class SavePolicyFileRunnable implements Runnable { 1184 @Override run()1185 public void run() { 1186 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 1187 synchronized (mPolicyFile) { 1188 final FileOutputStream stream; 1189 try { 1190 stream = mPolicyFile.startWrite(); 1191 } catch (IOException e) { 1192 Slog.w(TAG, "Failed to save policy file", e); 1193 return; 1194 } 1195 1196 try { 1197 writePolicyXml(stream, false /*forBackup*/, USER_ALL); 1198 mPolicyFile.finishWrite(stream); 1199 } catch (IOException e) { 1200 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 1201 mPolicyFile.failWrite(stream); 1202 } 1203 } 1204 BackupManager.dataChanged(getContext().getPackageName()); 1205 } 1206 } 1207 writePolicyXml(OutputStream stream, boolean forBackup, int userId)1208 private void writePolicyXml(OutputStream stream, boolean forBackup, int userId) 1209 throws IOException { 1210 final TypedXmlSerializer out; 1211 if (forBackup) { 1212 out = Xml.newFastSerializer(); 1213 out.setOutput(stream, StandardCharsets.UTF_8.name()); 1214 } else { 1215 out = Xml.resolveSerializer(stream); 1216 } 1217 out.startDocument(null, true); 1218 out.startTag(null, TAG_NOTIFICATION_POLICY); 1219 out.attributeInt(null, ATTR_VERSION, DB_VERSION); 1220 mZenModeHelper.writeXml(out, forBackup, null, userId); 1221 mPreferencesHelper.writeXml(out, forBackup, userId); 1222 mListeners.writeXml(out, forBackup, userId); 1223 mAssistants.writeXml(out, forBackup, userId); 1224 mSnoozeHelper.writeXml(out); 1225 mConditionProviders.writeXml(out, forBackup, userId); 1226 if (!forBackup || userId == USER_SYSTEM) { 1227 writeSecureNotificationsPolicy(out); 1228 } 1229 out.endTag(null, TAG_NOTIFICATION_POLICY); 1230 out.endDocument(); 1231 } 1232 1233 @VisibleForTesting 1234 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 1235 1236 @Override 1237 public void prepareForPossibleShutdown() { 1238 mHistoryManager.triggerWriteToDisk(); 1239 } 1240 1241 @Override 1242 public void onSetDisabled(int status) { 1243 synchronized (mNotificationLock) { 1244 mAttentionHelper.updateDisableNotificationEffectsLocked(status); 1245 } 1246 } 1247 1248 @Override 1249 public void onClearAll(int callingUid, int callingPid, int userId) { 1250 synchronized (mNotificationLock) { 1251 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null, 1252 /*includeCurrentProfiles*/ true, FLAG_ONGOING_EVENT | FLAG_NO_CLEAR); 1253 } 1254 } 1255 1256 @Override 1257 public void onNotificationClick(int callingUid, int callingPid, String key, 1258 NotificationVisibility nv) { 1259 exitIdle(); 1260 synchronized (mNotificationLock) { 1261 NotificationRecord r = mNotificationsByKey.get(key); 1262 if (r == null) { 1263 Slog.w(TAG, "No notification with key: " + key); 1264 return; 1265 } 1266 final long now = System.currentTimeMillis(); 1267 MetricsLogger.action(r.getItemLogMaker() 1268 .setType(MetricsEvent.TYPE_ACTION) 1269 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 1270 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); 1271 mNotificationRecordLogger.log( 1272 NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, r); 1273 EventLogTags.writeNotificationClicked(key, 1274 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 1275 nv.rank, nv.count); 1276 1277 StatusBarNotification sbn = r.getSbn(); 1278 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 1279 sbn.getId(), FLAG_AUTO_CANCEL, 1280 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_BUBBLE, 1281 false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null); 1282 nv.recycle(); 1283 reportUserInteraction(r); 1284 mAssistants.notifyAssistantNotificationClicked(r); 1285 } 1286 } 1287 1288 @Override 1289 public void onNotificationActionClick(int callingUid, int callingPid, String key, 1290 int actionIndex, Notification.Action action, NotificationVisibility nv, 1291 boolean generatedByAssistant) { 1292 exitIdle(); 1293 synchronized (mNotificationLock) { 1294 NotificationRecord r = mNotificationsByKey.get(key); 1295 if (r == null) { 1296 Slog.w(TAG, "No notification with key: " + key); 1297 return; 1298 } 1299 final long now = System.currentTimeMillis(); 1300 MetricsLogger.action(r.getLogMaker(now) 1301 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) 1302 .setType(MetricsEvent.TYPE_ACTION) 1303 .setSubtype(actionIndex) 1304 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 1305 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count) 1306 .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART, 1307 action.isContextual() ? 1 : 0) 1308 .addTaggedData( 1309 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1310 generatedByAssistant ? 1 : 0) 1311 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 1312 nv.location.toMetricsEventEnum())); 1313 mNotificationRecordLogger.log( 1314 NotificationRecordLogger.NotificationEvent.fromAction(actionIndex, 1315 generatedByAssistant, action.isContextual()), r); 1316 EventLogTags.writeNotificationActionClicked(key, 1317 action.actionIntent.getTarget().toString(), 1318 action.actionIntent.getIntent().toString(), actionIndex, 1319 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 1320 nv.rank, nv.count); 1321 nv.recycle(); 1322 reportUserInteraction(r); 1323 mAssistants.notifyAssistantActionClicked(r, action, generatedByAssistant); 1324 // Notifications that have been interacted with should no longer be lifetime 1325 // extended. 1326 if (lifetimeExtensionRefactor()) { 1327 // This cancellation should only work if 1328 // the notification still has FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY 1329 // We wait for 200 milliseconds before posting the cancel, to allow the app 1330 // time to update the notification in response instead. 1331 // If that update goes through, the notification won't have the lifetime 1332 // extended flag, and this cancellation will be dropped. 1333 mHandler.scheduleCancelNotification( 1334 new CancelNotificationRunnable( 1335 callingUid, 1336 callingPid, 1337 r.getSbn().getPackageName(), 1338 r.getSbn().getTag(), 1339 r.getSbn().getId(), 1340 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY /*=mustHaveFlags*/, 1341 FLAG_NO_DISMISS /*=mustNotHaveFlags*/, 1342 false /*=sendDelete*/, 1343 r.getUserId(), 1344 REASON_CLICK, 1345 -1 /*=rank*/, 1346 -1 /*=count*/, 1347 null /*=listener*/, 1348 SystemClock.elapsedRealtime()), 1349 200); 1350 } 1351 } 1352 } 1353 1354 @Override 1355 public void onNotificationClear(int callingUid, int callingPid, 1356 String pkg, int userId, String key, 1357 @NotificationStats.DismissalSurface int dismissalSurface, 1358 @NotificationStats.DismissalSentiment int dismissalSentiment, 1359 NotificationVisibility nv) { 1360 String tag = null; 1361 int id = 0; 1362 synchronized (mNotificationLock) { 1363 NotificationRecord r = mNotificationsByKey.get(key); 1364 if (r != null) { 1365 r.recordDismissalSurface(dismissalSurface); 1366 r.recordDismissalSentiment(dismissalSentiment); 1367 tag = r.getSbn().getTag(); 1368 id = r.getSbn().getId(); 1369 } 1370 } 1371 1372 int mustNotHaveFlags = FLAG_NO_DISMISS; 1373 cancelNotification(callingUid, callingPid, pkg, tag, id, 1374 /* mustHaveFlags= */ 0, 1375 /* mustNotHaveFlags= */ mustNotHaveFlags, 1376 /* sendDelete= */ true, 1377 userId, REASON_CANCEL, nv.rank, nv.count, /* listener= */ null); 1378 nv.recycle(); 1379 } 1380 1381 @Override 1382 public void onPanelRevealed(boolean clearEffects, int items) { 1383 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL); 1384 MetricsLogger.histogram(getContext(), "note_load", items); 1385 mNotificationRecordLogger.log( 1386 NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN); 1387 EventLogTags.writeNotificationPanelRevealed(items); 1388 if (clearEffects) { 1389 clearEffects(); 1390 } 1391 mAssistants.onPanelRevealed(items); 1392 } 1393 1394 @Override 1395 public void onPanelHidden() { 1396 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL); 1397 mNotificationRecordLogger.log( 1398 NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE); 1399 EventLogTags.writeNotificationPanelHidden(); 1400 mAssistants.onPanelHidden(); 1401 } 1402 1403 @Override 1404 public void clearEffects() { 1405 synchronized (mNotificationLock) { 1406 if (DBG) Slog.d(TAG, "clearEffects"); 1407 mAttentionHelper.clearAttentionEffects(); 1408 } 1409 } 1410 1411 @Override 1412 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, 1413 int id, int uid, int initialPid, String message, int userId) { 1414 final boolean fgService; 1415 final boolean uiJob; 1416 synchronized (mNotificationLock) { 1417 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 1418 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; 1419 uiJob = r != null && (r.getNotification().flags & FLAG_USER_INITIATED_JOB) != 0; 1420 } 1421 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 1422 REASON_ERROR, null); 1423 if (fgService || uiJob) { 1424 // Still crash for foreground services or user-initiated jobs, preventing the 1425 // not-crash behaviour abused by apps to give us a garbage notification and 1426 // silently start a fg service or user-initiated job. 1427 final int exceptionTypeId = fgService 1428 ? BadForegroundServiceNotificationException.TYPE_ID 1429 : BadUserInitiatedJobNotificationException.TYPE_ID; 1430 Binder.withCleanCallingIdentity( 1431 () -> mAm.crashApplicationWithType(uid, initialPid, pkg, -1, 1432 "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " 1433 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " 1434 + message, true /* force */, exceptionTypeId)); 1435 } 1436 } 1437 1438 @Override 1439 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 1440 NotificationVisibility[] noLongerVisibleKeys) { 1441 synchronized (mNotificationLock) { 1442 for (NotificationVisibility nv : newlyVisibleKeys) { 1443 NotificationRecord r = mNotificationsByKey.get(nv.key); 1444 if (r == null) continue; 1445 if (!r.isSeen()) { 1446 // Report to usage stats that notification was made visible 1447 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key); 1448 reportSeen(r); 1449 } 1450 r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger); 1451 mAssistants.notifyAssistantVisibilityChangedLocked(r, true); 1452 boolean isHun = (nv.location 1453 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP); 1454 // hasBeenVisiblyExpanded must be called after updating the expansion state of 1455 // the NotificationRecord to ensure the expansion state is up-to-date. 1456 if (isHun || r.hasBeenVisiblyExpanded()) { 1457 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum()); 1458 } 1459 maybeRecordInterruptionLocked(r); 1460 nv.recycle(); 1461 } 1462 // Note that we might receive this event after notifications 1463 // have already left the system, e.g. after dismissing from the 1464 // shade. Hence not finding notifications in 1465 // mNotificationsByKey is not an exceptional condition. 1466 for (NotificationVisibility nv : noLongerVisibleKeys) { 1467 NotificationRecord r = mNotificationsByKey.get(nv.key); 1468 if (r == null) continue; 1469 r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger); 1470 mAssistants.notifyAssistantVisibilityChangedLocked(r, false); 1471 nv.recycle(); 1472 } 1473 } 1474 } 1475 1476 @Override 1477 public void onNotificationExpansionChanged(String key, 1478 boolean userAction, boolean expanded, int notificationLocation) { 1479 synchronized (mNotificationLock) { 1480 NotificationRecord r = mNotificationsByKey.get(key); 1481 if (r != null) { 1482 r.stats.onExpansionChanged(userAction, expanded); 1483 // hasBeenVisiblyExpanded must be called after updating the expansion state of 1484 // the NotificationRecord to ensure the expansion state is up-to-date. 1485 if (r.hasBeenVisiblyExpanded()) { 1486 logSmartSuggestionsVisible(r, notificationLocation); 1487 } 1488 if (userAction) { 1489 MetricsLogger.action(r.getItemLogMaker() 1490 .setType(expanded ? MetricsEvent.TYPE_DETAIL 1491 : MetricsEvent.TYPE_COLLAPSE)); 1492 mNotificationRecordLogger.log( 1493 NotificationRecordLogger.NotificationEvent.fromExpanded(expanded, 1494 userAction), 1495 r); 1496 } 1497 if (expanded && userAction) { 1498 r.recordExpanded(); 1499 reportUserInteraction(r); 1500 } 1501 mAssistants.notifyAssistantExpansionChangedLocked( 1502 r.getSbn(), r.getNotificationType(), userAction, expanded); 1503 } 1504 } 1505 } 1506 1507 @Override 1508 public void onNotificationDirectReplied(String key) { 1509 exitIdle(); 1510 String packageName = null; 1511 final int packageImportance; 1512 synchronized (mNotificationLock) { 1513 NotificationRecord r = mNotificationsByKey.get(key); 1514 if (r != null) { 1515 packageName = r.getSbn().getPackageName(); 1516 } 1517 } 1518 if (lifetimeExtensionRefactor() && packageName != null) { 1519 packageImportance = getPackageImportanceWithIdentity(packageName); 1520 } else { 1521 packageImportance = IMPORTANCE_NONE; 1522 } 1523 synchronized (mNotificationLock) { 1524 NotificationRecord r = mNotificationsByKey.get(key); 1525 if (r != null) { 1526 // If the notification is already marked as lifetime extended before we record 1527 // the new direct reply, there must have been a previous lifetime extension 1528 // event, and the app has already cancelled the notification, or does not 1529 // respond to direct replies with updates. So we need to update System UI 1530 // immediately. 1531 if (lifetimeExtensionRefactor()) { 1532 maybeNotifySystemUiListenerLifetimeExtendedLocked(r, 1533 r.getSbn().getPackageName(), packageImportance); 1534 } 1535 1536 r.recordDirectReplied(); 1537 mMetricsLogger.write(r.getLogMaker() 1538 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION) 1539 .setType(MetricsEvent.TYPE_ACTION)); 1540 mNotificationRecordLogger.log( 1541 NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED, 1542 r); 1543 reportUserInteraction(r); 1544 mAssistants.notifyAssistantNotificationDirectReplyLocked(r); 1545 } 1546 } 1547 } 1548 1549 @Override 1550 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, 1551 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) { 1552 synchronized (mNotificationLock) { 1553 NotificationRecord r = mNotificationsByKey.get(key); 1554 if (r != null) { 1555 r.setNumSmartRepliesAdded(smartReplyCount); 1556 r.setNumSmartActionsAdded(smartActionCount); 1557 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 1558 r.setEditChoicesBeforeSending(editBeforeSending); 1559 } 1560 } 1561 } 1562 1563 @Override 1564 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply, 1565 int notificationLocation, boolean modifiedBeforeSending) { 1566 String packageName = null; 1567 final int packageImportance; 1568 synchronized (mNotificationLock) { 1569 NotificationRecord r = mNotificationsByKey.get(key); 1570 if (r != null) { 1571 packageName = r.getSbn().getPackageName(); 1572 } 1573 } 1574 if (lifetimeExtensionRefactor() && packageName != null) { 1575 packageImportance = getPackageImportanceWithIdentity(packageName); 1576 } else { 1577 packageImportance = IMPORTANCE_NONE; 1578 } 1579 synchronized (mNotificationLock) { 1580 NotificationRecord r = mNotificationsByKey.get(key); 1581 if (r != null) { 1582 // If the notification is already marked as lifetime extended before we record 1583 // the new direct reply, there must have been a previous lifetime extension 1584 // event, and the app has already cancelled the notification, or does not 1585 // respond to direct replies with updates. So we need to update System UI 1586 // immediately. 1587 if (lifetimeExtensionRefactor()) { 1588 maybeNotifySystemUiListenerLifetimeExtendedLocked(r, 1589 r.getSbn().getPackageName(), packageImportance); 1590 } 1591 r.recordSmartReplied(); 1592 LogMaker logMaker = r.getLogMaker() 1593 .setCategory(MetricsEvent.SMART_REPLY_ACTION) 1594 .setSubtype(replyIndex) 1595 .addTaggedData( 1596 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1597 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1598 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 1599 notificationLocation) 1600 .addTaggedData( 1601 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1602 r.getEditChoicesBeforeSending() ? 1 : 0) 1603 .addTaggedData( 1604 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING, 1605 modifiedBeforeSending ? 1 : 0); 1606 mMetricsLogger.write(logMaker); 1607 mNotificationRecordLogger.log( 1608 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED, 1609 r); 1610 // Treat clicking on a smart reply as a user interaction. 1611 reportUserInteraction(r); 1612 mAssistants.notifyAssistantSuggestedReplySent( 1613 r.getSbn(), r.getNotificationType(), reply, 1614 r.getSuggestionsGeneratedByAssistant()); 1615 } 1616 } 1617 } 1618 1619 @Override 1620 public void onNotificationSettingsViewed(String key) { 1621 synchronized (mNotificationLock) { 1622 NotificationRecord r = mNotificationsByKey.get(key); 1623 if (r != null) { 1624 r.recordViewedSettings(); 1625 } 1626 } 1627 } 1628 1629 @Override 1630 public void onNotificationBubbleChanged(String key, boolean isBubble, int bubbleFlags) { 1631 synchronized (mNotificationLock) { 1632 NotificationRecord r = mNotificationsByKey.get(key); 1633 if (r != null) { 1634 if (!isBubble) { 1635 // This happens if the user has dismissed the bubble but the notification 1636 // is still active in the shade, enqueuing would create a bubble since 1637 // the notification is technically allowed. Flip the flag so that 1638 // apps querying noMan will know that their notification is not showing 1639 // as a bubble. 1640 r.getNotification().flags &= ~FLAG_BUBBLE; 1641 r.setFlagBubbleRemoved(true); 1642 } else { 1643 // Enqueue will trigger resort & if the flag is allowed to be true it'll 1644 // be applied there. 1645 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 1646 r.setFlagBubbleRemoved(false); 1647 if (r.getNotification().getBubbleMetadata() != null) { 1648 r.getNotification().getBubbleMetadata().setFlags(bubbleFlags); 1649 } 1650 // Force isAppForeground true here, because for sysui's purposes we 1651 // want to adjust the flag behaviour. 1652 mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), 1653 r, true /* isAppForeground*/, 1654 mPostNotificationTrackerFactory.newTracker(null))); 1655 } 1656 } 1657 } 1658 } 1659 1660 @Override 1661 public void onBubbleMetadataFlagChanged(String key, int flags) { 1662 synchronized (mNotificationLock) { 1663 NotificationRecord r = mNotificationsByKey.get(key); 1664 if (r != null) { 1665 Notification.BubbleMetadata data = r.getNotification().getBubbleMetadata(); 1666 if (data == null) { 1667 // No data, do nothing 1668 return; 1669 } 1670 1671 if (flags != data.getFlags()) { 1672 int changedFlags = data.getFlags() ^ flags; 1673 if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) { 1674 // Suppress notification flag changed, clear any effects 1675 mAttentionHelper.clearEffectsLocked(key); 1676 } 1677 data.setFlags(flags); 1678 // Shouldn't alert again just because of a flag change. 1679 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 1680 // Force isAppForeground true here, because for sysui's purposes we 1681 // want to be able to adjust the flag behaviour. 1682 mHandler.post( 1683 new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r, 1684 /* foreground= */ true, 1685 mPostNotificationTrackerFactory.newTracker(null))); 1686 } 1687 } 1688 } 1689 } 1690 1691 /** 1692 * Grant permission to read the specified URI to the package specified in the 1693 * NotificationRecord associated with the given key. The callingUid represents the UID of 1694 * SystemUI from which this method is being called. 1695 * 1696 * For this to work, SystemUI must have permission to read the URI when running under the 1697 * user associated with the NotificationRecord, and this grant will fail when trying 1698 * to grant URI permissions across users. 1699 */ 1700 @Override 1701 public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, 1702 String packageName, int callingUid) { 1703 synchronized (mNotificationLock) { 1704 InlineReplyUriRecord r = mInlineReplyRecordsByKey.get(key); 1705 if (r == null) { 1706 InlineReplyUriRecord newRecord = new InlineReplyUriRecord( 1707 mUgmInternal.newUriPermissionOwner("INLINE_REPLY:" + key), 1708 user, 1709 packageName, 1710 key); 1711 r = newRecord; 1712 mInlineReplyRecordsByKey.put(key, r); 1713 } 1714 IBinder owner = r.getPermissionOwner(); 1715 int uid = callingUid; 1716 int userId = r.getUserId(); 1717 if (UserHandle.getUserId(uid) != userId) { 1718 try { 1719 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 1720 if (pkgs == null) { 1721 Log.e(TAG, "Cannot grant uri permission to unknown UID: " 1722 + callingUid); 1723 } 1724 final String pkg = pkgs[0]; // Get the SystemUI package 1725 // Find the UID for SystemUI for the correct user 1726 uid = mPackageManager.getPackageUid(pkg, 0, userId); 1727 } catch (RemoteException re) { 1728 Log.e(TAG, "Cannot talk to package manager", re); 1729 } 1730 } 1731 r.addUri(uri); 1732 grantUriPermission(owner, uri, uid, r.getPackageName(), userId); 1733 } 1734 } 1735 1736 @Override 1737 /** 1738 * Clears inline URI permission grants by destroying the permission owner for the specified 1739 * notification. 1740 */ 1741 public void clearInlineReplyUriPermissions(String key, int callingUid) { 1742 synchronized (mNotificationLock) { 1743 InlineReplyUriRecord uriRecord = mInlineReplyRecordsByKey.get(key); 1744 if (uriRecord != null) { 1745 destroyPermissionOwner(uriRecord.getPermissionOwner(), uriRecord.getUserId(), 1746 "INLINE_REPLY: " + uriRecord.getKey()); 1747 mInlineReplyRecordsByKey.remove(key); 1748 } 1749 } 1750 } 1751 1752 @Override 1753 public void onNotificationFeedbackReceived(String key, Bundle feedback) { 1754 exitIdle(); 1755 synchronized (mNotificationLock) { 1756 NotificationRecord r = mNotificationsByKey.get(key); 1757 if (r == null) { 1758 if (DBG) Slog.w(TAG, "No notification with key: " + key); 1759 return; 1760 } 1761 mAssistants.notifyAssistantFeedbackReceived(r, feedback); 1762 } 1763 } 1764 1765 }; 1766 1767 NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() { 1768 @Nullable 1769 @Override 1770 public NotificationRecord getNotificationByKey(String key) { 1771 synchronized (mNotificationLock) { 1772 return mNotificationsByKey.get(key); 1773 } 1774 } 1775 1776 @Override 1777 @FlaggedApi(Flags.FLAG_ALL_NOTIFS_NEED_TTL) 1778 public void timeoutNotification(String key) { 1779 boolean foundNotification = false; 1780 int uid = 0; 1781 int pid = 0; 1782 String packageName = null; 1783 String tag = null; 1784 int id = 0; 1785 int userId = 0; 1786 1787 synchronized (mNotificationLock) { 1788 NotificationRecord record = findNotificationByKeyLocked(key); 1789 if (record != null) { 1790 foundNotification = true; 1791 uid = record.getUid(); 1792 pid = record.getSbn().getInitialPid(); 1793 packageName = record.getSbn().getPackageName(); 1794 tag = record.getSbn().getTag(); 1795 id = record.getSbn().getId(); 1796 userId = record.getUserId(); 1797 } 1798 } 1799 if (foundNotification) { 1800 if (lifetimeExtensionRefactor()) { 1801 cancelNotification(uid, pid, packageName, tag, id, 0, 1802 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 1803 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 1804 true, userId, REASON_TIMEOUT, null); 1805 } else { 1806 cancelNotification(uid, pid, packageName, tag, id, 0, 1807 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, 1808 true, userId, REASON_TIMEOUT, null); 1809 } 1810 } 1811 } 1812 }; 1813 1814 @VisibleForTesting logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)1815 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) { 1816 // If the newly visible notification has smart suggestions 1817 // then log that the user has seen them. 1818 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0) 1819 && !r.hasSeenSmartReplies()) { 1820 r.setSeenSmartReplies(true); 1821 LogMaker logMaker = r.getLogMaker() 1822 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE) 1823 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT, 1824 r.getNumSmartRepliesAdded()) 1825 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT, 1826 r.getNumSmartActionsAdded()) 1827 .addTaggedData( 1828 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1829 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1830 // The fields in the NotificationVisibility.NotificationLocation enum map 1831 // directly to the fields in the MetricsEvent.NotificationLocation enum. 1832 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation) 1833 .addTaggedData( 1834 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1835 r.getEditChoicesBeforeSending() ? 1 : 0); 1836 mMetricsLogger.write(logMaker); 1837 mNotificationRecordLogger.log( 1838 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLY_VISIBLE, 1839 r); 1840 } 1841 } 1842 logSensitiveAdjustmentReceived(boolean hasPosted, boolean hasSensitiveContent, int lifespanMs)1843 protected void logSensitiveAdjustmentReceived(boolean hasPosted, 1844 boolean hasSensitiveContent, int lifespanMs) { 1845 FrameworkStatsLog.write(FrameworkStatsLog.SENSITIVE_NOTIFICATION_REDACTION, hasPosted, 1846 hasSensitiveContent, lifespanMs); 1847 } 1848 1849 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { 1850 @Override 1851 public void onReceive(Context context, Intent intent) { 1852 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 1853 // update system notification channels 1854 SystemNotificationChannels.createAll(context); 1855 mZenModeHelper.updateZenRulesOnLocaleChange(); 1856 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser()); 1857 } 1858 } 1859 }; 1860 1861 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() { 1862 @Override 1863 public void onReceive(Context context, Intent intent) { 1864 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) { 1865 try { 1866 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); 1867 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); 1868 int restoredFromSdkInt = intent.getIntExtra( 1869 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0); 1870 mListeners.onSettingRestored( 1871 element, newValue, restoredFromSdkInt, getSendingUserId()); 1872 mConditionProviders.onSettingRestored( 1873 element, newValue, restoredFromSdkInt, getSendingUserId()); 1874 } catch (Exception e) { 1875 Slog.wtf(TAG, "Cannot restore managed services from settings", e); 1876 } 1877 } 1878 } 1879 }; 1880 1881 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() { 1882 @Override 1883 public void onReceive(Context context, Intent intent) { 1884 String action = intent.getAction(); 1885 if (action == null) { 1886 return; 1887 } 1888 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) { 1889 final NotificationRecord record; 1890 // TODO: b/323013410 - Record should be cloned instead of used directly. 1891 synchronized (mNotificationLock) { 1892 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY)); 1893 } 1894 if (record != null) { 1895 if (lifetimeExtensionRefactor()) { 1896 cancelNotification(record.getSbn().getUid(), 1897 record.getSbn().getInitialPid(), 1898 record.getSbn().getPackageName(), record.getSbn().getTag(), 1899 record.getSbn().getId(), 0, 1900 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 1901 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 1902 true, record.getUserId(), REASON_TIMEOUT, null); 1903 } else { 1904 cancelNotification(record.getSbn().getUid(), 1905 record.getSbn().getInitialPid(), 1906 record.getSbn().getPackageName(), record.getSbn().getTag(), 1907 record.getSbn().getId(), 0, 1908 FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, 1909 true, record.getUserId(), REASON_TIMEOUT, null); 1910 } 1911 } 1912 } 1913 } 1914 }; 1915 1916 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 1917 @Override 1918 public void onReceive(Context context, Intent intent) { 1919 String action = intent.getAction(); 1920 if (action == null) { 1921 return; 1922 } 1923 1924 boolean queryRemove = false; 1925 boolean packageChanged = false; 1926 boolean cancelNotifications = true; 1927 boolean hideNotifications = false; 1928 boolean unhideNotifications = false; 1929 int reason = REASON_PACKAGE_CHANGED; 1930 1931 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1932 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 1933 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1934 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 1935 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) 1936 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED) 1937 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED) 1938 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 1939 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1940 USER_ALL); 1941 String pkgList[] = null; 1942 int uidList[] = null; 1943 boolean removingPackage = queryRemove && 1944 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 1945 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage); 1946 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1947 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1948 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1949 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 1950 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1951 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1952 cancelNotifications = false; 1953 hideNotifications = true; 1954 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { 1955 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1956 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1957 cancelNotifications = false; 1958 unhideNotifications = true; 1959 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 1960 final int distractionRestrictions = 1961 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS, 1962 PackageManager.RESTRICTION_NONE); 1963 if ((distractionRestrictions 1964 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) { 1965 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1966 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1967 cancelNotifications = false; 1968 hideNotifications = true; 1969 } else { 1970 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1971 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1972 cancelNotifications = false; 1973 unhideNotifications = true; 1974 } 1975 } else { 1976 Uri uri = intent.getData(); 1977 if (uri == null) { 1978 return; 1979 } 1980 String pkgName = uri.getSchemeSpecificPart(); 1981 if (pkgName == null) { 1982 return; 1983 } 1984 if (packageChanged) { 1985 // We cancel notifications for packages which have just been disabled 1986 try { 1987 final int enabled = mPackageManager.getApplicationEnabledSetting( 1988 pkgName, 1989 changeUserId != USER_ALL ? changeUserId : 1990 USER_SYSTEM); 1991 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 1992 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 1993 cancelNotifications = false; 1994 } 1995 } catch (IllegalArgumentException e) { 1996 // Package doesn't exist; probably racing with uninstall. 1997 // cancelNotifications is already true, so nothing to do here. 1998 if (DBG) { 1999 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 2000 } 2001 } catch (RemoteException e) { 2002 // Failed to talk to PackageManagerService Should never happen! 2003 } 2004 } 2005 pkgList = new String[]{pkgName}; 2006 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 2007 } 2008 if (pkgList != null && (pkgList.length > 0)) { 2009 if (cancelNotifications) { 2010 for (String pkgName : pkgList) { 2011 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, 2012 changeUserId, reason); 2013 } 2014 } else if (hideNotifications && uidList != null && (uidList.length > 0)) { 2015 hideNotificationsForPackages(pkgList, uidList); 2016 } else if (unhideNotifications && uidList != null && (uidList.length > 0)) { 2017 unhideNotificationsForPackages(pkgList, uidList); 2018 } 2019 } 2020 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList); 2021 } 2022 } 2023 }; 2024 2025 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 2026 @Override 2027 public void onReceive(Context context, Intent intent) { 2028 String action = intent.getAction(); 2029 2030 if (action.equals(Intent.ACTION_USER_STOPPED)) { 2031 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 2032 if (userHandle >= 0) { 2033 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle, 2034 REASON_USER_STOPPED); 2035 } 2036 } else if ( 2037 isProfileUnavailable(action)) { 2038 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 2039 if (userHandle >= 0) { 2040 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle, 2041 REASON_PROFILE_TURNED_OFF); 2042 mSnoozeHelper.clearData(userHandle); 2043 } 2044 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 2045 if (!Flags.useSsmUserSwitchSignal()) { 2046 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2047 mUserProfiles.updateCache(context); 2048 if (!mUserProfiles.isProfileUser(userId, context)) { 2049 // reload per-user settings 2050 mSettingsObserver.update(null); 2051 // Refresh managed services 2052 mConditionProviders.onUserSwitched(userId); 2053 mListeners.onUserSwitched(userId); 2054 mZenModeHelper.onUserSwitched(userId); 2055 mPreferencesHelper.syncChannelsBypassingDnd(); 2056 } 2057 // assistant is the only thing that cares about managed profiles specifically 2058 mAssistants.onUserSwitched(userId); 2059 } 2060 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 2061 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2062 if (userId != USER_NULL) { 2063 mUserProfiles.updateCache(context); 2064 if (!mUserProfiles.isProfileUser(userId, context)) { 2065 allowDefaultApprovedServices(userId); 2066 } 2067 mHistoryManager.onUserAdded(userId); 2068 mSettingsObserver.update(null, userId); 2069 } 2070 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 2071 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2072 mUserProfiles.updateCache(context); 2073 mZenModeHelper.onUserRemoved(userId); 2074 mPreferencesHelper.onUserRemoved(userId); 2075 mListeners.onUserRemoved(userId); 2076 mConditionProviders.onUserRemoved(userId); 2077 mAssistants.onUserRemoved(userId); 2078 mHistoryManager.onUserRemoved(userId); 2079 mPreferencesHelper.syncChannelsBypassingDnd(); 2080 handleSavePolicyFile(); 2081 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { 2082 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 2083 mUserProfiles.updateCache(context); 2084 mAssistants.onUserUnlocked(userId); 2085 if (!mUserProfiles.isProfileUser(userId, context)) { 2086 mConditionProviders.onUserUnlocked(userId); 2087 mListeners.onUserUnlocked(userId); 2088 if (!android.app.Flags.modesApi()) { 2089 mZenModeHelper.onUserUnlocked(userId); 2090 } 2091 } 2092 } 2093 } 2094 2095 private boolean isProfileUnavailable(String action) { 2096 return privateSpaceFlagsEnabled() ? 2097 action.equals(Intent.ACTION_PROFILE_UNAVAILABLE) : 2098 action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 2099 } 2100 }; 2101 2102 private final class SettingsObserver extends ContentObserver { 2103 private final Uri NOTIFICATION_BADGING_URI 2104 = Secure.getUriFor(Secure.NOTIFICATION_BADGING); 2105 private final Uri NOTIFICATION_BUBBLES_URI 2106 = Secure.getUriFor(Secure.NOTIFICATION_BUBBLES); 2107 private final Uri NOTIFICATION_RATE_LIMIT_URI 2108 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); 2109 private final Uri NOTIFICATION_HISTORY_ENABLED 2110 = Secure.getUriFor(Secure.NOTIFICATION_HISTORY_ENABLED); 2111 private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI 2112 = Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS); 2113 private final Uri LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS 2114 = Secure.getUriFor( 2115 Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS); 2116 private final Uri LOCK_SCREEN_SHOW_NOTIFICATIONS 2117 = Secure.getUriFor(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS); 2118 private final Uri SHOW_NOTIFICATION_SNOOZE 2119 = Secure.getUriFor(Secure.SHOW_NOTIFICATION_SNOOZE); 2120 SettingsObserver(Handler handler)2121 SettingsObserver(Handler handler) { 2122 super(handler); 2123 } 2124 observe()2125 void observe() { 2126 ContentResolver resolver = getContext().getContentResolver(); 2127 resolver.registerContentObserver(NOTIFICATION_BADGING_URI, 2128 false, this, USER_ALL); 2129 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, 2130 false, this, USER_ALL); 2131 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI, 2132 false, this, USER_ALL); 2133 resolver.registerContentObserver(NOTIFICATION_HISTORY_ENABLED, 2134 false, this, USER_ALL); 2135 resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI, 2136 false, this, USER_ALL); 2137 2138 resolver.registerContentObserver(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 2139 false, this, USER_ALL); 2140 resolver.registerContentObserver(LOCK_SCREEN_SHOW_NOTIFICATIONS, 2141 false, this, USER_ALL); 2142 2143 resolver.registerContentObserver(SHOW_NOTIFICATION_SNOOZE, 2144 false, this, USER_ALL); 2145 2146 update(null); 2147 } 2148 destroy()2149 void destroy() { 2150 getContext().getContentResolver().unregisterContentObserver(this); 2151 } 2152 onChange(boolean selfChange, Uri uri, int userId)2153 @Override public void onChange(boolean selfChange, Uri uri, int userId) { 2154 update(uri); 2155 } 2156 update(Uri uri)2157 public void update(Uri uri) { 2158 ContentResolver resolver = getContext().getContentResolver(); 2159 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) { 2160 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver, 2161 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate); 2162 } 2163 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { 2164 mPreferencesHelper.updateBadgingEnabled(); 2165 } 2166 if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) { 2167 mPreferencesHelper.updateBubblesEnabled(); 2168 } 2169 if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) { 2170 for (UserInfo userInfo : mUm.getUsers()) { 2171 update(uri, userInfo.id); 2172 } 2173 } 2174 if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) { 2175 mPreferencesHelper.updateMediaNotificationFilteringEnabled(); 2176 } 2177 if (uri == null || LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS.equals(uri)) { 2178 mPreferencesHelper.updateLockScreenPrivateNotifications(); 2179 } 2180 if (uri == null || LOCK_SCREEN_SHOW_NOTIFICATIONS.equals(uri)) { 2181 mPreferencesHelper.updateLockScreenShowNotifications(); 2182 } 2183 if (SHOW_NOTIFICATION_SNOOZE.equals(uri)) { 2184 final boolean snoozeEnabled = Secure.getIntForUser(resolver, 2185 Secure.SHOW_NOTIFICATION_SNOOZE, 0, UserHandle.USER_CURRENT) 2186 != 0; 2187 if (!snoozeEnabled) { 2188 unsnoozeAll(); 2189 } 2190 } 2191 } 2192 update(Uri uri, int userId)2193 public void update(Uri uri, int userId) { 2194 ContentResolver resolver = getContext().getContentResolver(); 2195 if (uri == null || NOTIFICATION_HISTORY_ENABLED.equals(uri)) { 2196 mArchive.updateHistoryEnabled(userId, 2197 Secure.getIntForUser(resolver, 2198 Secure.NOTIFICATION_HISTORY_ENABLED, 0, 2199 userId) == 1); 2200 // note: this setting is also handled in NotificationHistoryManager 2201 } 2202 } 2203 } 2204 2205 private SettingsObserver mSettingsObserver; 2206 protected ZenModeHelper mZenModeHelper; 2207 2208 protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { 2209 2210 SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray(); 2211 StrongAuthTracker(Context context)2212 StrongAuthTracker(Context context) { 2213 super(context); 2214 } 2215 containsFlag(int haystack, int needle)2216 private boolean containsFlag(int haystack, int needle) { 2217 return (haystack & needle) != 0; 2218 } 2219 2220 // Return whether the user is in lockdown mode. 2221 // If the flag is not set, we assume the user is not in lockdown. isInLockDownMode(int userId)2222 public boolean isInLockDownMode(int userId) { 2223 return mUserInLockDownMode.get(userId, false); 2224 } 2225 2226 @Override onStrongAuthRequiredChanged(int userId)2227 public synchronized void onStrongAuthRequiredChanged(int userId) { 2228 boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId), 2229 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 2230 2231 // Nothing happens if the lockdown mode of userId keeps the same. 2232 if (userInLockDownModeNext == isInLockDownMode(userId)) { 2233 return; 2234 } 2235 2236 // When the lockdown mode is changed, we perform the following steps. 2237 // If the userInLockDownModeNext is true, all the function calls to 2238 // notifyPostedLocked and notifyRemovedLocked will not be executed. 2239 // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked 2240 // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked. 2241 // So we shall call cancelNotificationsWhenEnterLockDownMode before 2242 // we set mUserInLockDownMode as true. 2243 // On the other hand, if the userInLockDownModeNext is false, we shall call 2244 // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode 2245 if (userInLockDownModeNext) { 2246 cancelNotificationsWhenEnterLockDownMode(userId); 2247 } 2248 2249 mUserInLockDownMode.put(userId, userInLockDownModeNext); 2250 2251 if (!userInLockDownModeNext) { 2252 postNotificationsWhenExitLockDownMode(userId); 2253 } 2254 } 2255 } 2256 2257 private StrongAuthTracker mStrongAuthTracker; 2258 NotificationManagerService(Context context)2259 public NotificationManagerService(Context context) { 2260 this(context, 2261 new NotificationRecordLoggerImpl(), 2262 new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX)); 2263 } 2264 2265 @VisibleForTesting NotificationManagerService(Context context, NotificationRecordLogger notificationRecordLogger, InstanceIdSequence notificationInstanceIdSequence)2266 public NotificationManagerService(Context context, 2267 NotificationRecordLogger notificationRecordLogger, 2268 InstanceIdSequence notificationInstanceIdSequence) { 2269 super(context); 2270 mNotificationRecordLogger = notificationRecordLogger; 2271 mNotificationInstanceIdSequence = notificationInstanceIdSequence; 2272 Notification.processAllowlistToken = ALLOWLIST_TOKEN; 2273 } 2274 2275 // TODO - replace these methods with new fields in the VisibleForTesting constructor 2276 @VisibleForTesting setStrongAuthTracker(StrongAuthTracker strongAuthTracker)2277 void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) { 2278 mStrongAuthTracker = strongAuthTracker; 2279 } 2280 2281 @VisibleForTesting setLockPatternUtils(LockPatternUtils lockUtils)2282 void setLockPatternUtils(LockPatternUtils lockUtils) { 2283 mLockUtils = lockUtils; 2284 } 2285 2286 @VisibleForTesting getShortcutHelper()2287 ShortcutHelper getShortcutHelper() { 2288 return mShortcutHelper; 2289 } 2290 2291 @VisibleForTesting setShortcutHelper(ShortcutHelper helper)2292 void setShortcutHelper(ShortcutHelper helper) { 2293 mShortcutHelper = helper; 2294 } 2295 2296 @VisibleForTesting getNotificationRecordCount()2297 int getNotificationRecordCount() { 2298 synchronized (mNotificationLock) { 2299 int count = mNotificationList.size() + mNotificationsByKey.size() 2300 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size(); 2301 // subtract duplicates 2302 for (NotificationRecord posted : mNotificationList) { 2303 if (mNotificationsByKey.containsKey(posted.getKey())) { 2304 count--; 2305 } 2306 if (posted.getSbn().isGroup() && posted.getNotification().isGroupSummary()) { 2307 count--; 2308 } 2309 } 2310 2311 return count; 2312 } 2313 } 2314 2315 @VisibleForTesting clearNotifications()2316 void clearNotifications() { 2317 synchronized (mNotificationLock) { 2318 mEnqueuedNotifications.clear(); 2319 mNotificationList.clear(); 2320 mNotificationsByKey.clear(); 2321 mSummaryByGroupKey.clear(); 2322 } 2323 } 2324 2325 @VisibleForTesting addNotification(NotificationRecord r)2326 void addNotification(NotificationRecord r) { 2327 synchronized (mNotificationLock) { 2328 mNotificationList.add(r); 2329 mNotificationsByKey.put(r.getSbn().getKey(), r); 2330 if (r.getSbn().isGroup()) { 2331 mSummaryByGroupKey.put(r.getGroupKey(), r); 2332 } 2333 } 2334 } 2335 2336 @VisibleForTesting addEnqueuedNotification(NotificationRecord r)2337 void addEnqueuedNotification(NotificationRecord r) { 2338 synchronized (mNotificationLock) { 2339 mEnqueuedNotifications.add(r); 2340 } 2341 } 2342 2343 @VisibleForTesting getNotificationRecord(String key)2344 NotificationRecord getNotificationRecord(String key) { 2345 synchronized (mNotificationLock) { 2346 return mNotificationsByKey.get(key); 2347 } 2348 } 2349 2350 @VisibleForTesting setHandler(WorkerHandler handler)2351 void setHandler(WorkerHandler handler) { 2352 mHandler = handler; 2353 } 2354 2355 @VisibleForTesting setRankingHelper(RankingHelper rankingHelper)2356 void setRankingHelper(RankingHelper rankingHelper) { 2357 mRankingHelper = rankingHelper; 2358 } 2359 2360 @VisibleForTesting setPreferencesHelper(PreferencesHelper prefHelper)2361 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; } 2362 2363 @VisibleForTesting setZenHelper(ZenModeHelper zenHelper)2364 void setZenHelper(ZenModeHelper zenHelper) { 2365 mZenModeHelper = zenHelper; 2366 } 2367 2368 @VisibleForTesting setAttentionHelper(NotificationAttentionHelper nah)2369 void setAttentionHelper(NotificationAttentionHelper nah) { 2370 mAttentionHelper = nah; 2371 } 2372 2373 @VisibleForTesting setIsTelevision(boolean isTelevision)2374 void setIsTelevision(boolean isTelevision) { 2375 mIsTelevision = isTelevision; 2376 } 2377 2378 @VisibleForTesting setTelecomManager(TelecomManager tm)2379 void setTelecomManager(TelecomManager tm) { 2380 mTelecomManager = tm; 2381 } 2382 2383 // TODO: All tests should use this init instead of the one-off setters above. 2384 @VisibleForTesting init(WorkerHandler handler, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, LightsManager lightsManager, NotificationListeners notificationListeners, NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, NotificationUsageStats usageStats, AtomicFile policyFile, ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, NotificationHistoryManager historyManager, StatsManager statsManager, ActivityManagerInternal ami, MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper, UsageStatsManagerInternal usageStatsManagerInternal, TelecomManager telecomManager, NotificationChannelLogger channelLogger, SystemUiSystemPropertiesFlags.FlagResolver flagResolver, PermissionManager permissionManager, PowerManager powerManager, PostNotificationTrackerFactory postNotificationTrackerFactory)2385 void init(WorkerHandler handler, RankingHandler rankingHandler, 2386 IPackageManager packageManager, PackageManager packageManagerClient, 2387 LightsManager lightsManager, NotificationListeners notificationListeners, 2388 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, 2389 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, 2390 NotificationUsageStats usageStats, AtomicFile policyFile, 2391 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, 2392 ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats, 2393 DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, 2394 UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, 2395 NotificationHistoryManager historyManager, StatsManager statsManager, 2396 ActivityManagerInternal ami, 2397 MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper, 2398 UsageStatsManagerInternal usageStatsManagerInternal, 2399 TelecomManager telecomManager, NotificationChannelLogger channelLogger, 2400 SystemUiSystemPropertiesFlags.FlagResolver flagResolver, 2401 PermissionManager permissionManager, PowerManager powerManager, 2402 PostNotificationTrackerFactory postNotificationTrackerFactory) { 2403 mHandler = handler; 2404 Resources resources = getContext().getResources(); 2405 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), 2406 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, 2407 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); 2408 2409 mAccessibilityManager = 2410 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 2411 mAm = am; 2412 mAtm = atm; 2413 mAtm.setBackgroundActivityStartCallback(new NotificationTrampolineCallback()); 2414 mUgm = ugm; 2415 mUgmInternal = ugmInternal; 2416 mPackageManager = packageManager; 2417 mPackageManagerClient = packageManagerClient; 2418 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 2419 mPermissionManager = permissionManager; 2420 mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class); 2421 mUmInternal = LocalServices.getService(UserManagerInternal.class); 2422 mUsageStatsManagerInternal = usageStatsManagerInternal; 2423 mAppOps = appOps; 2424 mAppUsageStats = appUsageStats; 2425 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 2426 mCompanionManager = companionManager; 2427 mActivityManager = activityManager; 2428 mAmi = ami; 2429 mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class); 2430 mDpm = dpm; 2431 mUm = userManager; 2432 mTelecomManager = telecomManager; 2433 mPowerManager = powerManager; 2434 mPostNotificationTrackerFactory = postNotificationTrackerFactory; 2435 mPlatformCompat = IPlatformCompat.Stub.asInterface( 2436 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); 2437 2438 mStrongAuthTracker = new StrongAuthTracker(getContext()); 2439 String[] extractorNames; 2440 try { 2441 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 2442 } catch (Resources.NotFoundException e) { 2443 extractorNames = new String[0]; 2444 } 2445 mUsageStats = usageStats; 2446 mMetricsLogger = new MetricsLogger(); 2447 mRankingHandler = rankingHandler; 2448 mConditionProviders = conditionProviders; 2449 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(), 2450 mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient)); 2451 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 2452 @Override 2453 public void onConfigChanged() { 2454 handleSavePolicyFile(); 2455 } 2456 2457 @Override 2458 void onZenModeChanged() { 2459 Binder.withCleanCallingIdentity(() -> { 2460 sendRegisteredOnlyBroadcast(ACTION_INTERRUPTION_FILTER_CHANGED); 2461 getContext().sendBroadcastAsUser( 2462 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 2463 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 2464 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); 2465 synchronized (mNotificationLock) { 2466 updateInterruptionFilterLocked(); 2467 } 2468 mRankingHandler.requestSort(); 2469 }); 2470 } 2471 2472 @Override 2473 void onPolicyChanged(Policy newPolicy) { 2474 Binder.withCleanCallingIdentity(() -> { 2475 Intent intent = new Intent(ACTION_NOTIFICATION_POLICY_CHANGED); 2476 if (android.app.Flags.modesApi()) { 2477 intent.putExtra(EXTRA_NOTIFICATION_POLICY, newPolicy); 2478 } 2479 sendRegisteredOnlyBroadcast(intent); 2480 mRankingHandler.requestSort(); 2481 }); 2482 } 2483 2484 @Override 2485 void onConsolidatedPolicyChanged(Policy newConsolidatedPolicy) { 2486 Binder.withCleanCallingIdentity(() -> { 2487 if (android.app.Flags.modesApi()) { 2488 Intent intent = new Intent(ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED); 2489 intent.putExtra(EXTRA_NOTIFICATION_POLICY, newConsolidatedPolicy); 2490 sendRegisteredOnlyBroadcast(intent); 2491 } 2492 mRankingHandler.requestSort(); 2493 }); 2494 } 2495 2496 @Override 2497 void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) { 2498 Binder.withCleanCallingIdentity(() -> { 2499 Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED); 2500 intent.setPackage(pkg); 2501 intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id); 2502 intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status); 2503 getContext().sendBroadcastAsUser(intent, UserHandle.of(userId)); 2504 }); 2505 } 2506 }); 2507 mPermissionHelper = permissionHelper; 2508 mNotificationChannelLogger = channelLogger; 2509 mUserProfiles.updateCache(getContext()); 2510 mPreferencesHelper = new PreferencesHelper(getContext(), 2511 mPackageManagerClient, 2512 mRankingHandler, 2513 mZenModeHelper, 2514 mPermissionHelper, 2515 mPermissionManager, 2516 mNotificationChannelLogger, 2517 mAppOps, 2518 mUserProfiles, 2519 mShowReviewPermissionsNotification, 2520 Clock.systemUTC()); 2521 mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, 2522 mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat); 2523 mSnoozeHelper = snoozeHelper; 2524 mGroupHelper = groupHelper; 2525 mHistoryManager = historyManager; 2526 if (Flags.allNotifsNeedTtl()) { 2527 mTtlHelper = new TimeToLiveHelper(mNotificationManagerPrivate, getContext()); 2528 } 2529 2530 // This is a ManagedServices object that keeps track of the listeners. 2531 mListeners = notificationListeners; 2532 2533 // This is a MangedServices object that keeps track of the assistant. 2534 mAssistants = notificationAssistants; 2535 2536 // Needs to be set before loadPolicyFile 2537 mAllowedManagedServicePackages = this::canUseManagedServices; 2538 2539 mPolicyFile = policyFile; 2540 loadPolicyFile(); 2541 mStatusBar = getLocalService(StatusBarManagerInternal.class); 2542 if (mStatusBar != null) { 2543 mStatusBar.setNotificationDelegate(mNotificationDelegate); 2544 } 2545 2546 mZenModeHelper.initZenMode(); 2547 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 2548 2549 mSettingsObserver = new SettingsObserver(mHandler); 2550 2551 mArchive = new Archive(resources.getInteger( 2552 R.integer.config_notificationServiceArchiveSize)); 2553 2554 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK) 2555 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION); 2556 2557 mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( 2558 com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); 2559 2560 mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger( 2561 com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes); 2562 mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( 2563 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); 2564 2565 mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource( 2566 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos)); 2567 mDefaultSearchSelectorPkg = getContext().getString(getContext().getResources() 2568 .getIdentifier("config_defaultSearchSelectorPackageName", "string", "android")); 2569 2570 mFlagResolver = flagResolver; 2571 2572 mStatsManager = statsManager; 2573 2574 mToastRateLimiter = toastRateLimiter; 2575 2576 mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager, 2577 mAccessibilityManager, mPackageManagerClient, userManager, usageStats, 2578 mNotificationManagerPrivate, mZenModeHelper, flagResolver); 2579 2580 // register for various Intents. 2581 // If this is called within a test, make sure to unregister the intent receivers by 2582 // calling onDestroy() 2583 IntentFilter filter = new IntentFilter(); 2584 filter.addAction(Intent.ACTION_USER_STOPPED); 2585 if (!Flags.useSsmUserSwitchSignal()) { 2586 filter.addAction(Intent.ACTION_USER_SWITCHED); 2587 } 2588 filter.addAction(Intent.ACTION_USER_ADDED); 2589 filter.addAction(Intent.ACTION_USER_REMOVED); 2590 filter.addAction(Intent.ACTION_USER_UNLOCKED); 2591 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 2592 if (privateSpaceFlagsEnabled()){ 2593 filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE); 2594 } 2595 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null); 2596 2597 IntentFilter pkgFilter = new IntentFilter(); 2598 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 2599 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 2600 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 2601 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 2602 pkgFilter.addDataScheme("package"); 2603 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 2604 null); 2605 2606 IntentFilter suspendedPkgFilter = new IntentFilter(); 2607 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 2608 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); 2609 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 2610 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, 2611 suspendedPkgFilter, null, null); 2612 2613 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 2614 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 2615 null); 2616 2617 if (!Flags.allNotifsNeedTtl()) { 2618 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT); 2619 timeoutFilter.addDataScheme(SCHEME_TIMEOUT); 2620 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter, 2621 Context.RECEIVER_EXPORTED_UNAUDITED); 2622 } 2623 2624 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED); 2625 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter); 2626 2627 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED); 2628 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter); 2629 2630 mReviewNotificationPermissionsReceiver = new ReviewNotificationPermissionsReceiver(); 2631 getContext().registerReceiver(mReviewNotificationPermissionsReceiver, 2632 ReviewNotificationPermissionsReceiver.getFilter(), 2633 Context.RECEIVER_NOT_EXPORTED); 2634 2635 mAppOpsListener = new AppOpsManager.OnOpChangedInternalListener() { 2636 @Override 2637 public void onOpChanged(@NonNull String op, @NonNull String packageName, 2638 int userId) { 2639 mHandler.post( 2640 () -> handleNotificationPermissionChange(packageName, userId)); 2641 } 2642 }; 2643 2644 mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsListener); 2645 } 2646 2647 /** 2648 * Cleanup broadcast receivers change listeners. 2649 */ onDestroy()2650 public void onDestroy() { 2651 if (mIntentReceiver != null) { 2652 getContext().unregisterReceiver(mIntentReceiver); 2653 } 2654 if (mPackageIntentReceiver != null) { 2655 getContext().unregisterReceiver(mPackageIntentReceiver); 2656 } 2657 if (Flags.allNotifsNeedTtl()) { 2658 if (mTtlHelper != null) { 2659 mTtlHelper.destroy(); 2660 } 2661 } else { 2662 if (mNotificationTimeoutReceiver != null) { 2663 getContext().unregisterReceiver(mNotificationTimeoutReceiver); 2664 } 2665 } 2666 if (mRestoreReceiver != null) { 2667 getContext().unregisterReceiver(mRestoreReceiver); 2668 } 2669 if (mLocaleChangeReceiver != null) { 2670 getContext().unregisterReceiver(mLocaleChangeReceiver); 2671 } 2672 if (mSettingsObserver != null) { 2673 mSettingsObserver.destroy(); 2674 } 2675 if (mRoleObserver != null) { 2676 mRoleObserver.destroy(); 2677 } 2678 if (mShortcutHelper != null) { 2679 mShortcutHelper.destroy(); 2680 } 2681 if (mStatsManager != null) { 2682 mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES); 2683 mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES); 2684 mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES); 2685 mStatsManager.clearPullAtomCallback(DND_MODE_RULE); 2686 } 2687 if (mAppOps != null) { 2688 mAppOps.stopWatchingMode(mAppOpsListener); 2689 } 2690 if (mAlarmManager != null) { 2691 mAlarmManager.cancelAll(); 2692 } 2693 } 2694 getStringArrayResource(int key)2695 protected String[] getStringArrayResource(int key) { 2696 return getContext().getResources().getStringArray(key); 2697 } 2698 2699 @Override onStart()2700 public void onStart() { 2701 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> { 2702 try { 2703 if (DBG) { 2704 Slog.d(TAG, "Reposting " + r.getKey() + " " + muteOnReturn); 2705 } 2706 enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), 2707 r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), 2708 r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn, 2709 false /* byForegroundService */); 2710 } catch (Exception e) { 2711 Slog.e(TAG, "Cannot un-snooze notification", e); 2712 } 2713 }, mUserProfiles); 2714 2715 final File systemDir = new File(Environment.getDataDirectory(), "system"); 2716 mRankingThread.start(); 2717 2718 WorkerHandler handler = new WorkerHandler(Looper.myLooper()); 2719 2720 mShowReviewPermissionsNotification = getContext().getResources().getBoolean( 2721 R.bool.config_notificationReviewPermissions); 2722 2723 init(handler, new RankingHandlerWorker(mRankingThread.getLooper()), 2724 AppGlobals.getPackageManager(), getContext().getPackageManager(), 2725 getLocalService(LightsManager.class), 2726 new NotificationListeners(getContext(), mNotificationLock, mUserProfiles, 2727 AppGlobals.getPackageManager()), 2728 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles, 2729 AppGlobals.getPackageManager()), 2730 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()), 2731 null /*CDM is not initialized yet*/, snoozeHelper, 2732 new NotificationUsageStats(getContext()), 2733 new AtomicFile(new File( 2734 systemDir, "notification_policy.xml"), "notification-policy"), 2735 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE), 2736 getGroupHelper(), ActivityManager.getService(), 2737 LocalServices.getService(ActivityTaskManagerInternal.class), 2738 LocalServices.getService(UsageStatsManagerInternal.class), 2739 LocalServices.getService(DevicePolicyManagerInternal.class), 2740 UriGrantsManager.getService(), 2741 LocalServices.getService(UriGrantsManagerInternal.class), 2742 getContext().getSystemService(AppOpsManager.class), 2743 getContext().getSystemService(UserManager.class), 2744 new NotificationHistoryManager(getContext(), handler), 2745 mStatsManager = (StatsManager) getContext().getSystemService( 2746 Context.STATS_MANAGER), 2747 LocalServices.getService(ActivityManagerInternal.class), 2748 createToastRateLimiter(), new PermissionHelper(getContext(), 2749 AppGlobals.getPackageManager(), 2750 AppGlobals.getPermissionManager()), 2751 LocalServices.getService(UsageStatsManagerInternal.class), 2752 getContext().getSystemService(TelecomManager.class), 2753 new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(), 2754 getContext().getSystemService(PermissionManager.class), 2755 getContext().getSystemService(PowerManager.class), 2756 new PostNotificationTrackerFactory() {}); 2757 2758 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, 2759 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); 2760 publishLocalService(NotificationManagerInternal.class, mInternalService); 2761 } 2762 registerNotificationPreferencesPullers()2763 private void registerNotificationPreferencesPullers() { 2764 mPullAtomCallback = new StatsPullAtomCallbackImpl(); 2765 mStatsManager.setPullAtomCallback( 2766 PACKAGE_NOTIFICATION_PREFERENCES, 2767 null, // use default PullAtomMetadata values 2768 ConcurrentUtils.DIRECT_EXECUTOR, 2769 mPullAtomCallback 2770 ); 2771 mStatsManager.setPullAtomCallback( 2772 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES, 2773 null, // use default PullAtomMetadata values 2774 ConcurrentUtils.DIRECT_EXECUTOR, 2775 mPullAtomCallback 2776 ); 2777 mStatsManager.setPullAtomCallback( 2778 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES, 2779 null, // use default PullAtomMetadata values 2780 ConcurrentUtils.DIRECT_EXECUTOR, 2781 mPullAtomCallback 2782 ); 2783 mStatsManager.setPullAtomCallback( 2784 DND_MODE_RULE, 2785 null, // use default PullAtomMetadata values 2786 ConcurrentUtils.DIRECT_EXECUTOR, 2787 mPullAtomCallback 2788 ); 2789 } 2790 2791 private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { 2792 @Override onPullAtom(int atomTag, List<StatsEvent> data)2793 public int onPullAtom(int atomTag, List<StatsEvent> data) { 2794 switch (atomTag) { 2795 case PACKAGE_NOTIFICATION_PREFERENCES: 2796 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: 2797 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: 2798 case DND_MODE_RULE: 2799 return pullNotificationStates(atomTag, data); 2800 default: 2801 throw new UnsupportedOperationException("Unknown tagId=" + atomTag); 2802 } 2803 } 2804 } 2805 pullNotificationStates(int atomTag, List<StatsEvent> data)2806 private int pullNotificationStates(int atomTag, List<StatsEvent> data) { 2807 switch(atomTag) { 2808 case PACKAGE_NOTIFICATION_PREFERENCES: 2809 mPreferencesHelper.pullPackagePreferencesStats(data, 2810 getAllUsersNotificationPermissions()); 2811 break; 2812 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: 2813 mPreferencesHelper.pullPackageChannelPreferencesStats(data); 2814 break; 2815 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: 2816 mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data); 2817 break; 2818 case DND_MODE_RULE: 2819 mZenModeHelper.pullRules(data); 2820 break; 2821 } 2822 return StatsManager.PULL_SUCCESS; 2823 } 2824 getGroupHelper()2825 private GroupHelper getGroupHelper() { 2826 mAutoGroupAtCount = 2827 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount); 2828 return new GroupHelper(getContext(), getContext().getPackageManager(), 2829 mAutoGroupAtCount, new GroupHelper.Callback() { 2830 @Override 2831 public void addAutoGroup(String key, boolean requestSort) { 2832 synchronized (mNotificationLock) { 2833 addAutogroupKeyLocked(key, requestSort); 2834 } 2835 } 2836 2837 @Override 2838 public void removeAutoGroup(String key) { 2839 synchronized (mNotificationLock) { 2840 removeAutogroupKeyLocked(key); 2841 } 2842 } 2843 2844 @Override 2845 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey, 2846 NotificationAttributes summaryAttr) { 2847 NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey, 2848 summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor, 2849 summaryAttr.visibility); 2850 if (r != null) { 2851 final boolean isAppForeground = 2852 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 2853 mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, 2854 mPostNotificationTrackerFactory.newTracker(null))); 2855 } 2856 } 2857 2858 @Override 2859 public void removeAutoGroupSummary(int userId, String pkg) { 2860 synchronized (mNotificationLock) { 2861 clearAutogroupSummaryLocked(userId, pkg); 2862 } 2863 } 2864 2865 @Override 2866 public void updateAutogroupSummary(int userId, String pkg, 2867 NotificationAttributes summaryAttr) { 2868 boolean isAppForeground = pkg != null 2869 && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 2870 synchronized (mNotificationLock) { 2871 updateAutobundledSummaryLocked(userId, pkg, summaryAttr, isAppForeground); 2872 } 2873 } 2874 }); 2875 } 2876 2877 private void sendRegisteredOnlyBroadcast(String action) { 2878 sendRegisteredOnlyBroadcast(new Intent(action)); 2879 } 2880 2881 private void sendRegisteredOnlyBroadcast(Intent baseIntent) { 2882 int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true); 2883 Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 2884 for (int userId : userIds) { 2885 getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null); 2886 } 2887 // explicitly send the broadcast to all DND packages, even if they aren't currently running 2888 for (int userId : userIds) { 2889 for (String pkg : mConditionProviders.getAllowedPackages(userId)) { 2890 Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags( 2891 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2892 getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId)); 2893 } 2894 } 2895 } 2896 2897 @Override 2898 public void onBootPhase(int phase) { 2899 onBootPhase(phase, Looper.getMainLooper()); 2900 } 2901 2902 @VisibleForTesting 2903 void onBootPhase(int phase, Looper mainLooper) { 2904 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 2905 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 2906 mZenModeHelper.onSystemReady(); 2907 RoleObserver roleObserver = new RoleObserver(getContext(), 2908 getContext().getSystemService(RoleManager.class), 2909 mPackageManager, mainLooper); 2910 roleObserver.init(); 2911 mRoleObserver = roleObserver; 2912 LauncherApps launcherApps = 2913 (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE); 2914 UserManager userManager = (UserManager) getContext().getSystemService( 2915 Context.USER_SERVICE); 2916 mShortcutHelper = new ShortcutHelper(launcherApps, mShortcutListener, getLocalService( 2917 ShortcutServiceInternal.class), userManager); 2918 BubbleExtractor bubbsExtractor = mRankingHelper.findExtractor(BubbleExtractor.class); 2919 if (bubbsExtractor != null) { 2920 bubbsExtractor.setShortcutHelper(mShortcutHelper); 2921 } 2922 registerNotificationPreferencesPullers(); 2923 if (mLockUtils == null) { 2924 mLockUtils = new LockPatternUtils(getContext()); 2925 } 2926 mLockUtils.registerStrongAuthTracker(mStrongAuthTracker); 2927 mAttentionHelper.onSystemReady(); 2928 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 2929 // This observer will force an update when observe is called, causing us to 2930 // bind to listener services. 2931 mSettingsObserver.observe(); 2932 mListeners.onBootPhaseAppsCanStart(); 2933 mAssistants.onBootPhaseAppsCanStart(); 2934 mConditionProviders.onBootPhaseAppsCanStart(); 2935 mHistoryManager.onBootPhaseAppsCanStart(); 2936 migrateDefaultNAS(); 2937 maybeShowInitialReviewPermissionsNotification(); 2938 2939 if (android.app.Flags.modesApi()) { 2940 // Cannot be done earlier, as some services aren't ready until this point. 2941 mZenModeHelper.setDeviceEffectsApplier( 2942 new DefaultDeviceEffectsApplier(getContext())); 2943 } 2944 List<ModuleInfo> moduleInfoList = 2945 mPackageManagerClient.getInstalledModules( 2946 PackageManager.MATCH_DEBUG_TRIAGED_MISSING); 2947 // Cache adservices module info 2948 for (ModuleInfo mi : moduleInfoList) { 2949 if (Objects.equals(mi.getApexModuleName(), ADSERVICES_MODULE_PKG_NAME)) { 2950 mAdservicesModuleInfo = mi; 2951 } 2952 } 2953 } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 2954 mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis()); 2955 } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) { 2956 mPreferencesHelper.updateFixedImportance(mUm.getUsers()); 2957 mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers()); 2958 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { 2959 if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) { 2960 new Thread(() -> { 2961 while (true) { 2962 try { 2963 Thread.sleep(5000); 2964 } catch (InterruptedException e) { } 2965 mInternalService.removeBitmaps(); 2966 } 2967 }).start(); 2968 } else if (expireBitmaps()) { 2969 NotificationBitmapJobService.scheduleJob(getContext()); 2970 } 2971 } 2972 } 2973 2974 @Override 2975 public void onUserUnlocked(@NonNull TargetUser user) { 2976 mHandler.post(() -> { 2977 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser"); 2978 try { 2979 mHistoryManager.onUserUnlocked(user.getUserIdentifier()); 2980 } finally { 2981 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 2982 } 2983 }); 2984 } 2985 2986 private void sendAppBlockStateChangedBroadcast(String pkg, int uid, boolean blocked) { 2987 // From Android T, revoking the notification permission will cause the app to be killed. 2988 // delay this broadcast so it doesn't race with that process death 2989 mHandler.postDelayed(() -> { 2990 try { 2991 getContext().sendBroadcastAsUser( 2992 new Intent(ACTION_APP_BLOCK_STATE_CHANGED) 2993 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, blocked) 2994 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 2995 .setPackage(pkg), 2996 UserHandle.of(UserHandle.getUserId(uid)), null); 2997 } catch (SecurityException e) { 2998 Slog.w(TAG, "Can't notify app about app block change", e); 2999 } 3000 }, 500); 3001 } 3002 3003 @Override 3004 public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { 3005 if (!Flags.useSsmUserSwitchSignal()) { 3006 return; 3007 } 3008 final int userId = to.getUserIdentifier(); 3009 mUserProfiles.updateCache(getContext()); 3010 if (!mUserProfiles.isProfileUser(userId, getContext())) { 3011 // reload per-user settings 3012 mSettingsObserver.update(null); 3013 // Refresh managed services 3014 mConditionProviders.onUserSwitched(userId); 3015 mListeners.onUserSwitched(userId); 3016 mZenModeHelper.onUserSwitched(userId); 3017 mPreferencesHelper.syncChannelsBypassingDnd(); 3018 } 3019 // assistant is the only thing that cares about managed profiles specifically 3020 mAssistants.onUserSwitched(userId); 3021 } 3022 3023 @Override 3024 public void onUserStopping(@NonNull TargetUser user) { 3025 mHandler.post(() -> { 3026 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser"); 3027 try { 3028 mHistoryManager.onUserStopped(user.getUserIdentifier()); 3029 } finally { 3030 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 3031 } 3032 }); 3033 } 3034 3035 @GuardedBy("mNotificationLock") 3036 private void updateListenerHintsLocked() { 3037 final int hints = calculateHints(); 3038 if (hints == mListenerHints) return; 3039 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size()); 3040 mListenerHints = hints; 3041 scheduleListenerHintsChanged(hints); 3042 } 3043 3044 @GuardedBy("mNotificationLock") 3045 private void updateEffectsSuppressorLocked() { 3046 final long updatedSuppressedEffects = calculateSuppressedEffects(); 3047 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; 3048 final List<ComponentName> suppressors = getSuppressors(); 3049 ZenLog.traceEffectsSuppressorChanged( 3050 mEffectsSuppressors, suppressors, updatedSuppressedEffects); 3051 mEffectsSuppressors = suppressors; 3052 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); 3053 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 3054 } 3055 3056 private void exitIdle() { 3057 if (mDeviceIdleManager != null) { 3058 mDeviceIdleManager.endIdle("notification interaction"); 3059 } 3060 } 3061 3062 void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel, 3063 boolean fromListener) { 3064 if (channel.getImportance() == IMPORTANCE_NONE) { 3065 // cancel 3066 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, 3067 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED 3068 ); 3069 if (isUidSystemOrPhone(uid)) { 3070 IntArray profileIds = mUserProfiles.getCurrentProfileIds(); 3071 int N = profileIds.size(); 3072 for (int i = 0; i < N; i++) { 3073 int profileId = profileIds.get(i); 3074 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, 3075 profileId, REASON_CHANNEL_BANNED 3076 ); 3077 } 3078 } 3079 } 3080 final NotificationChannel preUpdate = 3081 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true); 3082 3083 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true, 3084 Binder.getCallingUid(), isCallerSystemOrSystemUi()); 3085 if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) { 3086 mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid), 3087 channel.getImportance() != IMPORTANCE_NONE, true); 3088 } 3089 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel); 3090 3091 if (!fromListener) { 3092 final NotificationChannel modifiedChannel = mPreferencesHelper.getNotificationChannel( 3093 pkg, uid, channel.getId(), false); 3094 mListeners.notifyNotificationChannelChanged( 3095 pkg, UserHandle.getUserHandleForUid(uid), 3096 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); 3097 } 3098 3099 handleSavePolicyFile(); 3100 } 3101 3102 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate, 3103 NotificationChannel update) { 3104 try { 3105 if ((preUpdate.getImportance() == IMPORTANCE_NONE 3106 && update.getImportance() != IMPORTANCE_NONE) 3107 || (preUpdate.getImportance() != IMPORTANCE_NONE 3108 && update.getImportance() == IMPORTANCE_NONE)) { 3109 getContext().sendBroadcastAsUser( 3110 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED) 3111 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID, 3112 update.getId()) 3113 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 3114 update.getImportance() == IMPORTANCE_NONE) 3115 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3116 .setPackage(pkg), 3117 UserHandle.of(UserHandle.getUserId(uid)), null); 3118 } 3119 } catch (SecurityException e) { 3120 Slog.w(TAG, "Can't notify app about channel change", e); 3121 } 3122 } 3123 3124 void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, 3125 boolean fromApp, boolean fromListener) { 3126 Objects.requireNonNull(group); 3127 Objects.requireNonNull(pkg); 3128 3129 final NotificationChannelGroup preUpdate = 3130 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid); 3131 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group, 3132 fromApp, Binder.getCallingUid(), isCallerSystemOrSystemUi()); 3133 if (!fromApp) { 3134 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group); 3135 } 3136 if (!fromListener) { 3137 mListeners.notifyNotificationChannelGroupChanged(pkg, 3138 UserHandle.of(UserHandle.getCallingUserId()), group, 3139 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 3140 } 3141 } 3142 3143 private void maybeNotifyChannelGroupOwner(String pkg, int uid, 3144 NotificationChannelGroup preUpdate, NotificationChannelGroup update) { 3145 try { 3146 if (preUpdate.isBlocked() != update.isBlocked()) { 3147 getContext().sendBroadcastAsUser( 3148 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED) 3149 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID, 3150 update.getId()) 3151 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 3152 update.isBlocked()) 3153 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3154 .setPackage(pkg), 3155 UserHandle.of(UserHandle.getUserId(uid)), null); 3156 } 3157 } catch (SecurityException e) { 3158 Slog.w(TAG, "Can't notify app about group change", e); 3159 } 3160 } 3161 3162 private ArrayList<ComponentName> getSuppressors() { 3163 ArrayList<ComponentName> names = new ArrayList<ComponentName>(); 3164 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 3165 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 3166 3167 for (ComponentName info : serviceInfoList) { 3168 names.add(info); 3169 } 3170 } 3171 3172 return names; 3173 } 3174 3175 private boolean removeDisabledHints(ManagedServiceInfo info) { 3176 return removeDisabledHints(info, 0); 3177 } 3178 3179 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) { 3180 boolean removed = false; 3181 3182 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 3183 final int hint = mListenersDisablingEffects.keyAt(i); 3184 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 3185 3186 if (hints == 0 || (hint & hints) == hint) { 3187 removed |= listeners.remove(info.component); 3188 } 3189 } 3190 3191 return removed; 3192 } 3193 3194 private void addDisabledHints(ManagedServiceInfo info, int hints) { 3195 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 3196 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS); 3197 } 3198 3199 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 3200 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 3201 } 3202 3203 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 3204 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS); 3205 } 3206 } 3207 3208 private void addDisabledHint(ManagedServiceInfo info, int hint) { 3209 if (mListenersDisablingEffects.indexOfKey(hint) < 0) { 3210 mListenersDisablingEffects.put(hint, new ArraySet<>()); 3211 } 3212 3213 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint); 3214 hintListeners.add(info.component); 3215 } 3216 3217 private int calculateHints() { 3218 int hints = 0; 3219 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 3220 int hint = mListenersDisablingEffects.keyAt(i); 3221 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 3222 3223 if (!serviceInfoList.isEmpty()) { 3224 hints |= hint; 3225 } 3226 } 3227 3228 return hints; 3229 } 3230 3231 private long calculateSuppressedEffects() { 3232 int hints = calculateHints(); 3233 long suppressedEffects = 0; 3234 3235 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 3236 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL; 3237 } 3238 3239 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 3240 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS; 3241 } 3242 3243 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 3244 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS; 3245 } 3246 3247 return suppressedEffects; 3248 } 3249 3250 @GuardedBy("mNotificationLock") 3251 private void updateInterruptionFilterLocked() { 3252 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 3253 if (interruptionFilter == mInterruptionFilter) return; 3254 mInterruptionFilter = interruptionFilter; 3255 scheduleInterruptionFilterChanged(interruptionFilter); 3256 } 3257 3258 int correctCategory(int requestedCategoryList, int categoryType, 3259 int currentCategoryList) { 3260 if ((requestedCategoryList & categoryType) != 0 3261 && (currentCategoryList & categoryType) == 0) { 3262 requestedCategoryList &= ~categoryType; 3263 } else if ((requestedCategoryList & categoryType) == 0 3264 && (currentCategoryList & categoryType) != 0){ 3265 requestedCategoryList |= categoryType; 3266 } 3267 return requestedCategoryList; 3268 } 3269 3270 @VisibleForTesting 3271 INotificationManager getBinderService() { 3272 return INotificationManager.Stub.asInterface(mService); 3273 } 3274 3275 /** 3276 * Report to usage stats that the notification was seen. 3277 * @param r notification record 3278 */ 3279 @GuardedBy("mNotificationLock") 3280 protected void reportSeen(NotificationRecord r) { 3281 if (!r.isProxied()) { 3282 mAppUsageStats.reportEvent(r.getSbn().getPackageName(), 3283 getRealUserId(r.getSbn().getUserId()), 3284 UsageEvents.Event.NOTIFICATION_SEEN); 3285 } 3286 } 3287 3288 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy, 3289 int targetSdkVersion) { 3290 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) { 3291 return incomingPolicy.suppressedVisualEffects; 3292 } 3293 final int[] effectsIntroducedInP = { 3294 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT, 3295 SUPPRESSED_EFFECT_LIGHTS, 3296 SUPPRESSED_EFFECT_PEEK, 3297 SUPPRESSED_EFFECT_STATUS_BAR, 3298 SUPPRESSED_EFFECT_BADGE, 3299 SUPPRESSED_EFFECT_AMBIENT, 3300 SUPPRESSED_EFFECT_NOTIFICATION_LIST 3301 }; 3302 3303 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects; 3304 if (targetSdkVersion < Build.VERSION_CODES.P) { 3305 // unset higher order bits introduced in P, maintain the user's higher order bits 3306 for (int i = 0; i < effectsIntroducedInP.length ; i++) { 3307 newSuppressedVisualEffects &= ~effectsIntroducedInP[i]; 3308 newSuppressedVisualEffects |= 3309 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]); 3310 } 3311 // set higher order bits according to lower order bits 3312 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 3313 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 3314 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 3315 } 3316 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 3317 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 3318 } 3319 } else { 3320 boolean hasNewEffects = (newSuppressedVisualEffects 3321 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0; 3322 // if any of the new effects introduced in P are set 3323 if (hasNewEffects) { 3324 // clear out the deprecated effects 3325 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON 3326 | SUPPRESSED_EFFECT_SCREEN_OFF); 3327 3328 // set the deprecated effects according to the new more specific effects 3329 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) != 0) { 3330 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON; 3331 } 3332 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) != 0 3333 && (newSuppressedVisualEffects 3334 & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0 3335 && (newSuppressedVisualEffects 3336 & SUPPRESSED_EFFECT_AMBIENT) != 0) { 3337 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF; 3338 } 3339 } else { 3340 // set higher order bits according to lower order bits 3341 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 3342 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 3343 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 3344 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT; 3345 } 3346 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 3347 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 3348 } 3349 } 3350 } 3351 3352 return newSuppressedVisualEffects; 3353 } 3354 3355 @GuardedBy("mNotificationLock") 3356 protected void maybeRecordInterruptionLocked(NotificationRecord r) { 3357 if (r.isInterruptive() && !r.hasRecordedInterruption()) { 3358 mAppUsageStats.reportInterruptiveNotification(r.getSbn().getPackageName(), 3359 r.getChannel().getId(), 3360 getRealUserId(r.getSbn().getUserId())); 3361 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryAddItem"); 3362 try { 3363 if (r.getNotification().getSmallIcon() != null) { 3364 mHistoryManager.addNotification(new HistoricalNotification.Builder() 3365 .setPackage(r.getSbn().getPackageName()) 3366 .setUid(r.getSbn().getUid()) 3367 .setUserId(r.getSbn().getNormalizedUserId()) 3368 .setChannelId(r.getChannel().getId()) 3369 .setChannelName(r.getChannel().getName().toString()) 3370 .setPostedTimeMs(System.currentTimeMillis()) 3371 .setTitle(getHistoryTitle(r.getNotification())) 3372 .setText(getHistoryText(r.getNotification())) 3373 .setIcon(r.getNotification().getSmallIcon()) 3374 .build()); 3375 } 3376 } finally { 3377 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 3378 } 3379 r.setRecordedInterruption(true); 3380 } 3381 } 3382 3383 protected void reportForegroundServiceUpdate(boolean shown, 3384 final Notification notification, final int id, final String pkg, final int userId) { 3385 mHandler.post(() -> { 3386 mAmi.onForegroundServiceNotificationUpdate(shown, notification, id, pkg, userId); 3387 }); 3388 } 3389 3390 protected void maybeReportForegroundServiceUpdate(final NotificationRecord r, boolean shown) { 3391 if (r.isForegroundService()) { 3392 // snapshot live state for the asynchronous operation 3393 final StatusBarNotification sbn = r.getSbn(); 3394 reportForegroundServiceUpdate(shown, sbn.getNotification(), sbn.getId(), 3395 sbn.getPackageName(), sbn.getUser().getIdentifier()); 3396 } 3397 } 3398 3399 private String getHistoryTitle(Notification n) { 3400 CharSequence title = null; 3401 if (n.extras != null) { 3402 title = n.extras.getCharSequence(Notification.EXTRA_TITLE); 3403 if (title == null) { 3404 title = n.extras.getCharSequence(EXTRA_TITLE_BIG); 3405 } 3406 } 3407 return title == null ? getContext().getResources().getString( 3408 com.android.internal.R.string.notification_history_title_placeholder) 3409 : String.valueOf(title); 3410 } 3411 3412 /** 3413 * Returns the appropriate substring for this notification based on the style of notification. 3414 */ 3415 private String getHistoryText(Notification n) { 3416 CharSequence text = null; 3417 if (n.extras != null) { 3418 text = n.extras.getCharSequence(EXTRA_TEXT); 3419 Notification.Builder nb = Notification.Builder.recoverBuilder(getContext(), n); 3420 3421 if (nb.getStyle() instanceof Notification.BigTextStyle) { 3422 text = ((Notification.BigTextStyle) nb.getStyle()).getBigText(); 3423 } else if (nb.getStyle() instanceof MessagingStyle) { 3424 MessagingStyle ms = (MessagingStyle) nb.getStyle(); 3425 final List<MessagingStyle.Message> messages = ms.getMessages(); 3426 if (messages != null && messages.size() > 0) { 3427 text = messages.get(messages.size() - 1).getText(); 3428 } 3429 } 3430 3431 if (TextUtils.isEmpty(text)) { 3432 text = n.extras.getCharSequence(EXTRA_TEXT); 3433 } 3434 } 3435 return text == null ? null : String.valueOf(text); 3436 } 3437 3438 protected void maybeRegisterMessageSent(NotificationRecord r) { 3439 if (r.isConversation()) { 3440 if (r.getShortcutInfo() != null) { 3441 if (mPreferencesHelper.setValidMessageSent( 3442 r.getSbn().getPackageName(), r.getUid())) { 3443 handleSavePolicyFile(); 3444 } else if (r.getNotification().getBubbleMetadata() != null) { 3445 // If bubble metadata is present it is valid (if invalid it's removed 3446 // via BubbleExtractor). 3447 if (mPreferencesHelper.setValidBubbleSent( 3448 r.getSbn().getPackageName(), r.getUid())) { 3449 handleSavePolicyFile(); 3450 } 3451 } 3452 } else { 3453 if (mPreferencesHelper.setInvalidMessageSent( 3454 r.getSbn().getPackageName(), r.getUid())) { 3455 handleSavePolicyFile(); 3456 } 3457 } 3458 } 3459 } 3460 3461 /** 3462 * Report to usage stats that the user interacted with the notification. 3463 * @param r notification record 3464 */ 3465 protected void reportUserInteraction(NotificationRecord r) { 3466 mAppUsageStats.reportEvent(r.getSbn().getPackageName(), 3467 getRealUserId(r.getSbn().getUserId()), 3468 UsageEvents.Event.USER_INTERACTION); 3469 3470 if (Flags.politeNotifications()) { 3471 mAttentionHelper.onUserInteraction(r); 3472 } 3473 } 3474 3475 private int getRealUserId(int userId) { 3476 return userId == USER_ALL ? USER_SYSTEM : userId; 3477 } 3478 3479 private ToastRecord getToastRecord(int uid, int pid, String packageName, boolean isSystemToast, 3480 IBinder token, @Nullable CharSequence text, @Nullable ITransientNotification callback, 3481 int duration, Binder windowToken, int displayId, 3482 @Nullable ITransientNotificationCallback textCallback) { 3483 if (callback == null) { 3484 return new TextToastRecord(this, mStatusBar, uid, pid, packageName, 3485 isSystemToast, token, text, duration, windowToken, displayId, textCallback); 3486 } else { 3487 return new CustomToastRecord(this, uid, pid, packageName, 3488 isSystemToast, token, callback, duration, windowToken, displayId); 3489 } 3490 } 3491 3492 @VisibleForTesting 3493 NotificationManagerInternal getInternalService() { 3494 return mInternalService; 3495 } 3496 3497 private MultiRateLimiter createToastRateLimiter() { 3498 return new MultiRateLimiter.Builder(getContext()).addRateLimits(TOAST_RATE_LIMITS).build(); 3499 } 3500 3501 protected int checkComponentPermission(String permission, int uid, int owningUid, 3502 boolean exported) { 3503 return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); 3504 } 3505 3506 @VisibleForTesting 3507 final IBinder mService = new INotificationManager.Stub() { 3508 // Toasts 3509 // ============================================================================ 3510 3511 @Override 3512 public boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, 3513 boolean isUiContext, int displayId, 3514 @Nullable ITransientNotificationCallback textCallback) { 3515 return enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext, 3516 displayId, textCallback); 3517 } 3518 3519 @Override 3520 public boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback, 3521 int duration, boolean isUiContext, int displayId) { 3522 return enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext, 3523 displayId, /* textCallback= */ null); 3524 } 3525 3526 private boolean enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, 3527 @Nullable ITransientNotification callback, int duration, boolean isUiContext, 3528 int displayId, @Nullable ITransientNotificationCallback textCallback) { 3529 if (DBG) { 3530 Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration 3531 + " isUiContext=" + isUiContext + " displayId=" + displayId); 3532 } 3533 3534 if (pkg == null || (text == null && callback == null) 3535 || (text != null && callback != null) || token == null) { 3536 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback=" 3537 + " token=" + token); 3538 return false; 3539 } 3540 3541 final int callingUid = Binder.getCallingUid(); 3542 if (!isUiContext && displayId == Display.DEFAULT_DISPLAY 3543 && mUm.isVisibleBackgroundUsersSupported()) { 3544 // When the caller is a visible background user using a non-UI context (like the 3545 // application context), the Toast must be displayed in the display the user was 3546 // started visible on. 3547 int userId = UserHandle.getUserId(callingUid); 3548 int userDisplayId = mUmInternal.getMainDisplayAssignedToUser(userId); 3549 if (displayId != userDisplayId) { 3550 if (DBG) { 3551 Slogf.d(TAG, "Changing display id from %d to %d on user %d", displayId, 3552 userDisplayId, userId); 3553 } 3554 displayId = userDisplayId; 3555 } 3556 } 3557 3558 checkCallerIsSameApp(pkg); 3559 final boolean isSystemToast = isCallerSystemOrSystemUi() 3560 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); 3561 boolean isAppRenderedToast = (callback != null); 3562 if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast, 3563 isSystemToast)) { 3564 return false; 3565 } 3566 3567 synchronized (mToastQueue) { 3568 int callingPid = Binder.getCallingPid(); 3569 final long callingId = Binder.clearCallingIdentity(); 3570 try { 3571 ToastRecord record; 3572 int index = indexOfToastLocked(pkg, token); 3573 // If it's already in the queue, we update it in place, we don't 3574 // move it to the end of the queue. 3575 if (index >= 0) { 3576 record = mToastQueue.get(index); 3577 record.update(duration); 3578 } else { 3579 // Limit the number of toasts that any given package can enqueue. 3580 // Prevents DOS attacks and deals with leaks. 3581 int count = 0; 3582 final int N = mToastQueue.size(); 3583 for (int i = 0; i < N; i++) { 3584 final ToastRecord r = mToastQueue.get(i); 3585 if (r.pkg.equals(pkg)) { 3586 count++; 3587 if (count >= MAX_PACKAGE_TOASTS) { 3588 Slog.e(TAG, "Package has already queued " + count 3589 + " toasts. Not showing more. Package=" + pkg); 3590 return false; 3591 } 3592 } 3593 } 3594 3595 Binder windowToken = new Binder(); 3596 mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId, 3597 null /* options */); 3598 record = getToastRecord(callingUid, callingPid, pkg, isSystemToast, token, 3599 text, callback, duration, windowToken, displayId, textCallback); 3600 3601 // Insert system toasts at the front of the queue 3602 int systemToastInsertIdx = mToastQueue.size(); 3603 if (isSystemToast) { 3604 systemToastInsertIdx = getInsertIndexForSystemToastLocked(); 3605 } 3606 if (systemToastInsertIdx < mToastQueue.size()) { 3607 index = systemToastInsertIdx; 3608 mToastQueue.add(index, record); 3609 } else { 3610 mToastQueue.add(record); 3611 index = mToastQueue.size() - 1; 3612 } 3613 keepProcessAliveForToastIfNeededLocked(callingPid); 3614 } 3615 // If it's at index 0, it's the current toast. It doesn't matter if it's 3616 // new or just been updated, show it. 3617 // If the callback fails, this will remove it from the list, so don't 3618 // assume that it's valid after this. 3619 if (index == 0) { 3620 showNextToastLocked(false); 3621 } 3622 } finally { 3623 Binder.restoreCallingIdentity(callingId); 3624 } 3625 } 3626 return true; 3627 } 3628 3629 @GuardedBy("mToastQueue") 3630 private int getInsertIndexForSystemToastLocked() { 3631 // If there are other system toasts: insert after the last one 3632 int idx = 0; 3633 for (ToastRecord r : mToastQueue) { 3634 if (idx == 0 && mIsCurrentToastShown) { 3635 idx++; 3636 continue; 3637 } 3638 if (!r.isSystemToast) { 3639 return idx; 3640 } 3641 idx++; 3642 } 3643 return idx; 3644 } 3645 3646 private boolean checkCanEnqueueToast(String pkg, int callingUid, int displayId, 3647 boolean isAppRenderedToast, boolean isSystemToast) { 3648 final boolean isPackageSuspended = isPackagePaused(pkg); 3649 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, 3650 callingUid); 3651 3652 final boolean appIsForeground; 3653 final long callingIdentity = Binder.clearCallingIdentity(); 3654 try { 3655 appIsForeground = mActivityManager.getUidImportance(callingUid) 3656 == IMPORTANCE_FOREGROUND; 3657 } finally { 3658 Binder.restoreCallingIdentity(callingIdentity); 3659 } 3660 3661 if (!isSystemToast && ((notificationsDisabledForPackage && !appIsForeground) 3662 || isPackageSuspended)) { 3663 Slog.e(TAG, "Suppressing toast from package " + pkg 3664 + (isPackageSuspended ? " due to package suspended." 3665 : " by user request.")); 3666 return false; 3667 } 3668 3669 if (blockToast(callingUid, isSystemToast, isAppRenderedToast, 3670 isPackageInForegroundForToast(callingUid))) { 3671 Slog.w(TAG, "Blocking custom toast from package " + pkg 3672 + " due to package not in the foreground at time the toast was posted"); 3673 return false; 3674 } 3675 3676 int userId = UserHandle.getUserId(callingUid); 3677 if (!isSystemToast && !mUmInternal.isUserVisible(userId, displayId)) { 3678 Slog.e(TAG, "Suppressing toast from package " + pkg + "/" + callingUid + " as user " 3679 + userId + " is not visible on display " + displayId); 3680 return false; 3681 } 3682 3683 return true; 3684 } 3685 3686 @Override 3687 public void cancelToast(String pkg, IBinder token) { 3688 Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token); 3689 3690 if (pkg == null || token == null) { 3691 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token); 3692 return; 3693 } 3694 3695 synchronized (mToastQueue) { 3696 final long callingId = Binder.clearCallingIdentity(); 3697 try { 3698 int index = indexOfToastLocked(pkg, token); 3699 if (index >= 0) { 3700 cancelToastLocked(index); 3701 } else { 3702 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 3703 + " token=" + token); 3704 } 3705 } finally { 3706 Binder.restoreCallingIdentity(callingId); 3707 } 3708 } 3709 } 3710 3711 @Override 3712 @EnforcePermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) 3713 public void setToastRateLimitingEnabled(boolean enable) { 3714 3715 super.setToastRateLimitingEnabled_enforcePermission(); 3716 3717 synchronized (mToastQueue) { 3718 int uid = Binder.getCallingUid(); 3719 int userId = UserHandle.getUserId(uid); 3720 if (enable) { 3721 mToastRateLimitingDisabledUids.remove(uid); 3722 try { 3723 String[] packages = mPackageManager.getPackagesForUid(uid); 3724 if (packages == null) { 3725 Slog.e(TAG, "setToastRateLimitingEnabled method haven't found any " 3726 + "packages for the given uid: " + uid + ", toast rate " 3727 + "limiter not reset for that uid."); 3728 return; 3729 } 3730 for (String pkg : packages) { 3731 mToastRateLimiter.clear(userId, pkg); 3732 } 3733 } catch (RemoteException e) { 3734 Slog.e(TAG, "Failed to reset toast rate limiter for given uid", e); 3735 } 3736 } else { 3737 mToastRateLimitingDisabledUids.add(uid); 3738 } 3739 } 3740 } 3741 3742 @Override 3743 public void finishToken(String pkg, IBinder token) { 3744 synchronized (mToastQueue) { 3745 final long callingId = Binder.clearCallingIdentity(); 3746 try { 3747 int index = indexOfToastLocked(pkg, token); 3748 if (index >= 0) { 3749 ToastRecord record = mToastQueue.get(index); 3750 finishWindowTokenLocked(record.windowToken, record.displayId); 3751 } else { 3752 Slog.w(TAG, "Toast already killed. pkg=" + pkg 3753 + " token=" + token); 3754 } 3755 } finally { 3756 Binder.restoreCallingIdentity(callingId); 3757 } 3758 } 3759 } 3760 3761 @Override 3762 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 3763 Notification notification, int userId) throws RemoteException { 3764 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 3765 Binder.getCallingPid(), tag, id, notification, userId, 3766 false /* byForegroundService */); 3767 } 3768 3769 @Override 3770 public void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id, 3771 int userId) { 3772 // Don't allow client applications to cancel foreground service notifs, user-initiated 3773 // job notifs, autobundled summaries, or notifs that have been replied to. 3774 int mustNotHaveFlags = isCallingUidSystem() ? 0 : 3775 (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY); 3776 if (lifetimeExtensionRefactor()) { 3777 // Also don't allow client apps to cancel lifetime extended notifs. 3778 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3779 } 3780 3781 cancelNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), 3782 tag, id, userId, mustNotHaveFlags); 3783 } 3784 3785 @Override 3786 public void cancelAllNotifications(String pkg, int userId) { 3787 checkCallerIsSystemOrSameApp(pkg); 3788 3789 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 3790 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 3791 3792 // Don't allow the app to cancel active FGS or UIJ notifications 3793 if (lifetimeExtensionRefactor()) { 3794 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 3795 pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB 3796 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, 3797 userId, REASON_APP_CANCEL_ALL); 3798 final int packageImportance = getPackageImportanceWithIdentity(pkg); 3799 // If cancellation will be prevented due to lifetime extension, we send updates 3800 // to system UI. 3801 synchronized (mNotificationLock) { 3802 maybeNotifySystemUiListenerLifetimeExtendedListLocked(mNotificationList, 3803 packageImportance); 3804 maybeNotifySystemUiListenerLifetimeExtendedListLocked(mEnqueuedNotifications, 3805 packageImportance); 3806 } 3807 } else { 3808 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 3809 pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, 3810 userId, REASON_APP_CANCEL_ALL); 3811 } 3812 } 3813 3814 @Override 3815 public void silenceNotificationSound() { 3816 checkCallerIsSystem(); 3817 3818 mNotificationDelegate.clearEffects(); 3819 } 3820 3821 @Override 3822 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 3823 enforceSystemOrSystemUI("setNotificationsEnabledForPackage"); 3824 boolean wasEnabled = mPermissionHelper.hasPermission(uid); 3825 if (wasEnabled == enabled) { 3826 return; 3827 } 3828 mPermissionHelper.setNotificationPermission( 3829 pkg, UserHandle.getUserId(uid), enabled, true); 3830 sendAppBlockStateChangedBroadcast(pkg, uid, !enabled); 3831 3832 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) 3833 .setType(MetricsEvent.TYPE_ACTION) 3834 .setPackageName(pkg) 3835 .setSubtype(enabled ? 1 : 0)); 3836 mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled); 3837 3838 // Outstanding notifications from this package will be cancelled as soon as we get the 3839 // callback from AppOpsManager. 3840 } 3841 3842 /** 3843 * Updates the enabled state for notifications for the given package (and uid). 3844 * Additionally, this method marks the app importance as locked by the user, which 3845 * means 3846 * that notifications from the app will <b>not</b> be considered for showing a 3847 * blocking helper. 3848 * 3849 * @param pkg package that owns the notifications to update 3850 * @param uid uid of the app providing notifications 3851 * @param enabled whether notifications should be enabled for the app 3852 * @see #setNotificationsEnabledForPackage(String, int, boolean) 3853 */ 3854 @Override 3855 public void setNotificationsEnabledWithImportanceLockForPackage( 3856 String pkg, int uid, boolean enabled) { 3857 setNotificationsEnabledForPackage(pkg, uid, enabled); 3858 } 3859 3860 /** 3861 * Use this when you just want to know if notifications are OK for this package. 3862 */ 3863 @Override 3864 public boolean areNotificationsEnabled(String pkg) { 3865 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()); 3866 } 3867 3868 /** 3869 * Use this when you just want to know if notifications are OK for this package. 3870 */ 3871 @Override 3872 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 3873 enforceSystemOrSystemUIOrSamePackage(pkg, 3874 "Caller not system or systemui or same package"); 3875 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 3876 getContext().enforceCallingPermission( 3877 android.Manifest.permission.INTERACT_ACROSS_USERS, 3878 "canNotifyAsPackage for uid " + uid); 3879 } 3880 3881 return areNotificationsEnabledForPackageInt(pkg, uid); 3882 } 3883 3884 /** 3885 * @return true if and only if "all" bubbles are allowed from the provided package. 3886 */ 3887 @Override 3888 public boolean areBubblesAllowed(String pkg) { 3889 return getBubblePreferenceForPackage(pkg, Binder.getCallingUid()) 3890 == BUBBLE_PREFERENCE_ALL; 3891 } 3892 3893 /** 3894 * @return true if this user has bubbles enabled at the feature-level. 3895 */ 3896 @Override 3897 public boolean areBubblesEnabled(UserHandle user) { 3898 if (UserHandle.getCallingUserId() != user.getIdentifier()) { 3899 getContext().enforceCallingPermission( 3900 android.Manifest.permission.INTERACT_ACROSS_USERS, 3901 "areBubblesEnabled for user " + user.getIdentifier()); 3902 } 3903 return mPreferencesHelper.bubblesEnabled(user); 3904 } 3905 3906 @Override 3907 public int getBubblePreferenceForPackage(String pkg, int uid) { 3908 enforceSystemOrSystemUIOrSamePackage(pkg, 3909 "Caller not system or systemui or same package"); 3910 3911 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 3912 getContext().enforceCallingPermission( 3913 android.Manifest.permission.INTERACT_ACROSS_USERS, 3914 "getBubblePreferenceForPackage for uid " + uid); 3915 } 3916 3917 return mPreferencesHelper.getBubblePreference(pkg, uid); 3918 } 3919 3920 @Override 3921 public void setBubblesAllowed(String pkg, int uid, int bubblePreference) { 3922 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 3923 mPreferencesHelper.setBubblesAllowed(pkg, uid, bubblePreference); 3924 handleSavePolicyFile(); 3925 } 3926 3927 @Override 3928 public boolean shouldHideSilentStatusIcons(String callingPkg) { 3929 checkCallerIsSameApp(callingPkg); 3930 3931 if (isCallerSystemOrPhone() 3932 || mListeners.isListenerPackage(callingPkg)) { 3933 return mPreferencesHelper.shouldHideSilentStatusIcons(); 3934 } else { 3935 throw new SecurityException("Only available for notification listeners"); 3936 } 3937 } 3938 3939 @Override 3940 public void setHideSilentStatusIcons(boolean hide) { 3941 checkCallerIsSystem(); 3942 3943 mPreferencesHelper.setHideSilentStatusIcons(hide); 3944 handleSavePolicyFile(); 3945 3946 mListeners.onStatusBarIconsBehaviorChanged(hide); 3947 } 3948 3949 @Override 3950 public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) { 3951 checkCallerIsSystem(); 3952 mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime); 3953 } 3954 3955 @Override 3956 public NotificationListenerFilter getListenerFilter(ComponentName cn, int userId) { 3957 checkCallerIsSystem(); 3958 return mListeners.getNotificationListenerFilter(Pair.create(cn, userId)); 3959 } 3960 3961 @Override 3962 public void setListenerFilter(ComponentName cn, int userId, 3963 NotificationListenerFilter nlf) { 3964 checkCallerIsSystem(); 3965 mListeners.setNotificationListenerFilter(Pair.create(cn, userId), nlf); 3966 // TODO (b/173052211): cancel notifications for listeners that can no longer see them 3967 handleSavePolicyFile(); 3968 } 3969 3970 @Override 3971 public int getPackageImportance(String pkg) { 3972 checkCallerIsSystemOrSameApp(pkg); 3973 if (mPermissionHelper.hasPermission(Binder.getCallingUid())) { 3974 return IMPORTANCE_DEFAULT; 3975 } else { 3976 return IMPORTANCE_NONE; 3977 } 3978 } 3979 3980 @Override 3981 public boolean isImportanceLocked(String pkg, int uid) { 3982 checkCallerIsSystem(); 3983 return mPreferencesHelper.isImportanceLocked(pkg, uid); 3984 } 3985 3986 @Override 3987 public boolean canShowBadge(String pkg, int uid) { 3988 checkCallerIsSystem(); 3989 return mPreferencesHelper.canShowBadge(pkg, uid); 3990 } 3991 3992 @Override 3993 public void setShowBadge(String pkg, int uid, boolean showBadge) { 3994 checkCallerIsSystem(); 3995 mPreferencesHelper.setShowBadge(pkg, uid, showBadge); 3996 handleSavePolicyFile(); 3997 } 3998 3999 @Override 4000 public boolean hasSentValidMsg(String pkg, int uid) { 4001 checkCallerIsSystem(); 4002 return mPreferencesHelper.hasSentValidMsg(pkg, uid); 4003 } 4004 4005 @Override 4006 public boolean isInInvalidMsgState(String pkg, int uid) { 4007 checkCallerIsSystem(); 4008 return mPreferencesHelper.isInInvalidMsgState(pkg, uid); 4009 } 4010 4011 @Override 4012 public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) { 4013 checkCallerIsSystem(); 4014 return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid); 4015 } 4016 4017 @Override 4018 public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) { 4019 checkCallerIsSystem(); 4020 mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted); 4021 handleSavePolicyFile(); 4022 } 4023 4024 @Override 4025 public boolean hasSentValidBubble(String pkg, int uid) { 4026 checkCallerIsSystem(); 4027 return mPreferencesHelper.hasSentValidBubble(pkg, uid); 4028 } 4029 4030 @Override 4031 public void setNotificationDelegate(String callingPkg, String delegate) { 4032 checkCallerIsSameApp(callingPkg); 4033 final int callingUid = Binder.getCallingUid(); 4034 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 4035 if (delegate == null) { 4036 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid()); 4037 handleSavePolicyFile(); 4038 } else { 4039 try { 4040 ApplicationInfo info = 4041 mPackageManager.getApplicationInfo(delegate, 4042 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 4043 user.getIdentifier()); 4044 if (info != null) { 4045 mPreferencesHelper.setNotificationDelegate( 4046 callingPkg, callingUid, delegate, info.uid); 4047 handleSavePolicyFile(); 4048 } 4049 } catch (RemoteException e) { 4050 e.rethrowFromSystemServer(); 4051 } 4052 } 4053 } 4054 4055 @Override 4056 public String getNotificationDelegate(String callingPkg) { 4057 // callable by Settings also 4058 checkCallerIsSystemOrSameApp(callingPkg); 4059 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid()); 4060 } 4061 4062 @Override 4063 public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) { 4064 checkCallerIsSameApp(callingPkg); 4065 final int callingUid = Binder.getCallingUid(); 4066 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 4067 if (user.getIdentifier() != userId) { 4068 getContext().enforceCallingPermission( 4069 android.Manifest.permission.INTERACT_ACROSS_USERS, 4070 "canNotifyAsPackage for user " + userId); 4071 } 4072 if (callingPkg.equals(targetPkg)) { 4073 return true; 4074 } 4075 try { 4076 ApplicationInfo info = 4077 mPackageManager.getApplicationInfo(targetPkg, 4078 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 4079 userId); 4080 if (info != null) { 4081 return mPreferencesHelper.isDelegateAllowed( 4082 targetPkg, info.uid, callingPkg, callingUid); 4083 } 4084 } catch (RemoteException e) { 4085 // :( 4086 } 4087 return false; 4088 } 4089 4090 @Override 4091 public boolean canUseFullScreenIntent(@NonNull AttributionSource attributionSource) { 4092 final String packageName = attributionSource.getPackageName(); 4093 final int uid = attributionSource.getUid(); 4094 final int userId = UserHandle.getUserId(uid); 4095 checkCallerIsSameApp(packageName, uid, userId); 4096 4097 final ApplicationInfo applicationInfo; 4098 try { 4099 applicationInfo = mPackageManagerClient.getApplicationInfoAsUser( 4100 packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId); 4101 } catch (NameNotFoundException e) { 4102 Slog.e(TAG, "Failed to getApplicationInfo() in canUseFullScreenIntent()", e); 4103 return false; 4104 } 4105 return checkUseFullScreenIntentPermission(attributionSource, applicationInfo, 4106 false /* forDataDelivery */); 4107 } 4108 4109 @Override 4110 public void updateNotificationChannelGroupForPackage(String pkg, int uid, 4111 NotificationChannelGroup group) throws RemoteException { 4112 enforceSystemOrSystemUI("Caller not system or systemui"); 4113 createNotificationChannelGroup(pkg, uid, group, false, false); 4114 handleSavePolicyFile(); 4115 } 4116 4117 @Override 4118 public void createNotificationChannelGroups(String pkg, 4119 ParceledListSlice channelGroupList) throws RemoteException { 4120 checkCallerIsSystemOrSameApp(pkg); 4121 List<NotificationChannelGroup> groups = channelGroupList.getList(); 4122 final int groupSize = groups.size(); 4123 for (int i = 0; i < groupSize; i++) { 4124 final NotificationChannelGroup group = groups.get(i); 4125 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false); 4126 } 4127 handleSavePolicyFile(); 4128 } 4129 4130 private void createNotificationChannelsImpl(String pkg, int uid, 4131 ParceledListSlice channelsList) { 4132 createNotificationChannelsImpl(pkg, uid, channelsList, 4133 ActivityTaskManager.INVALID_TASK_ID); 4134 } 4135 4136 private void createNotificationChannelsImpl(String pkg, int uid, 4137 ParceledListSlice channelsList, int startingTaskId) { 4138 List<NotificationChannel> channels = channelsList.getList(); 4139 final int channelsSize = channels.size(); 4140 ParceledListSlice<NotificationChannel> oldChannels = 4141 mPreferencesHelper.getNotificationChannels(pkg, uid, true); 4142 final boolean hadChannel = oldChannels != null && !oldChannels.getList().isEmpty(); 4143 boolean needsPolicyFileChange = false; 4144 boolean hasRequestedNotificationPermission = false; 4145 for (int i = 0; i < channelsSize; i++) { 4146 final NotificationChannel channel = channels.get(i); 4147 Objects.requireNonNull(channel, "channel in list is null"); 4148 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid, 4149 channel, true /* fromTargetApp */, 4150 mConditionProviders.isPackageOrComponentAllowed( 4151 pkg, UserHandle.getUserId(uid)), Binder.getCallingUid(), 4152 isCallerSystemOrSystemUi()); 4153 if (needsPolicyFileChange) { 4154 mListeners.notifyNotificationChannelChanged(pkg, 4155 UserHandle.getUserHandleForUid(uid), 4156 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), 4157 false), 4158 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 4159 boolean hasChannel = hadChannel || hasRequestedNotificationPermission; 4160 if (!hasChannel) { 4161 ParceledListSlice<NotificationChannel> currChannels = 4162 mPreferencesHelper.getNotificationChannels(pkg, uid, true); 4163 hasChannel = currChannels != null && !currChannels.getList().isEmpty(); 4164 } 4165 if (!hadChannel && hasChannel && !hasRequestedNotificationPermission 4166 && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) { 4167 hasRequestedNotificationPermission = true; 4168 if (mPermissionPolicyInternal == null) { 4169 mPermissionPolicyInternal = 4170 LocalServices.getService(PermissionPolicyInternal.class); 4171 } 4172 mHandler.post(new ShowNotificationPermissionPromptRunnable(pkg, 4173 UserHandle.getUserId(uid), startingTaskId, 4174 mPermissionPolicyInternal)); 4175 } 4176 } 4177 } 4178 if (needsPolicyFileChange) { 4179 handleSavePolicyFile(); 4180 } 4181 } 4182 4183 @Override 4184 public void createNotificationChannels(String pkg, ParceledListSlice channelsList) { 4185 checkCallerIsSystemOrSameApp(pkg); 4186 int taskId = ActivityTaskManager.INVALID_TASK_ID; 4187 try { 4188 int uid = mPackageManager.getPackageUid(pkg, 0, 4189 UserHandle.getUserId(Binder.getCallingUid())); 4190 taskId = mAtm.getTaskToShowPermissionDialogOn(pkg, uid); 4191 } catch (RemoteException e) { 4192 // Do nothing 4193 } 4194 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList, taskId); 4195 } 4196 4197 @Override 4198 public void createNotificationChannelsForPackage(String pkg, int uid, 4199 ParceledListSlice channelsList) { 4200 enforceSystemOrSystemUI("only system can call this"); 4201 createNotificationChannelsImpl(pkg, uid, channelsList); 4202 } 4203 4204 @Override 4205 public void createConversationNotificationChannelForPackage(String pkg, int uid, 4206 NotificationChannel parentChannel, String conversationId) { 4207 enforceSystemOrSystemUI("only system can call this"); 4208 checkNotNull(parentChannel); 4209 checkNotNull(conversationId); 4210 String parentId = parentChannel.getId(); 4211 NotificationChannel conversationChannel = parentChannel; 4212 conversationChannel.setId(String.format( 4213 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId)); 4214 conversationChannel.setConversationId(parentId, conversationId); 4215 createNotificationChannelsImpl( 4216 pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel))); 4217 mRankingHandler.requestSort(); 4218 handleSavePolicyFile(); 4219 } 4220 4221 @Override 4222 public NotificationChannel getNotificationChannel(String callingPkg, int userId, 4223 String targetPkg, String channelId) { 4224 return getConversationNotificationChannel( 4225 callingPkg, userId, targetPkg, channelId, true, null); 4226 } 4227 4228 @Override 4229 public NotificationChannel getConversationNotificationChannel(String callingPkg, int userId, 4230 String targetPkg, String channelId, boolean returnParentIfNoConversationChannel, 4231 String conversationId) { 4232 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 4233 || isCallerSystemOrSystemUiOrShell()) { 4234 int targetUid = -1; 4235 try { 4236 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 4237 } catch (NameNotFoundException e) { 4238 /* ignore */ 4239 } 4240 return mPreferencesHelper.getConversationNotificationChannel( 4241 targetPkg, targetUid, channelId, conversationId, 4242 returnParentIfNoConversationChannel, false /* includeDeleted */); 4243 } 4244 throw new SecurityException("Pkg " + callingPkg 4245 + " cannot read channels for " + targetPkg + " in " + userId); 4246 } 4247 4248 @Override 4249 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, 4250 String channelId, String conversationId, boolean includeDeleted) { 4251 checkCallerIsSystem(); 4252 return mPreferencesHelper.getConversationNotificationChannel( 4253 pkg, uid, channelId, conversationId, true, includeDeleted); 4254 } 4255 4256 // Returns 'true' if the given channel has a notification associated 4257 // with an active foreground service. 4258 private void enforceDeletingChannelHasNoFgService(String pkg, int userId, 4259 String channelId) { 4260 if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { 4261 Slog.w(TAG, "Package u" + userId + "/" + pkg 4262 + " may not delete notification channel '" 4263 + channelId + "' with fg service"); 4264 throw new SecurityException("Not allowed to delete channel " + channelId 4265 + " with a foreground service"); 4266 } 4267 } 4268 4269 // Throws a security exception if the given channel has a notification associated 4270 // with an active user-initiated job. 4271 private void enforceDeletingChannelHasNoUserInitiatedJob(String pkg, int userId, 4272 String channelId) { 4273 final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); 4274 if (js != null && js.isNotificationChannelAssociatedWithAnyUserInitiatedJobs( 4275 channelId, userId, pkg)) { 4276 Slog.w(TAG, "Package u" + userId + "/" + pkg 4277 + " may not delete notification channel '" 4278 + channelId + "' with user-initiated job"); 4279 throw new SecurityException("Not allowed to delete channel " + channelId 4280 + " with a user-initiated job"); 4281 } 4282 } 4283 4284 @Override 4285 public void deleteNotificationChannel(String pkg, String channelId) { 4286 checkCallerIsSystemOrSameApp(pkg); 4287 final int callingUid = Binder.getCallingUid(); 4288 final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi(); 4289 final int callingUser = UserHandle.getUserId(callingUid); 4290 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 4291 throw new IllegalArgumentException("Cannot delete default channel"); 4292 } 4293 enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); 4294 enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId); 4295 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, 4296 callingUser, REASON_CHANNEL_REMOVED); 4297 boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel( 4298 pkg, callingUid, channelId, callingUid, isSystemOrSystemUi); 4299 if (previouslyExisted) { 4300 // Remove from both recent notification archive (recently dismissed notifications) 4301 // and notification history 4302 mArchive.removeChannelNotifications(pkg, callingUser, channelId); 4303 mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId); 4304 mListeners.notifyNotificationChannelChanged(pkg, 4305 UserHandle.getUserHandleForUid(callingUid), 4306 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true), 4307 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 4308 handleSavePolicyFile(); 4309 } 4310 } 4311 4312 @Override 4313 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) { 4314 checkCallerIsSystemOrSameApp(pkg); 4315 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 4316 pkg, Binder.getCallingUid(), groupId, false); 4317 } 4318 4319 @Override 4320 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups( 4321 String pkg) { 4322 checkCallerIsSystemOrSameApp(pkg); 4323 return mPreferencesHelper.getNotificationChannelGroups( 4324 pkg, Binder.getCallingUid(), false, false, true, true, null); 4325 } 4326 4327 @Override 4328 public void deleteNotificationChannelGroup(String pkg, String groupId) { 4329 checkCallerIsSystemOrSameApp(pkg); 4330 4331 final int callingUid = Binder.getCallingUid(); 4332 final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi(); 4333 NotificationChannelGroup groupToDelete = 4334 mPreferencesHelper.getNotificationChannelGroupWithChannels( 4335 pkg, callingUid, groupId, false); 4336 if (groupToDelete != null) { 4337 // Preflight for allowability 4338 final int userId = UserHandle.getUserId(callingUid); 4339 List<NotificationChannel> groupChannels = groupToDelete.getChannels(); 4340 for (int i = 0; i < groupChannels.size(); i++) { 4341 final String channelId = groupChannels.get(i).getId(); 4342 enforceDeletingChannelHasNoFgService(pkg, userId, channelId); 4343 enforceDeletingChannelHasNoUserInitiatedJob(pkg, userId, channelId); 4344 } 4345 List<NotificationChannel> deletedChannels = 4346 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId, 4347 callingUid, isSystemOrSystemUi); 4348 for (int i = 0; i < deletedChannels.size(); i++) { 4349 final NotificationChannel deletedChannel = deletedChannels.get(i); 4350 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, 4351 userId, REASON_CHANNEL_REMOVED 4352 ); 4353 mListeners.notifyNotificationChannelChanged(pkg, 4354 UserHandle.getUserHandleForUid(callingUid), 4355 deletedChannel, 4356 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 4357 } 4358 mListeners.notifyNotificationChannelGroupChanged( 4359 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, 4360 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 4361 handleSavePolicyFile(); 4362 } 4363 } 4364 4365 @Override 4366 public void updateNotificationChannelForPackage(String pkg, int uid, 4367 NotificationChannel channel) { 4368 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 4369 Objects.requireNonNull(channel); 4370 updateNotificationChannelInt(pkg, uid, channel, false); 4371 } 4372 4373 @Override 4374 public void unlockNotificationChannel(String pkg, int uid, String channelId) { 4375 checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); 4376 mPreferencesHelper.unlockNotificationChannelImportance(pkg, uid, channelId); 4377 handleSavePolicyFile(); 4378 } 4379 4380 @Override 4381 public void unlockAllNotificationChannels() { 4382 checkCallerIsSystem(); 4383 mPreferencesHelper.unlockAllNotificationChannels(); 4384 handleSavePolicyFile(); 4385 } 4386 4387 @Override 4388 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg, 4389 int uid, boolean includeDeleted) { 4390 enforceSystemOrSystemUI("getNotificationChannelsForPackage"); 4391 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted); 4392 } 4393 4394 @Override 4395 public int getNumNotificationChannelsForPackage(String pkg, int uid, 4396 boolean includeDeleted) { 4397 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage"); 4398 return NotificationManagerService.this 4399 .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted); 4400 } 4401 4402 @Override 4403 public boolean onlyHasDefaultChannel(String pkg, int uid) { 4404 enforceSystemOrSystemUI("onlyHasDefaultChannel"); 4405 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid); 4406 } 4407 4408 @Override 4409 public int getDeletedChannelCount(String pkg, int uid) { 4410 enforceSystemOrSystemUI("getDeletedChannelCount"); 4411 return mPreferencesHelper.getDeletedChannelCount(pkg, uid); 4412 } 4413 4414 @Override 4415 public int getBlockedChannelCount(String pkg, int uid) { 4416 enforceSystemOrSystemUI("getBlockedChannelCount"); 4417 return mPreferencesHelper.getBlockedChannelCount(pkg, uid); 4418 } 4419 4420 @Override 4421 public ParceledListSlice<ConversationChannelWrapper> getConversations( 4422 boolean onlyImportant) { 4423 enforceSystemOrSystemUI("getConversations"); 4424 IntArray userIds = mUserProfiles.getCurrentProfileIds(); 4425 ArrayList<ConversationChannelWrapper> conversations = 4426 mPreferencesHelper.getConversations(userIds, onlyImportant); 4427 for (ConversationChannelWrapper conversation : conversations) { 4428 if (mShortcutHelper == null) { 4429 conversation.setShortcutInfo(null); 4430 } else { 4431 conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo( 4432 conversation.getNotificationChannel().getConversationId(), 4433 conversation.getPkg(), 4434 UserHandle.of(UserHandle.getUserId(conversation.getUid())))); 4435 } 4436 } 4437 return new ParceledListSlice<>(conversations); 4438 } 4439 4440 @Override 4441 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage( 4442 String pkg, int uid, boolean includeDeleted) { 4443 enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage"); 4444 return mPreferencesHelper.getNotificationChannelGroups( 4445 pkg, uid, includeDeleted, true, false, true, null); 4446 } 4447 4448 @Override 4449 public ParceledListSlice<NotificationChannelGroup> 4450 getRecentBlockedNotificationChannelGroupsForPackage(String pkg, int uid) { 4451 enforceSystemOrSystemUI("getRecentBlockedNotificationChannelGroupsForPackage"); 4452 Set<String> recentlySentChannels = new HashSet<>(); 4453 long now = System.currentTimeMillis(); 4454 long startTime = now - (DateUtils.DAY_IN_MILLIS * 14); 4455 UsageEvents events = mUsageStatsManagerInternal.queryEventsForUser( 4456 UserHandle.getUserId(uid), startTime, now, UsageEvents.SHOW_ALL_EVENT_DATA); 4457 // get all channelids that sent notifs in the past 2 weeks 4458 if (events != null) { 4459 UsageEvents.Event event = new UsageEvents.Event(); 4460 while (events.hasNextEvent()) { 4461 events.getNextEvent(event); 4462 if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { 4463 if (pkg.equals(event.mPackage)) { 4464 String channelId = event.mNotificationChannelId; 4465 if (channelId != null) { 4466 recentlySentChannels.add(channelId); 4467 } 4468 } 4469 } 4470 } 4471 } 4472 4473 return mPreferencesHelper.getNotificationChannelGroups( 4474 pkg, uid, false, true, false, true, recentlySentChannels); 4475 } 4476 4477 @Override 4478 public ParceledListSlice<ConversationChannelWrapper> getConversationsForPackage(String pkg, 4479 int uid) { 4480 enforceSystemOrSystemUI("getConversationsForPackage"); 4481 ArrayList<ConversationChannelWrapper> conversations = 4482 mPreferencesHelper.getConversations(pkg, uid); 4483 for (ConversationChannelWrapper conversation : conversations) { 4484 if (mShortcutHelper == null) { 4485 conversation.setShortcutInfo(null); 4486 } else { 4487 conversation.setShortcutInfo(mShortcutHelper.getValidShortcutInfo( 4488 conversation.getNotificationChannel().getConversationId(), 4489 pkg, 4490 UserHandle.of(UserHandle.getUserId(uid)))); 4491 } 4492 } 4493 return new ParceledListSlice<>(conversations); 4494 } 4495 4496 @Override 4497 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage( 4498 String pkg, int uid, String groupId, boolean includeDeleted) { 4499 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage"); 4500 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 4501 pkg, uid, groupId, includeDeleted); 4502 } 4503 4504 @Override 4505 public NotificationChannelGroup getNotificationChannelGroupForPackage( 4506 String groupId, String pkg, int uid) { 4507 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage"); 4508 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid); 4509 } 4510 4511 @Override 4512 public ParceledListSlice<NotificationChannel> getNotificationChannels( 4513 String callingPkg, String targetPkg, int userId) { 4514 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 4515 || isCallingUidSystem()) { 4516 int targetUid = -1; 4517 try { 4518 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 4519 } catch (NameNotFoundException e) { 4520 /* ignore */ 4521 } 4522 return mPreferencesHelper.getNotificationChannels( 4523 targetPkg, targetUid, false /* includeDeleted */); 4524 } 4525 throw new SecurityException("Pkg " + callingPkg 4526 + " cannot read channels for " + targetPkg + " in " + userId); 4527 } 4528 4529 @Override 4530 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( 4531 String pkg, int uid) { 4532 checkCallerIsSystem(); 4533 if (!areNotificationsEnabledForPackage(pkg, uid)) { 4534 return ParceledListSlice.emptyList(); 4535 } 4536 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid); 4537 } 4538 4539 @Override 4540 public List<String> getPackagesBypassingDnd(int userId, 4541 boolean includeConversationChannels) { 4542 checkCallerIsSystem(); 4543 4544 final ArraySet<String> packageNames = new ArraySet<>(); 4545 4546 for (int user : mUm.getProfileIds(userId, false)) { 4547 List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, user); 4548 for (PackageInfo pi : pkgs) { 4549 String pkg = pi.packageName; 4550 // If any NotificationChannel for this package is bypassing, the 4551 // package is considered bypassing. 4552 for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg, 4553 pi.applicationInfo.uid).getList()) { 4554 // Skips non-demoted conversation channels. 4555 if (!includeConversationChannels 4556 && !TextUtils.isEmpty(channel.getConversationId()) 4557 && !channel.isDemoted()) { 4558 continue; 4559 } 4560 packageNames.add(pkg); 4561 } 4562 } 4563 } 4564 return new ArrayList<String>(packageNames); 4565 } 4566 4567 @Override 4568 public boolean areChannelsBypassingDnd() { 4569 if (android.app.Flags.modesApi()) { 4570 return mZenModeHelper.getConsolidatedNotificationPolicy().allowPriorityChannels() 4571 && mPreferencesHelper.areChannelsBypassingDnd(); 4572 } 4573 return mPreferencesHelper.areChannelsBypassingDnd(); 4574 } 4575 4576 @Override 4577 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException { 4578 boolean packagesChanged = false; 4579 checkCallerIsSystem(); 4580 // Cancel posted notifications 4581 final int userId = UserHandle.getUserId(uid); 4582 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, 4583 UserHandle.getUserId(Binder.getCallingUid()), REASON_CLEAR_DATA); 4584 4585 // Zen 4586 packagesChanged |= 4587 mConditionProviders.resetPackage(packageName, userId); 4588 4589 // Listener 4590 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 4591 mListeners.resetComponents(packageName, userId); 4592 packagesChanged |= changedListeners.get(true).size() > 0 4593 || changedListeners.get(false).size() > 0; 4594 4595 // When a listener is enabled, we enable the dnd package as a secondary 4596 for (int i = 0; i < changedListeners.get(true).size(); i++) { 4597 mConditionProviders.setPackageOrComponentEnabled( 4598 changedListeners.get(true).get(i).getPackageName(), 4599 userId, false, true); 4600 } 4601 4602 // Assistant 4603 ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants = 4604 mAssistants.resetComponents(packageName, userId); 4605 packagesChanged |= changedAssistants.get(true).size() > 0 4606 || changedAssistants.get(false).size() > 0; 4607 4608 // we want only one assistant enabled 4609 for (int i = 1; i < changedAssistants.get(true).size(); i++) { 4610 mAssistants.setPackageOrComponentEnabled( 4611 changedAssistants.get(true).get(i).flattenToString(), 4612 userId, true, false); 4613 } 4614 4615 // When the default assistant is enabled, we enable the dnd package as a secondary 4616 if (changedAssistants.get(true).size() > 0) { 4617 //we want only one assistant active 4618 mConditionProviders 4619 .setPackageOrComponentEnabled( 4620 changedAssistants.get(true).get(0).getPackageName(), 4621 userId, false, true); 4622 4623 } 4624 4625 // Snoozing 4626 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName); 4627 4628 // Reset notification preferences 4629 if (!fromApp) { 4630 mPreferencesHelper.clearData(packageName, uid); 4631 } 4632 4633 if (packagesChanged) { 4634 getContext().sendBroadcastAsUser(new Intent( 4635 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4636 .setPackage(packageName) 4637 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 4638 UserHandle.of(userId), null); 4639 } 4640 4641 handleSavePolicyFile(); 4642 } 4643 4644 @Override 4645 public List<String> getAllowedAssistantAdjustments(String pkg) { 4646 checkCallerIsSystemOrSameApp(pkg); 4647 4648 if (!isCallerSystemOrPhone() 4649 && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) { 4650 throw new SecurityException("Not currently an assistant"); 4651 } 4652 4653 return mAssistants.getAllowedAssistantAdjustments(); 4654 } 4655 4656 /** 4657 * @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead. 4658 */ 4659 @Deprecated 4660 @Override 4661 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 4662 return getActiveNotificationsWithAttribution(callingPkg, null); 4663 } 4664 4665 /** 4666 * System-only API for getting a list of current (i.e. not cleared) notifications. 4667 * 4668 * Requires ACCESS_NOTIFICATIONS which is signature|system. 4669 * @returns A list of all the notifications, in natural order. 4670 */ 4671 @Override 4672 @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 4673 public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg, 4674 String callingAttributionTag) { 4675 // enforce() will ensure the calling uid has the correct permission 4676 getActiveNotificationsWithAttribution_enforcePermission(); 4677 4678 ArrayList<StatusBarNotification> tmp = new ArrayList<>(); 4679 int uid = Binder.getCallingUid(); 4680 4681 ArrayList<Integer> currentUsers = new ArrayList<>(); 4682 currentUsers.add(USER_ALL); 4683 Binder.withCleanCallingIdentity(() -> { 4684 for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) { 4685 currentUsers.add(user); 4686 } 4687 }); 4688 4689 // noteOp will check to make sure the callingPkg matches the uid 4690 int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 4691 callingAttributionTag, null); 4692 if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { 4693 synchronized (mNotificationLock) { 4694 final int N = mNotificationList.size(); 4695 for (int i = 0; i < N; i++) { 4696 final StatusBarNotification sbn = mNotificationList.get(i).getSbn(); 4697 if (currentUsers.contains(sbn.getUserId())) { 4698 tmp.add(sbn); 4699 } 4700 } 4701 } 4702 } 4703 return tmp.toArray(new StatusBarNotification[tmp.size()]); 4704 } 4705 4706 /** 4707 * Public API for getting a list of current notifications for the calling package/uid. 4708 * 4709 * Note that since notification posting is done asynchronously, this will not return 4710 * notifications that are in the process of being posted. 4711 * 4712 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as 4713 * an app's notification delegate via 4714 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}. 4715 * 4716 * @returns A list of all the package's notifications, in natural order. 4717 */ 4718 @Override 4719 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 4720 int incomingUserId) { 4721 checkCallerIsSystemOrSameApp(pkg); 4722 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 4723 Binder.getCallingUid(), incomingUserId, true, false, 4724 "getAppActiveNotifications", pkg); 4725 synchronized (mNotificationLock) { 4726 final ArrayMap<String, StatusBarNotification> map 4727 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); 4728 final int N = mNotificationList.size(); 4729 for (int i = 0; i < N; i++) { 4730 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 4731 mNotificationList.get(i).getSbn()); 4732 if (sbn != null) { 4733 map.put(sbn.getKey(), sbn); 4734 } 4735 } 4736 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) { 4737 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.getSbn()); 4738 if (sbn != null) { 4739 map.put(sbn.getKey(), sbn); 4740 } 4741 } 4742 final int M = mEnqueuedNotifications.size(); 4743 for (int i = 0; i < M; i++) { 4744 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 4745 mEnqueuedNotifications.get(i).getSbn()); 4746 if (sbn != null) { 4747 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here 4748 } 4749 } 4750 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); 4751 list.addAll(map.values()); 4752 return new ParceledListSlice<StatusBarNotification>(list); 4753 } 4754 } 4755 4756 /** Notifications returned here will have allowlistToken stripped from them. */ 4757 private StatusBarNotification sanitizeSbn(String pkg, int userId, 4758 StatusBarNotification sbn) { 4759 if (sbn.getUserId() == userId) { 4760 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) { 4761 // We could pass back a cloneLight() but clients might get confused and 4762 // try to send this thing back to notify() again, which would not work 4763 // very well. 4764 Notification notification = sbn.getNotification().clone(); 4765 // Remove background token before returning notification to untrusted app, this 4766 // ensures the app isn't able to perform background operations that are 4767 // associated with notification interactions. 4768 notification.overrideAllowlistToken(null); 4769 return new StatusBarNotification( 4770 sbn.getPackageName(), 4771 sbn.getOpPkg(), 4772 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 4773 notification, 4774 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); 4775 } 4776 } 4777 return null; 4778 } 4779 4780 /** 4781 * @deprecated Use {@link #getHistoricalNotificationsWithAttribution} instead. 4782 */ 4783 @Deprecated 4784 @Override 4785 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 4786 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count, 4787 boolean includeSnoozed) { 4788 return getHistoricalNotificationsWithAttribution(callingPkg, null, count, 4789 includeSnoozed); 4790 } 4791 4792 /** 4793 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 4794 */ 4795 @Override 4796 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 4797 @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 4798 public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg, 4799 String callingAttributionTag, int count, boolean includeSnoozed) { 4800 // enforce() will ensure the calling uid has the correct permission 4801 getHistoricalNotificationsWithAttribution_enforcePermission(); 4802 4803 StatusBarNotification[] tmp = null; 4804 int uid = Binder.getCallingUid(); 4805 4806 // noteOp will check to make sure the callingPkg matches the uid 4807 int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 4808 callingAttributionTag, null); 4809 if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { 4810 synchronized (mArchive) { 4811 tmp = mArchive.getArray(mUm, count, includeSnoozed); 4812 } 4813 } 4814 return tmp; 4815 } 4816 4817 /** 4818 * System-only API for getting a list of historical notifications. May contain multiple days 4819 * of notifications. 4820 */ 4821 @Override 4822 @WorkerThread 4823 @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 4824 @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) 4825 public NotificationHistory getNotificationHistory(String callingPkg, 4826 String callingAttributionTag) { 4827 // enforce() will ensure the calling uid has the correct permission 4828 getNotificationHistory_enforcePermission(); 4829 int uid = Binder.getCallingUid(); 4830 4831 // noteOp will check to make sure the callingPkg matches the uid 4832 int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, 4833 callingAttributionTag, null); 4834 if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { 4835 IntArray currentUserIds = mUserProfiles.getCurrentProfileIds(); 4836 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory"); 4837 try { 4838 return mHistoryManager.readNotificationHistory(currentUserIds.toArray()); 4839 } finally { 4840 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 4841 } 4842 } 4843 return new NotificationHistory(); 4844 } 4845 4846 /** 4847 * Register a listener to be notified when a call notification is posted or removed 4848 * for a specific package and user. 4849 * @param packageName Which package to monitor 4850 * @param userHandle Which user to monitor 4851 * @param listener Listener to register 4852 */ 4853 @Override 4854 @EnforcePermission(allOf = { 4855 android.Manifest.permission.INTERACT_ACROSS_USERS, 4856 android.Manifest.permission.ACCESS_NOTIFICATIONS}) 4857 public void registerCallNotificationEventListener(String packageName, UserHandle userHandle, 4858 ICallNotificationEventCallback listener) { 4859 registerCallNotificationEventListener_enforcePermission(); 4860 4861 final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT 4862 ? userHandle.getIdentifier() : mAmi.getCurrentUserId(); 4863 4864 synchronized (mCallNotificationEventCallbacks) { 4865 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 4866 callbacksForPackage = 4867 mCallNotificationEventCallbacks.getOrDefault(packageName, new ArrayMap<>()); 4868 RemoteCallbackList<ICallNotificationEventCallback> callbackList = 4869 callbacksForPackage.getOrDefault(userId, new RemoteCallbackList<>()); 4870 4871 if (callbackList.register(listener)) { 4872 callbacksForPackage.put(userId, callbackList); 4873 mCallNotificationEventCallbacks.put(packageName, callbacksForPackage); 4874 } else { 4875 Log.e(TAG, 4876 "registerCallNotificationEventListener failed to register listener: " 4877 + packageName + " " + userHandle + " " + listener); 4878 return; 4879 } 4880 } 4881 4882 synchronized (mNotificationLock) { 4883 for (NotificationRecord r : mNotificationList) { 4884 if (r.getNotification().isStyle(Notification.CallStyle.class) 4885 && notificationMatchesUserId(r, userId, false) 4886 && r.getSbn().getPackageName().equals(packageName)) { 4887 try { 4888 listener.onCallNotificationPosted(packageName, r.getUser()); 4889 } catch (RemoteException e) { 4890 throw new RuntimeException(e); 4891 } 4892 } 4893 } 4894 } 4895 } 4896 4897 /** 4898 * Unregister a listener that was previously 4899 * registered with {@link #registerCallNotificationEventListener} 4900 * 4901 * @param packageName Which package to stop monitoring 4902 * @param userHandle Which user to stop monitoring 4903 * @param listener Listener to unregister 4904 */ 4905 @Override 4906 @EnforcePermission(allOf = { 4907 android.Manifest.permission.INTERACT_ACROSS_USERS, 4908 android.Manifest.permission.ACCESS_NOTIFICATIONS}) 4909 public void unregisterCallNotificationEventListener(String packageName, 4910 UserHandle userHandle, ICallNotificationEventCallback listener) { 4911 unregisterCallNotificationEventListener_enforcePermission(); 4912 synchronized (mCallNotificationEventCallbacks) { 4913 final int userId = userHandle.getIdentifier() != UserHandle.USER_CURRENT 4914 ? userHandle.getIdentifier() : mAmi.getCurrentUserId(); 4915 4916 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 4917 callbacksForPackage = mCallNotificationEventCallbacks.get(packageName); 4918 if (callbacksForPackage == null) { 4919 return; 4920 } 4921 RemoteCallbackList<ICallNotificationEventCallback> callbackList = 4922 callbacksForPackage.get(userId); 4923 if (callbackList == null) { 4924 return; 4925 } 4926 if (!callbackList.unregister(listener)) { 4927 Log.e(TAG, 4928 "unregisterCallNotificationEventListener listener not found for: " 4929 + packageName + " " + userHandle + " " + listener); 4930 } 4931 } 4932 } 4933 4934 /** 4935 * Register a listener binder directly with the notification manager. 4936 * 4937 * Only works with system callers. Apps should extend 4938 * {@link NotificationListenerService}. 4939 */ 4940 @Override 4941 public void registerListener(final INotificationListener listener, 4942 final ComponentName component, final int userid) { 4943 enforceSystemOrSystemUI("INotificationManager.registerListener"); 4944 mListeners.registerSystemService(listener, component, userid, Binder.getCallingUid()); 4945 } 4946 4947 /** 4948 * Remove a listener binder directly 4949 */ 4950 @Override 4951 public void unregisterListener(INotificationListener token, int userid) { 4952 mListeners.unregisterService(token, userid); 4953 } 4954 4955 /** 4956 * Allow an INotificationListener to simulate a "clear all" operation. 4957 * 4958 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 4959 * 4960 * @param token The binder for the listener, to check that the caller is allowed 4961 */ 4962 @Override 4963 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 4964 final int callingUid = Binder.getCallingUid(); 4965 final int callingPid = Binder.getCallingPid(); 4966 final long identity = Binder.clearCallingIdentity(); 4967 boolean notificationsRapidlyCleared = false; 4968 final String pkg; 4969 final int packageImportance; 4970 final ManagedServiceInfo info; 4971 try { 4972 synchronized (mNotificationLock) { 4973 info = mListeners.checkServiceTokenLocked(token); 4974 pkg = info.component.getPackageName(); 4975 } 4976 if (lifetimeExtensionRefactor()) { 4977 packageImportance = getPackageImportanceWithIdentity(pkg); 4978 } else { 4979 packageImportance = IMPORTANCE_NONE; 4980 } 4981 synchronized (mNotificationLock) { 4982 // Cancellation reason. If the token comes from assistant, label the 4983 // cancellation as coming from the assistant; default to LISTENER_CANCEL. 4984 int reason = REASON_LISTENER_CANCEL; 4985 if (mAssistants.isServiceTokenValidLocked(token)) { 4986 reason = REASON_ASSISTANT_CANCEL; 4987 } 4988 4989 if (keys != null) { 4990 final int N = keys.length; 4991 for (int i = 0; i < N; i++) { 4992 NotificationRecord r = mNotificationsByKey.get(keys[i]); 4993 if (r == null) continue; 4994 final int userId = r.getSbn().getUserId(); 4995 if (userId != info.userid && userId != USER_ALL && 4996 !mUserProfiles.isCurrentProfile(userId)) { 4997 continue; 4998 } 4999 notificationsRapidlyCleared = notificationsRapidlyCleared 5000 || isNotificationRecent(r.getUpdateTimeMs()); 5001 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 5002 r.getSbn().getPackageName(), r.getSbn().getTag(), 5003 r.getSbn().getId(), userId, reason); 5004 } 5005 } else { 5006 for (NotificationRecord notificationRecord : mNotificationList) { 5007 if (isNotificationRecent(notificationRecord.getUpdateTimeMs())) { 5008 notificationsRapidlyCleared = true; 5009 break; 5010 } 5011 } 5012 if (lifetimeExtensionRefactor()) { 5013 cancelAllLocked(callingUid, callingPid, info.userid, 5014 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(), 5015 FLAG_ONGOING_EVENT | FLAG_NO_CLEAR 5016 | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 5017 // If cancellation will be prevented due to lifetime extension, we send 5018 // an update to system UI. 5019 maybeNotifySystemUiListenerLifetimeExtendedListLocked( 5020 mNotificationList, packageImportance); 5021 maybeNotifySystemUiListenerLifetimeExtendedListLocked( 5022 mEnqueuedNotifications, packageImportance); 5023 } else { 5024 cancelAllLocked(callingUid, callingPid, info.userid, 5025 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(), 5026 FLAG_ONGOING_EVENT | FLAG_NO_CLEAR); 5027 } 5028 } 5029 } 5030 if (notificationsRapidlyCleared) { 5031 mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, 5032 callingUid, pkg, /* attributionTag= */ null, /* message= */ null); 5033 } 5034 } finally { 5035 Binder.restoreCallingIdentity(identity); 5036 } 5037 } 5038 5039 /** 5040 * Handle request from an approved listener to re-enable itself. 5041 * 5042 * @param component The componenet to be re-enabled, caller must match package. 5043 */ 5044 @Override 5045 public void requestBindListener(ComponentName component) { 5046 checkCallerIsSystemOrSameApp(component.getPackageName()); 5047 int uid = Binder.getCallingUid(); 5048 final long identity = Binder.clearCallingIdentity(); 5049 try { 5050 ManagedServices manager = 5051 mAssistants.isComponentEnabledForCurrentProfiles(component) 5052 ? mAssistants 5053 : mListeners; 5054 manager.setComponentState(component, UserHandle.getUserId(uid), true); 5055 } finally { 5056 Binder.restoreCallingIdentity(identity); 5057 } 5058 } 5059 5060 @Override 5061 public void requestUnbindListener(INotificationListener token) { 5062 int uid = Binder.getCallingUid(); 5063 final long identity = Binder.clearCallingIdentity(); 5064 try { 5065 // allow bound services to disable themselves 5066 synchronized (mNotificationLock) { 5067 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5068 info.getOwner().setComponentState( 5069 info.component, UserHandle.getUserId(uid), false); 5070 } 5071 } finally { 5072 Binder.restoreCallingIdentity(identity); 5073 } 5074 } 5075 5076 @Override 5077 public void requestUnbindListenerComponent(ComponentName component) { 5078 checkCallerIsSameApp(component.getPackageName()); 5079 int uid = Binder.getCallingUid(); 5080 final long identity = Binder.clearCallingIdentity(); 5081 try { 5082 synchronized (mNotificationLock) { 5083 ManagedServices manager = 5084 mAssistants.isComponentEnabledForCurrentProfiles(component) 5085 ? mAssistants 5086 : mListeners; 5087 if (manager.isPackageOrComponentAllowed(component.flattenToString(), 5088 UserHandle.getUserId(uid))) { 5089 manager.setComponentState(component, UserHandle.getUserId(uid), false); 5090 } 5091 } 5092 } finally { 5093 Binder.restoreCallingIdentity(identity); 5094 } 5095 } 5096 5097 @Override 5098 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 5099 final long identity = Binder.clearCallingIdentity(); 5100 try { 5101 synchronized (mNotificationLock) { 5102 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5103 if (keys == null) { 5104 return; 5105 } 5106 ArrayList<NotificationRecord> seen = new ArrayList<>(); 5107 final int n = keys.length; 5108 for (int i = 0; i < n; i++) { 5109 NotificationRecord r = mNotificationsByKey.get(keys[i]); 5110 if (r == null) continue; 5111 final int userId = r.getSbn().getUserId(); 5112 if (userId != info.userid && userId != USER_ALL 5113 && !mUserProfiles.isCurrentProfile(userId)) { 5114 continue; 5115 } 5116 seen.add(r); 5117 if (!r.isSeen()) { 5118 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 5119 reportSeen(r); 5120 r.setSeen(); 5121 maybeRecordInterruptionLocked(r); 5122 } 5123 } 5124 if (!seen.isEmpty()) { 5125 mAssistants.onNotificationsSeenLocked(seen); 5126 } 5127 } 5128 } finally { 5129 Binder.restoreCallingIdentity(identity); 5130 } 5131 } 5132 5133 /** 5134 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 5135 * 5136 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 5137 * 5138 * @param info The binder for the listener, to check that the caller is allowed 5139 */ 5140 @GuardedBy("mNotificationLock") 5141 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 5142 int callingUid, int callingPid, String pkg, String tag, int id, int userId, 5143 int reason) { 5144 int mustNotHaveFlags = FLAG_ONGOING_EVENT; 5145 if (lifetimeExtensionRefactor()) { 5146 mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 5147 } 5148 cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */, 5149 mustNotHaveFlags, 5150 true, 5151 userId, reason, info); 5152 } 5153 5154 /** 5155 * Allow an INotificationListener to snooze a single notification until a context. 5156 * 5157 * @param token The binder for the listener, to check that the caller is allowed 5158 */ 5159 @Override 5160 public void snoozeNotificationUntilContextFromListener(INotificationListener token, 5161 String key, String snoozeCriterionId) { 5162 final int callingUid = Binder.getCallingUid(); 5163 final long identity = Binder.clearCallingIdentity(); 5164 try { 5165 snoozeNotificationInt(callingUid, token, key, SNOOZE_UNTIL_UNSPECIFIED, 5166 snoozeCriterionId); 5167 } finally { 5168 Binder.restoreCallingIdentity(identity); 5169 } 5170 } 5171 5172 /** 5173 * Allow an INotificationListener to snooze a single notification until a time. 5174 * 5175 * @param token The binder for the listener, to check that the caller is allowed 5176 */ 5177 @Override 5178 public void snoozeNotificationUntilFromListener(INotificationListener token, String key, 5179 long duration) { 5180 final int callingUid = Binder.getCallingUid(); 5181 final long identity = Binder.clearCallingIdentity(); 5182 try { 5183 snoozeNotificationInt(callingUid, token, key, duration, null); 5184 } finally { 5185 Binder.restoreCallingIdentity(identity); 5186 } 5187 } 5188 5189 /** 5190 * Allows the notification assistant to un-snooze a single notification. 5191 * 5192 * @param token The binder for the assistant, to check that the caller is allowed 5193 */ 5194 @Override 5195 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { 5196 final long identity = Binder.clearCallingIdentity(); 5197 try { 5198 synchronized (mNotificationLock) { 5199 final ManagedServiceInfo info = 5200 mAssistants.checkServiceTokenLocked(token); 5201 unsnoozeNotificationInt(key, info, false); 5202 } 5203 } finally { 5204 Binder.restoreCallingIdentity(identity); 5205 } 5206 } 5207 5208 /** 5209 * Allows the notification assistant to un-snooze a single notification. 5210 * 5211 * @param token The binder for the listener, to check that the caller is allowed 5212 */ 5213 @Override 5214 public void unsnoozeNotificationFromSystemListener(INotificationListener token, 5215 String key) { 5216 final long identity = Binder.clearCallingIdentity(); 5217 try { 5218 synchronized (mNotificationLock) { 5219 final ManagedServiceInfo info = 5220 mListeners.checkServiceTokenLocked(token); 5221 if (!info.isSystem) { 5222 throw new SecurityException("Not allowed to unsnooze before deadline"); 5223 } 5224 unsnoozeNotificationInt(key, info, true); 5225 } 5226 } finally { 5227 Binder.restoreCallingIdentity(identity); 5228 } 5229 } 5230 5231 /** 5232 * Allows an app to set an initial notification listener filter 5233 * 5234 * @param token The binder for the listener, to check that the caller is allowed 5235 */ 5236 @Override 5237 public void migrateNotificationFilter(INotificationListener token, int defaultTypes, 5238 List<String> disallowedApps) { 5239 final long identity = Binder.clearCallingIdentity(); 5240 try { 5241 synchronized (mNotificationLock) { 5242 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5243 5244 Pair key = Pair.create(info.component, info.userid); 5245 5246 NotificationListenerFilter nlf = mListeners.getNotificationListenerFilter(key); 5247 if (nlf == null) { 5248 nlf = new NotificationListenerFilter(); 5249 } 5250 if (nlf.getDisallowedPackages().isEmpty() && disallowedApps != null) { 5251 for (String pkg : disallowedApps) { 5252 // block the current user's version and any work profile versions 5253 for (int userId : mUm.getProfileIds(info.userid, false)) { 5254 try { 5255 int uid = getUidForPackageAndUser(pkg, UserHandle.of(userId)); 5256 if (uid != INVALID_UID) { 5257 VersionedPackage vp = new VersionedPackage(pkg, uid); 5258 nlf.addPackage(vp); 5259 } 5260 } catch (Exception e) { 5261 // pkg doesn't exist on that user; skip 5262 } 5263 } 5264 } 5265 } 5266 if (nlf.areAllTypesAllowed()) { 5267 nlf.setTypes(defaultTypes); 5268 } 5269 mListeners.setNotificationListenerFilter(key, nlf); 5270 } 5271 } finally { 5272 Binder.restoreCallingIdentity(identity); 5273 } 5274 } 5275 5276 /** 5277 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 5278 * 5279 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 5280 * 5281 * @param token The binder for the listener, to check that the caller is allowed 5282 */ 5283 @Override 5284 public void cancelNotificationFromListener(INotificationListener token, String pkg, 5285 String tag, int id) { 5286 Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) use " + 5287 "cancelNotification(key) instead."); 5288 } 5289 5290 /** 5291 * Allow an INotificationListener to request the list of outstanding notifications seen by 5292 * the current user. Useful when starting up, after which point the listener callbacks 5293 * should be used. 5294 * 5295 * @param token The binder for the listener, to check that the caller is allowed 5296 * @param keys An array of notification keys to fetch, or null to fetch everything 5297 * @returns The return value will contain the notifications specified in keys, in that 5298 * order, or if keys is null, all the notifications, in natural order. 5299 */ 5300 @Override 5301 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 5302 INotificationListener token, String[] keys, int trim) { 5303 synchronized (mNotificationLock) { 5304 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5305 final boolean getKeys = keys != null; 5306 final int N = getKeys ? keys.length : mNotificationList.size(); 5307 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 5308 for (int i=0; i<N; i++) { 5309 final NotificationRecord r = getKeys 5310 ? mNotificationsByKey.get(keys[i]) 5311 : mNotificationList.get(i); 5312 addToListIfNeeded(r, info, list, trim); 5313 } 5314 return new ParceledListSlice<>(list); 5315 } 5316 } 5317 5318 /** 5319 * Allow an INotificationListener to request the list of outstanding snoozed notifications 5320 * seen by the current user. Useful when starting up, after which point the listener 5321 * callbacks should be used. 5322 * 5323 * @param token The binder for the listener, to check that the caller is allowed 5324 * @returns The return value will contain the notifications specified in keys, in that 5325 * order, or if keys is null, all the notifications, in natural order. 5326 */ 5327 @Override 5328 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener( 5329 INotificationListener token, int trim) { 5330 synchronized (mNotificationLock) { 5331 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5332 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed(); 5333 final int N = snoozedRecords.size(); 5334 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 5335 for (int i=0; i < N; i++) { 5336 addToListIfNeeded(snoozedRecords.get(i), info, list, trim); 5337 } 5338 return new ParceledListSlice<>(list); 5339 } 5340 } 5341 5342 private void addToListIfNeeded(NotificationRecord r, ManagedServiceInfo info, 5343 ArrayList<StatusBarNotification> notifications, int trim) { 5344 if (r == null) return; 5345 StatusBarNotification sbn = r.getSbn(); 5346 if (!isVisibleToListener(sbn, r.getNotificationType(), info)) return; 5347 if (mListeners.hasSensitiveContent(r) && !mListeners.isUidTrusted(info.uid)) { 5348 notifications.add(mListeners.redactStatusBarNotification(sbn)); 5349 } else { 5350 notifications.add((trim == TRIM_FULL) ? sbn : sbn.cloneLight()); 5351 } 5352 5353 } 5354 5355 @Override 5356 public void clearRequestedListenerHints(INotificationListener token) { 5357 final long identity = Binder.clearCallingIdentity(); 5358 try { 5359 synchronized (mNotificationLock) { 5360 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5361 removeDisabledHints(info); 5362 updateListenerHintsLocked(); 5363 updateEffectsSuppressorLocked(); 5364 } 5365 } finally { 5366 Binder.restoreCallingIdentity(identity); 5367 } 5368 } 5369 5370 @Override 5371 public void requestHintsFromListener(INotificationListener token, int hints) { 5372 final long identity = Binder.clearCallingIdentity(); 5373 try { 5374 synchronized (mNotificationLock) { 5375 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5376 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS 5377 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS 5378 | HINT_HOST_DISABLE_CALL_EFFECTS; 5379 final boolean disableEffects = (hints & disableEffectsMask) != 0; 5380 if (disableEffects) { 5381 addDisabledHints(info, hints); 5382 } else { 5383 removeDisabledHints(info, hints); 5384 } 5385 updateListenerHintsLocked(); 5386 updateEffectsSuppressorLocked(); 5387 } 5388 } finally { 5389 Binder.restoreCallingIdentity(identity); 5390 } 5391 } 5392 5393 @Override 5394 public int getHintsFromListener(INotificationListener token) { 5395 synchronized (mNotificationLock) { 5396 return mListenerHints; 5397 } 5398 } 5399 5400 @Override 5401 public int getHintsFromListenerNoToken() { 5402 synchronized (mNotificationLock) { 5403 return mListenerHints; 5404 } 5405 } 5406 5407 @Override 5408 public void requestInterruptionFilterFromListener(INotificationListener token, 5409 int interruptionFilter) throws RemoteException { 5410 if (android.app.Flags.modesApi()) { 5411 final int callingUid = Binder.getCallingUid(); 5412 ManagedServiceInfo info; 5413 synchronized (mNotificationLock) { 5414 info = mListeners.checkServiceTokenLocked(token); 5415 } 5416 5417 final int zenMode = zenModeFromInterruptionFilter(interruptionFilter, -1); 5418 if (zenMode == -1) return; 5419 if (!canManageGlobalZenPolicy(info.component.getPackageName(), callingUid)) { 5420 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule( 5421 info.component.getPackageName(), callingUid, zenMode); 5422 } else { 5423 int origin = computeZenOrigin(/* fromUser= */ false); 5424 Binder.withCleanCallingIdentity(() -> { 5425 mZenModeHelper.setManualZenMode(zenMode, /* conditionId= */ null, origin, 5426 "listener:" + info.component.flattenToShortString(), 5427 /* caller= */ info.component.getPackageName(), 5428 callingUid); 5429 }); 5430 } 5431 } else { 5432 final int callingUid = Binder.getCallingUid(); 5433 final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi(); 5434 final long identity = Binder.clearCallingIdentity(); 5435 try { 5436 synchronized (mNotificationLock) { 5437 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5438 mZenModeHelper.requestFromListener(info.component, interruptionFilter, 5439 callingUid, isSystemOrSystemUi); 5440 updateInterruptionFilterLocked(); 5441 } 5442 } finally { 5443 Binder.restoreCallingIdentity(identity); 5444 } 5445 } 5446 } 5447 5448 @Override 5449 public int getInterruptionFilterFromListener(INotificationListener token) 5450 throws RemoteException { 5451 synchronized (mNotificationLock) { 5452 return mInterruptionFilter; 5453 } 5454 } 5455 5456 @Override 5457 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 5458 throws RemoteException { 5459 synchronized (mNotificationLock) { 5460 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 5461 if (info == null) return; 5462 mListeners.setOnNotificationPostedTrimLocked(info, trim); 5463 } 5464 } 5465 5466 @Override 5467 public int getZenMode() { 5468 return mZenModeHelper.getZenMode(); 5469 } 5470 5471 @Override 5472 public ZenModeConfig getZenModeConfig() { 5473 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig"); 5474 return mZenModeHelper.getConfig(); 5475 } 5476 5477 @Override 5478 public void setZenMode(int mode, Uri conditionId, String reason, boolean fromUser) { 5479 enforceSystemOrSystemUI("INotificationManager.setZenMode"); 5480 enforceUserOriginOnlyFromSystem(fromUser, "setZenMode"); 5481 5482 final int callingUid = Binder.getCallingUid(); 5483 final long identity = Binder.clearCallingIdentity(); 5484 try { 5485 mZenModeHelper.setManualZenMode(mode, conditionId, computeZenOrigin(fromUser), 5486 reason, /* caller= */ null, callingUid); 5487 } finally { 5488 Binder.restoreCallingIdentity(identity); 5489 } 5490 } 5491 5492 // TODO: b/310620812 - Remove getZenRules() when MODES_API is inlined. 5493 @Override 5494 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException { 5495 enforcePolicyAccess(Binder.getCallingUid(), "getZenRules"); 5496 return mZenModeHelper.getZenRules(); 5497 } 5498 5499 @Override 5500 public Map<String, AutomaticZenRule> getAutomaticZenRules() { 5501 if (!android.app.Flags.modesApi()) { 5502 throw new IllegalStateException("getAutomaticZenRules called with flag off!"); 5503 } 5504 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); 5505 return mZenModeHelper.getAutomaticZenRules(); 5506 } 5507 5508 @Override 5509 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 5510 Objects.requireNonNull(id, "Id is null"); 5511 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); 5512 return mZenModeHelper.getAutomaticZenRule(id); 5513 } 5514 5515 @Override 5516 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg, 5517 boolean fromUser) { 5518 validateAutomaticZenRule(/* updateId= */ null, automaticZenRule); 5519 checkCallerIsSameApp(pkg); 5520 if (automaticZenRule.getZenPolicy() != null 5521 && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { 5522 throw new IllegalArgumentException("ZenPolicy is only applicable to " 5523 + "INTERRUPTION_FILTER_PRIORITY filters"); 5524 } 5525 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 5526 enforceUserOriginOnlyFromSystem(fromUser, "addAutomaticZenRule"); 5527 5528 // If the calling app is the system (from any user), take the package name from the 5529 // rule's owner rather than from the caller's package. 5530 String rulePkg = pkg; 5531 if (isCallingAppIdSystem()) { 5532 if (automaticZenRule.getOwner() != null) { 5533 rulePkg = automaticZenRule.getOwner().getPackageName(); 5534 } 5535 } 5536 5537 return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule, 5538 computeZenOrigin(fromUser), "addAutomaticZenRule", Binder.getCallingUid()); 5539 } 5540 5541 @Override 5542 public void setManualZenRuleDeviceEffects(ZenDeviceEffects effects) throws RemoteException { 5543 checkCallerIsSystem(); 5544 5545 mZenModeHelper.setManualZenRuleDeviceEffects(effects, computeZenOrigin(true), 5546 "Update manual mode non-policy settings", Binder.getCallingUid()); 5547 } 5548 5549 @Override 5550 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule, 5551 boolean fromUser) throws RemoteException { 5552 validateAutomaticZenRule(id, automaticZenRule); 5553 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 5554 enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule"); 5555 5556 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule, 5557 computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid()); 5558 } 5559 5560 private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) { 5561 Objects.requireNonNull(rule, "automaticZenRule is null"); 5562 Objects.requireNonNull(rule.getName(), "Name is null"); 5563 rule.validate(); 5564 5565 // Implicit rules have no ConditionProvider or Activity. We allow the user to customize 5566 // them (via Settings), but not the owner app. Should the app want to start using it as 5567 // a "normal" rule, it must provide a CP/ConfigActivity too. 5568 if (android.app.Flags.modesApi()) { 5569 boolean isImplicitRuleUpdateFromSystem = updateId != null 5570 && ZenModeHelper.isImplicitRuleId(updateId) 5571 && isCallerSystemOrSystemUi(); 5572 if (!isImplicitRuleUpdateFromSystem 5573 && rule.getOwner() == null 5574 && rule.getConfigurationActivity() == null) { 5575 throw new NullPointerException( 5576 "Rule must have a ConditionProviderService and/or configuration " 5577 + "activity"); 5578 } 5579 } else { 5580 if (rule.getOwner() == null && rule.getConfigurationActivity() == null) { 5581 throw new NullPointerException( 5582 "Rule must have a ConditionProviderService and/or configuration " 5583 + "activity"); 5584 } 5585 } 5586 Objects.requireNonNull(rule.getConditionId(), "ConditionId is null"); 5587 5588 if (android.app.Flags.modesApi()) { 5589 if (isCallerSystemOrSystemUi()) { 5590 return; // System callers can use any type. 5591 } 5592 int uid = Binder.getCallingUid(); 5593 int userId = UserHandle.getUserId(uid); 5594 5595 if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) { 5596 boolean isDeviceOwner = Binder.withCleanCallingIdentity( 5597 () -> mDpm.isActiveDeviceOwner(uid)); 5598 if (!isDeviceOwner) { 5599 throw new IllegalArgumentException( 5600 "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED"); 5601 } 5602 } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) { 5603 String wellbeingPackage = getContext().getResources().getString( 5604 com.android.internal.R.string.config_systemWellbeing); 5605 boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage) 5606 && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId); 5607 if (!isCallerWellbeing) { 5608 throw new IllegalArgumentException( 5609 "Only the 'Wellbeing' package can use AutomaticZenRules with " 5610 + "TYPE_BEDTIME"); 5611 } 5612 } 5613 } 5614 } 5615 5616 @Override 5617 public boolean removeAutomaticZenRule(String id, boolean fromUser) throws RemoteException { 5618 Objects.requireNonNull(id, "Id is null"); 5619 // Verify that they can modify zen rules. 5620 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 5621 enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRule"); 5622 5623 return mZenModeHelper.removeAutomaticZenRule(id, computeZenOrigin(fromUser), 5624 "removeAutomaticZenRule", Binder.getCallingUid()); 5625 } 5626 5627 @Override 5628 public boolean removeAutomaticZenRules(String packageName, boolean fromUser) 5629 throws RemoteException { 5630 Objects.requireNonNull(packageName, "Package name is null"); 5631 enforceSystemOrSystemUI("removeAutomaticZenRules"); 5632 enforceUserOriginOnlyFromSystem(fromUser, "removeAutomaticZenRules"); 5633 5634 return mZenModeHelper.removeAutomaticZenRules(packageName, computeZenOrigin(fromUser), 5635 packageName + "|removeAutomaticZenRules", Binder.getCallingUid()); 5636 } 5637 5638 @Override 5639 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 5640 Objects.requireNonNull(owner, "Owner is null"); 5641 enforceSystemOrSystemUI("getRuleInstanceCount"); 5642 5643 return mZenModeHelper.getCurrentInstanceCount(owner); 5644 } 5645 5646 @Override 5647 @Condition.State 5648 public int getAutomaticZenRuleState(@NonNull String id) { 5649 Objects.requireNonNull(id, "id is null"); 5650 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRuleState"); 5651 return mZenModeHelper.getAutomaticZenRuleState(id); 5652 } 5653 5654 @Override 5655 public void setAutomaticZenRuleState(String id, Condition condition) { 5656 Objects.requireNonNull(id, "id is null"); 5657 Objects.requireNonNull(condition, "Condition is null"); 5658 condition.validate(); 5659 5660 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState"); 5661 boolean fromUser = (condition.source == Condition.SOURCE_USER_ACTION); 5662 5663 mZenModeHelper.setAutomaticZenRuleState(id, condition, computeZenOrigin(fromUser), 5664 Binder.getCallingUid()); 5665 } 5666 5667 @ZenModeConfig.ConfigChangeOrigin 5668 private int computeZenOrigin(boolean fromUser) { 5669 // "fromUser" is introduced with MODES_API, so only consider it in that case. 5670 // (Non-MODES_API behavior should also not depend at all on UPDATE_ORIGIN_USER). 5671 if (android.app.Flags.modesApi() && fromUser) { 5672 return ZenModeConfig.UPDATE_ORIGIN_USER; 5673 } else if (isCallerSystemOrSystemUi()) { 5674 return ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI; 5675 } else { 5676 return ZenModeConfig.UPDATE_ORIGIN_APP; 5677 } 5678 } 5679 5680 private void enforceUserOriginOnlyFromSystem(boolean fromUser, String method) { 5681 if (android.app.Flags.modesApi() 5682 && fromUser 5683 && !isCallerSystemOrSystemUiOrShell()) { 5684 throw new SecurityException(TextUtils.formatSimple( 5685 "Calling %s with fromUser == true is only allowed for system", method)); 5686 } 5687 } 5688 5689 @Override 5690 public void setInterruptionFilter(String pkg, int filter, boolean fromUser) { 5691 enforcePolicyAccess(pkg, "setInterruptionFilter"); 5692 final int zen = zenModeFromInterruptionFilter(filter, -1); 5693 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 5694 final int callingUid = Binder.getCallingUid(); 5695 enforceUserOriginOnlyFromSystem(fromUser, "setInterruptionFilter"); 5696 5697 if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) { 5698 mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(pkg, callingUid, zen); 5699 return; 5700 } 5701 5702 final long identity = Binder.clearCallingIdentity(); 5703 try { 5704 mZenModeHelper.setManualZenMode(zen, null, computeZenOrigin(fromUser), 5705 /* reason= */ "setInterruptionFilter", /* caller= */ pkg, 5706 callingUid); 5707 } finally { 5708 Binder.restoreCallingIdentity(identity); 5709 } 5710 } 5711 5712 @Override 5713 public void notifyConditions(final String pkg, IConditionProvider provider, 5714 final Condition[] conditions) { 5715 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 5716 checkCallerIsSystemOrSameApp(pkg); 5717 mHandler.post(new Runnable() { 5718 @Override 5719 public void run() { 5720 mConditionProviders.notifyConditions(pkg, info, conditions); 5721 } 5722 }); 5723 } 5724 5725 @Override 5726 public void requestUnbindProvider(IConditionProvider provider) { 5727 int uid = Binder.getCallingUid(); 5728 final long identity = Binder.clearCallingIdentity(); 5729 try { 5730 // allow bound services to disable themselves 5731 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 5732 info.getOwner().setComponentState(info.component, UserHandle.getUserId(uid), false); 5733 } finally { 5734 Binder.restoreCallingIdentity(identity); 5735 } 5736 } 5737 5738 @Override 5739 public void requestBindProvider(ComponentName component) { 5740 checkCallerIsSystemOrSameApp(component.getPackageName()); 5741 int uid = Binder.getCallingUid(); 5742 final long identity = Binder.clearCallingIdentity(); 5743 try { 5744 mConditionProviders.setComponentState(component, UserHandle.getUserId(uid), true); 5745 } finally { 5746 Binder.restoreCallingIdentity(identity); 5747 } 5748 } 5749 5750 private void enforceSystemOrSystemUI(String message) { 5751 if (isCallerSystemOrPhone()) return; 5752 getContext().enforceCallingPermission(STATUS_BAR_SERVICE, 5753 message); 5754 } 5755 5756 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) { 5757 try { 5758 checkCallerIsSystemOrSameApp(pkg); 5759 } catch (SecurityException e) { 5760 getContext().enforceCallingPermission( 5761 STATUS_BAR_SERVICE, 5762 message); 5763 } 5764 } 5765 5766 private void enforcePolicyAccess(int uid, String method) { 5767 if (PERMISSION_GRANTED == getContext().checkCallingPermission( 5768 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 5769 return; 5770 } 5771 boolean accessAllowed = false; 5772 String[] packages = mPackageManagerClient.getPackagesForUid(uid); 5773 final int packageCount = packages.length; 5774 for (int i = 0; i < packageCount; i++) { 5775 if (mConditionProviders.isPackageOrComponentAllowed( 5776 packages[i], UserHandle.getUserId(uid))) { 5777 accessAllowed = true; 5778 } 5779 } 5780 if (!accessAllowed) { 5781 Slog.w(TAG, "Notification policy access denied calling " + method); 5782 throw new SecurityException("Notification policy access denied"); 5783 } 5784 } 5785 5786 private boolean canManageGlobalZenPolicy(String callingPkg, int callingUid) { 5787 boolean isCompatChangeEnabled = Binder.withCleanCallingIdentity( 5788 () -> CompatChanges.isChangeEnabled(MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES, 5789 callingUid)); 5790 return !isCompatChangeEnabled 5791 || isCallerSystemOrSystemUi() 5792 || hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid), 5793 Set.of(AssociationRequest.DEVICE_PROFILE_WATCH, 5794 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)); 5795 } 5796 5797 private void enforcePolicyAccess(String pkg, String method) { 5798 if (PERMISSION_GRANTED == getContext().checkCallingPermission( 5799 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 5800 return; 5801 } 5802 checkCallerIsSameApp(pkg); 5803 if (!checkPolicyAccess(pkg)) { 5804 Slog.w(TAG, "Notification policy access denied calling " + method); 5805 throw new SecurityException("Notification policy access denied"); 5806 } 5807 } 5808 5809 private boolean checkPackagePolicyAccess(String pkg) { 5810 return mConditionProviders.isPackageOrComponentAllowed( 5811 pkg, getCallingUserHandle().getIdentifier()); 5812 } 5813 5814 private boolean checkPolicyAccess(String pkg) { 5815 final int uid; 5816 try { 5817 uid = getContext().getPackageManager().getPackageUidAsUser(pkg, 5818 UserHandle.getCallingUserId()); 5819 if (PERMISSION_GRANTED == checkComponentPermission( 5820 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, 5821 -1, true)) { 5822 return true; 5823 } 5824 } catch (NameNotFoundException e) { 5825 return false; 5826 } 5827 //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. 5828 return checkPackagePolicyAccess(pkg) 5829 || mListeners.isComponentEnabledForPackage(pkg) 5830 || (mDpm != null && (mDpm.isActiveProfileOwner(uid) 5831 || mDpm.isActiveDeviceOwner(uid))); 5832 } 5833 5834 @Override 5835 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5836 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; 5837 final DumpFilter filter = DumpFilter.parseFromArguments(args); 5838 final long token = Binder.clearCallingIdentity(); 5839 try { 5840 final ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions = 5841 getAllUsersNotificationPermissions(); 5842 if (filter.stats) { 5843 dumpJson(pw, filter, pkgPermissions); 5844 } else if (filter.rvStats) { 5845 dumpRemoteViewStats(pw, filter); 5846 } else if (filter.proto) { 5847 dumpProto(fd, filter, pkgPermissions); 5848 } else if (filter.criticalPriority) { 5849 dumpNotificationRecords(pw, filter); 5850 } else { 5851 dumpImpl(pw, filter, pkgPermissions); 5852 } 5853 } finally { 5854 Binder.restoreCallingIdentity(token); 5855 } 5856 } 5857 5858 @Override 5859 public ComponentName getEffectsSuppressor() { 5860 ComponentName suppressor = !mEffectsSuppressors.isEmpty() 5861 ? mEffectsSuppressors.get(0) 5862 : null; 5863 if (isCallerSystemOrSystemUiOrShell() || suppressor == null 5864 || mPackageManagerInternal.isSameApp(suppressor.getPackageName(), 5865 Binder.getCallingUid(), UserHandle.getUserId(Binder.getCallingUid()))) { 5866 return suppressor; 5867 } 5868 5869 return null; 5870 } 5871 5872 @Override 5873 public boolean matchesCallFilter(Bundle extras) { 5874 // Because matchesCallFilter may use contact data to filter calls, the callers of this 5875 // method need to either have notification listener access or permission to read 5876 // contacts. 5877 boolean systemAccess = false; 5878 try { 5879 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 5880 systemAccess = true; 5881 } catch (SecurityException e) { 5882 } 5883 5884 boolean listenerAccess = false; 5885 try { 5886 String[] pkgNames = mPackageManager.getPackagesForUid(Binder.getCallingUid()); 5887 for (int i = 0; i < pkgNames.length; i++) { 5888 // in most cases there should only be one package here 5889 listenerAccess |= mListeners.hasAllowedListener(pkgNames[i], 5890 Binder.getCallingUserHandle().getIdentifier()); 5891 } 5892 } catch (RemoteException e) { 5893 } finally { 5894 if (!systemAccess && !listenerAccess) { 5895 getContext().enforceCallingPermission(Manifest.permission.READ_CONTACTS, 5896 "matchesCallFilter requires listener permission, contacts read access," 5897 + " or system level access"); 5898 } 5899 } 5900 5901 return mZenModeHelper.matchesCallFilter( 5902 Binder.getCallingUserHandle(), 5903 extras, 5904 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 5905 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 5906 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY, 5907 Binder.getCallingUid()); 5908 } 5909 5910 @Override 5911 public void cleanUpCallersAfter(long timeThreshold) { 5912 enforceSystemOrSystemUI("INotificationManager.cleanUpCallersAfter"); 5913 mZenModeHelper.cleanUpCallersAfter(timeThreshold); 5914 } 5915 5916 @Override 5917 public boolean isSystemConditionProviderEnabled(String path) { 5918 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled"); 5919 return mConditionProviders.isSystemProviderEnabled(path); 5920 } 5921 5922 // Backup/restore interface 5923 @Override 5924 public byte[] getBackupPayload(int user) { 5925 checkCallerIsSystem(); 5926 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 5927 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 5928 try { 5929 writePolicyXml(baos, true /*forBackup*/, user); 5930 return baos.toByteArray(); 5931 } catch (IOException e) { 5932 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 5933 } 5934 return null; 5935 } 5936 5937 @Override 5938 public void applyRestore(byte[] payload, int user) { 5939 checkCallerIsSystem(); 5940 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 5941 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 5942 if (payload == null) { 5943 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 5944 return; 5945 } 5946 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 5947 try { 5948 readPolicyXml(bais, true /*forRestore*/, user); 5949 handleSavePolicyFile(); 5950 } catch (NumberFormatException | XmlPullParserException | IOException e) { 5951 Slog.w(TAG, "applyRestore: error reading payload", e); 5952 } 5953 } 5954 5955 @Override 5956 public boolean isNotificationPolicyAccessGranted(String pkg) { 5957 return checkPolicyAccess(pkg); 5958 } 5959 5960 @Override 5961 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { 5962 enforceSystemOrSystemUIOrSamePackage(pkg, 5963 "request policy access status for another package"); 5964 return checkPolicyAccess(pkg); 5965 } 5966 5967 @Override 5968 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 5969 throws RemoteException { 5970 setNotificationPolicyAccessGrantedForUser( 5971 pkg, getCallingUserHandle().getIdentifier(), granted); 5972 } 5973 5974 @Override 5975 public void setNotificationPolicyAccessGrantedForUser( 5976 String pkg, int userId, boolean granted) { 5977 checkCallerIsSystemOrShell(); 5978 final long identity = Binder.clearCallingIdentity(); 5979 try { 5980 if (mAllowedManagedServicePackages.test( 5981 pkg, userId, mConditionProviders.getRequiredPermission())) { 5982 mConditionProviders.setPackageOrComponentEnabled( 5983 pkg, userId, true, granted); 5984 5985 getContext().sendBroadcastAsUser(new Intent( 5986 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 5987 .setPackage(pkg) 5988 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 5989 UserHandle.of(userId), null); 5990 handleSavePolicyFile(); 5991 } 5992 } finally { 5993 Binder.restoreCallingIdentity(identity); 5994 } 5995 } 5996 5997 @Override 5998 public Policy getNotificationPolicy(String pkg) { 5999 final int callingUid = Binder.getCallingUid(); 6000 if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) { 6001 return mZenModeHelper.getNotificationPolicyFromImplicitZenRule(pkg); 6002 } 6003 final long identity = Binder.clearCallingIdentity(); 6004 try { 6005 return mZenModeHelper.getNotificationPolicy(); 6006 } finally { 6007 Binder.restoreCallingIdentity(identity); 6008 } 6009 } 6010 6011 @Override 6012 public Policy getConsolidatedNotificationPolicy() { 6013 final long identity = Binder.clearCallingIdentity(); 6014 try { 6015 return mZenModeHelper.getConsolidatedNotificationPolicy(); 6016 } finally { 6017 Binder.restoreCallingIdentity(identity); 6018 } 6019 } 6020 6021 /** 6022 * Sets the notification policy. Apps that target API levels below 6023 * {@link Build.VERSION_CODES#P} cannot change user-designated values to 6024 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS}, 6025 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and 6026 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd 6027 */ 6028 @Override 6029 public void setNotificationPolicy(String pkg, Policy policy, boolean fromUser) { 6030 enforcePolicyAccess(pkg, "setNotificationPolicy"); 6031 enforceUserOriginOnlyFromSystem(fromUser, "setNotificationPolicy"); 6032 int callingUid = Binder.getCallingUid(); 6033 @ZenModeConfig.ConfigChangeOrigin int origin = computeZenOrigin(fromUser); 6034 6035 boolean shouldApplyAsImplicitRule = android.app.Flags.modesApi() 6036 && !canManageGlobalZenPolicy(pkg, callingUid); 6037 6038 final long identity = Binder.clearCallingIdentity(); 6039 try { 6040 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg, 6041 0, UserHandle.getUserId(callingUid)); 6042 Policy currPolicy = mZenModeHelper.getNotificationPolicy(); 6043 6044 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) { 6045 int priorityCategories = policy.priorityCategories; 6046 // ignore alarm and media values from new policy 6047 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS; 6048 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA; 6049 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM; 6050 // use user-designated values 6051 priorityCategories |= currPolicy.priorityCategories 6052 & Policy.PRIORITY_CATEGORY_ALARMS; 6053 priorityCategories |= currPolicy.priorityCategories 6054 & Policy.PRIORITY_CATEGORY_MEDIA; 6055 priorityCategories |= currPolicy.priorityCategories 6056 & Policy.PRIORITY_CATEGORY_SYSTEM; 6057 6058 policy = new Policy(priorityCategories, 6059 policy.priorityCallSenders, policy.priorityMessageSenders, 6060 policy.suppressedVisualEffects); 6061 } 6062 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) { 6063 int priorityCategories = correctCategory(policy.priorityCategories, 6064 Policy.PRIORITY_CATEGORY_CONVERSATIONS, 6065 currPolicy.priorityCategories); 6066 6067 policy = new Policy(priorityCategories, 6068 policy.priorityCallSenders, policy.priorityMessageSenders, 6069 policy.suppressedVisualEffects, currPolicy.priorityConversationSenders); 6070 } 6071 int newVisualEffects = calculateSuppressedVisualEffects( 6072 policy, currPolicy, applicationInfo.targetSdkVersion); 6073 policy = new Policy(policy.priorityCategories, 6074 policy.priorityCallSenders, policy.priorityMessageSenders, 6075 newVisualEffects, policy.priorityConversationSenders); 6076 6077 if (shouldApplyAsImplicitRule) { 6078 mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(pkg, callingUid, policy); 6079 } else { 6080 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, 6081 policy); 6082 mZenModeHelper.setNotificationPolicy(policy, origin, callingUid); 6083 } 6084 } catch (RemoteException e) { 6085 Slog.e(TAG, "Failed to set notification policy", e); 6086 } finally { 6087 Binder.restoreCallingIdentity(identity); 6088 } 6089 } 6090 6091 /** 6092 * Gets the device-default zen policy as a ZenPolicy. 6093 */ 6094 @Override 6095 public ZenPolicy getDefaultZenPolicy() { 6096 enforceSystemOrSystemUI("INotificationManager.getDefaultZenPolicy"); 6097 final long identity = Binder.clearCallingIdentity(); 6098 try { 6099 return mZenModeHelper.getDefaultZenPolicy(); 6100 } finally { 6101 Binder.restoreCallingIdentity(identity); 6102 } 6103 } 6104 6105 @Override 6106 public List<String> getEnabledNotificationListenerPackages() { 6107 checkCallerIsSystem(); 6108 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier()); 6109 } 6110 6111 @Override 6112 public List<ComponentName> getEnabledNotificationListeners(int userId) { 6113 checkNotificationListenerAccess(); 6114 return mListeners.getAllowedComponents(userId); 6115 } 6116 6117 @Override 6118 public ComponentName getAllowedNotificationAssistantForUser(int userId) { 6119 checkCallerIsSystemOrSystemUiOrShell(); 6120 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 6121 if (allowedComponents.size() > 1) { 6122 throw new IllegalStateException( 6123 "At most one NotificationAssistant: " + allowedComponents.size()); 6124 } 6125 return CollectionUtils.firstOrNull(allowedComponents); 6126 } 6127 6128 @Override 6129 public ComponentName getAllowedNotificationAssistant() { 6130 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier()); 6131 } 6132 6133 @Override 6134 public ComponentName getDefaultNotificationAssistant() { 6135 checkCallerIsSystem(); 6136 return mAssistants.getDefaultFromConfig(); 6137 } 6138 6139 @Override 6140 public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) { 6141 checkCallerIsSystem(); 6142 setNASMigrationDone(userId); 6143 if (loadFromConfig) { 6144 mAssistants.resetDefaultFromConfig(); 6145 } else { 6146 mAssistants.clearDefaults(); 6147 } 6148 } 6149 6150 6151 @Override 6152 public boolean hasEnabledNotificationListener(String packageName, int userId) { 6153 checkCallerIsSystem(); 6154 return mListeners.isPackageAllowed(packageName, userId); 6155 } 6156 6157 @Override 6158 public boolean isNotificationListenerAccessGranted(ComponentName listener) { 6159 Objects.requireNonNull(listener); 6160 checkCallerIsSystemOrSameApp(listener.getPackageName()); 6161 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 6162 getCallingUserHandle().getIdentifier()); 6163 } 6164 6165 @Override 6166 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener, 6167 int userId) { 6168 Objects.requireNonNull(listener); 6169 checkCallerIsSystem(); 6170 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 6171 userId); 6172 } 6173 6174 @Override 6175 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { 6176 Objects.requireNonNull(assistant); 6177 checkCallerIsSystemOrSameApp(assistant.getPackageName()); 6178 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(), 6179 getCallingUserHandle().getIdentifier()); 6180 } 6181 6182 @Override 6183 public void setNotificationListenerAccessGranted(ComponentName listener, 6184 boolean granted, boolean userSet) throws RemoteException { 6185 setNotificationListenerAccessGrantedForUser( 6186 listener, getCallingUserHandle().getIdentifier(), granted, userSet); 6187 } 6188 6189 @Override 6190 public void setNotificationAssistantAccessGranted(ComponentName assistant, 6191 boolean granted) { 6192 setNotificationAssistantAccessGrantedForUser( 6193 assistant, getCallingUserHandle().getIdentifier(), granted); 6194 } 6195 6196 @Override 6197 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, 6198 boolean granted, boolean userSet) { 6199 Objects.requireNonNull(listener); 6200 if (UserHandle.getCallingUserId() != userId) { 6201 getContext().enforceCallingOrSelfPermission( 6202 android.Manifest.permission.INTERACT_ACROSS_USERS, 6203 "setNotificationListenerAccessGrantedForUser for user " + userId); 6204 } 6205 checkNotificationListenerAccess(); 6206 if (granted && listener.flattenToString().length() 6207 > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) { 6208 throw new IllegalArgumentException( 6209 "Component name too long: " + listener.flattenToString()); 6210 } 6211 if (!userSet && isNotificationListenerAccessUserSet(listener, userId)) { 6212 // Don't override user's choice 6213 return; 6214 } 6215 final long identity = Binder.clearCallingIdentity(); 6216 try { 6217 if (mAllowedManagedServicePackages.test( 6218 listener.getPackageName(), userId, mListeners.getRequiredPermission())) { 6219 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(), 6220 userId, false, granted, userSet); 6221 mListeners.setPackageOrComponentEnabled(listener.flattenToString(), 6222 userId, true, granted, userSet); 6223 6224 getContext().sendBroadcastAsUser(new Intent( 6225 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 6226 .setPackage(listener.getPackageName()) 6227 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 6228 UserHandle.of(userId), null); 6229 6230 handleSavePolicyFile(); 6231 } 6232 } finally { 6233 Binder.restoreCallingIdentity(identity); 6234 } 6235 } 6236 6237 private boolean isNotificationListenerAccessUserSet(ComponentName listener, int userId) { 6238 return mListeners.isPackageOrComponentUserSet(listener.flattenToString(), userId); 6239 } 6240 6241 @Override 6242 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, 6243 int userId, boolean granted) { 6244 checkCallerIsSystemOrSystemUiOrShell(); 6245 for (UserInfo ui : mUm.getEnabledProfiles(userId)) { 6246 mAssistants.setUserSet(ui.id, true); 6247 } 6248 final long identity = Binder.clearCallingIdentity(); 6249 try { 6250 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted, 6251 true); 6252 } finally { 6253 Binder.restoreCallingIdentity(identity); 6254 } 6255 } 6256 6257 @Override 6258 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token, 6259 Adjustment adjustment) { 6260 boolean foundEnqueued = false; 6261 final long identity = Binder.clearCallingIdentity(); 6262 try { 6263 synchronized (mNotificationLock) { 6264 mAssistants.checkServiceTokenLocked(token); 6265 int N = mEnqueuedNotifications.size(); 6266 for (int i = 0; i < N; i++) { 6267 final NotificationRecord r = mEnqueuedNotifications.get(i); 6268 if (Objects.equals(adjustment.getKey(), r.getKey()) 6269 && Objects.equals(adjustment.getUser(), r.getUserId()) 6270 && mAssistants.isSameUser(token, r.getUserId())) { 6271 applyAdjustmentLocked(r, adjustment, false); 6272 r.applyAdjustments(); 6273 // importance is checked at the beginning of the 6274 // PostNotificationRunnable, before the signal extractors are run, so 6275 // calculate the final importance here 6276 r.calculateImportance(); 6277 foundEnqueued = true; 6278 } 6279 } 6280 if (!foundEnqueued) { 6281 applyAdjustmentsFromAssistant(token, List.of(adjustment)); 6282 } 6283 } 6284 } finally { 6285 Binder.restoreCallingIdentity(identity); 6286 } 6287 } 6288 6289 @Override 6290 public void applyAdjustmentFromAssistant(INotificationListener token, 6291 Adjustment adjustment) { 6292 List<Adjustment> adjustments = new ArrayList<>(); 6293 adjustments.add(adjustment); 6294 applyAdjustmentsFromAssistant(token, adjustments); 6295 } 6296 6297 @Override 6298 public void applyAdjustmentsFromAssistant(INotificationListener token, 6299 List<Adjustment> adjustments) { 6300 6301 boolean needsSort = false; 6302 final long identity = Binder.clearCallingIdentity(); 6303 try { 6304 synchronized (mNotificationLock) { 6305 mAssistants.checkServiceTokenLocked(token); 6306 for (Adjustment adjustment : adjustments) { 6307 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey()); 6308 if (r != null && mAssistants.isSameUser(token, r.getUserId())) { 6309 applyAdjustmentLocked(r, adjustment, true); 6310 // If the assistant has blocked the notification, cancel it 6311 // This will trigger a sort, so we don't have to explicitly ask for 6312 // one here. 6313 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE) 6314 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE) 6315 == IMPORTANCE_NONE) { 6316 cancelNotificationsFromListener(token, new String[]{r.getKey()}); 6317 } else { 6318 r.setPendingLogUpdate(true); 6319 needsSort = true; 6320 } 6321 } 6322 } 6323 } 6324 if (needsSort) { 6325 mRankingHandler.requestSort(); 6326 } 6327 } finally { 6328 Binder.restoreCallingIdentity(identity); 6329 } 6330 } 6331 6332 @Override 6333 public void updateNotificationChannelGroupFromPrivilegedListener( 6334 INotificationListener token, String pkg, UserHandle user, 6335 NotificationChannelGroup group) throws RemoteException { 6336 Objects.requireNonNull(user); 6337 verifyPrivilegedListener(token, user, false); 6338 createNotificationChannelGroup( 6339 pkg, getUidForPackageAndUser(pkg, user), group, false, true); 6340 handleSavePolicyFile(); 6341 } 6342 6343 @Override 6344 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, 6345 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { 6346 Objects.requireNonNull(channel); 6347 Objects.requireNonNull(pkg); 6348 Objects.requireNonNull(user); 6349 6350 verifyPrivilegedListener(token, user, false); 6351 6352 final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( 6353 pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true); 6354 verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel); 6355 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); 6356 } 6357 6358 @Override 6359 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( 6360 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 6361 Objects.requireNonNull(pkg); 6362 Objects.requireNonNull(user); 6363 verifyPrivilegedListener(token, user, true); 6364 6365 return mPreferencesHelper.getNotificationChannels(pkg, 6366 getUidForPackageAndUser(pkg, user), false /* includeDeleted */); 6367 } 6368 6369 @Override 6370 public ParceledListSlice<NotificationChannelGroup> 6371 getNotificationChannelGroupsFromPrivilegedListener( 6372 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 6373 Objects.requireNonNull(pkg); 6374 Objects.requireNonNull(user); 6375 verifyPrivilegedListener(token, user, true); 6376 6377 List<NotificationChannelGroup> groups = new ArrayList<>(); 6378 groups.addAll(mPreferencesHelper.getNotificationChannelGroups( 6379 pkg, getUidForPackageAndUser(pkg, user))); 6380 return new ParceledListSlice<>(groups); 6381 } 6382 6383 @Override 6384 public boolean isInCall(String pkg, int uid) { 6385 checkCallerIsSystemOrSystemUiOrShell(); 6386 return isCallNotification(pkg, uid); 6387 } 6388 6389 @Override 6390 public void setPrivateNotificationsAllowed(boolean allow) { 6391 if (PERMISSION_GRANTED 6392 != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 6393 throw new SecurityException( 6394 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 6395 } 6396 if (allow != mLockScreenAllowSecureNotifications) { 6397 mLockScreenAllowSecureNotifications = allow; 6398 if (android.app.Flags.keyguardPrivateNotifications()) { 6399 getContext().sendBroadcast( 6400 new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) 6401 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, 6402 mLockScreenAllowSecureNotifications), 6403 STATUS_BAR_SERVICE); 6404 } 6405 6406 handleSavePolicyFile(); 6407 } 6408 } 6409 6410 @Override 6411 public boolean getPrivateNotificationsAllowed() { 6412 if (PERMISSION_GRANTED 6413 != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 6414 throw new SecurityException( 6415 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 6416 } 6417 return mLockScreenAllowSecureNotifications; 6418 } 6419 6420 @Override 6421 public boolean isPackagePaused(String pkg) { 6422 Objects.requireNonNull(pkg); 6423 checkCallerIsSameApp(pkg); 6424 6425 return isPackagePausedOrSuspended(pkg, Binder.getCallingUid()); 6426 } 6427 6428 @Override 6429 public boolean isPermissionFixed(String pkg, @UserIdInt int userId) { 6430 enforceSystemOrSystemUI("isPermissionFixed"); 6431 return mPermissionHelper.isPermissionFixed(pkg, userId); 6432 } 6433 6434 private void verifyPrivilegedListener(INotificationListener token, UserHandle user, 6435 boolean assistantAllowed) { 6436 ManagedServiceInfo info; 6437 synchronized (mNotificationLock) { 6438 info = mListeners.checkServiceTokenLocked(token); 6439 } 6440 if (!hasCompanionDevice(info)) { 6441 synchronized (mNotificationLock) { 6442 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) { 6443 throw new SecurityException(info + " does not have access"); 6444 } 6445 } 6446 } 6447 if (!info.enabledAndUserMatches(user.getIdentifier())) { 6448 throw new SecurityException(info + " does not have access"); 6449 } 6450 } 6451 6452 private void verifyPrivilegedListenerUriPermission(int sourceUid, 6453 @NonNull NotificationChannel updateChannel, 6454 @Nullable NotificationChannel originalChannel) { 6455 // Check that the NLS has the required permissions to access the channel 6456 final Uri soundUri = updateChannel.getSound(); 6457 final Uri originalSoundUri = 6458 (originalChannel != null) ? originalChannel.getSound() : null; 6459 if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) { 6460 Binder.withCleanCallingIdentity(() -> { 6461 mUgmInternal.checkGrantUriPermission(sourceUid, null, 6462 ContentProvider.getUriWithoutUserId(soundUri), 6463 Intent.FLAG_GRANT_READ_URI_PERMISSION, 6464 ContentProvider.getUserIdFromUri(soundUri, 6465 UserHandle.getUserId(sourceUid))); 6466 }); 6467 } 6468 } 6469 6470 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { 6471 int uid = INVALID_UID; 6472 final long identity = Binder.clearCallingIdentity(); 6473 try { 6474 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); 6475 } finally { 6476 Binder.restoreCallingIdentity(identity); 6477 } 6478 return uid; 6479 } 6480 6481 @Override 6482 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 6483 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 6484 throws RemoteException { 6485 new NotificationShellCmd(NotificationManagerService.this) 6486 .exec(this, in, out, err, args, callback, resultReceiver); 6487 } 6488 6489 /** 6490 * Get stats committed after startNs 6491 * 6492 * @param startNs Report stats committed after this time in nanoseconds. 6493 * @param report Indicatess which section to include in the stats. 6494 * @param doAgg Whether to aggregate the stats or keep them separated. 6495 * @param out List of protos of individual commits or one representing the 6496 * aggregate. 6497 * @return the report time in nanoseconds, or 0 on error. 6498 */ 6499 @Override 6500 public long pullStats(long startNs, int report, boolean doAgg, 6501 List<ParcelFileDescriptor> out) { 6502 checkCallerIsSystemOrShell(); 6503 long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS); 6504 6505 final long identity = Binder.clearCallingIdentity(); 6506 try { 6507 switch (report) { 6508 case REPORT_REMOTE_VIEWS: 6509 Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: " 6510 + startMs + " with " + doAgg); 6511 PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg); 6512 if (stats != null) { 6513 out.add(stats.toParcelFileDescriptor(report)); 6514 Slog.e(TAG, "exiting pullStats with: " + out.size()); 6515 long endNs = TimeUnit.NANOSECONDS 6516 .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS); 6517 return endNs; 6518 } 6519 Slog.e(TAG, "null stats for: " + report); 6520 } 6521 } catch (IOException e) { 6522 6523 Slog.e(TAG, "exiting pullStats: on error", e); 6524 return 0; 6525 } finally { 6526 Binder.restoreCallingIdentity(identity); 6527 } 6528 Slog.e(TAG, "exiting pullStats: bad request"); 6529 return 0; 6530 } 6531 }; 6532 6533 private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) { 6534 if (!mUmInternal.isUserInitialized(userId)) { 6535 return; // App-op "updates" are sent when starting a new user the first time. 6536 } 6537 int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId); 6538 if (uid == INVALID_UID) { 6539 Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId)); 6540 return; 6541 } 6542 boolean hasPermission = mPermissionHelper.hasPermission(uid); 6543 if (!hasPermission) { 6544 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null, 6545 /* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId, 6546 REASON_PACKAGE_BANNED); 6547 } 6548 } 6549 6550 protected void checkNotificationListenerAccess() { 6551 if (!isCallerSystemOrPhone()) { 6552 getContext().enforceCallingPermission( 6553 permission.MANAGE_NOTIFICATION_LISTENERS, 6554 "Caller must hold " + permission.MANAGE_NOTIFICATION_LISTENERS); 6555 } 6556 } 6557 6558 @VisibleForTesting 6559 protected void setNotificationAssistantAccessGrantedForUserInternal( 6560 ComponentName assistant, int baseUserId, boolean granted, boolean userSet) { 6561 List<UserInfo> users = mUm.getEnabledProfiles(baseUserId); 6562 if (users != null) { 6563 for (UserInfo user : users) { 6564 int userId = user.id; 6565 if (assistant == null) { 6566 ComponentName allowedAssistant = CollectionUtils.firstOrNull( 6567 mAssistants.getAllowedComponents(userId)); 6568 if (allowedAssistant != null) { 6569 setNotificationAssistantAccessGrantedForUserInternal( 6570 allowedAssistant, userId, false, userSet); 6571 } 6572 continue; 6573 } 6574 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), 6575 userId, mAssistants.getRequiredPermission())) { 6576 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(), 6577 userId, false, granted); 6578 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(), 6579 userId, true, granted, userSet); 6580 6581 getContext().sendBroadcastAsUser( 6582 new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 6583 .setPackage(assistant.getPackageName()) 6584 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 6585 UserHandle.of(userId), null); 6586 6587 handleSavePolicyFile(); 6588 } 6589 } 6590 } 6591 } 6592 6593 @GuardedBy("mNotificationLock") 6594 private void applyAdjustmentLocked(NotificationRecord r, Adjustment adjustment, 6595 boolean isPosted) { 6596 if (r == null) { 6597 return; 6598 } 6599 if (adjustment.getSignals() != null) { 6600 final Bundle adjustments = adjustment.getSignals(); 6601 Bundle.setDefusable(adjustments, true); 6602 List<String> toRemove = new ArrayList<>(); 6603 for (String potentialKey : adjustments.keySet()) { 6604 if (!mAssistants.isAdjustmentAllowed(potentialKey)) { 6605 toRemove.add(potentialKey); 6606 } 6607 } 6608 for (String removeKey : toRemove) { 6609 adjustments.remove(removeKey); 6610 } 6611 r.addAdjustment(adjustment); 6612 if (adjustment.getSignals().containsKey(Adjustment.KEY_SENSITIVE_CONTENT)) { 6613 logSensitiveAdjustmentReceived(isPosted, 6614 adjustment.getSignals().getBoolean(Adjustment.KEY_SENSITIVE_CONTENT), 6615 r.getLifespanMs(System.currentTimeMillis())); 6616 } 6617 } 6618 } 6619 6620 @GuardedBy("mNotificationLock") 6621 void addAutogroupKeyLocked(String key, boolean requestSort) { 6622 NotificationRecord r = mNotificationsByKey.get(key); 6623 if (r == null) { 6624 return; 6625 } 6626 if (r.getSbn().getOverrideGroupKey() == null) { 6627 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY); 6628 EventLogTags.writeNotificationAutogrouped(key); 6629 if (!android.app.Flags.checkAutogroupBeforePost() || requestSort) { 6630 mRankingHandler.requestSort(); 6631 } 6632 } 6633 } 6634 6635 @GuardedBy("mNotificationLock") 6636 void removeAutogroupKeyLocked(String key) { 6637 NotificationRecord r = mNotificationsByKey.get(key); 6638 if (r == null) { 6639 Slog.w(TAG, "Failed to remove autogroup " + key); 6640 return; 6641 } 6642 if (r.getSbn().getOverrideGroupKey() != null) { 6643 addAutoGroupAdjustment(r, null); 6644 EventLogTags.writeNotificationUnautogrouped(key); 6645 mRankingHandler.requestSort(); 6646 } 6647 } 6648 6649 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) { 6650 Bundle signals = new Bundle(); 6651 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey); 6652 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 6653 r.getSbn().getUserId()); 6654 r.addAdjustment(adjustment); 6655 } 6656 6657 // Clears the 'fake' auto-group summary. 6658 @VisibleForTesting 6659 @GuardedBy("mNotificationLock") 6660 void clearAutogroupSummaryLocked(int userId, String pkg) { 6661 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 6662 if (summaries != null && summaries.containsKey(pkg)) { 6663 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg)); 6664 if (removed != null) { 6665 final StatusBarNotification sbn = removed.getSbn(); 6666 cancelNotification(MY_UID, MY_PID, pkg, sbn.getTag(), sbn.getId(), 0, 0, false, 6667 userId, REASON_UNAUTOBUNDLED, null); 6668 } 6669 } 6670 } 6671 6672 @GuardedBy("mNotificationLock") 6673 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) { 6674 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId()); 6675 return summaries != null && summaries.containsKey(sbn.getPackageName()); 6676 } 6677 6678 // Creates a 'fake' summary for a package that has exceeded the solo-notification limit. 6679 NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey, 6680 int flagsToSet, Icon summaryIcon, int summaryIconColor, int summaryVisibilty) { 6681 NotificationRecord summaryRecord = null; 6682 boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId); 6683 synchronized (mNotificationLock) { 6684 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey); 6685 if (notificationRecord == null) { 6686 // The notification could have been cancelled again already. A successive 6687 // adjustment will post a summary if needed. 6688 return null; 6689 } 6690 final StatusBarNotification adjustedSbn = notificationRecord.getSbn(); 6691 userId = adjustedSbn.getUser().getIdentifier(); 6692 int uid = adjustedSbn.getUid(); 6693 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 6694 if (summaries == null) { 6695 summaries = new ArrayMap<>(); 6696 } 6697 mAutobundledSummaries.put(userId, summaries); 6698 if (!summaries.containsKey(pkg)) { 6699 // Add summary 6700 final ApplicationInfo appInfo = 6701 adjustedSbn.getNotification().extras.getParcelable( 6702 EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class); 6703 final Bundle extras = new Bundle(); 6704 extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, appInfo); 6705 final String channelId = notificationRecord.getChannel().getId(); 6706 6707 final Notification summaryNotification = 6708 new Notification.Builder(getContext(), channelId) 6709 .setSmallIcon(summaryIcon) 6710 .setGroupSummary(true) 6711 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) 6712 .setGroup(GroupHelper.AUTOGROUP_KEY) 6713 .setFlag(flagsToSet, true) 6714 .setColor(summaryIconColor) 6715 .setVisibility(summaryVisibilty) 6716 .build(); 6717 summaryNotification.extras.putAll(extras); 6718 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); 6719 if (appIntent != null) { 6720 summaryNotification.contentIntent = mAmi.getPendingIntentActivityAsApp( 6721 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null, 6722 pkg, appInfo.uid); 6723 } 6724 final StatusBarNotification summarySbn = 6725 new StatusBarNotification(adjustedSbn.getPackageName(), 6726 adjustedSbn.getOpPkg(), 6727 Integer.MAX_VALUE, 6728 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(), 6729 adjustedSbn.getInitialPid(), summaryNotification, 6730 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY, 6731 System.currentTimeMillis()); 6732 summaryRecord = new NotificationRecord(getContext(), summarySbn, 6733 notificationRecord.getChannel()); 6734 summaryRecord.setImportanceFixed(isPermissionFixed); 6735 summaryRecord.setIsAppImportanceLocked( 6736 notificationRecord.getIsAppImportanceLocked()); 6737 summaries.put(pkg, summarySbn.getKey()); 6738 } 6739 if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid, 6740 summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord, 6741 true, false)) { 6742 return summaryRecord; 6743 } 6744 } 6745 return null; 6746 } 6747 6748 // Gets packages that have requested notification permission, and whether that has been 6749 // allowed/denied, for all users on the device. 6750 // Returns a single map containing that info keyed by (uid, package name) for all users. 6751 // Because this calls into mPermissionHelper, this method must never be called with a lock held. 6752 @VisibleForTesting 6753 protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> 6754 getAllUsersNotificationPermissions() { 6755 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>(); 6756 final List<UserInfo> allUsers = mUm.getUsers(); 6757 // for each of these, get the package notification permissions that are associated 6758 // with this user and add it to the map 6759 for (UserInfo ui : allUsers) { 6760 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> userPermissions = 6761 mPermissionHelper.getNotificationPermissionValues( 6762 ui.getUserHandle().getIdentifier()); 6763 for (Pair<Integer, String> pair : userPermissions.keySet()) { 6764 allPermissions.put(pair, userPermissions.get(pair)); 6765 } 6766 } 6767 return allPermissions; 6768 } 6769 6770 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter, 6771 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { 6772 JSONObject dump = new JSONObject(); 6773 try { 6774 dump.put("service", "Notification Manager"); 6775 dump.put("bans", mPreferencesHelper.dumpBansJson(filter, pkgPermissions)); 6776 dump.put("ranking", mPreferencesHelper.dumpJson(filter, pkgPermissions)); 6777 dump.put("stats", mUsageStats.dumpJson(filter)); 6778 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter)); 6779 } catch (JSONException e) { 6780 e.printStackTrace(); 6781 } 6782 pw.println(dump); 6783 } 6784 6785 private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) { 6786 PulledStats stats = mUsageStats.remoteViewStats(filter.since, true); 6787 if (stats == null) { 6788 pw.println("no remote view stats reported."); 6789 return; 6790 } 6791 stats.dump(REPORT_REMOTE_VIEWS, pw, filter); 6792 } 6793 6794 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter, 6795 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { 6796 final ProtoOutputStream proto = new ProtoOutputStream(fd); 6797 synchronized (mNotificationLock) { 6798 int N = mNotificationList.size(); 6799 for (int i = 0; i < N; i++) { 6800 final NotificationRecord nr = mNotificationList.get(i); 6801 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 6802 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 6803 NotificationRecordProto.POSTED); 6804 } 6805 N = mEnqueuedNotifications.size(); 6806 for (int i = 0; i < N; i++) { 6807 final NotificationRecord nr = mEnqueuedNotifications.get(i); 6808 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 6809 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 6810 NotificationRecordProto.ENQUEUED); 6811 } 6812 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed(); 6813 N = snoozed.size(); 6814 for (int i = 0; i < N; i++) { 6815 final NotificationRecord nr = snoozed.get(i); 6816 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 6817 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 6818 NotificationRecordProto.SNOOZED); 6819 } 6820 6821 long zenLog = proto.start(NotificationServiceDumpProto.ZEN); 6822 mZenModeHelper.dump(proto); 6823 for (ComponentName suppressor : mEffectsSuppressors) { 6824 suppressor.dumpDebug(proto, ZenModeProto.SUPPRESSORS); 6825 } 6826 proto.end(zenLog); 6827 6828 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS); 6829 mListeners.dump(proto, filter); 6830 proto.end(listenersToken); 6831 6832 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints); 6833 6834 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) { 6835 long effectsToken = proto.start( 6836 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS); 6837 6838 proto.write( 6839 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i)); 6840 final ArraySet<ComponentName> listeners = 6841 mListenersDisablingEffects.valueAt(i); 6842 for (int j = 0; j < listeners.size(); j++) { 6843 final ComponentName componentName = listeners.valueAt(j); 6844 componentName.dumpDebug(proto, 6845 ListenersDisablingEffectsProto.LISTENER_COMPONENTS); 6846 } 6847 6848 proto.end(effectsToken); 6849 } 6850 6851 long assistantsToken = proto.start( 6852 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS); 6853 mAssistants.dump(proto, filter); 6854 proto.end(assistantsToken); 6855 6856 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS); 6857 mConditionProviders.dump(proto, filter); 6858 proto.end(conditionsToken); 6859 6860 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG); 6861 mRankingHelper.dump(proto, filter); 6862 mPreferencesHelper.dump(proto, filter, pkgPermissions); 6863 proto.end(rankingToken); 6864 } 6865 6866 proto.flush(); 6867 } 6868 6869 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) { 6870 synchronized (mNotificationLock) { 6871 int N; 6872 N = mNotificationList.size(); 6873 if (N > 0) { 6874 pw.println(" Notification List:"); 6875 for (int i = 0; i < N; i++) { 6876 final NotificationRecord nr = mNotificationList.get(i); 6877 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 6878 nr.dump(pw, " ", getContext(), filter.redact); 6879 } 6880 pw.println(" "); 6881 } 6882 } 6883 } 6884 6885 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter, 6886 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { 6887 pw.print("Current Notification Manager state"); 6888 if (filter.filtered) { 6889 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 6890 } 6891 pw.println(':'); 6892 int N; 6893 final boolean zenOnly = filter.filtered && filter.zen; 6894 6895 if (!zenOnly) { 6896 synchronized (mToastQueue) { 6897 N = mToastQueue.size(); 6898 if (N > 0) { 6899 pw.println(" Toast Queue:"); 6900 for (int i=0; i<N; i++) { 6901 mToastQueue.get(i).dump(pw, " ", filter); 6902 } 6903 pw.println(" "); 6904 } 6905 } 6906 } 6907 6908 synchronized (mNotificationLock) { 6909 if (!zenOnly) { 6910 // Priority filters are only set when called via bugreport. If set 6911 // skip sections that are part of the critical section. 6912 if (!filter.normalPriority) { 6913 dumpNotificationRecords(pw, filter); 6914 } 6915 if (!filter.filtered) { 6916 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate); 6917 pw.println(" hideSilentStatusBar=" 6918 + mPreferencesHelper.shouldHideSilentStatusIcons()); 6919 mAttentionHelper.dump(pw, " ", filter); 6920 } 6921 pw.println(" mArchive=" + mArchive.toString()); 6922 mArchive.dumpImpl(pw, filter); 6923 6924 if (!zenOnly) { 6925 N = mEnqueuedNotifications.size(); 6926 if (N > 0) { 6927 pw.println(" Enqueued Notification List:"); 6928 for (int i = 0; i < N; i++) { 6929 final NotificationRecord nr = mEnqueuedNotifications.get(i); 6930 if (filter.filtered && !filter.matches(nr.getSbn())) continue; 6931 nr.dump(pw, " ", getContext(), filter.redact); 6932 } 6933 pw.println(" "); 6934 } 6935 6936 mSnoozeHelper.dump(pw, filter); 6937 } 6938 } 6939 6940 if (!zenOnly) { 6941 pw.println("\n Ranking Config:"); 6942 mRankingHelper.dump(pw, " ", filter); 6943 6944 pw.println("\n Notification Preferences:"); 6945 mPreferencesHelper.dump(pw, " ", filter, pkgPermissions); 6946 6947 pw.println("\n Notification listeners:"); 6948 mListeners.dump(pw, filter); 6949 pw.print(" mListenerHints: "); pw.println(mListenerHints); 6950 pw.print(" mListenersDisablingEffects: ("); 6951 N = mListenersDisablingEffects.size(); 6952 for (int i = 0; i < N; i++) { 6953 final int hint = mListenersDisablingEffects.keyAt(i); 6954 if (i > 0) pw.print(';'); 6955 pw.print("hint[" + hint + "]:"); 6956 6957 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 6958 final int listenerSize = listeners.size(); 6959 6960 for (int j = 0; j < listenerSize; j++) { 6961 if (j > 0) pw.print(','); 6962 final ComponentName listener = listeners.valueAt(j); 6963 if (listener != null) { 6964 pw.print(listener); 6965 } 6966 } 6967 } 6968 pw.println(')'); 6969 pw.println("\n Notification assistant services:"); 6970 mAssistants.dump(pw, filter); 6971 } 6972 6973 if (!filter.filtered || zenOnly) { 6974 pw.println("\n Zen Mode:"); 6975 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 6976 mZenModeHelper.dump(pw, " "); 6977 6978 pw.println("\n Zen Log:"); 6979 ZenLog.dump(pw, " "); 6980 } 6981 6982 pw.println("\n Condition providers:"); 6983 mConditionProviders.dump(pw, filter); 6984 6985 pw.println("\n Group summaries:"); 6986 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 6987 NotificationRecord r = entry.getValue(); 6988 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 6989 if (mNotificationsByKey.get(r.getKey()) != r) { 6990 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 6991 r.dump(pw, " ", getContext(), filter.redact); 6992 } 6993 } 6994 6995 if (!zenOnly) { 6996 pw.println("\n Usage Stats:"); 6997 mUsageStats.dump(pw, " ", filter); 6998 6999 if (Flags.allNotifsNeedTtl()) { 7000 pw.println("\n TimeToLive alarms:"); 7001 mTtlHelper.dump(pw, " "); 7002 } 7003 } 7004 } 7005 } 7006 7007 /** 7008 * The private API only accessible to the system process. 7009 */ 7010 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 7011 7012 @Override 7013 public NotificationChannel getNotificationChannel(String pkg, int uid, String 7014 channelId) { 7015 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false); 7016 } 7017 7018 @Override 7019 public NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String 7020 channelId) { 7021 return mPreferencesHelper.getGroupForChannel(pkg, uid, channelId); 7022 } 7023 7024 @Override 7025 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 7026 String tag, int id, Notification notification, int userId) { 7027 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 7028 userId, false /* byForegroundService */); 7029 } 7030 7031 @Override 7032 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 7033 String tag, int id, Notification notification, int userId, 7034 boolean byForegroundService) { 7035 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 7036 userId, byForegroundService); 7037 } 7038 7039 @Override 7040 public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid, 7041 String tag, int id, int userId) { 7042 // Don't allow client applications to cancel foreground service notifs, 7043 // user-initiated job notifs or autobundled summaries. 7044 final int mustNotHaveFlags = isCallingUidSystem() ? 0 : 7045 (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY); 7046 cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId, 7047 mustNotHaveFlags); 7048 } 7049 7050 @Override 7051 public boolean isNotificationShown(String pkg, String tag, int notificationId, int userId) { 7052 return isNotificationShownInternal(pkg, tag, notificationId, userId); 7053 } 7054 7055 @Override 7056 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 7057 int userId) { 7058 checkCallerIsSystem(); 7059 mHandler.post(() -> { 7060 synchronized (mNotificationLock) { 7061 removeFlagFromNotificationLocked(pkg, notificationId, userId, 7062 FLAG_FOREGROUND_SERVICE); 7063 } 7064 }); 7065 } 7066 7067 @Override 7068 public void removeUserInitiatedJobFlagFromNotification(String pkg, int notificationId, 7069 int userId) { 7070 checkCallerIsSystem(); 7071 mHandler.post(() -> { 7072 synchronized (mNotificationLock) { 7073 removeFlagFromNotificationLocked(pkg, notificationId, userId, 7074 FLAG_USER_INITIATED_JOB); 7075 } 7076 }); 7077 } 7078 7079 @GuardedBy("mNotificationLock") 7080 private void removeFlagFromNotificationLocked(String pkg, int notificationId, int userId, 7081 int flag) { 7082 int count = getNotificationCount(pkg, userId); 7083 boolean removeFlagFromNotification = false; 7084 if (count > MAX_PACKAGE_NOTIFICATIONS) { 7085 mUsageStats.registerOverCountQuota(pkg); 7086 removeFlagFromNotification = true; 7087 } 7088 if (removeFlagFromNotification) { 7089 NotificationRecord r = findNotificationLocked(pkg, null, notificationId, userId); 7090 if (r != null) { 7091 if (DBG) { 7092 final String type = (flag == FLAG_FOREGROUND_SERVICE) ? "FGS" : "UIJ"; 7093 Slog.d(TAG, "Remove " + type + " flag not allow. " 7094 + "Cancel " + type + " notification"); 7095 } 7096 removeFromNotificationListsLocked(r); 7097 cancelNotificationLocked(r, false, REASON_APP_CANCEL, true, 7098 null, SystemClock.elapsedRealtime()); 7099 } 7100 } else { 7101 List<NotificationRecord> enqueued = findNotificationsByListLocked( 7102 mEnqueuedNotifications, pkg, null, notificationId, userId); 7103 for (int i = 0; i < enqueued.size(); i++) { 7104 final NotificationRecord r = enqueued.get(i); 7105 if (r != null) { 7106 // strip flag from all enqueued notifications. listeners will be informed 7107 // in post runnable. 7108 StatusBarNotification sbn = r.getSbn(); 7109 sbn.getNotification().flags = (r.mOriginalFlags & ~flag); 7110 } 7111 } 7112 7113 NotificationRecord r = findNotificationByListLocked( 7114 mNotificationList, pkg, null, notificationId, userId); 7115 if (r != null) { 7116 // if posted notification exists, strip its flag and tell listeners 7117 StatusBarNotification sbn = r.getSbn(); 7118 sbn.getNotification().flags = (r.mOriginalFlags & ~flag); 7119 mRankingHelper.sort(mNotificationList); 7120 mListeners.notifyPostedLocked(r, r); 7121 } 7122 } 7123 } 7124 7125 @Override 7126 public void onConversationRemoved(String pkg, int uid, Set<String> shortcuts) { 7127 onConversationRemovedInternal(pkg, uid, shortcuts); 7128 } 7129 7130 @Override 7131 public int getNumNotificationChannelsForPackage(String pkg, int uid, 7132 boolean includeDeleted) { 7133 return NotificationManagerService.this 7134 .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted); 7135 } 7136 7137 @Override 7138 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 7139 return areNotificationsEnabledForPackageInt(pkg, uid); 7140 } 7141 7142 @Override 7143 public void sendReviewPermissionsNotification() { 7144 if (!mShowReviewPermissionsNotification) { 7145 // don't show if this notification is turned off 7146 return; 7147 } 7148 7149 // This method is meant to be called from the JobService upon running the job for this 7150 // notification having been rescheduled; so without checking any other state, it will 7151 // send the notification. 7152 checkCallerIsSystem(); 7153 NotificationManager nm = getContext().getSystemService(NotificationManager.class); 7154 nm.notify(TAG, 7155 SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS, 7156 createReviewPermissionsNotification()); 7157 Settings.Global.putInt(getContext().getContentResolver(), 7158 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 7159 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 7160 } 7161 7162 @Override 7163 public void cleanupHistoryFiles() { 7164 checkCallerIsSystem(); 7165 mHistoryManager.cleanupHistoryFiles(); 7166 } 7167 7168 @Override 7169 public void removeBitmaps() { 7170 // Check all NotificationRecords, remove expired bitmaps and icon URIs, repost silently. 7171 synchronized (mNotificationLock) { 7172 for (NotificationRecord r: mNotificationList) { 7173 7174 // System#currentTimeMillis when posted 7175 final long timePostedMs = r.getSbn().getPostTime(); 7176 final long timeNowMs = System.currentTimeMillis(); 7177 7178 final long bitmapDuration; 7179 if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) { 7180 bitmapDuration = Duration.ofSeconds(5).toMillis(); 7181 } else { 7182 bitmapDuration = BITMAP_DURATION.toMillis(); 7183 } 7184 7185 if (isBitmapExpired(timePostedMs, timeNowMs, bitmapDuration)) { 7186 removeBitmapAndRepost(r); 7187 } 7188 } 7189 } 7190 } 7191 7192 @Override 7193 public void setDeviceEffectsApplier(DeviceEffectsApplier applier) { 7194 if (!android.app.Flags.modesApi()) { 7195 return; 7196 } 7197 if (mZenModeHelper == null) { 7198 throw new IllegalStateException("ZenModeHelper is not yet ready!"); 7199 } 7200 // This can also throw IllegalStateException if called too late. 7201 mZenModeHelper.setDeviceEffectsApplier(applier); 7202 } 7203 }; 7204 7205 private static boolean isBigPictureWithBitmapOrIcon(Notification n) { 7206 final boolean isBigPicture = n.isStyle(Notification.BigPictureStyle.class); 7207 if (!isBigPicture) { 7208 return false; 7209 } 7210 7211 final boolean hasBitmap = n.extras.containsKey(Notification.EXTRA_PICTURE) 7212 && n.extras.getParcelable(Notification.EXTRA_PICTURE) != null; 7213 if (hasBitmap) { 7214 return true; 7215 } 7216 7217 final boolean hasIcon = n.extras.containsKey(Notification.EXTRA_PICTURE_ICON) 7218 && n.extras.getParcelable(Notification.EXTRA_PICTURE_ICON) != null; 7219 if (hasIcon) { 7220 return true; 7221 } 7222 return false; 7223 } 7224 7225 private static boolean isBitmapExpired(long timePostedMs, long timeNowMs, long timeToLiveMs) { 7226 final long timeDiff = timeNowMs - timePostedMs; 7227 return timeDiff > timeToLiveMs; 7228 } 7229 7230 private void removeBitmapAndRepost(NotificationRecord r) { 7231 if (!isBigPictureWithBitmapOrIcon(r.getNotification())) { 7232 return; 7233 } 7234 // Remove Notification object's reference to picture bitmap or URI. Leave the extras set to 7235 // null to avoid crashing apps that came to expect them to be present but null. 7236 r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE, null); 7237 r.getNotification().extras.putParcelable(Notification.EXTRA_PICTURE_ICON, null); 7238 7239 // Make Notification silent 7240 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 7241 7242 // Repost 7243 enqueueNotificationInternal(r.getSbn().getPackageName(), 7244 r.getSbn().getOpPkg(), r.getSbn().getUid(), 7245 r.getSbn().getInitialPid(), r.getSbn().getTag(), 7246 r.getSbn().getId(), r.getNotification(), 7247 r.getSbn().getUserId(), /* postSilently= */ true, 7248 /* byForegroundService= */ false); 7249 } 7250 7251 int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) { 7252 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted).getList() 7253 .size(); 7254 } 7255 7256 void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid, 7257 String tag, int id, int userId, int mustNotHaveFlags) { 7258 userId = ActivityManager.handleIncomingUser(callingPid, 7259 callingUid, userId, true, false, "cancelNotificationWithTag", pkg); 7260 7261 // ensure opPkg is delegate if does not match pkg 7262 7263 int uid = INVALID_UID; 7264 7265 try { 7266 uid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 7267 } catch (NameNotFoundException e) { 7268 // package either never existed so there's no posted notification or it's being 7269 // uninstalled so we'll be cleaning it up soon. log and return immediately below. 7270 } 7271 7272 if (uid == INVALID_UID) { 7273 Slog.w(TAG, opPkg + ":" + callingUid + " trying to cancel notification " 7274 + "for nonexistent pkg " + pkg + " in user " + userId); 7275 return; 7276 } 7277 7278 // if opPkg is not the same as pkg, make sure the notification given was posted 7279 // by opPkg 7280 if (!Objects.equals(pkg, opPkg)) { 7281 synchronized (mNotificationLock) { 7282 // Look for the notification, searching both the posted and enqueued lists. 7283 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 7284 if (r != null) { 7285 if (!Objects.equals(opPkg, r.getSbn().getOpPkg())) { 7286 throw new SecurityException(opPkg + " does not have permission to " 7287 + "cancel a notification they did not post " + tag + " " + id); 7288 } 7289 } 7290 } 7291 } 7292 if (Flags.traceCancelEvents()) { 7293 Trace.instant(Trace.TRACE_TAG_SYSTEM_SERVER, "cancelNotificationInternal: " + 7294 SmallHash.hash(Objects.hashCode(tag) ^ id)); 7295 } 7296 7297 cancelNotification(uid, callingPid, pkg, tag, id, 0, 7298 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); 7299 } 7300 7301 boolean isNotificationShownInternal(String pkg, String tag, int notificationId, int userId) { 7302 synchronized (mNotificationLock) { 7303 return findNotificationLocked(pkg, tag, notificationId, userId) != null; 7304 } 7305 } 7306 7307 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 7308 final int callingPid, final String tag, final int id, final Notification notification, 7309 int incomingUserId, boolean byForegroundService) { 7310 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 7311 incomingUserId, false /* postSilently */, byForegroundService); 7312 } 7313 7314 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 7315 final int callingPid, final String tag, final int id, final Notification notification, 7316 int incomingUserId, boolean postSilently, boolean byForegroundService) { 7317 PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid); 7318 boolean enqueued = false; 7319 try { 7320 enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, 7321 notification, incomingUserId, postSilently, tracker, byForegroundService); 7322 } finally { 7323 if (!enqueued) { 7324 tracker.cancel(); 7325 } 7326 } 7327 } 7328 7329 private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) { 7330 // The package probably doesn't have WAKE_LOCK permission and should not require it. 7331 return Binder.withCleanCallingIdentity(() -> { 7332 WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 7333 "NotificationManagerService:post:" + pkg); 7334 wakeLock.setWorkSource(new WorkSource(uid, pkg)); 7335 wakeLock.acquire(POST_WAKE_LOCK_TIMEOUT.toMillis()); 7336 return mPostNotificationTrackerFactory.newTracker(wakeLock); 7337 }); 7338 } 7339 7340 /** 7341 * @return True if we successfully processed the notification and handed off the task of 7342 * enqueueing it to a background thread; false otherwise. 7343 */ 7344 private boolean enqueueNotificationInternal(final String pkg, final String opPkg, //HUI 7345 final int callingUid, final int callingPid, final String tag, final int id, 7346 final Notification notification, int incomingUserId, boolean postSilently, 7347 PostNotificationTracker tracker, boolean byForegroundService) { 7348 if (DBG) { 7349 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 7350 + " notification=" + notification); 7351 } 7352 7353 if (pkg == null || notification == null) { 7354 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 7355 + " id=" + id + " notification=" + notification); 7356 } 7357 7358 final int userId = ActivityManager.handleIncomingUser(callingPid, 7359 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 7360 final UserHandle user = UserHandle.of(userId); 7361 7362 // Can throw a SecurityException if the calling uid doesn't have permission to post 7363 // as "pkg" 7364 int notificationUid = INVALID_UID; 7365 7366 try { 7367 notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 7368 } catch (NameNotFoundException e) { 7369 // not great - throw immediately below 7370 } 7371 7372 if (notificationUid == INVALID_UID) { 7373 throw new SecurityException("Caller " + opPkg + ":" + callingUid 7374 + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId); 7375 } 7376 7377 if (android.app.Flags.secureAllowlistToken()) { 7378 IBinder allowlistToken = notification.getAllowlistToken(); 7379 if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) { 7380 throw new SecurityException( 7381 "Unexpected allowlist token received from " + callingUid); 7382 } 7383 // allowlistToken is populated by unparceling, so it can be null if the notification was 7384 // posted from inside system_server. Ensure it's the expected value. 7385 notification.overrideAllowlistToken(ALLOWLIST_TOKEN); 7386 } 7387 7388 checkRestrictedCategories(notification); 7389 7390 // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE, 7391 // but it's also possible that the app has called notify() with an update to an 7392 // FGS notification that hasn't yet been displayed. Make sure we check for any 7393 // FGS-related situation up front, outside of any locks so it's safe to call into 7394 // the Activity Manager. 7395 final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification( 7396 notification, tag, id, pkg, userId); 7397 7398 boolean stripUijFlag = true; 7399 final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); 7400 if (js != null) { 7401 stripUijFlag = !js.isNotificationAssociatedWithAnyUserInitiatedJobs(id, userId, pkg); 7402 } 7403 7404 // Fix the notification as best we can. 7405 try { 7406 fixNotification(notification, pkg, tag, id, userId, notificationUid, 7407 policy, stripUijFlag); 7408 } catch (Exception e) { 7409 if (notification.isForegroundService()) { 7410 throw new SecurityException("Invalid FGS notification", e); 7411 } 7412 Slog.e(TAG, "Cannot fix notification", e); 7413 return false; 7414 } 7415 7416 if (policy == ServiceNotificationPolicy.UPDATE_ONLY) { 7417 // Proceed if the notification is already showing/known, otherwise ignore 7418 // because the service lifecycle logic has retained responsibility for its 7419 // handling. 7420 if (!isNotificationShownInternal(pkg, tag, id, userId)) { 7421 reportForegroundServiceUpdate(false, notification, id, pkg, userId); 7422 return false; 7423 } 7424 } 7425 7426 mUsageStats.registerEnqueuedByApp(pkg); 7427 7428 final StatusBarNotification n = new StatusBarNotification( 7429 pkg, opPkg, id, tag, notificationUid, callingPid, notification, 7430 user, null, System.currentTimeMillis()); 7431 7432 // setup local book-keeping 7433 String channelId = notification.getChannelId(); 7434 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) { 7435 channelId = (new Notification.TvExtender(notification)).getChannelId(); 7436 } 7437 String shortcutId = n.getShortcutId(); 7438 final NotificationChannel channel = getNotificationChannelRestoreDeleted(pkg, 7439 callingUid, notificationUid, channelId, shortcutId); 7440 if (channel == null) { 7441 final String noChannelStr = "No Channel found for " 7442 + "pkg=" + pkg 7443 + ", channelId=" + channelId 7444 + ", id=" + id 7445 + ", tag=" + tag 7446 + ", opPkg=" + opPkg 7447 + ", callingUid=" + callingUid 7448 + ", userId=" + userId 7449 + ", incomingUserId=" + incomingUserId 7450 + ", notificationUid=" + notificationUid 7451 + ", notification=" + notification; 7452 Slog.e(TAG, noChannelStr); 7453 boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid); 7454 7455 7456 if (!appNotificationsOff) { 7457 doChannelWarningToast(notificationUid, 7458 "Developer warning for package \"" + pkg + "\"\n" + 7459 "Failed to post notification on channel \"" + channelId + "\"\n" + 7460 "See log for more details"); 7461 } 7462 return false; 7463 } 7464 7465 final NotificationRecord r = new NotificationRecord(getContext(), n, channel); 7466 r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId)); 7467 r.setPostSilently(postSilently); 7468 r.setFlagBubbleRemoved(false); 7469 r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg)); 7470 boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId); 7471 r.setImportanceFixed(isImportanceFixed); 7472 7473 if (notification.isFgsOrUij()) { 7474 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0 7475 || !channel.isUserVisibleTaskShown()) 7476 && (r.getImportance() == IMPORTANCE_MIN 7477 || r.getImportance() == IMPORTANCE_NONE)) { 7478 // Increase the importance of fgs/uij notifications unless the user had 7479 // an opinion otherwise (and the channel hasn't yet shown a fgs/uij). 7480 channel.setImportance(IMPORTANCE_LOW); 7481 r.setSystemImportance(IMPORTANCE_LOW); 7482 if (!channel.isUserVisibleTaskShown()) { 7483 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); 7484 channel.setUserVisibleTaskShown(true); 7485 } 7486 mPreferencesHelper.updateNotificationChannel( 7487 pkg, notificationUid, channel, false, callingUid, 7488 isCallerSystemOrSystemUi()); 7489 r.updateNotificationChannel(channel); 7490 } else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId) 7491 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 7492 channel.setUserVisibleTaskShown(true); 7493 r.updateNotificationChannel(channel); 7494 } 7495 } 7496 7497 ShortcutInfo info = mShortcutHelper != null 7498 ? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user) 7499 : null; 7500 if (notification.getShortcutId() != null && info == null) { 7501 Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut"); 7502 } 7503 r.setShortcutInfo(info); 7504 r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid)); 7505 r.userDemotedAppFromConvoSpace( 7506 mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid)); 7507 7508 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, 7509 r.getSbn().getOverrideGroupKey() != null, byForegroundService)) { 7510 return false; 7511 } 7512 7513 mUsageStats.registerEnqueuedByAppAndAccepted(pkg); 7514 7515 if (info != null) { 7516 // Cache the shortcut synchronously after the associated notification is posted in case 7517 // the app unpublishes this shortcut immediately after posting the notification. If the 7518 // user does not modify the notification settings on this conversation, the shortcut 7519 // will be uncached by People Service when all the associated notifications are removed. 7520 mShortcutHelper.cacheShortcut(info, user); 7521 } 7522 7523 // temporarily allow apps to perform extra work when their pending intents are launched 7524 if (notification.allPendingIntents != null) { 7525 final int intentCount = notification.allPendingIntents.size(); 7526 if (intentCount > 0) { 7527 final long duration = LocalServices.getService( 7528 DeviceIdleInternal.class).getNotificationAllowlistDuration(); 7529 for (int i = 0; i < intentCount; i++) { 7530 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); 7531 if (pendingIntent != null) { 7532 mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(), 7533 ALLOWLIST_TOKEN, duration, 7534 TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, 7535 REASON_NOTIFICATION_SERVICE, 7536 "NotificationManagerService"); 7537 mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(), 7538 ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER 7539 | FLAG_SERVICE_SENDER)); 7540 } 7541 } 7542 } 7543 } 7544 7545 // Need escalated privileges to get package importance. 7546 final int packageImportance = getPackageImportanceWithIdentity(pkg); 7547 boolean isAppForeground = packageImportance == IMPORTANCE_FOREGROUND; 7548 mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, tracker)); 7549 return true; 7550 } 7551 7552 /** 7553 * Returns a channel, if exists, and restores deleted conversation channels. 7554 */ 7555 @Nullable 7556 private NotificationChannel getNotificationChannelRestoreDeleted(String pkg, 7557 int callingUid, int notificationUid, String channelId, String conversationId) { 7558 // Restore a deleted conversation channel, if exists. Otherwise use the parent channel. 7559 NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel( 7560 pkg, notificationUid, channelId, conversationId, 7561 true /* parent ok */, !TextUtils.isEmpty(conversationId) /* includeDeleted */); 7562 // Restore deleted conversation channel 7563 if (channel != null && channel.isDeleted()) { 7564 if (Objects.equals(conversationId, channel.getConversationId())) { 7565 boolean needsPolicyFileChange = mPreferencesHelper.createNotificationChannel( 7566 pkg, notificationUid, channel, true /* fromTargetApp */, 7567 mConditionProviders.isPackageOrComponentAllowed(pkg, 7568 UserHandle.getUserId(notificationUid)), callingUid, true); 7569 // Update policy file if the conversation channel was restored 7570 if (needsPolicyFileChange) { 7571 handleSavePolicyFile(); 7572 } 7573 } else { 7574 // Do not restore parent channel 7575 channel = null; 7576 } 7577 } 7578 return channel; 7579 } 7580 7581 private void onConversationRemovedInternal(String pkg, int uid, Set<String> shortcuts) { 7582 checkCallerIsSystem(); 7583 Preconditions.checkStringNotEmpty(pkg); 7584 7585 mHistoryManager.deleteConversations(pkg, uid, shortcuts); 7586 List<String> deletedChannelIds = 7587 mPreferencesHelper.deleteConversations(pkg, uid, shortcuts, 7588 /* callingUid */ Process.SYSTEM_UID, /* is system */ true); 7589 for (String channelId : deletedChannelIds) { 7590 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, 7591 UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED 7592 ); 7593 } 7594 handleSavePolicyFile(); 7595 } 7596 7597 private void makeStickyHun(Notification notification, String pkg, @UserIdInt int userId) { 7598 if (mPermissionHelper.hasRequestedPermission( 7599 Manifest.permission.USE_FULL_SCREEN_INTENT, pkg, userId)) { 7600 notification.flags |= FLAG_FSI_REQUESTED_BUT_DENIED; 7601 } 7602 if (notification.contentIntent == null) { 7603 // On notification click, if contentIntent is null, SystemUI launches the 7604 // fullScreenIntent instead. 7605 notification.contentIntent = notification.fullScreenIntent; 7606 } 7607 notification.fullScreenIntent = null; 7608 } 7609 7610 @VisibleForTesting 7611 protected void fixNotification(Notification notification, String pkg, String tag, int id, 7612 @UserIdInt int userId, int notificationUid, 7613 ServiceNotificationPolicy fgsPolicy, boolean stripUijFlag) 7614 throws NameNotFoundException, RemoteException { 7615 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( 7616 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 7617 (userId == USER_ALL) ? USER_SYSTEM : userId); 7618 Notification.addFieldsFromContext(ai, notification); 7619 7620 if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) { 7621 notification.flags &= ~FLAG_FOREGROUND_SERVICE; 7622 } 7623 if (notification.isUserInitiatedJob() && stripUijFlag) { 7624 notification.flags &= ~FLAG_USER_INITIATED_JOB; 7625 } 7626 7627 // Remove FLAG_AUTO_CANCEL from notifications that are associated with a FGS or UIJ. 7628 if (notification.isFgsOrUij()) { 7629 notification.flags &= ~FLAG_AUTO_CANCEL; 7630 } 7631 7632 // Only notifications that can be non-dismissible can have the flag FLAG_NO_DISMISS 7633 if (((notification.flags & FLAG_ONGOING_EVENT) > 0) 7634 && canBeNonDismissible(ai, notification)) { 7635 notification.flags |= FLAG_NO_DISMISS; 7636 } else { 7637 notification.flags &= ~FLAG_NO_DISMISS; 7638 } 7639 7640 int canColorize = getContext().checkPermission( 7641 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, -1, notificationUid); 7642 7643 if (canColorize == PERMISSION_GRANTED) { 7644 notification.flags |= Notification.FLAG_CAN_COLORIZE; 7645 } else { 7646 notification.flags &= ~Notification.FLAG_CAN_COLORIZE; 7647 } 7648 7649 if (notification.extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, false)) { 7650 int hasShowDuringSetupPerm = getContext().checkPermission( 7651 android.Manifest.permission.NOTIFICATION_DURING_SETUP, -1, notificationUid); 7652 if (hasShowDuringSetupPerm != PERMISSION_GRANTED) { 7653 notification.extras.remove(Notification.EXTRA_ALLOW_DURING_SETUP); 7654 if (DBG) { 7655 Slog.w(TAG, "warning: pkg " + pkg + " attempting to show during setup" 7656 + " without holding perm " 7657 + Manifest.permission.NOTIFICATION_DURING_SETUP); 7658 } 7659 } 7660 } 7661 7662 notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED; 7663 7664 // Apps cannot post notifications that are lifetime extended. 7665 if (lifetimeExtensionRefactor()) { 7666 notification.flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7667 } 7668 7669 if (notification.fullScreenIntent != null) { 7670 final AttributionSource attributionSource = 7671 new AttributionSource.Builder(notificationUid).setPackageName(pkg).build(); 7672 final boolean canUseFullScreenIntent = checkUseFullScreenIntentPermission( 7673 attributionSource, ai, true /* forDataDelivery */); 7674 if (!canUseFullScreenIntent) { 7675 makeStickyHun(notification, pkg, userId); 7676 } 7677 } 7678 7679 // Ensure all actions are present 7680 if (notification.actions != null) { 7681 boolean hasNullActions = false; 7682 int nActions = notification.actions.length; 7683 for (int i = 0; i < nActions; i++) { 7684 if (notification.actions[i] == null) { 7685 hasNullActions = true; 7686 break; 7687 } 7688 } 7689 if (hasNullActions) { 7690 ArrayList<Notification.Action> nonNullActions = new ArrayList<>(); 7691 for (int i = 0; i < nActions; i++) { 7692 if (notification.actions[i] != null) { 7693 nonNullActions.add(notification.actions[i]); 7694 } 7695 } 7696 if (nonNullActions.size() != 0) { 7697 notification.actions = nonNullActions.toArray(new Notification.Action[0]); 7698 } else { 7699 notification.actions = null; 7700 } 7701 } 7702 } 7703 7704 // Ensure CallStyle has all the correct actions 7705 if (notification.isStyle(Notification.CallStyle.class)) { 7706 Notification.Builder builder = 7707 Notification.Builder.recoverBuilder(getContext(), notification); 7708 Notification.CallStyle style = (Notification.CallStyle) builder.getStyle(); 7709 List<Notification.Action> actions = style.getActionsListWithSystemActions(); 7710 notification.actions = new Notification.Action[actions.size()]; 7711 actions.toArray(notification.actions); 7712 } 7713 7714 // Ensure MediaStyle has correct permissions for remote device extras 7715 if (notification.isStyle(Notification.MediaStyle.class) 7716 || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) { 7717 int hasMediaContentControlPermission = getContext().checkPermission( 7718 android.Manifest.permission.MEDIA_CONTENT_CONTROL, -1, notificationUid); 7719 if (hasMediaContentControlPermission != PERMISSION_GRANTED) { 7720 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE); 7721 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON); 7722 notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT); 7723 if (DBG) { 7724 Slog.w(TAG, "Package " + pkg + ": Use of setRemotePlayback requires the " 7725 + "MEDIA_CONTENT_CONTROL permission"); 7726 } 7727 } 7728 7729 // Enforce NO_CLEAR flag on MediaStyle notification for apps with targetSdk >= V. 7730 if (CompatChanges.isChangeEnabled(ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION, 7731 notificationUid)) { 7732 notification.flags |= FLAG_NO_CLEAR; 7733 } 7734 } 7735 7736 // Ensure only allowed packages have a substitute app name 7737 if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { 7738 int hasSubstituteAppNamePermission = getContext().checkPermission( 7739 permission.SUBSTITUTE_NOTIFICATION_APP_NAME, -1, notificationUid); 7740 if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) { 7741 notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME); 7742 if (DBG) { 7743 Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name" 7744 + " without holding perm " 7745 + Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME); 7746 } 7747 } 7748 } 7749 7750 // Remote views? Are they too big? 7751 checkRemoteViews(pkg, tag, id, notification); 7752 7753 if (Flags.allNotifsNeedTtl()) { 7754 if (notification.getTimeoutAfter() == 0) { 7755 notification.setTimeoutAfter(NOTIFICATION_TTL); 7756 } 7757 } 7758 } 7759 7760 /** 7761 * Whether a notification can be non-dismissible. 7762 * A notification should be dismissible, unless it's exempted for some reason. 7763 */ 7764 private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) { 7765 return notification.isMediaNotification() || isEnterpriseExempted(ai) 7766 || notification.isStyle(Notification.CallStyle.class) 7767 || isDefaultSearchSelectorPackage(ai.packageName) 7768 || isDefaultAdservicesPackage(ai.packageName); 7769 } 7770 7771 private boolean isDefaultSearchSelectorPackage(String pkg) { 7772 return Objects.equals(mDefaultSearchSelectorPkg, pkg); 7773 } 7774 7775 private boolean isDefaultAdservicesPackage(String pkg) { 7776 if (mAdservicesModuleInfo == null) { 7777 return false; 7778 } 7779 // Handles the special package structure for mainline modules 7780 for (String apkName : mAdservicesModuleInfo.getApkInApexPackageNames()) { 7781 if (Objects.equals(apkName, pkg)) { 7782 return true; 7783 } 7784 } 7785 return false; 7786 } 7787 7788 private boolean isEnterpriseExempted(ApplicationInfo ai) { 7789 // Check if the app is an organization admin app 7790 // TODO(b/234609037): Replace with new DPM APIs to check if organization admin 7791 if (mDpm != null && (mDpm.isActiveProfileOwner(ai.uid) 7792 || mDpm.isActiveDeviceOwner(ai.uid))) { 7793 return true; 7794 } 7795 // Check if an app has been given system exemption 7796 if (ai.uid == Process.SYSTEM_UID) { 7797 return false; 7798 } 7799 return mAppOps.checkOpNoThrow( 7800 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 7801 ai.packageName) == MODE_ALLOWED; 7802 } 7803 7804 private boolean checkUseFullScreenIntentPermission(@NonNull AttributionSource attributionSource, 7805 @NonNull ApplicationInfo applicationInfo, 7806 boolean forDataDelivery) { 7807 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) { 7808 return true; 7809 } 7810 final int permissionResult; 7811 if (forDataDelivery) { 7812 permissionResult = mPermissionManager.checkPermissionForDataDelivery( 7813 permission.USE_FULL_SCREEN_INTENT, attributionSource, /* message= */ null); 7814 } else { 7815 permissionResult = mPermissionManager.checkPermissionForPreflight( 7816 permission.USE_FULL_SCREEN_INTENT, attributionSource); 7817 } 7818 return permissionResult == PermissionManager.PERMISSION_GRANTED; 7819 } 7820 7821 private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { 7822 if (android.app.Flags.removeRemoteViews()) { 7823 if (notification.contentView != null || notification.bigContentView != null 7824 || notification.headsUpContentView != null 7825 || (notification.publicVersion != null 7826 && (notification.publicVersion.contentView != null 7827 || notification.publicVersion.bigContentView != null 7828 || notification.publicVersion.headsUpContentView != null))) { 7829 Slog.i(TAG, "Removed customViews for " + pkg); 7830 mUsageStats.registerImageRemoved(pkg); 7831 } 7832 notification.contentView = null; 7833 notification.bigContentView = null; 7834 notification.headsUpContentView = null; 7835 if (notification.publicVersion != null) { 7836 notification.publicVersion.contentView = null; 7837 notification.publicVersion.bigContentView = null; 7838 notification.publicVersion.headsUpContentView = null; 7839 } 7840 } else { 7841 if (removeRemoteView(pkg, tag, id, notification.contentView)) { 7842 notification.contentView = null; 7843 } 7844 if (removeRemoteView(pkg, tag, id, notification.bigContentView)) { 7845 notification.bigContentView = null; 7846 } 7847 if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) { 7848 notification.headsUpContentView = null; 7849 } 7850 if (notification.publicVersion != null) { 7851 if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) { 7852 notification.publicVersion.contentView = null; 7853 } 7854 if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) { 7855 notification.publicVersion.bigContentView = null; 7856 } 7857 if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) { 7858 notification.publicVersion.headsUpContentView = null; 7859 } 7860 } 7861 } 7862 } 7863 7864 private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) { 7865 if (contentView == null) { 7866 return false; 7867 } 7868 final int contentViewSize = contentView.estimateMemoryUsage(); 7869 if (contentViewSize > mWarnRemoteViewsSizeBytes 7870 && contentViewSize < mStripRemoteViewsSizeBytes) { 7871 Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id 7872 + " this might be stripped in a future release"); 7873 } 7874 if (contentViewSize >= mStripRemoteViewsSizeBytes) { 7875 mUsageStats.registerImageRemoved(pkg); 7876 Slog.w(TAG, "Removed too large RemoteViews (" + contentViewSize + " bytes) on pkg: " 7877 + pkg + " tag: " + tag + " id: " + id); 7878 return true; 7879 } 7880 return false; 7881 } 7882 7883 /** 7884 * Strips any flags from BubbleMetadata that wouldn't apply (e.g. app not foreground). 7885 */ 7886 private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) { 7887 Notification notification = r.getNotification(); 7888 Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); 7889 if (metadata == null) { 7890 // Nothing to update 7891 return; 7892 } 7893 if (!isAppForeground) { 7894 // Auto expand only works if foreground 7895 int flags = metadata.getFlags(); 7896 flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 7897 metadata.setFlags(flags); 7898 } 7899 if (!metadata.isBubbleSuppressable()) { 7900 // If it's not suppressable remove the suppress flag 7901 int flags = metadata.getFlags(); 7902 flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; 7903 metadata.setFlags(flags); 7904 } 7905 } 7906 7907 private ShortcutHelper.ShortcutListener mShortcutListener = 7908 new ShortcutHelper.ShortcutListener() { 7909 @Override 7910 public void onShortcutRemoved(String key) { 7911 String packageName; 7912 synchronized (mNotificationLock) { 7913 NotificationRecord r = mNotificationsByKey.get(key); 7914 packageName = r != null ? r.getSbn().getPackageName() : null; 7915 } 7916 final int packageImportance = getPackageImportanceWithIdentity(packageName); 7917 boolean isAppForeground = packageName != null 7918 && packageImportance == IMPORTANCE_FOREGROUND; 7919 synchronized (mNotificationLock) { 7920 NotificationRecord r = mNotificationsByKey.get(key); 7921 if (r != null) { 7922 r.setShortcutInfo(null); 7923 // Enqueue will trigger resort & flag is updated that way. 7924 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 7925 mHandler.post( 7926 new EnqueueNotificationRunnable( 7927 r.getUser().getIdentifier(), r, isAppForeground, 7928 mPostNotificationTrackerFactory.newTracker(null))); 7929 } 7930 } 7931 } 7932 }; 7933 7934 protected void doChannelWarningToast(int forUid, CharSequence toastText) { 7935 Binder.withCleanCallingIdentity(() -> { 7936 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(), 7937 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0) != 0; 7938 if (warningEnabled) { 7939 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText, 7940 Toast.LENGTH_SHORT); 7941 toast.show(); 7942 } 7943 }); 7944 } 7945 7946 @VisibleForTesting 7947 int resolveNotificationUid(String callingPkg, String targetPkg, int callingUid, int userId) 7948 throws NameNotFoundException { 7949 if (userId == USER_ALL) { 7950 userId = USER_SYSTEM; 7951 } 7952 // posted from app A on behalf of app A 7953 if (isCallerSameApp(targetPkg, callingUid, userId) 7954 && (TextUtils.equals(callingPkg, targetPkg) 7955 || isCallerSameApp(callingPkg, callingUid, userId))) { 7956 return callingUid; 7957 } 7958 7959 int targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 7960 7961 // posted from app A on behalf of app B 7962 if (isCallerAndroid(callingPkg, callingUid) 7963 || mPreferencesHelper.isDelegateAllowed( 7964 targetPkg, targetUid, callingPkg, callingUid)) { 7965 return targetUid; 7966 } 7967 7968 throw new SecurityException("Caller " + callingPkg + ":" + callingUid 7969 + " cannot post for pkg " + targetPkg + " in user " + userId); 7970 } 7971 7972 public boolean hasFlag(final int flags, final int flag) { 7973 return (flags & flag) != 0; 7974 } 7975 /** 7976 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking. 7977 * 7978 * Has side effects. 7979 */ 7980 boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag, 7981 NotificationRecord r, boolean isAutogroup, boolean byForegroundService) { 7982 Notification n = r.getNotification(); 7983 final String pkg = r.getSbn().getPackageName(); 7984 final boolean isSystemNotification = 7985 isUidSystemOrPhone(uid) || ("android".equals(pkg)); 7986 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 7987 7988 // Limit the number of notifications that any given package except the android 7989 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 7990 if (!isSystemNotification && !isNotificationFromListener) { 7991 final int callingUid = Binder.getCallingUid(); 7992 synchronized (mNotificationLock) { 7993 if (mNotificationsByKey.get(r.getSbn().getKey()) == null 7994 && isCallerInstantApp(callingUid, userId)) { 7995 // Ephemeral apps have some special constraints for notifications. 7996 // They are not allowed to create new notifications however they are allowed to 7997 // update notifications created by the system (e.g. a foreground service 7998 // notification). 7999 throw new SecurityException("Instant app " + pkg 8000 + " cannot create notifications"); 8001 } 8002 8003 // Rate limit updates that aren't completed progress notifications 8004 // Search for the original one in the posted and not-yet-posted (enqueued) lists. 8005 boolean isUpdate = mNotificationsByKey.get(r.getSbn().getKey()) != null 8006 || findNotificationByListLocked(mEnqueuedNotifications, r.getSbn().getKey()) 8007 != null; 8008 if (isUpdate && !r.getNotification().hasCompletedProgress() && !isAutogroup) { 8009 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); 8010 if (appEnqueueRate > mMaxPackageEnqueueRate) { 8011 mUsageStats.registerOverRateQuota(pkg); 8012 final long now = SystemClock.elapsedRealtime(); 8013 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { 8014 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate 8015 + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg); 8016 mLastOverRateLogTime = now; 8017 } 8018 return false; 8019 } 8020 } 8021 } 8022 8023 // limit the number of non-fgs/uij outstanding notificationrecords an app can have 8024 if (!n.isFgsOrUij()) { 8025 int count = getNotificationCount(pkg, userId, id, tag); 8026 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 8027 mUsageStats.registerOverCountQuota(pkg); 8028 Slog.e(TAG, "Package has already posted or enqueued " + count 8029 + " notifications. Not showing more. package=" + pkg); 8030 return false; 8031 } 8032 } 8033 } 8034 8035 // bubble or inline reply that's immutable? 8036 if (n.getBubbleMetadata() != null 8037 && n.getBubbleMetadata().getIntent() != null 8038 && hasFlag(mAmi.getPendingIntentFlags( 8039 n.getBubbleMetadata().getIntent().getTarget()), 8040 PendingIntent.FLAG_IMMUTABLE)) { 8041 throw new IllegalArgumentException(r.getKey() + " Not posted." 8042 + " PendingIntents attached to bubbles must be mutable"); 8043 } 8044 8045 if (n.actions != null) { 8046 for (Notification.Action action : n.actions) { 8047 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null) 8048 && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()), 8049 PendingIntent.FLAG_IMMUTABLE)) { 8050 throw new IllegalArgumentException(r.getKey() + " Not posted." 8051 + " PendingIntents attached to actions with remote" 8052 + " inputs must be mutable"); 8053 } 8054 } 8055 } 8056 8057 if (r.getSystemGeneratedSmartActions() != null) { 8058 for (Notification.Action action : r.getSystemGeneratedSmartActions()) { 8059 if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null) 8060 && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()), 8061 PendingIntent.FLAG_IMMUTABLE)) { 8062 throw new IllegalArgumentException(r.getKey() + " Not posted." 8063 + " PendingIntents attached to contextual actions with remote inputs" 8064 + " must be mutable"); 8065 } 8066 } 8067 } 8068 8069 if (n.isStyle(Notification.CallStyle.class)) { 8070 boolean hasFullScreenIntent = n.fullScreenIntent != null; 8071 boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0; 8072 if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent 8073 && !byForegroundService) { 8074 throw new IllegalArgumentException(r.getKey() + " Not posted." 8075 + " CallStyle notifications must be for a foreground service or" 8076 + " user initated job or use a fullScreenIntent."); 8077 } 8078 } 8079 8080 // snoozed apps 8081 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) { 8082 MetricsLogger.action(r.getLogMaker() 8083 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE) 8084 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)); 8085 mNotificationRecordLogger.log( 8086 NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED, 8087 r); 8088 if (DBG) { 8089 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); 8090 } 8091 mSnoozeHelper.update(userId, r); 8092 handleSavePolicyFile(); 8093 return false; 8094 } 8095 8096 // blocked apps 8097 boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid); 8098 synchronized (mNotificationLock) { 8099 isBlocked |= isRecordBlockedLocked(r); 8100 } 8101 if (isBlocked && !(n.isMediaNotification() || isCallNotification(pkg, uid, n))) { 8102 if (DBG) { 8103 Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName() 8104 + " by user request."); 8105 } 8106 mUsageStats.registerBlocked(r); 8107 return false; 8108 } 8109 8110 if (Flags.rejectOldNotifications() && n.hasAppProvidedWhen() && n.getWhen() > 0 8111 && (System.currentTimeMillis() - n.getWhen()) > NOTIFICATION_MAX_AGE_AT_POST) { 8112 Slog.d(TAG, "Ignored enqueue for old " + n.getWhen() + " notification " + r.getKey()); 8113 mUsageStats.registerTooOldBlocked(r); 8114 return false; 8115 } 8116 8117 return true; 8118 } 8119 8120 private boolean isCallNotification(String pkg, int uid, Notification n) { 8121 if (n.isStyle(Notification.CallStyle.class)) { 8122 return isCallNotification(pkg, uid); 8123 } 8124 return false; 8125 } 8126 8127 private boolean isCallNotification(String pkg, int uid) { 8128 final long identity = Binder.clearCallingIdentity(); 8129 try { 8130 if (mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM) 8131 && mTelecomManager != null) { 8132 try { 8133 return mTelecomManager.isInManagedCall() 8134 || mTelecomManager.isInSelfManagedCall(pkg, 8135 UserHandle.ALL); 8136 } catch (IllegalStateException ise) { 8137 // Telecom is not ready (this is likely early boot), so there are no calls. 8138 return false; 8139 } 8140 } 8141 return false; 8142 } finally { 8143 Binder.restoreCallingIdentity(identity); 8144 } 8145 } 8146 8147 private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) { 8148 return mPermissionHelper.hasPermission(uid); 8149 } 8150 8151 private int getNotificationCount(String pkg, int userId) { 8152 int count = 0; 8153 synchronized (mNotificationLock) { 8154 final int numListSize = mNotificationList.size(); 8155 for (int i = 0; i < numListSize; i++) { 8156 final NotificationRecord existing = mNotificationList.get(i); 8157 if (existing.getSbn().getPackageName().equals(pkg) 8158 && existing.getSbn().getUserId() == userId) { 8159 count++; 8160 } 8161 } 8162 final int numEnqSize = mEnqueuedNotifications.size(); 8163 for (int i = 0; i < numEnqSize; i++) { 8164 final NotificationRecord existing = mEnqueuedNotifications.get(i); 8165 if (existing.getSbn().getPackageName().equals(pkg) 8166 && existing.getSbn().getUserId() == userId) { 8167 count++; 8168 } 8169 } 8170 } 8171 return count; 8172 } 8173 8174 protected int getNotificationCount(String pkg, int userId, int excludedId, 8175 String excludedTag) { 8176 int count = 0; 8177 synchronized (mNotificationLock) { 8178 final int N = mNotificationList.size(); 8179 for (int i = 0; i < N; i++) { 8180 final NotificationRecord existing = mNotificationList.get(i); 8181 if (existing.getSbn().getPackageName().equals(pkg) 8182 && existing.getSbn().getUserId() == userId) { 8183 if (existing.getSbn().getId() == excludedId 8184 && TextUtils.equals(existing.getSbn().getTag(), excludedTag)) { 8185 continue; 8186 } 8187 count++; 8188 } 8189 } 8190 final int M = mEnqueuedNotifications.size(); 8191 for (int i = 0; i < M; i++) { 8192 final NotificationRecord existing = mEnqueuedNotifications.get(i); 8193 if (existing.getSbn().getPackageName().equals(pkg) 8194 && existing.getSbn().getUserId() == userId) { 8195 count++; 8196 } 8197 } 8198 } 8199 return count; 8200 } 8201 8202 /** 8203 * Checks whether a notification is banned at a group or channel level or if the NAS or system 8204 * has blocked the notification. 8205 */ 8206 @GuardedBy("mNotificationLock") 8207 boolean isRecordBlockedLocked(NotificationRecord r) { 8208 final String pkg = r.getSbn().getPackageName(); 8209 final int callingUid = r.getSbn().getUid(); 8210 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup()) 8211 || r.getImportance() == IMPORTANCE_NONE; 8212 } 8213 8214 protected class SnoozeNotificationRunnable implements Runnable { 8215 private final String mKey; 8216 private final long mDuration; 8217 private final String mSnoozeCriterionId; 8218 8219 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) { 8220 mKey = key; 8221 mDuration = duration; 8222 mSnoozeCriterionId = snoozeCriterionId; 8223 } 8224 8225 @Override 8226 public void run() { 8227 synchronized (mNotificationLock) { 8228 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey); 8229 if (r != null) { 8230 snoozeLocked(r); 8231 } 8232 } 8233 } 8234 8235 @GuardedBy("mNotificationLock") 8236 void snoozeLocked(NotificationRecord r) { 8237 final List<NotificationRecord> recordsToSnooze = new ArrayList<>(); 8238 if (r.getSbn().isGroup()) { 8239 final List<NotificationRecord> groupNotifications = 8240 findCurrentAndSnoozedGroupNotificationsLocked( 8241 r.getSbn().getPackageName(), 8242 r.getSbn().getGroupKey(), r.getSbn().getUserId()); 8243 if (r.getNotification().isGroupSummary()) { 8244 // snooze all children 8245 for (int i = 0; i < groupNotifications.size(); i++) { 8246 if (!mKey.equals(groupNotifications.get(i).getKey())) { 8247 recordsToSnooze.add(groupNotifications.get(i)); 8248 } 8249 } 8250 } else { 8251 // if there is a valid summary for this group, and we are snoozing the only 8252 // child, also snooze the summary 8253 if (mSummaryByGroupKey.containsKey(r.getSbn().getGroupKey())) { 8254 if (groupNotifications.size() == 2) { 8255 // snooze summary and the one child 8256 for (int i = 0; i < groupNotifications.size(); i++) { 8257 if (!mKey.equals(groupNotifications.get(i).getKey())) { 8258 recordsToSnooze.add(groupNotifications.get(i)); 8259 } 8260 } 8261 } 8262 } 8263 } 8264 } 8265 // snooze the notification 8266 recordsToSnooze.add(r); 8267 8268 if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) { 8269 for (int i = 0; i < recordsToSnooze.size(); i++) { 8270 snoozeNotificationLocked(recordsToSnooze.get(i)); 8271 } 8272 } else { 8273 Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications"); 8274 } 8275 } 8276 8277 @GuardedBy("mNotificationLock") 8278 void snoozeNotificationLocked(NotificationRecord r) { 8279 MetricsLogger.action(r.getLogMaker() 8280 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED) 8281 .setType(MetricsEvent.TYPE_CLOSE) 8282 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, 8283 mDuration) 8284 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA, 8285 mSnoozeCriterionId == null ? 0 : 1)); 8286 mNotificationRecordLogger.log( 8287 NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, r); 8288 reportUserInteraction(r); 8289 boolean wasPosted = removeFromNotificationListsLocked(r); 8290 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null, 8291 SystemClock.elapsedRealtime()); 8292 mAttentionHelper.updateLightsLocked(); 8293 if (isSnoozable(r)) { 8294 if (mSnoozeCriterionId != null) { 8295 mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId); 8296 mSnoozeHelper.snooze(r, mSnoozeCriterionId); 8297 } else { 8298 mSnoozeHelper.snooze(r, mDuration); 8299 } 8300 r.recordSnoozed(); 8301 handleSavePolicyFile(); 8302 } 8303 } 8304 8305 /** 8306 * Autogroup summaries are not snoozable 8307 * They will be recreated as needed when the group children are unsnoozed 8308 */ 8309 private boolean isSnoozable(NotificationRecord record) { 8310 return !(record.getNotification().isGroupSummary() && GroupHelper.AUTOGROUP_KEY.equals( 8311 record.getNotification().getGroup())); 8312 } 8313 } 8314 8315 private void unsnoozeAll() { 8316 synchronized (mNotificationLock) { 8317 mSnoozeHelper.repostAll(mUserProfiles.getCurrentProfileIds()); 8318 handleSavePolicyFile(); 8319 } 8320 } 8321 8322 protected class CancelNotificationRunnable implements Runnable { 8323 private final int mCallingUid; 8324 private final int mCallingPid; 8325 private final String mPkg; 8326 private final String mTag; 8327 private final int mId; 8328 private final int mMustHaveFlags; 8329 private final int mMustNotHaveFlags; 8330 private final boolean mSendDelete; 8331 private final int mUserId; 8332 private final int mReason; 8333 private final int mRank; 8334 private final int mCount; 8335 private final ManagedServiceInfo mListener; 8336 private final long mCancellationElapsedTimeMs; 8337 8338 CancelNotificationRunnable(final int callingUid, final int callingPid, 8339 final String pkg, final String tag, final int id, 8340 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 8341 final int userId, final int reason, int rank, int count, 8342 final ManagedServiceInfo listener, 8343 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 8344 this.mCallingUid = callingUid; 8345 this.mCallingPid = callingPid; 8346 this.mPkg = pkg; 8347 this.mTag = tag; 8348 this.mId = id; 8349 this.mMustHaveFlags = mustHaveFlags; 8350 this.mMustNotHaveFlags = mustNotHaveFlags; 8351 this.mSendDelete = sendDelete; 8352 this.mUserId = userId; 8353 this.mReason = reason; 8354 this.mRank = rank; 8355 this.mCount = count; 8356 this.mListener = listener; 8357 this.mCancellationElapsedTimeMs = cancellationElapsedTimeMs; 8358 } 8359 8360 @Override 8361 public void run() { 8362 String listenerName = mListener == null ? null : mListener.component.toShortString(); 8363 if (DBG) { 8364 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag, 8365 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName); 8366 } 8367 int packageImportance = IMPORTANCE_NONE; 8368 if (lifetimeExtensionRefactor()) { 8369 packageImportance = getPackageImportanceWithIdentity(mPkg); 8370 } 8371 synchronized (mNotificationLock) { 8372 // Look for the notification, searching both the posted and enqueued lists. 8373 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId); 8374 8375 if (r != null) { 8376 // The notification was found, check if it should be removed. 8377 // Ideally we'd do this in the caller of this method. However, that would 8378 // require the caller to also find the notification. 8379 if (mReason == REASON_CLICK) { 8380 mUsageStats.registerClickedByUser(r); 8381 } 8382 8383 if ((mReason == REASON_LISTENER_CANCEL 8384 && r.getNotification().isBubbleNotification()) 8385 || (mReason == REASON_CLICK && r.canBubble() 8386 && r.isFlagBubbleRemoved())) { 8387 int flags = 0; 8388 if (r.getNotification().getBubbleMetadata() != null) { 8389 flags = r.getNotification().getBubbleMetadata().getFlags(); 8390 } 8391 flags |= FLAG_SUPPRESS_NOTIFICATION; 8392 mNotificationDelegate.onBubbleMetadataFlagChanged(r.getKey(), flags); 8393 return; 8394 } 8395 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { 8396 return; 8397 } 8398 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { 8399 if (lifetimeExtensionRefactor()) { 8400 // If cancellation will be prevented due to lifetime extension, 8401 // we need to send an update to system UI first. 8402 maybeNotifySystemUiListenerLifetimeExtendedLocked(r, mPkg, 8403 packageImportance); 8404 } 8405 return; 8406 } 8407 8408 FlagChecker childrenFlagChecker = (flags) -> { 8409 if (mReason == REASON_CANCEL 8410 || mReason == REASON_CLICK 8411 || mReason == REASON_CANCEL_ALL) { 8412 // Bubbled children get to stick around if the summary was manually 8413 // cancelled (user removed) from systemui. 8414 if ((flags & FLAG_BUBBLE) != 0) { 8415 return false; 8416 } 8417 } else if (mReason == REASON_APP_CANCEL) { 8418 if ((flags & FLAG_FOREGROUND_SERVICE) != 0 8419 || (flags & FLAG_USER_INITIATED_JOB) != 0) { 8420 return false; 8421 } 8422 } 8423 if ((flags & mMustNotHaveFlags) != 0) { 8424 return false; 8425 } 8426 return true; 8427 }; 8428 8429 // Cancel the notification. 8430 boolean wasPosted = removeFromNotificationListsLocked(r); 8431 cancelNotificationLocked( 8432 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName, 8433 mCancellationElapsedTimeMs); 8434 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName, 8435 mSendDelete, childrenFlagChecker, mReason, 8436 mCancellationElapsedTimeMs); 8437 mAttentionHelper.updateLightsLocked(); 8438 if (mShortcutHelper != null) { 8439 mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, 8440 true /* isRemoved */, 8441 mHandler); 8442 } 8443 } else { 8444 // No notification was found, assume that it is snoozed and cancel it. 8445 if (mReason != REASON_SNOOZED) { 8446 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId); 8447 if (wasSnoozed) { 8448 handleSavePolicyFile(); 8449 } 8450 } 8451 } 8452 } 8453 } 8454 } 8455 8456 protected static class ShowNotificationPermissionPromptRunnable implements Runnable { 8457 private final String mPkgName; 8458 private final int mUserId; 8459 private final int mTaskId; 8460 private final PermissionPolicyInternal mPpi; 8461 8462 ShowNotificationPermissionPromptRunnable(String pkg, int user, int task, 8463 PermissionPolicyInternal pPi) { 8464 mPkgName = pkg; 8465 mUserId = user; 8466 mTaskId = task; 8467 mPpi = pPi; 8468 } 8469 8470 @Override 8471 public boolean equals(Object o) { 8472 if (!(o instanceof ShowNotificationPermissionPromptRunnable)) { 8473 return false; 8474 } 8475 8476 ShowNotificationPermissionPromptRunnable other = 8477 (ShowNotificationPermissionPromptRunnable) o; 8478 8479 return Objects.equals(mPkgName, other.mPkgName) && mUserId == other.mUserId 8480 && mTaskId == other.mTaskId; 8481 } 8482 8483 @Override 8484 public int hashCode() { 8485 return Objects.hash(mPkgName, mUserId, mTaskId); 8486 } 8487 8488 @Override 8489 public void run() { 8490 mPpi.showNotificationPromptIfNeeded(mPkgName, mUserId, mTaskId); 8491 } 8492 } 8493 8494 protected class EnqueueNotificationRunnable implements Runnable { 8495 private final NotificationRecord r; 8496 private final int userId; 8497 private final boolean isAppForeground; 8498 private final PostNotificationTracker mTracker; 8499 8500 EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground, 8501 PostNotificationTracker tracker) { 8502 this.userId = userId; 8503 this.r = r; 8504 this.isAppForeground = foreground; 8505 this.mTracker = checkNotNull(tracker); 8506 } 8507 8508 @Override 8509 public void run() { 8510 boolean enqueued = false; 8511 try { 8512 enqueued = enqueueNotification(); 8513 } finally { 8514 if (!enqueued) { 8515 mTracker.cancel(); 8516 } 8517 } 8518 } 8519 8520 /** 8521 * @return True if we successfully enqueued the notification and handed off the task of 8522 * posting it to a background thread; false otherwise. 8523 */ 8524 private boolean enqueueNotification() { 8525 synchronized (mNotificationLock) { 8526 final long snoozeAt = 8527 mSnoozeHelper.getSnoozeTimeForUnpostedNotification( 8528 r.getUser().getIdentifier(), 8529 r.getSbn().getPackageName(), r.getSbn().getKey()); 8530 final long currentTime = System.currentTimeMillis(); 8531 if (snoozeAt > currentTime) { 8532 (new SnoozeNotificationRunnable(r.getSbn().getKey(), 8533 snoozeAt - currentTime, null)).snoozeLocked(r); 8534 return false; 8535 } 8536 8537 final String contextId = 8538 mSnoozeHelper.getSnoozeContextForUnpostedNotification( 8539 r.getUser().getIdentifier(), 8540 r.getSbn().getPackageName(), r.getSbn().getKey()); 8541 if (contextId != null) { 8542 (new SnoozeNotificationRunnable(r.getSbn().getKey(), 8543 0, contextId)).snoozeLocked(r); 8544 return false; 8545 } 8546 8547 mEnqueuedNotifications.add(r); 8548 if (Flags.allNotifsNeedTtl()) { 8549 mTtlHelper.scheduleTimeoutLocked(r, SystemClock.elapsedRealtime()); 8550 } else { 8551 scheduleTimeoutLocked(r); 8552 } 8553 8554 final StatusBarNotification n = r.getSbn(); 8555 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 8556 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 8557 if (old != null) { 8558 // Retain ranking information from previous record 8559 r.copyRankingInformation(old); 8560 } 8561 8562 final int callingUid = n.getUid(); 8563 final int callingPid = n.getInitialPid(); 8564 final Notification notification = n.getNotification(); 8565 final String pkg = n.getPackageName(); 8566 final int id = n.getId(); 8567 final String tag = n.getTag(); 8568 8569 // We need to fix the notification up a little for bubbles 8570 updateNotificationBubbleFlags(r, isAppForeground); 8571 8572 // Handle grouped notifications and bail out early if we 8573 // can to avoid extracting signals. 8574 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 8575 8576 // if this is a group child, unsnooze parent summary 8577 if (n.isGroup() && notification.isGroupChild()) { 8578 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey()); 8579 } 8580 8581 // This conditional is a dirty hack to limit the logging done on 8582 // behalf of the download manager without affecting other apps. 8583 if (!pkg.equals("com.android.providers.downloads") 8584 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 8585 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 8586 if (old != null) { 8587 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 8588 } 8589 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 8590 pkg, id, tag, userId, notification.toString(), 8591 enqueueStatus); 8592 } 8593 8594 // tell the assistant service about the notification 8595 if (mAssistants.isEnabled()) { 8596 mAssistants.onNotificationEnqueuedLocked(r); 8597 mHandler.postDelayed( 8598 new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 8599 r.getUid(), mTracker), 8600 DELAY_FOR_ASSISTANT_TIME); 8601 } else { 8602 mHandler.post( 8603 new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 8604 r.getUid(), mTracker)); 8605 } 8606 return true; 8607 } 8608 } 8609 } 8610 8611 @GuardedBy("mNotificationLock") 8612 boolean isPackagePausedOrSuspended(String pkg, int uid) { 8613 boolean isPaused; 8614 8615 final PackageManagerInternal pmi = LocalServices.getService( 8616 PackageManagerInternal.class); 8617 int flags = pmi.getDistractingPackageRestrictions( 8618 pkg, Binder.getCallingUserHandle().getIdentifier()); 8619 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0); 8620 8621 isPaused |= isPackageSuspendedForUser(pkg, uid); 8622 8623 return isPaused; 8624 } 8625 8626 protected class PostNotificationRunnable implements Runnable { 8627 private final String key; 8628 private final String pkg; 8629 private final int uid; 8630 private final PostNotificationTracker mTracker; 8631 8632 PostNotificationRunnable(String key, String pkg, int uid, PostNotificationTracker tracker) { 8633 this.key = key; 8634 this.pkg = pkg; 8635 this.uid = uid; 8636 this.mTracker = checkNotNull(tracker); 8637 } 8638 8639 @Override 8640 public void run() { 8641 boolean posted = false; 8642 try { 8643 posted = postNotification(); 8644 } catch (Exception e) { 8645 Slog.e(TAG, "Error posting", e); 8646 } finally { 8647 if (!posted) { 8648 mTracker.cancel(); 8649 } 8650 } 8651 } 8652 8653 /** 8654 * @return True if we successfully processed the notification and handed off the task of 8655 * notifying all listeners to a background thread; false otherwise. 8656 */ 8657 private boolean postNotification() { 8658 boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid); 8659 boolean isCallNotification = isCallNotification(pkg, uid); 8660 boolean posted = false; 8661 synchronized (mNotificationLock) { 8662 try { 8663 NotificationRecord r = findNotificationByListLocked(mEnqueuedNotifications, 8664 key); 8665 if (r == null) { 8666 Slog.i(TAG, "Cannot find enqueued record for key: " + key); 8667 return false; 8668 } 8669 8670 final StatusBarNotification n = r.getSbn(); 8671 final Notification notification = n.getNotification(); 8672 boolean isCallNotificationAndCorrectStyle = isCallNotification 8673 && notification.isStyle(Notification.CallStyle.class); 8674 8675 if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle) 8676 && (appBanned || isRecordBlockedLocked(r))) { 8677 mUsageStats.registerBlocked(r); 8678 if (DBG) { 8679 Slog.e(TAG, "Suppressing notification from package " + pkg); 8680 } 8681 return false; 8682 } 8683 8684 final boolean isPackageSuspended = 8685 isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid()); 8686 r.setHidden(isPackageSuspended); 8687 if (isPackageSuspended) { 8688 mUsageStats.registerSuspendedByAdmin(r); 8689 } 8690 NotificationRecord old = mNotificationsByKey.get(key); 8691 8692 // Make sure the SBN has an instance ID for statsd logging. 8693 if (old == null || old.getSbn().getInstanceId() == null) { 8694 n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 8695 } else { 8696 n.setInstanceId(old.getSbn().getInstanceId()); 8697 } 8698 8699 int index = indexOfNotificationLocked(n.getKey()); 8700 if (index < 0) { 8701 mNotificationList.add(r); 8702 mUsageStats.registerPostedByApp(r); 8703 mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(), 8704 r.getSbn().getUser(), mTracker.getStartTime()); 8705 final boolean isInterruptive = isVisuallyInterruptive(null, r); 8706 r.setInterruptive(isInterruptive); 8707 r.setTextChanged(isInterruptive); 8708 } else { 8709 old = mNotificationList.get(index); // Potentially *changes* old 8710 mNotificationList.set(index, r); 8711 mUsageStats.registerUpdatedByApp(r, old); 8712 mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(), 8713 r.getSbn().getUser(), mTracker.getStartTime()); 8714 // Make sure we don't lose the foreground service state. 8715 notification.flags |= 8716 old.getNotification().flags & FLAG_FOREGROUND_SERVICE; 8717 r.isUpdate = true; 8718 final boolean isInterruptive = isVisuallyInterruptive(old, r); 8719 r.setTextChanged(isInterruptive); 8720 if (sortSectionByTime()) { 8721 if (isInterruptive) { 8722 r.resetRankingTime(); 8723 } 8724 } 8725 } 8726 8727 mNotificationsByKey.put(n.getKey(), r); 8728 8729 // Ensure if this is a foreground service that the proper additional 8730 // flags are set. 8731 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) { 8732 notification.flags |= FLAG_NO_CLEAR; 8733 } 8734 8735 // Posts the notification if it has a small icon, and potentially autogroup 8736 // the new notification. 8737 if (android.app.Flags.checkAutogroupBeforePost()) { 8738 if (notification.getSmallIcon() != null && !isCritical(r)) { 8739 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 8740 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()) 8741 || oldSbn.getNotification().flags 8742 != n.getNotification().flags) { 8743 synchronized (mNotificationLock) { 8744 boolean willBeAutogrouped = mGroupHelper.onNotificationPosted(n, 8745 hasAutoGroupSummaryLocked(n)); 8746 if (willBeAutogrouped) { 8747 // The newly posted notification will be autogrouped, but 8748 // was not autogrouped onPost, to avoid an unnecessary sort. 8749 // We add the autogroup key to the notification without a 8750 // sort here, and it'll be sorted below with extractSignals. 8751 addAutogroupKeyLocked(key, /*requestSort=*/false); 8752 } 8753 } 8754 } 8755 } 8756 } 8757 8758 mRankingHelper.extractSignals(r); 8759 mRankingHelper.sort(mNotificationList); 8760 final int position = mRankingHelper.indexOf(mNotificationList, r); 8761 8762 int buzzBeepBlinkLoggingCode = 0; 8763 if (!r.isHidden()) { 8764 buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r, 8765 new NotificationAttentionHelper.Signals( 8766 mUserProfiles.isCurrentProfile(r.getUserId()), 8767 mListenerHints)); 8768 } 8769 8770 if (notification.getSmallIcon() != null) { 8771 NotificationRecordLogger.NotificationReported maybeReport = 8772 mNotificationRecordLogger.prepareToLogNotificationPosted(r, old, 8773 position, buzzBeepBlinkLoggingCode, 8774 getGroupInstanceId(r.getSbn().getGroupKey())); 8775 notifyListenersPostedAndLogLocked(r, old, mTracker, maybeReport); 8776 posted = true; 8777 8778 if (!android.app.Flags.checkAutogroupBeforePost()) { 8779 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 8780 if (oldSbn == null 8781 || !Objects.equals(oldSbn.getGroup(), n.getGroup()) 8782 || oldSbn.getNotification().flags 8783 != n.getNotification().flags) { 8784 if (!isCritical(r)) { 8785 mHandler.post(() -> { 8786 synchronized (mNotificationLock) { 8787 mGroupHelper.onNotificationPosted( 8788 n, hasAutoGroupSummaryLocked(n)); 8789 } 8790 }); 8791 } 8792 } 8793 } 8794 } else { 8795 Slog.e(TAG, "Not posting notification without small icon: " + notification); 8796 if (old != null && !old.isCanceled) { 8797 mListeners.notifyRemovedLocked(r, 8798 REASON_ERROR, r.getStats()); 8799 mHandler.post(new Runnable() { 8800 @Override 8801 public void run() { 8802 mGroupHelper.onNotificationRemoved(n); 8803 } 8804 }); 8805 } 8806 8807 if (callstyleCallbackApi()) { 8808 notifyCallNotificationEventListenerOnRemoved(r); 8809 } 8810 8811 // ATTENTION: in a future release we will bail out here 8812 // so that we do not play sounds, show lights, etc. for invalid 8813 // notifications 8814 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 8815 + n.getPackageName()); 8816 } 8817 8818 if (mShortcutHelper != null) { 8819 mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, 8820 false /* isRemoved */, 8821 mHandler); 8822 } 8823 8824 maybeRecordInterruptionLocked(r); 8825 maybeRegisterMessageSent(r); 8826 maybeReportForegroundServiceUpdate(r, true); 8827 } finally { 8828 int N = mEnqueuedNotifications.size(); 8829 for (int i = 0; i < N; i++) { 8830 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 8831 if (Objects.equals(key, enqueued.getKey())) { 8832 mEnqueuedNotifications.remove(i); 8833 break; 8834 } 8835 } 8836 } 8837 } 8838 return posted; 8839 } 8840 } 8841 8842 /** 8843 * 8844 */ 8845 @GuardedBy("mNotificationLock") 8846 InstanceId getGroupInstanceId(String groupKey) { 8847 if (groupKey == null) { 8848 return null; 8849 } 8850 NotificationRecord group = mSummaryByGroupKey.get(groupKey); 8851 if (group == null) { 8852 return null; 8853 } 8854 return group.getSbn().getInstanceId(); 8855 } 8856 8857 /** 8858 * If the notification differs enough visually, consider it a new interruptive notification. 8859 */ 8860 @GuardedBy("mNotificationLock") 8861 @VisibleForTesting 8862 protected boolean isVisuallyInterruptive(@Nullable NotificationRecord old, 8863 @NonNull NotificationRecord r) { 8864 // Ignore summary updates because we don't display most of the information. 8865 if (r.getSbn().isGroup() && r.getSbn().getNotification().isGroupSummary()) { 8866 if (DEBUG_INTERRUPTIVENESS) { 8867 Slog.v(TAG, "INTERRUPTIVENESS: " 8868 + r.getKey() + " is not interruptive: summary"); 8869 } 8870 return false; 8871 } 8872 8873 if (old == null) { 8874 if (DEBUG_INTERRUPTIVENESS) { 8875 Slog.v(TAG, "INTERRUPTIVENESS: " 8876 + r.getKey() + " is interruptive: new notification"); 8877 } 8878 return true; 8879 } 8880 8881 Notification oldN = old.getSbn().getNotification(); 8882 Notification newN = r.getSbn().getNotification(); 8883 if (oldN.extras == null || newN.extras == null) { 8884 if (DEBUG_INTERRUPTIVENESS) { 8885 Slog.v(TAG, "INTERRUPTIVENESS: " 8886 + r.getKey() + " is not interruptive: no extras"); 8887 } 8888 return false; 8889 } 8890 8891 if (sortSectionByTime()) { 8892 // Ignore visual interruptions from FGS/UIJs because users 8893 // consider them one 'session'. Count them for everything else. 8894 if (r.getSbn().getNotification().isFgsOrUij()) { 8895 if (DEBUG_INTERRUPTIVENESS) { 8896 Slog.v(TAG, "INTERRUPTIVENESS: " 8897 + r.getKey() + " is not interruptive: FGS/UIJ"); 8898 } 8899 return false; 8900 } 8901 } else { 8902 // Ignore visual interruptions from foreground services because users 8903 // consider them one 'session'. Count them for everything else. 8904 if ((r.getSbn().getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { 8905 if (DEBUG_INTERRUPTIVENESS) { 8906 Slog.v(TAG, "INTERRUPTIVENESS: " 8907 + r.getKey() + " is not interruptive: foreground service"); 8908 } 8909 return false; 8910 } 8911 } 8912 8913 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); 8914 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); 8915 if (!Objects.equals(oldTitle, newTitle)) { 8916 if (DEBUG_INTERRUPTIVENESS) { 8917 Slog.v(TAG, "INTERRUPTIVENESS: " 8918 + r.getKey() + " is interruptive: changed title"); 8919 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)", 8920 oldTitle, oldTitle.getClass(), oldTitle.hashCode())); 8921 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)", 8922 newTitle, newTitle.getClass(), newTitle.hashCode())); 8923 } 8924 return true; 8925 } 8926 8927 // Do not compare Spannables (will always return false); compare unstyled Strings 8928 final String oldText = String.valueOf(oldN.extras.get(EXTRA_TEXT)); 8929 final String newText = String.valueOf(newN.extras.get(EXTRA_TEXT)); 8930 if (!Objects.equals(oldText, newText)) { 8931 if (DEBUG_INTERRUPTIVENESS) { 8932 Slog.v(TAG, "INTERRUPTIVENESS: " 8933 + r.getKey() + " is interruptive: changed text"); 8934 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)", 8935 oldText, oldText.getClass(), oldText.hashCode())); 8936 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)", 8937 newText, newText.getClass(), newText.hashCode())); 8938 } 8939 return true; 8940 } 8941 8942 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) { 8943 if (DEBUG_INTERRUPTIVENESS) { 8944 Slog.v(TAG, "INTERRUPTIVENESS: " 8945 + r.getKey() + " is interruptive: completed progress"); 8946 } 8947 return true; 8948 } 8949 8950 if (Notification.areIconsDifferent(oldN, newN)) { 8951 if (DEBUG_INTERRUPTIVENESS) { 8952 Slog.v(TAG, "INTERRUPTIVENESS: " 8953 + r.getKey() + " is interruptive: icons differ"); 8954 } 8955 return true; 8956 } 8957 8958 // Fields below are invisible to bubbles. 8959 if (r.canBubble()) { 8960 if (DEBUG_INTERRUPTIVENESS) { 8961 Slog.v(TAG, "INTERRUPTIVENESS: " 8962 + r.getKey() + " is not interruptive: bubble"); 8963 } 8964 return false; 8965 } 8966 8967 // Actions 8968 if (Notification.areActionsVisiblyDifferent(oldN, newN)) { 8969 if (DEBUG_INTERRUPTIVENESS) { 8970 Slog.v(TAG, "INTERRUPTIVENESS: " 8971 + r.getKey() + " is interruptive: changed actions"); 8972 } 8973 return true; 8974 } 8975 8976 try { 8977 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN); 8978 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN); 8979 8980 // Style based comparisons 8981 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) { 8982 if (DEBUG_INTERRUPTIVENESS) { 8983 Slog.v(TAG, "INTERRUPTIVENESS: " 8984 + r.getKey() + " is interruptive: styles differ"); 8985 } 8986 return true; 8987 } 8988 8989 // Remote views 8990 if (Notification.areRemoteViewsChanged(oldB, newB)) { 8991 if (DEBUG_INTERRUPTIVENESS) { 8992 Slog.v(TAG, "INTERRUPTIVENESS: " 8993 + r.getKey() + " is interruptive: remoteviews differ"); 8994 } 8995 return true; 8996 } 8997 } catch (Exception e) { 8998 Slog.w(TAG, "error recovering builder", e); 8999 } 9000 return false; 9001 } 9002 9003 /** 9004 * Check if the notification is classified as critical. 9005 * 9006 * @param record the record to test for criticality 9007 * @return {@code true} if notification is considered critical 9008 * 9009 * @see CriticalNotificationExtractor for criteria 9010 */ 9011 private boolean isCritical(NotificationRecord record) { 9012 // 0 is the most critical 9013 return record.getCriticality() < CriticalNotificationExtractor.NORMAL; 9014 } 9015 9016 /** 9017 * Ensures that grouped notification receive their special treatment. 9018 * 9019 * <p>Cancels group children if the new notification causes a group to lose 9020 * its summary.</p> 9021 * 9022 * <p>Updates mSummaryByGroupKey.</p> 9023 */ 9024 @GuardedBy("mNotificationLock") 9025 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 9026 int callingUid, int callingPid) { 9027 StatusBarNotification sbn = r.getSbn(); 9028 Notification n = sbn.getNotification(); 9029 if (n.isGroupSummary() && !sbn.isAppGroup()) { 9030 // notifications without a group shouldn't be a summary, otherwise autobundling can 9031 // lead to bugs 9032 n.flags &= ~Notification.FLAG_GROUP_SUMMARY; 9033 } 9034 9035 String group = sbn.getGroupKey(); 9036 boolean isSummary = n.isGroupSummary(); 9037 9038 Notification oldN = old != null ? old.getSbn().getNotification() : null; 9039 String oldGroup = old != null ? old.getSbn().getGroupKey() : null; 9040 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 9041 9042 if (oldIsSummary) { 9043 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 9044 if (removedSummary != old) { 9045 String removedKey = 9046 removedSummary != null ? removedSummary.getKey() : "<null>"; 9047 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 9048 ", removed=" + removedKey); 9049 } 9050 } 9051 if (isSummary) { 9052 mSummaryByGroupKey.put(group, r); 9053 } 9054 9055 FlagChecker childrenFlagChecker = (flags) -> { 9056 if ((flags & FLAG_FOREGROUND_SERVICE) != 0 || (flags & FLAG_USER_INITIATED_JOB) != 0) { 9057 return false; 9058 } 9059 return true; 9060 }; 9061 9062 // Clear out group children of the old notification if the update 9063 // causes the group summary to go away. This happens when the old 9064 // notification was a summary and the new one isn't, or when the old 9065 // notification was a summary and its group key changed. 9066 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 9067 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */, 9068 childrenFlagChecker, REASON_APP_CANCEL, SystemClock.elapsedRealtime()); 9069 } 9070 } 9071 9072 private PendingIntent getNotificationTimeoutPendingIntent(NotificationRecord record, 9073 int flags) { 9074 flags |= PendingIntent.FLAG_IMMUTABLE; 9075 return PendingIntent.getBroadcast(getContext(), 9076 REQUEST_CODE_TIMEOUT, 9077 new Intent(ACTION_NOTIFICATION_TIMEOUT) 9078 .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME) 9079 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT) 9080 .appendPath(record.getKey()).build()) 9081 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 9082 .putExtra(EXTRA_KEY, record.getKey()), 9083 flags); 9084 } 9085 9086 @VisibleForTesting 9087 @GuardedBy("mNotificationLock") 9088 void scheduleTimeoutLocked(NotificationRecord record) { 9089 if (record.getNotification().getTimeoutAfter() > 0) { 9090 final PendingIntent pi = getNotificationTimeoutPendingIntent( 9091 record, PendingIntent.FLAG_UPDATE_CURRENT); 9092 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 9093 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi); 9094 } 9095 } 9096 9097 @VisibleForTesting 9098 @GuardedBy("mNotificationLock") 9099 void cancelScheduledTimeoutLocked(NotificationRecord record) { 9100 final PendingIntent pi = getNotificationTimeoutPendingIntent( 9101 record, PendingIntent.FLAG_CANCEL_CURRENT); 9102 if (pi != null) { 9103 mAlarmManager.cancel(pi); 9104 } 9105 } 9106 9107 @GuardedBy("mToastQueue") 9108 void showNextToastLocked(boolean lastToastWasTextRecord) { 9109 if (mIsCurrentToastShown) { 9110 return; // Don't show the same toast twice. 9111 } 9112 9113 ToastRecord record = mToastQueue.get(0); 9114 while (record != null) { 9115 int userId = UserHandle.getUserId(record.uid); 9116 boolean rateLimitingEnabled = 9117 !mToastRateLimitingDisabledUids.contains(record.uid); 9118 boolean isWithinQuota = 9119 mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG) 9120 || isExemptFromRateLimiting(record.pkg, userId); 9121 boolean isPackageInForeground = isPackageInForegroundForToast(record.uid); 9122 9123 if (tryShowToast( 9124 record, rateLimitingEnabled, isWithinQuota, isPackageInForeground)) { 9125 scheduleDurationReachedLocked(record, lastToastWasTextRecord); 9126 mIsCurrentToastShown = true; 9127 if (rateLimitingEnabled && !isPackageInForeground) { 9128 mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG); 9129 } 9130 return; 9131 } 9132 9133 int index = mToastQueue.indexOf(record); 9134 if (index >= 0) { 9135 ToastRecord toast = mToastQueue.remove(index); 9136 mWindowManagerInternal.removeWindowToken( 9137 toast.windowToken, true /* removeWindows */, toast.displayId); 9138 } 9139 record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null; 9140 } 9141 } 9142 9143 /** Returns true if it successfully showed the toast. */ 9144 private boolean tryShowToast(ToastRecord record, boolean rateLimitingEnabled, 9145 boolean isWithinQuota, boolean isPackageInForeground) { 9146 if (rateLimitingEnabled && !isWithinQuota && !isPackageInForeground) { 9147 reportCompatRateLimitingToastsChange(record.uid); 9148 Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the " 9149 + "following toast was blocked and discarded: " + record); 9150 return false; 9151 } 9152 if (blockToast(record.uid, record.isSystemToast, record.isAppRendered(), 9153 isPackageInForeground)) { 9154 Slog.w(TAG, "Blocking custom toast from package " + record.pkg 9155 + " due to package not in the foreground at the time of showing the toast"); 9156 return false; 9157 } 9158 return record.show(); 9159 } 9160 9161 private boolean isExemptFromRateLimiting(String pkg, int userId) { 9162 boolean isExemptFromRateLimiting = false; 9163 try { 9164 isExemptFromRateLimiting = mPackageManager.checkPermission( 9165 android.Manifest.permission.UNLIMITED_TOASTS, pkg, userId) 9166 == PERMISSION_GRANTED; 9167 } catch (RemoteException e) { 9168 Slog.e(TAG, "Failed to connect with package manager"); 9169 } 9170 return isExemptFromRateLimiting; 9171 } 9172 9173 /** Reports rate limiting toasts compat change (used when the toast was blocked). */ 9174 private void reportCompatRateLimitingToastsChange(int uid) { 9175 final long id = Binder.clearCallingIdentity(); 9176 try { 9177 mPlatformCompat.reportChangeByUid(RATE_LIMIT_TOASTS, uid); 9178 } catch (RemoteException e) { 9179 Slog.e(TAG, "Unexpected exception while reporting toast was blocked due to rate" 9180 + " limiting", e); 9181 } finally { 9182 Binder.restoreCallingIdentity(id); 9183 } 9184 } 9185 9186 @GuardedBy("mToastQueue") 9187 void cancelToastLocked(int index) { 9188 ToastRecord record = mToastQueue.get(index); 9189 record.hide(); 9190 9191 if (index == 0) { 9192 mIsCurrentToastShown = false; 9193 } 9194 9195 ToastRecord lastToast = mToastQueue.remove(index); 9196 9197 // We need to schedule a timeout to make sure the token is eventually killed 9198 scheduleKillTokenTimeout(lastToast); 9199 9200 keepProcessAliveForToastIfNeededLocked(record.pid); 9201 if (mToastQueue.size() > 0) { 9202 // Show the next one. If the callback fails, this will remove 9203 // it from the list, so don't assume that the list hasn't changed 9204 // after this point. 9205 showNextToastLocked(lastToast instanceof TextToastRecord); 9206 } 9207 } 9208 9209 void finishWindowTokenLocked(IBinder t, int displayId) { 9210 mHandler.removeCallbacksAndMessages(t); 9211 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any 9212 // remaining surfaces as either the client has called finishToken indicating 9213 // it has successfully removed the views, or the client has timed out 9214 // at which point anything goes. 9215 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId); 9216 } 9217 9218 @GuardedBy("mToastQueue") 9219 private void scheduleDurationReachedLocked(ToastRecord r, boolean lastToastWasTextRecord) 9220 { 9221 mHandler.removeCallbacksAndMessages(r); 9222 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r); 9223 int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 9224 // Accessibility users may need longer timeout duration. This api compares original delay 9225 // with user's preference and return longer one. It returns original delay if there's no 9226 // preference. 9227 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay, 9228 AccessibilityManager.FLAG_CONTENT_TEXT); 9229 9230 if (lastToastWasTextRecord) { 9231 delay += 250; // delay to account for previous toast's "out" animation 9232 } 9233 if (r instanceof TextToastRecord) { 9234 delay += 333; // delay to account for this toast's "in" animation 9235 } 9236 9237 mHandler.sendMessageDelayed(m, delay); 9238 } 9239 9240 private void handleDurationReached(ToastRecord record) 9241 { 9242 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " token=" + record.token); 9243 synchronized (mToastQueue) { 9244 int index = indexOfToastLocked(record.pkg, record.token); 9245 if (index >= 0) { 9246 cancelToastLocked(index); 9247 } 9248 } 9249 } 9250 9251 @GuardedBy("mToastQueue") 9252 private void scheduleKillTokenTimeout(ToastRecord r) 9253 { 9254 mHandler.removeCallbacksAndMessages(r); 9255 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r); 9256 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT); 9257 } 9258 9259 private void handleKillTokenTimeout(ToastRecord record) 9260 { 9261 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.windowToken); 9262 synchronized (mToastQueue) { 9263 finishWindowTokenLocked(record.windowToken, record.displayId); 9264 } 9265 } 9266 9267 @GuardedBy("mToastQueue") 9268 int indexOfToastLocked(String pkg, IBinder token) { 9269 ArrayList<ToastRecord> list = mToastQueue; 9270 int len = list.size(); 9271 for (int i=0; i<len; i++) { 9272 ToastRecord r = list.get(i); 9273 if (r.pkg.equals(pkg) && r.token == token) { 9274 return i; 9275 } 9276 } 9277 return -1; 9278 } 9279 9280 /** 9281 * Adjust process {@code pid} importance according to whether it has toasts in the queue or not. 9282 */ 9283 public void keepProcessAliveForToastIfNeeded(int pid) { 9284 synchronized (mToastQueue) { 9285 keepProcessAliveForToastIfNeededLocked(pid); 9286 } 9287 } 9288 9289 @GuardedBy("mToastQueue") 9290 private void keepProcessAliveForToastIfNeededLocked(int pid) { 9291 int toastCount = 0; // toasts from this pid, rendered by the app 9292 ArrayList<ToastRecord> list = mToastQueue; 9293 int n = list.size(); 9294 for (int i = 0; i < n; i++) { 9295 ToastRecord r = list.get(i); 9296 if (r.pid == pid && r.keepProcessAlive()) { 9297 toastCount++; 9298 } 9299 } 9300 try { 9301 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast"); 9302 } catch (RemoteException e) { 9303 // Shouldn't happen. 9304 } 9305 } 9306 9307 /** 9308 * Implementation note: Our definition of foreground for toasts is an implementation matter 9309 * and should strike a balance between functionality and anti-abuse effectiveness. We 9310 * currently worry about the following cases: 9311 * <ol> 9312 * <li>App with fullscreen activity: Allow toasts 9313 * <li>App behind translucent activity from other app: Block toasts 9314 * <li>App in multi-window: Allow toasts 9315 * <li>App with expanded bubble: Allow toasts 9316 * <li>App posting toasts on onCreate(), onStart(), onResume(): Allow toasts 9317 * <li>App posting toasts on onPause(), onStop(), onDestroy(): Block toasts 9318 * </ol> 9319 * Checking if the UID has any resumed activities satisfy use-cases above. 9320 * 9321 * <p>Checking if {@code mActivityManager.getUidImportance(callingUid) == 9322 * IMPORTANCE_FOREGROUND} does not work because it considers the app in foreground if it has 9323 * any visible activities, failing case 2 in list above. 9324 */ 9325 private boolean isPackageInForegroundForToast(int callingUid) { 9326 return mAtm.hasResumedActivity(callingUid); 9327 } 9328 9329 /** 9330 * True if the toast should be blocked. It will return true if all of the following conditions 9331 * apply: it's a custom toast, it's not a system toast, the package that sent the toast is in 9332 * the background and CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is enabled. 9333 * 9334 * CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so it will return false for apps 9335 * with targetSdk < R. For apps with targetSdk R+, text toasts are not app-rendered, so 9336 * isAppRenderedToast == true means it's a custom toast. 9337 */ 9338 private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast, 9339 boolean isPackageInForeground) { 9340 return isAppRenderedToast 9341 && !isSystemToast 9342 && !isPackageInForeground 9343 && CompatChanges.isChangeEnabled(CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, uid); 9344 } 9345 9346 private void handleRankingReconsideration(Message message) { 9347 if (!(message.obj instanceof RankingReconsideration)) return; 9348 RankingReconsideration recon = (RankingReconsideration) message.obj; 9349 recon.run(); 9350 boolean changed; 9351 synchronized (mNotificationLock) { 9352 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 9353 if (record == null) { 9354 return; 9355 } 9356 int indexBefore = findNotificationRecordIndexLocked(record); 9357 boolean interceptBefore = record.isIntercepted(); 9358 int visibilityBefore = record.getPackageVisibilityOverride(); 9359 boolean interruptiveBefore = record.isInterruptive(); 9360 9361 recon.applyChangesLocked(record); 9362 applyZenModeLocked(record); 9363 mRankingHelper.sort(mNotificationList); 9364 boolean indexChanged = indexBefore != findNotificationRecordIndexLocked(record); 9365 boolean interceptChanged = interceptBefore != record.isIntercepted(); 9366 boolean visibilityChanged = visibilityBefore != record.getPackageVisibilityOverride(); 9367 9368 // Broadcast isInterruptive changes for bubbles. 9369 boolean interruptiveChanged = 9370 record.canBubble() && (interruptiveBefore != record.isInterruptive()); 9371 9372 changed = indexChanged 9373 || interceptChanged 9374 || visibilityChanged 9375 || interruptiveChanged; 9376 if (interceptBefore && !record.isIntercepted() 9377 && record.isNewEnoughForAlerting(System.currentTimeMillis())) { 9378 9379 mAttentionHelper.buzzBeepBlinkLocked(record, 9380 new NotificationAttentionHelper.Signals(mUserProfiles.isCurrentProfile( 9381 record.getUserId()), mListenerHints)); 9382 9383 // Log alert after change in intercepted state to Zen Log as well 9384 ZenLog.traceAlertOnUpdatedIntercept(record); 9385 } 9386 } 9387 if (changed) { 9388 mHandler.scheduleSendRankingUpdate(); 9389 } 9390 } 9391 9392 void handleRankingSort() { 9393 if (mRankingHelper == null) return; 9394 synchronized (mNotificationLock) { 9395 final int N = mNotificationList.size(); 9396 // Any field that can change via one of the extractors needs to be added here. 9397 ArrayMap<String, NotificationRecordExtractorData> extractorDataBefore = 9398 new ArrayMap<>(N); 9399 for (int i = 0; i < N; i++) { 9400 final NotificationRecord r = mNotificationList.get(i); 9401 NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData( 9402 i, 9403 r.getPackageVisibilityOverride(), 9404 r.canShowBadge(), 9405 r.canBubble(), 9406 r.getNotification().isBubbleNotification(), 9407 r.getChannel(), 9408 r.getGroupKey(), 9409 r.getPeopleOverride(), 9410 r.getSnoozeCriteria(), 9411 r.getUserSentiment(), 9412 r.getSuppressedVisualEffects(), 9413 r.getSystemGeneratedSmartActions(), 9414 r.getSmartReplies(), 9415 r.getImportance(), 9416 r.getRankingScore(), 9417 r.isConversation(), 9418 r.getProposedImportance(), 9419 r.hasSensitiveContent()); 9420 extractorDataBefore.put(r.getKey(), extractorData); 9421 mRankingHelper.extractSignals(r); 9422 } 9423 mRankingHelper.sort(mNotificationList); 9424 for (int i = 0; i < N; i++) { 9425 final NotificationRecord r = mNotificationList.get(i); 9426 if (!extractorDataBefore.containsKey(r.getKey())) { 9427 // This shouldn't happen given that we just built this with all the 9428 // notifications, but check just to be safe. 9429 continue; 9430 } 9431 if (extractorDataBefore.get(r.getKey()).hasDiffForRankingLocked(r, i)) { 9432 mHandler.scheduleSendRankingUpdate(); 9433 } 9434 9435 // If this notification is one for which we wanted to log an update, and 9436 // sufficient relevant bits are different, log update. 9437 if (r.hasPendingLogUpdate()) { 9438 // We need to acquire the previous data associated with this specific 9439 // notification, as the one at the current index may be unrelated if 9440 // notification order has changed. 9441 NotificationRecordExtractorData prevData = extractorDataBefore.get(r.getKey()); 9442 if (prevData.hasDiffForLoggingLocked(r, i)) { 9443 mNotificationRecordLogger.logNotificationAdjusted(r, i, 0, 9444 getGroupInstanceId(r.getSbn().getGroupKey())); 9445 } 9446 9447 // Remove whether there was a diff or not; we've sorted the key, so if it 9448 // turns out there was nothing to log, that's fine too. 9449 r.setPendingLogUpdate(false); 9450 } 9451 } 9452 } 9453 } 9454 9455 @GuardedBy("mNotificationLock") 9456 private void recordCallerLocked(NotificationRecord record) { 9457 if (mZenModeHelper.isCall(record)) { 9458 mZenModeHelper.recordCaller(record); 9459 } 9460 } 9461 9462 // let zen mode evaluate this record 9463 @GuardedBy("mNotificationLock") 9464 private void applyZenModeLocked(NotificationRecord record) { 9465 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 9466 if (record.isIntercepted()) { 9467 record.setSuppressedVisualEffects( 9468 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects); 9469 } else { 9470 record.setSuppressedVisualEffects(0); 9471 } 9472 } 9473 9474 @GuardedBy("mNotificationLock") 9475 private int findNotificationRecordIndexLocked(NotificationRecord target) { 9476 return mRankingHelper.indexOf(mNotificationList, target); 9477 } 9478 9479 private void handleSendRankingUpdate() { 9480 synchronized (mNotificationLock) { 9481 mListeners.notifyRankingUpdateLocked(null); 9482 } 9483 } 9484 9485 private void scheduleListenerHintsChanged(int state) { 9486 if (!Flags.notificationReduceMessagequeueUsage()) { 9487 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 9488 } 9489 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 9490 } 9491 9492 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 9493 if (!Flags.notificationReduceMessagequeueUsage()) { 9494 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 9495 } 9496 mHandler.obtainMessage( 9497 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 9498 listenerInterruptionFilter, 9499 0).sendToTarget(); 9500 } 9501 9502 private void handleListenerHintsChanged(int hints) { 9503 synchronized (mNotificationLock) { 9504 mListeners.notifyListenerHintsChangedLocked(hints); 9505 } 9506 } 9507 9508 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 9509 synchronized (mNotificationLock) { 9510 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 9511 } 9512 } 9513 9514 void handleOnPackageChanged(boolean removingPackage, int changeUserId, 9515 String[] pkgList, int[] uidList) { 9516 boolean preferencesChanged = removingPackage; 9517 mListeners.onPackagesChanged(removingPackage, pkgList, uidList); 9518 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList); 9519 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); 9520 preferencesChanged |= mPreferencesHelper.onPackagesChanged( 9521 removingPackage, changeUserId, pkgList, uidList); 9522 if (removingPackage) { 9523 int size = Math.min(pkgList.length, uidList.length); 9524 for (int i = 0; i < size; i++) { 9525 final String pkg = pkgList[i]; 9526 final int uid = uidList[i]; 9527 final int userHandle = UserHandle.getUserId(uid); 9528 // Removes this package's notifications from both recent notification archive 9529 // (recently dismissed notifications) and notification history. 9530 mArchive.removePackageNotifications(pkg, userHandle); 9531 mHistoryManager.onPackageRemoved(userHandle, pkg); 9532 } 9533 } 9534 if (preferencesChanged) { 9535 handleSavePolicyFile(); 9536 } 9537 } 9538 9539 protected class WorkerHandler extends Handler 9540 { 9541 public WorkerHandler(Looper looper) { 9542 super(looper); 9543 } 9544 9545 @Override 9546 public void handleMessage(Message msg) 9547 { 9548 switch (msg.what) 9549 { 9550 case MESSAGE_DURATION_REACHED: 9551 handleDurationReached((ToastRecord) msg.obj); 9552 break; 9553 case MESSAGE_FINISH_TOKEN_TIMEOUT: 9554 handleKillTokenTimeout((ToastRecord) msg.obj); 9555 break; 9556 case MESSAGE_SEND_RANKING_UPDATE: 9557 handleSendRankingUpdate(); 9558 break; 9559 case MESSAGE_LISTENER_HINTS_CHANGED: 9560 handleListenerHintsChanged(msg.arg1); 9561 break; 9562 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 9563 handleListenerInterruptionFilterChanged(msg.arg1); 9564 break; 9565 case MESSAGE_ON_PACKAGE_CHANGED: 9566 SomeArgs args = (SomeArgs) msg.obj; 9567 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2, 9568 (int[]) args.arg3); 9569 args.recycle(); 9570 break; 9571 } 9572 } 9573 9574 protected void scheduleSendRankingUpdate() { 9575 if (Flags.notificationReduceMessagequeueUsage()) { 9576 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); 9577 sendMessage(m); 9578 } else { 9579 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 9580 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); 9581 sendMessage(m); 9582 } 9583 } 9584 } 9585 9586 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable, 9587 int delay) { 9588 if (lifetimeExtensionRefactor()) { 9589 sendMessageDelayed(Message.obtain(this, cancelRunnable), delay); 9590 } else { 9591 if (Flags.notificationReduceMessagequeueUsage()) { 9592 sendMessage(Message.obtain(this, cancelRunnable)); 9593 } else { 9594 if (!hasCallbacks(cancelRunnable)) { 9595 sendMessage(Message.obtain(this, cancelRunnable)); 9596 } 9597 } 9598 } 9599 } 9600 9601 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId, 9602 String[] pkgList, int[] uidList) { 9603 SomeArgs args = SomeArgs.obtain(); 9604 args.arg1 = removingPackage; 9605 args.argi1 = changeUserId; 9606 args.arg2 = pkgList; 9607 args.arg3 = uidList; 9608 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args)); 9609 } 9610 } 9611 9612 private final class RankingHandlerWorker extends Handler implements RankingHandler 9613 { 9614 public RankingHandlerWorker(Looper looper) { 9615 super(looper); 9616 } 9617 9618 @Override 9619 public void handleMessage(Message msg) { 9620 switch (msg.what) { 9621 case MESSAGE_RECONSIDER_RANKING: 9622 handleRankingReconsideration(msg); 9623 break; 9624 case MESSAGE_RANKING_SORT: 9625 handleRankingSort(); 9626 break; 9627 } 9628 } 9629 9630 public void requestSort() { 9631 if (!Flags.notificationReduceMessagequeueUsage()) { 9632 removeMessages(MESSAGE_RANKING_SORT); 9633 } 9634 Message msg = Message.obtain(); 9635 msg.what = MESSAGE_RANKING_SORT; 9636 sendMessage(msg); 9637 } 9638 9639 public void requestReconsideration(RankingReconsideration recon) { 9640 Message m = Message.obtain(this, 9641 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 9642 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 9643 sendMessageDelayed(m, delay); 9644 } 9645 } 9646 9647 // Notifications 9648 // ============================================================================ 9649 static int clamp(int x, int low, int high) { 9650 return (x < low) ? low : ((x > high) ? high : x); 9651 } 9652 9653 /** 9654 * Removes all NotificationsRecords with the same key as the given notification record 9655 * from both lists. Do not call this method while iterating over either list. 9656 */ 9657 @GuardedBy("mNotificationLock") 9658 private boolean removeFromNotificationListsLocked(NotificationRecord r) { 9659 // Remove from both lists, either list could have a separate Record for what is 9660 // effectively the same notification. 9661 boolean wasPosted = false; 9662 NotificationRecord recordInList = null; 9663 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) 9664 != null) { 9665 mNotificationList.remove(recordInList); 9666 mNotificationsByKey.remove(recordInList.getSbn().getKey()); 9667 wasPosted = true; 9668 } 9669 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) 9670 != null) { 9671 mEnqueuedNotifications.remove(recordInList); 9672 } 9673 return wasPosted; 9674 } 9675 9676 @GuardedBy("mNotificationLock") 9677 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, 9678 @NotificationListenerService.NotificationCancelReason int reason, 9679 boolean wasPosted, String listenerName, 9680 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 9681 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName, 9682 cancellationElapsedTimeMs); 9683 } 9684 9685 @GuardedBy("mNotificationLock") 9686 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, 9687 @NotificationListenerService.NotificationCancelReason int reason, 9688 int rank, int count, boolean wasPosted, String listenerName, 9689 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 9690 final String canceledKey = r.getKey(); 9691 if (Flags.allNotifsNeedTtl()) { 9692 mTtlHelper.cancelScheduledTimeoutLocked(r); 9693 } else { 9694 cancelScheduledTimeoutLocked(r); 9695 } 9696 9697 // Record caller. 9698 recordCallerLocked(r); 9699 9700 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) { 9701 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER); 9702 } 9703 9704 // tell the app 9705 if (sendDelete) { 9706 final PendingIntent deleteIntent = r.getNotification().deleteIntent; 9707 if (deleteIntent != null) { 9708 try { 9709 // make sure deleteIntent cannot be used to start activities from background 9710 LocalServices.getService(ActivityManagerInternal.class) 9711 .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(), 9712 ALLOWLIST_TOKEN); 9713 deleteIntent.send(); 9714 } catch (PendingIntent.CanceledException ex) { 9715 // do nothing - there's no relevant way to recover, and 9716 // no reason to let this propagate 9717 Slog.w(TAG, "canceled PendingIntent for " + r.getSbn().getPackageName(), ex); 9718 } 9719 } 9720 } 9721 9722 // Only cancel these if this notification actually got to be posted. 9723 if (wasPosted) { 9724 // status bar 9725 if (r.getNotification().getSmallIcon() != null) { 9726 if (reason != REASON_SNOOZED) { 9727 r.isCanceled = true; 9728 } 9729 mListeners.notifyRemovedLocked(r, reason, r.getStats()); 9730 mHandler.post(new Runnable() { 9731 @Override 9732 public void run() { 9733 mGroupHelper.onNotificationRemoved(r.getSbn()); 9734 } 9735 }); 9736 if (callstyleCallbackApi()) { 9737 notifyCallNotificationEventListenerOnRemoved(r); 9738 } 9739 } 9740 9741 mAttentionHelper.clearEffectsLocked(canceledKey); 9742 } 9743 9744 // Record usage stats 9745 // TODO: add unbundling stats? 9746 switch (reason) { 9747 case REASON_CANCEL: 9748 case REASON_CANCEL_ALL: 9749 case REASON_LISTENER_CANCEL: 9750 case REASON_LISTENER_CANCEL_ALL: 9751 mUsageStats.registerDismissedByUser(r); 9752 break; 9753 case REASON_APP_CANCEL: 9754 case REASON_APP_CANCEL_ALL: 9755 mUsageStats.registerRemovedByApp(r); 9756 mUsageStatsManagerInternal.reportNotificationRemoved(r.getSbn().getOpPkg(), 9757 r.getUser(), cancellationElapsedTimeMs); 9758 break; 9759 } 9760 9761 String groupKey = r.getGroupKey(); 9762 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 9763 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) { 9764 mSummaryByGroupKey.remove(groupKey); 9765 } 9766 final ArrayMap<String, String> summaries = 9767 mAutobundledSummaries.get(r.getSbn().getUserId()); 9768 if (summaries != null && r.getSbn().getKey().equals( 9769 summaries.get(r.getSbn().getPackageName()))) { 9770 summaries.remove(r.getSbn().getPackageName()); 9771 } 9772 9773 // Save it for users of getHistoricalNotifications(), unless the whole channel was deleted 9774 if (reason != REASON_CHANNEL_REMOVED) { 9775 mArchive.record(r.getSbn(), reason); 9776 } 9777 9778 final long now = System.currentTimeMillis(); 9779 final LogMaker logMaker = r.getItemLogMaker() 9780 .setType(MetricsEvent.TYPE_DISMISS) 9781 .setSubtype(reason); 9782 if (rank != -1 && count != -1) { 9783 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank) 9784 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count); 9785 } 9786 MetricsLogger.action(logMaker); 9787 EventLogTags.writeNotificationCanceled(canceledKey, reason, 9788 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 9789 rank, count, listenerName); 9790 if (wasPosted) { 9791 mNotificationRecordLogger.logNotificationCancelled(r, reason, 9792 r.getStats().getDismissalSurface()); 9793 } 9794 } 9795 9796 @VisibleForTesting 9797 void updateUriPermissions(@Nullable NotificationRecord newRecord, 9798 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) { 9799 updateUriPermissions(newRecord, oldRecord, targetPkg, targetUserId, false); 9800 } 9801 9802 @VisibleForTesting 9803 void updateUriPermissions(@Nullable NotificationRecord newRecord, 9804 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId, 9805 boolean onlyRevokeCurrentTarget) { 9806 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey(); 9807 if (DBG) Slog.d(TAG, key + ": updating permissions"); 9808 9809 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null; 9810 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null; 9811 9812 // Shortcut when no Uris involved 9813 if (newUris == null && oldUris == null) { 9814 return; 9815 } 9816 9817 // Inherit any existing owner 9818 IBinder permissionOwner = null; 9819 if (newRecord != null && permissionOwner == null) { 9820 permissionOwner = newRecord.permissionOwner; 9821 } 9822 if (oldRecord != null && permissionOwner == null) { 9823 permissionOwner = oldRecord.permissionOwner; 9824 } 9825 9826 // If we have Uris to grant, but no owner yet, go create one 9827 if (newUris != null && permissionOwner == null) { 9828 if (DBG) Slog.d(TAG, key + ": creating owner"); 9829 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key); 9830 } 9831 9832 // If we have no Uris to grant, but an existing owner, go destroy it 9833 // When revoking permissions of a single listener, destroying the owner will revoke 9834 // permissions of other listeners who need to keep access. 9835 if (newUris == null && permissionOwner != null && !onlyRevokeCurrentTarget) { 9836 destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key); 9837 permissionOwner = null; 9838 } 9839 9840 // Grant access to new Uris 9841 if (newUris != null && permissionOwner != null) { 9842 for (int i = 0; i < newUris.size(); i++) { 9843 final Uri uri = newUris.valueAt(i); 9844 if (oldUris == null || !oldUris.contains(uri)) { 9845 if (DBG) { 9846 Slog.d(TAG, key + ": granting " + uri); 9847 } 9848 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg, 9849 targetUserId); 9850 } 9851 } 9852 } 9853 9854 // Revoke access to old Uris 9855 if (oldUris != null && permissionOwner != null) { 9856 for (int i = 0; i < oldUris.size(); i++) { 9857 final Uri uri = oldUris.valueAt(i); 9858 if (newUris == null || !newUris.contains(uri)) { 9859 if (DBG) Slog.d(TAG, key + ": revoking " + uri); 9860 if (onlyRevokeCurrentTarget) { 9861 // We're revoking permission from one listener only; other listeners may 9862 // still need access because the notification may still exist 9863 revokeUriPermission(permissionOwner, uri, 9864 UserHandle.getUserId(oldRecord.getUid()), targetPkg, targetUserId); 9865 } else { 9866 // This is broad to unilaterally revoke permissions to this Uri as granted 9867 // by this notification. But this code-path can only be used when the 9868 // reason for revoking is that the notification posted again without this 9869 // Uri, not when removing an individual listener. 9870 revokeUriPermission(permissionOwner, uri, 9871 UserHandle.getUserId(oldRecord.getUid()), 9872 null, USER_ALL); 9873 } 9874 } 9875 } 9876 } 9877 9878 if (newRecord != null) { 9879 newRecord.permissionOwner = permissionOwner; 9880 } 9881 } 9882 9883 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg, 9884 int targetUserId) { 9885 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 9886 final long ident = Binder.clearCallingIdentity(); 9887 try { 9888 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg, 9889 ContentProvider.getUriWithoutUserId(uri), 9890 Intent.FLAG_GRANT_READ_URI_PERMISSION, 9891 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)), 9892 targetUserId); 9893 } catch (RemoteException ignored) { 9894 // Ignored because we're in same process 9895 } catch (SecurityException e) { 9896 Slog.e(TAG, "Cannot grant uri access; " + sourceUid + " does not own " + uri); 9897 } finally { 9898 Binder.restoreCallingIdentity(ident); 9899 } 9900 } 9901 9902 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUserId, String targetPkg, 9903 int targetUserId) { 9904 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 9905 int userId = ContentProvider.getUserIdFromUri(uri, sourceUserId); 9906 9907 final long ident = Binder.clearCallingIdentity(); 9908 try { 9909 mUgmInternal.revokeUriPermissionFromOwner( 9910 owner, 9911 ContentProvider.getUriWithoutUserId(uri), 9912 Intent.FLAG_GRANT_READ_URI_PERMISSION, 9913 userId, targetPkg, targetUserId); 9914 } finally { 9915 Binder.restoreCallingIdentity(ident); 9916 } 9917 } 9918 9919 private void destroyPermissionOwner(IBinder owner, int userId, String logKey) { 9920 final long ident = Binder.clearCallingIdentity(); 9921 try { 9922 if (DBG) Slog.d(TAG, logKey + ": destroying owner"); 9923 mUgmInternal.revokeUriPermissionFromOwner(owner, null, ~0, userId); 9924 } finally { 9925 Binder.restoreCallingIdentity(ident); 9926 } 9927 } 9928 9929 /** 9930 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 9931 * and none of the {@code mustNotHaveFlags}. 9932 */ 9933 void cancelNotification(final int callingUid, final int callingPid, 9934 final String pkg, final String tag, int id, 9935 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 9936 final int userId, final int reason, final ManagedServiceInfo listener) { 9937 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags, 9938 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener); 9939 } 9940 9941 /** 9942 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 9943 * and none of the {@code mustNotHaveFlags}. 9944 */ 9945 void cancelNotification(final int callingUid, final int callingPid, 9946 final String pkg, final String tag, final int id, 9947 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 9948 final int userId, final int reason, int rank, int count, 9949 final ManagedServiceInfo listener) { 9950 // In enqueueNotificationInternal notifications are added by scheduling the 9951 // work on the worker handler. Hence, we also schedule the cancel on this 9952 // handler to avoid a scenario where an add notification call followed by a 9953 // remove notification call ends up in not removing the notification. 9954 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid, 9955 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank, 9956 count, listener, SystemClock.elapsedRealtime()), 0); 9957 } 9958 9959 /** 9960 * Determine whether the userId applies to the notification in question, either because 9961 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 9962 */ 9963 private static boolean notificationMatchesUserId(NotificationRecord r, int userId, 9964 boolean isAutogroupSummary) { 9965 if (isAutogroupSummary) { 9966 return r.getUserId() == userId; 9967 } else { 9968 return 9969 // looking for USER_ALL notifications? match everything 9970 userId == USER_ALL 9971 // a notification sent to USER_ALL matches any query 9972 || r.getUserId() == USER_ALL 9973 // an exact user match 9974 || r.getUserId() == userId; 9975 } 9976 } 9977 9978 /** 9979 * Determine whether the userId applies to the notification in question, either because 9980 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 9981 * because it matches one of the users profiles. 9982 */ 9983 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 9984 return notificationMatchesUserId(r, userId, false) 9985 || mUserProfiles.isCurrentProfile(r.getUserId()); 9986 } 9987 9988 /** 9989 * Cancels all notifications from a given package that have all of the 9990 * {@code mustHaveFlags} and none of the {@code mustNotHaveFlags}. 9991 */ 9992 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, 9993 @Nullable String channelId, int mustHaveFlags, int mustNotHaveFlags, int userId, 9994 int reason) { 9995 final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime(); 9996 mHandler.post(new Runnable() { 9997 @Override 9998 public void run() { 9999 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 10000 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 10001 /* listener= */ null); 10002 10003 synchronized (mNotificationLock) { 10004 FlagChecker flagChecker = (int flags) -> { 10005 if ((flags & mustHaveFlags) != mustHaveFlags) { 10006 return false; 10007 } 10008 if ((flags & mustNotHaveFlags) != 0) { 10009 return false; 10010 } 10011 return true; 10012 }; 10013 cancelAllNotificationsByListLocked(mNotificationList, pkg, 10014 true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 10015 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 10016 null /* listenerName */, true /* wasPosted */, 10017 cancellationElapsedTimeMs); 10018 cancelAllNotificationsByListLocked(mEnqueuedNotifications, pkg, 10019 true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 10020 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 10021 null /* listenerName */, false /* wasPosted */, 10022 cancellationElapsedTimeMs); 10023 mSnoozeHelper.cancel(userId, pkg); 10024 } 10025 } 10026 }); 10027 } 10028 10029 private interface FlagChecker { 10030 // Returns false if these flags do not pass the defined flag test. 10031 public boolean apply(int flags); 10032 } 10033 10034 @GuardedBy("mNotificationLock") 10035 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList, 10036 @Nullable String pkg, boolean nullPkgIndicatesUserSwitch, @Nullable String channelId, 10037 FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, boolean sendDelete, 10038 int reason, String listenerName, boolean wasPosted, 10039 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 10040 Set<String> childNotifications = null; 10041 for (int i = notificationList.size() - 1; i >= 0; --i) { 10042 NotificationRecord r = notificationList.get(i); 10043 if (includeCurrentProfiles) { 10044 if (!notificationMatchesCurrentProfiles(r, userId)) { 10045 continue; 10046 } 10047 } else if (!notificationMatchesUserId(r, userId, false)) { 10048 continue; 10049 } 10050 // Don't remove notifications to all, if there's no package name specified 10051 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == USER_ALL) { 10052 continue; 10053 } 10054 if (!flagChecker.apply(r.getFlags())) { 10055 continue; 10056 } 10057 if (pkg != null && !r.getSbn().getPackageName().equals(pkg)) { 10058 continue; 10059 } 10060 if (channelId != null && !channelId.equals(r.getChannel().getId())) { 10061 continue; 10062 } 10063 if (r.getSbn().isGroup() && r.getNotification().isGroupChild()) { 10064 if (childNotifications == null) { 10065 childNotifications = new HashSet<>(); 10066 } 10067 childNotifications.add(r.getKey()); 10068 continue; 10069 } 10070 notificationList.remove(i); 10071 mNotificationsByKey.remove(r.getKey()); 10072 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); 10073 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName, 10074 cancellationElapsedTimeMs); 10075 } 10076 if (childNotifications != null) { 10077 final int M = notificationList.size(); 10078 for (int i = M - 1; i >= 0; i--) { 10079 NotificationRecord r = notificationList.get(i); 10080 if (childNotifications.contains(r.getKey())) { 10081 // dismiss conditions were checked in the first loop and so don't need to be 10082 // checked again 10083 notificationList.remove(i); 10084 mNotificationsByKey.remove(r.getKey()); 10085 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); 10086 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName, 10087 cancellationElapsedTimeMs); 10088 } 10089 } 10090 mAttentionHelper.updateLightsLocked(); 10091 } 10092 } 10093 10094 void snoozeNotificationInt(int callingUid, INotificationListener token, String key, 10095 long duration, String snoozeCriterionId) { 10096 final String packageName; 10097 final long notificationUpdateTimeMs; 10098 10099 synchronized (mNotificationLock) { 10100 final ManagedServiceInfo listener = mListeners.checkServiceTokenLocked(token); 10101 if (listener == null) { 10102 return; 10103 } 10104 packageName = listener.component.getPackageName(); 10105 String listenerName = listener.component.toShortString(); 10106 if ((duration <= 0 && snoozeCriterionId == null) || key == null) { 10107 return; 10108 } 10109 10110 final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key); 10111 if (r == null) { 10112 return; 10113 } 10114 if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){ 10115 return; 10116 } 10117 notificationUpdateTimeMs = r.getUpdateTimeMs(); 10118 10119 if (DBG) { 10120 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration, 10121 snoozeCriterionId, listenerName)); 10122 } 10123 // Needs to post so that it can cancel notifications not yet enqueued. 10124 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); 10125 } 10126 10127 if (isNotificationRecent(notificationUpdateTimeMs)) { 10128 mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, 10129 callingUid, packageName, /* attributionTag= */ null, /* message= */ null); 10130 } 10131 } 10132 10133 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) { 10134 String listenerName = listener == null ? null : listener.component.toShortString(); 10135 if (DBG) { 10136 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); 10137 } 10138 mSnoozeHelper.repost(key, muteOnReturn); 10139 handleSavePolicyFile(); 10140 } 10141 10142 private boolean isNotificationRecent(long notificationUpdateTimeMs) { 10143 if (!rapidClearNotificationsByListenerAppOpEnabled()) { 10144 return false; 10145 } 10146 return System.currentTimeMillis() - notificationUpdateTimeMs 10147 < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS; 10148 } 10149 10150 @GuardedBy("mNotificationLock") 10151 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 10152 ManagedServiceInfo listener, boolean includeCurrentProfiles, int mustNotHaveFlags) { 10153 final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime(); 10154 mHandler.post(new Runnable() { 10155 @Override 10156 public void run() { 10157 synchronized (mNotificationLock) { 10158 String listenerName = 10159 listener == null ? null : listener.component.toShortString(); 10160 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 10161 null, userId, 0, 0, reason, listenerName); 10162 10163 FlagChecker flagChecker = (int flags) -> { 10164 int flagsToCheck = mustNotHaveFlags; 10165 if (REASON_LISTENER_CANCEL_ALL == reason 10166 || REASON_CANCEL_ALL == reason) { 10167 flagsToCheck |= FLAG_BUBBLE; 10168 } 10169 if ((flags & flagsToCheck) != 0) { 10170 return false; 10171 } 10172 return true; 10173 }; 10174 10175 cancelAllNotificationsByListLocked(mNotificationList, 10176 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker, 10177 includeCurrentProfiles, userId, true /*sendDelete*/, reason, 10178 listenerName, true, cancellationElapsedTimeMs); 10179 cancelAllNotificationsByListLocked(mEnqueuedNotifications, 10180 null, false /*nullPkgIndicatesUserSwitch*/, null, 10181 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/, 10182 reason, listenerName, false, cancellationElapsedTimeMs); 10183 mSnoozeHelper.cancel(userId, includeCurrentProfiles); 10184 } 10185 } 10186 }); 10187 } 10188 10189 // Warning: The caller is responsible for invoking updateLightsLocked(). 10190 @GuardedBy("mNotificationLock") 10191 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 10192 String listenerName, boolean sendDelete, FlagChecker flagChecker, int reason, 10193 @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 10194 Notification n = r.getNotification(); 10195 if (!n.isGroupSummary()) { 10196 return; 10197 } 10198 10199 String pkg = r.getSbn().getPackageName(); 10200 10201 if (pkg == null) { 10202 if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey()); 10203 return; 10204 } 10205 10206 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName, 10207 sendDelete, true, flagChecker, reason, cancellationElapsedTimeMs); 10208 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid, 10209 listenerName, sendDelete, false, flagChecker, reason, cancellationElapsedTimeMs); 10210 } 10211 10212 @GuardedBy("mNotificationLock") 10213 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList, 10214 NotificationRecord parentNotification, int callingUid, int callingPid, 10215 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker, 10216 int reason, @ElapsedRealtimeLong long cancellationElapsedTimeMs) { 10217 final String pkg = parentNotification.getSbn().getPackageName(); 10218 final int userId = parentNotification.getUserId(); 10219 final int childReason = REASON_GROUP_SUMMARY_CANCELED; 10220 for (int i = notificationList.size() - 1; i >= 0; i--) { 10221 final NotificationRecord childR = notificationList.get(i); 10222 final StatusBarNotification childSbn = childR.getSbn(); 10223 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 10224 childR.getGroupKey().equals(parentNotification.getGroupKey()) 10225 && (flagChecker == null || flagChecker.apply(childR.getFlags())) 10226 && (!childR.getChannel().isImportantConversation() 10227 || reason != REASON_CANCEL)) { 10228 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 10229 childSbn.getTag(), userId, 0, 0, childReason, listenerName); 10230 notificationList.remove(i); 10231 mNotificationsByKey.remove(childR.getKey()); 10232 cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName, 10233 cancellationElapsedTimeMs); 10234 } 10235 } 10236 } 10237 10238 @GuardedBy("mNotificationLock") 10239 @NonNull 10240 List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg, 10241 String groupKey, int userId) { 10242 List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId); 10243 records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId)); 10244 return records; 10245 } 10246 10247 @GuardedBy("mNotificationLock") 10248 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg, 10249 String groupKey, int userId) { 10250 List<NotificationRecord> records = new ArrayList<>(); 10251 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId)); 10252 records.addAll( 10253 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId)); 10254 return records; 10255 } 10256 10257 @GuardedBy("mNotificationLock") 10258 private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) { 10259 NotificationRecord r = findNotificationByKeyLocked(key); 10260 if (r == null) { 10261 r = mSnoozeHelper.getNotification(key); 10262 } 10263 return r; 10264 10265 } 10266 10267 @GuardedBy("mNotificationLock") 10268 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( 10269 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) { 10270 List<NotificationRecord> records = new ArrayList<>(); 10271 final int len = list.size(); 10272 for (int i = 0; i < len; i++) { 10273 NotificationRecord r = list.get(i); 10274 if (notificationMatchesUserId(r, userId, false) && r.getGroupKey().equals(groupKey) 10275 && r.getSbn().getPackageName().equals(pkg)) { 10276 records.add(r); 10277 } 10278 } 10279 return records; 10280 } 10281 10282 // Searches both enqueued and posted notifications by key. 10283 // TODO: need to combine a bunch of these getters with slightly different behavior. 10284 // TODO: Should enqueuing just add to mNotificationsByKey instead? 10285 @GuardedBy("mNotificationLock") 10286 private NotificationRecord findNotificationByKeyLocked(String key) { 10287 NotificationRecord r; 10288 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) { 10289 return r; 10290 } 10291 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) { 10292 return r; 10293 } 10294 return null; 10295 } 10296 10297 @GuardedBy("mNotificationLock") 10298 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) { 10299 NotificationRecord r; 10300 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) { 10301 return r; 10302 } 10303 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId)) 10304 != null) { 10305 return r; 10306 } 10307 return null; 10308 } 10309 10310 @Nullable 10311 private static NotificationRecord findNotificationByListLocked( 10312 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { 10313 final int len = list.size(); 10314 for (int i = 0; i < len; i++) { 10315 NotificationRecord r = list.get(i); 10316 if (notificationMatchesUserId(r, userId, (r.getFlags() & GroupHelper.BASE_FLAGS) != 0) 10317 && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag) 10318 && r.getSbn().getPackageName().equals(pkg)) { 10319 return r; 10320 } 10321 } 10322 return null; 10323 } 10324 10325 private static List<NotificationRecord> findNotificationsByListLocked( 10326 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { 10327 List<NotificationRecord> matching = new ArrayList<>(); 10328 final int len = list.size(); 10329 for (int i = 0; i < len; i++) { 10330 NotificationRecord r = list.get(i); 10331 if (notificationMatchesUserId(r, userId, false) && r.getSbn().getId() == id 10332 && TextUtils.equals(r.getSbn().getTag(), tag) 10333 && r.getSbn().getPackageName().equals(pkg)) { 10334 matching.add(r); 10335 } 10336 } 10337 return matching; 10338 } 10339 10340 @Nullable 10341 private static NotificationRecord findNotificationByListLocked( 10342 ArrayList<NotificationRecord> list, String key) { 10343 final int N = list.size(); 10344 for (int i = 0; i < N; i++) { 10345 if (key.equals(list.get(i).getKey())) { 10346 return list.get(i); 10347 } 10348 } 10349 return null; 10350 } 10351 10352 @GuardedBy("mNotificationLock") 10353 int indexOfNotificationLocked(String key) { 10354 final int N = mNotificationList.size(); 10355 for (int i = 0; i < N; i++) { 10356 if (key.equals(mNotificationList.get(i).getKey())) { 10357 return i; 10358 } 10359 } 10360 return -1; 10361 } 10362 10363 private void hideNotificationsForPackages(@NonNull String[] pkgs, @NonNull int[] uidList) { 10364 synchronized (mNotificationLock) { 10365 Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet()); 10366 List<String> pkgList = Arrays.asList(pkgs); 10367 List<NotificationRecord> changedNotifications = new ArrayList<>(); 10368 int numNotifications = mNotificationList.size(); 10369 for (int i = 0; i < numNotifications; i++) { 10370 NotificationRecord rec = mNotificationList.get(i); 10371 if (pkgList.contains(rec.getSbn().getPackageName()) 10372 && uidSet.contains(rec.getUid())) { 10373 rec.setHidden(true); 10374 changedNotifications.add(rec); 10375 } 10376 } 10377 10378 mListeners.notifyHiddenLocked(changedNotifications); 10379 } 10380 } 10381 10382 private void unhideNotificationsForPackages(@NonNull String[] pkgs, 10383 @NonNull int[] uidList) { 10384 synchronized (mNotificationLock) { 10385 Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet()); 10386 List<String> pkgList = Arrays.asList(pkgs); 10387 List<NotificationRecord> changedNotifications = new ArrayList<>(); 10388 int numNotifications = mNotificationList.size(); 10389 for (int i = 0; i < numNotifications; i++) { 10390 NotificationRecord rec = mNotificationList.get(i); 10391 if (pkgList.contains(rec.getSbn().getPackageName()) 10392 && uidSet.contains(rec.getUid())) { 10393 rec.setHidden(false); 10394 changedNotifications.add(rec); 10395 } 10396 } 10397 10398 mListeners.notifyUnhiddenLocked(changedNotifications); 10399 } 10400 } 10401 10402 private void cancelNotificationsWhenEnterLockDownMode(int userId) { 10403 synchronized (mNotificationLock) { 10404 int numNotifications = mNotificationList.size(); 10405 for (int i = 0; i < numNotifications; i++) { 10406 NotificationRecord rec = mNotificationList.get(i); 10407 if (rec.getUser().getIdentifier() != userId) { 10408 continue; 10409 } 10410 mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN, 10411 rec.getStats()); 10412 } 10413 10414 } 10415 } 10416 10417 private void postNotificationsWhenExitLockDownMode(int userId) { 10418 synchronized (mNotificationLock) { 10419 int numNotifications = mNotificationList.size(); 10420 // Set the delay to spread out the burst of notifications. 10421 long delay = 0; 10422 for (int i = 0; i < numNotifications; i++) { 10423 NotificationRecord rec = mNotificationList.get(i); 10424 if (rec.getUser().getIdentifier() != userId) { 10425 continue; 10426 } 10427 mHandler.postDelayed(() -> { 10428 synchronized (mNotificationLock) { 10429 mListeners.notifyPostedLocked(rec, rec); 10430 } 10431 }, delay); 10432 delay += 20; 10433 } 10434 } 10435 } 10436 10437 protected boolean isCallingUidSystem() { 10438 final int uid = Binder.getCallingUid(); 10439 return uid == Process.SYSTEM_UID; 10440 } 10441 10442 protected boolean isCallingAppIdSystem() { 10443 final int uid = Binder.getCallingUid(); 10444 final int appid = UserHandle.getAppId(uid); 10445 return appid == Process.SYSTEM_UID; 10446 } 10447 10448 protected boolean isUidSystemOrPhone(int uid) { 10449 final int appid = UserHandle.getAppId(uid); 10450 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID 10451 || uid == Process.ROOT_UID); 10452 } 10453 10454 // TODO: Most calls should probably move to isCallerSystem. 10455 protected boolean isCallerSystemOrPhone() { 10456 return isUidSystemOrPhone(Binder.getCallingUid()); 10457 } 10458 10459 @VisibleForTesting 10460 protected boolean isCallerSystemOrSystemUi() { 10461 if (isCallerSystemOrPhone()) { 10462 return true; 10463 } 10464 return getContext().checkCallingPermission(STATUS_BAR_SERVICE) 10465 == PERMISSION_GRANTED; 10466 } 10467 10468 private boolean isCallerSystemOrSystemUiOrShell() { 10469 int callingUid = Binder.getCallingUid(); 10470 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 10471 return true; 10472 } 10473 return isCallerSystemOrSystemUi(); 10474 } 10475 10476 private void checkCallerIsSystemOrShell() { 10477 int callingUid = Binder.getCallingUid(); 10478 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 10479 return; 10480 } 10481 checkCallerIsSystem(); 10482 } 10483 10484 private void checkCallerIsSystem() { 10485 if (isCallerSystemOrPhone()) { 10486 return; 10487 } 10488 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 10489 } 10490 10491 private void checkCallerIsSystemOrSystemUiOrShell() { 10492 checkCallerIsSystemOrSystemUiOrShell(null); 10493 } 10494 10495 private void checkCallerIsSystemOrSystemUiOrShell(String message) { 10496 int callingUid = Binder.getCallingUid(); 10497 if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { 10498 return; 10499 } 10500 if (isCallerSystemOrPhone()) { 10501 return; 10502 } 10503 getContext().enforceCallingPermission(STATUS_BAR_SERVICE, 10504 message); 10505 } 10506 10507 private void checkCallerIsSystemOrSameApp(String pkg) { 10508 if (isCallerSystemOrPhone()) { 10509 return; 10510 } 10511 checkCallerIsSameApp(pkg); 10512 } 10513 10514 private boolean isCallerAndroid(String callingPkg, int uid) { 10515 return isUidSystemOrPhone(uid) && callingPkg != null 10516 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg); 10517 } 10518 10519 /** 10520 * Check if the notification is of a category type that is restricted to system use only, 10521 * if so throw SecurityException 10522 */ 10523 private void checkRestrictedCategories(final Notification notification) { 10524 try { 10525 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) { 10526 return; 10527 } 10528 } catch (RemoteException re) { 10529 if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category " 10530 + "restrictions check thus the check will be done anyway"); 10531 } 10532 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category) 10533 || Notification.CATEGORY_CAR_WARNING.equals(notification.category) 10534 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) { 10535 getContext().enforceCallingPermission( 10536 android.Manifest.permission.SEND_CATEGORY_CAR_NOTIFICATIONS, 10537 String.format("Notification category %s restricted", 10538 notification.category)); 10539 } 10540 } 10541 10542 @VisibleForTesting 10543 boolean isCallerInstantApp(int callingUid, int userId) { 10544 // System is always allowed to act for ephemeral apps. 10545 if (isUidSystemOrPhone(callingUid)) { 10546 return false; 10547 } 10548 10549 if (userId == USER_ALL) { 10550 userId = USER_SYSTEM; 10551 } 10552 10553 try { 10554 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 10555 if (pkgs == null) { 10556 throw new SecurityException("Unknown uid " + callingUid); 10557 } 10558 final String pkg = pkgs[0]; 10559 mAppOps.checkPackage(callingUid, pkg); 10560 10561 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId); 10562 if (ai == null) { 10563 throw new SecurityException("Unknown package " + pkg); 10564 } 10565 return ai.isInstantApp(); 10566 } catch (RemoteException re) { 10567 throw new SecurityException("Unknown uid " + callingUid, re); 10568 } 10569 } 10570 10571 private void checkCallerIsSameApp(String pkg) { 10572 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId()); 10573 } 10574 10575 private void checkCallerIsSameApp(String pkg, int uid, int userId) { 10576 if (uid == Process.ROOT_UID && ROOT_PKG.equals(pkg)) { 10577 return; 10578 } 10579 if (!mPackageManagerInternal.isSameApp(pkg, uid, userId)) { 10580 throw new SecurityException("Package " + pkg + " is not owned by uid " + uid); 10581 } 10582 } 10583 10584 private boolean isCallerSameApp(String pkg, int uid, int userId) { 10585 try { 10586 checkCallerIsSameApp(pkg, uid, userId); 10587 return true; 10588 } catch (SecurityException e) { 10589 return false; 10590 } 10591 } 10592 10593 private static String callStateToString(int state) { 10594 switch (state) { 10595 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 10596 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 10597 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 10598 default: return "CALL_STATE_UNKNOWN_" + state; 10599 } 10600 } 10601 10602 /** 10603 * Generates a NotificationRankingUpdate from 'sbns', considering only 10604 * notifications visible to the given listener. 10605 */ 10606 @GuardedBy("mNotificationLock") 10607 NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 10608 final int N = mNotificationList.size(); 10609 final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>(); 10610 10611 for (int i = 0; i < N; i++) { 10612 NotificationRecord record = mNotificationList.get(i); 10613 if (isInLockDownMode(record.getUser().getIdentifier())) { 10614 continue; 10615 } 10616 if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) { 10617 continue; 10618 } 10619 final String key = record.getSbn().getKey(); 10620 final NotificationListenerService.Ranking ranking = 10621 new NotificationListenerService.Ranking(); 10622 ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions(); 10623 ArrayList<CharSequence> smartReplies = record.getSmartReplies(); 10624 if (redactSensitiveNotificationsFromUntrustedListeners() 10625 && info != null 10626 && !mListeners.isUidTrusted(info.uid) 10627 && mListeners.hasSensitiveContent(record)) { 10628 smartActions = null; 10629 smartReplies = null; 10630 } 10631 ranking.populate( 10632 key, 10633 rankings.size(), 10634 !record.isIntercepted(), 10635 record.getPackageVisibilityOverride(), 10636 record.getSuppressedVisualEffects(), 10637 record.getImportance(), 10638 record.getImportanceExplanation(), 10639 record.getSbn().getOverrideGroupKey(), 10640 record.getChannel(), 10641 record.getPeopleOverride(), 10642 record.getSnoozeCriteria(), 10643 record.canShowBadge(), 10644 record.getUserSentiment(), 10645 record.isHidden(), 10646 record.getLastAudiblyAlertedMs(), 10647 record.getSound() != null || record.getVibration() != null, 10648 smartActions, 10649 smartReplies, 10650 record.canBubble(), 10651 record.isTextChanged(), 10652 record.isConversation(), 10653 record.getShortcutInfo(), 10654 record.getRankingScore() == 0 10655 ? RANKING_UNCHANGED 10656 : (record.getRankingScore() > 0 ? RANKING_PROMOTED : RANKING_DEMOTED), 10657 record.getNotification().isBubbleNotification(), 10658 record.getProposedImportance(), 10659 record.hasSensitiveContent() 10660 ); 10661 rankings.add(ranking); 10662 } 10663 10664 return new NotificationRankingUpdate( 10665 rankings.toArray(new NotificationListenerService.Ranking[0])); 10666 } 10667 10668 boolean isInLockDownMode(int userId) { 10669 return mStrongAuthTracker.isInLockDownMode(userId); 10670 } 10671 10672 boolean hasCompanionDevice(ManagedServiceInfo info) { 10673 return hasCompanionDevice(info.component.getPackageName(), 10674 info.userid, /* withDeviceProfile= */ null); 10675 } 10676 10677 private boolean hasCompanionDevice(String pkg, @UserIdInt int userId, 10678 @Nullable Set</* @AssociationRequest.DeviceProfile */ String> withDeviceProfiles) { 10679 if (mCompanionManager == null) { 10680 mCompanionManager = getCompanionManager(); 10681 } 10682 // Companion mgr doesn't exist on all device types 10683 if (mCompanionManager == null) { 10684 return false; 10685 } 10686 final long identity = Binder.clearCallingIdentity(); 10687 try { 10688 List<AssociationInfo> associations = mCompanionManager.getAssociations(pkg, userId); 10689 for (AssociationInfo association : associations) { 10690 if (withDeviceProfiles == null || withDeviceProfiles.contains( 10691 association.getDeviceProfile())) { 10692 return true; 10693 } 10694 } 10695 } catch (SecurityException se) { 10696 // Not a privileged listener 10697 } catch (RemoteException re) { 10698 Slog.e(TAG, "Cannot reach companion device service", re); 10699 } catch (Exception e) { 10700 Slog.e(TAG, "Cannot verify caller pkg=" + pkg + ", userId=" + userId, e); 10701 } finally { 10702 Binder.restoreCallingIdentity(identity); 10703 } 10704 return false; 10705 } 10706 10707 protected ICompanionDeviceManager getCompanionManager() { 10708 return ICompanionDeviceManager.Stub.asInterface( 10709 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); 10710 } 10711 10712 @VisibleForTesting 10713 boolean isVisibleToListener(StatusBarNotification sbn, int notificationType, 10714 ManagedServiceInfo listener) { 10715 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 10716 return false; 10717 } 10718 if (!isInteractionVisibleToListener(listener, sbn.getUserId())) { 10719 return false; 10720 } 10721 NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey); 10722 if (nls != null 10723 && (!nls.isTypeAllowed(notificationType) 10724 || !nls.isPackageAllowed( 10725 new VersionedPackage(sbn.getPackageName(), sbn.getUid())))) { 10726 return false; 10727 } 10728 return true; 10729 } 10730 10731 /** 10732 * Returns whether the given assistant should be informed about interactions on the given user. 10733 * 10734 * Normally an assistant would be able to see all interactions on the current user and any 10735 * associated profiles because they are notification listeners, but since NASes have one 10736 * instance per user, we want to filter out interactions that are not for the user that the 10737 * given NAS is bound in. 10738 */ 10739 @VisibleForTesting 10740 boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) { 10741 boolean isAssistantService = isServiceTokenValid(info.getService()); 10742 return !isAssistantService || info.isSameUser(userId); 10743 } 10744 10745 private boolean isServiceTokenValid(IInterface service) { 10746 synchronized (mNotificationLock) { 10747 return mAssistants.isServiceTokenValidLocked(service); 10748 } 10749 } 10750 10751 private boolean isPackageSuspendedForUser(String pkg, int uid) { 10752 final long identity = Binder.clearCallingIdentity(); 10753 int userId = UserHandle.getUserId(uid); 10754 try { 10755 return mPackageManager.isPackageSuspendedForUser(pkg, userId); 10756 } catch (RemoteException re) { 10757 throw new SecurityException("Could not talk to package manager service"); 10758 } catch (IllegalArgumentException ex) { 10759 // Package not found. 10760 return false; 10761 } finally { 10762 Binder.restoreCallingIdentity(identity); 10763 } 10764 } 10765 10766 @VisibleForTesting 10767 boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) { 10768 boolean canUseManagedServices = true; 10769 if (requiredPermission != null) { 10770 try { 10771 if (mPackageManager.checkPermission(requiredPermission, pkg, userId) 10772 != PERMISSION_GRANTED) { 10773 canUseManagedServices = false; 10774 } 10775 } catch (RemoteException e) { 10776 Slog.e(TAG, "can't talk to pm", e); 10777 } 10778 } 10779 10780 return canUseManagedServices; 10781 } 10782 10783 private class TrimCache { 10784 StatusBarNotification heavy; 10785 StatusBarNotification sbnClone; 10786 StatusBarNotification sbnCloneLight; 10787 10788 TrimCache(StatusBarNotification sbn) { 10789 heavy = sbn; 10790 } 10791 10792 StatusBarNotification ForListener(ManagedServiceInfo info) { 10793 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 10794 if (sbnCloneLight == null) { 10795 sbnCloneLight = heavy.cloneLight(); 10796 } 10797 return sbnCloneLight; 10798 } else { 10799 if (sbnClone == null) { 10800 sbnClone = heavy.clone(); 10801 } 10802 return sbnClone; 10803 } 10804 } 10805 } 10806 10807 public class NotificationAssistants extends ManagedServices { 10808 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants"; 10809 10810 private static final String ATT_TYPES = "types"; 10811 10812 private final Object mLock = new Object(); 10813 10814 @GuardedBy("mLock") 10815 private Set<String> mAllowedAdjustments = new ArraySet<>(); 10816 10817 protected ComponentName mDefaultFromConfig = null; 10818 10819 @Override 10820 protected void loadDefaultsFromConfig() { 10821 loadDefaultsFromConfig(true); 10822 } 10823 10824 protected void loadDefaultsFromConfig(boolean addToDefault) { 10825 ArraySet<String> assistants = new ArraySet<>(); 10826 assistants.addAll(Arrays.asList(mContext.getResources().getString( 10827 com.android.internal.R.string.config_defaultAssistantAccessComponent) 10828 .split(ManagedServices.ENABLED_SERVICES_SEPARATOR))); 10829 for (int i = 0; i < assistants.size(); i++) { 10830 ComponentName assistantCn = ComponentName 10831 .unflattenFromString(assistants.valueAt(i)); 10832 String packageName = assistants.valueAt(i); 10833 if (assistantCn != null) { 10834 packageName = assistantCn.getPackageName(); 10835 } 10836 if (TextUtils.isEmpty(packageName)) { 10837 continue; 10838 } 10839 ArraySet<ComponentName> approved = queryPackageForServices(packageName, 10840 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM); 10841 if (approved.contains(assistantCn)) { 10842 if (addToDefault) { 10843 // add the default loaded from config file to mDefaultComponents and 10844 // mDefaultPackages 10845 addDefaultComponentOrPackage(assistantCn.flattenToString()); 10846 } else { 10847 // otherwise, store in the mDefaultFromConfig for NAS settings migration 10848 mDefaultFromConfig = assistantCn; 10849 } 10850 } 10851 } 10852 } 10853 10854 ComponentName getDefaultFromConfig() { 10855 if (mDefaultFromConfig == null) { 10856 loadDefaultsFromConfig(false); 10857 } 10858 return mDefaultFromConfig; 10859 } 10860 10861 @Override 10862 protected void upgradeUserSet() { 10863 for (int userId: mApproved.keySet()) { 10864 ArraySet<String> userSetServices = mUserSetServices.get(userId); 10865 mIsUserChanged.put(userId, (userSetServices != null && userSetServices.size() > 0)); 10866 } 10867 } 10868 10869 @Override 10870 protected void addApprovedList(String approved, int userId, boolean isPrimary, 10871 String userSet) { 10872 if (!TextUtils.isEmpty(approved)) { 10873 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR); 10874 if (approvedArray.length > 1) { 10875 Slog.d(TAG, "More than one approved assistants"); 10876 approved = approvedArray[0]; 10877 } 10878 } 10879 super.addApprovedList(approved, userId, isPrimary, userSet); 10880 } 10881 10882 public NotificationAssistants(Context context, Object lock, UserProfiles up, 10883 IPackageManager pm) { 10884 super(context, lock, up, pm); 10885 10886 // Add all default allowed adjustment types. 10887 for (int i = 0; i < ALLOWED_ADJUSTMENTS.length; i++) { 10888 mAllowedAdjustments.add(ALLOWED_ADJUSTMENTS[i]); 10889 } 10890 } 10891 10892 @Override 10893 protected Config getConfig() { 10894 Config c = new Config(); 10895 c.caption = "notification assistant"; 10896 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; 10897 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS; 10898 c.secureSettingName = Secure.ENABLED_NOTIFICATION_ASSISTANT; 10899 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; 10900 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 10901 c.clientLabel = R.string.notification_ranker_binding_label; 10902 return c; 10903 } 10904 10905 @Override 10906 protected IInterface asInterface(IBinder binder) { 10907 return INotificationListener.Stub.asInterface(binder); 10908 } 10909 10910 @Override 10911 protected boolean checkType(IInterface service) { 10912 return service instanceof INotificationListener; 10913 } 10914 10915 @Override 10916 protected void onServiceAdded(ManagedServiceInfo info) { 10917 mListeners.registerGuestService(info); 10918 } 10919 10920 @Override 10921 protected void ensureFilters(ServiceInfo si, int userId) { 10922 // nothing to filter; no user visible settings for types/packages like other 10923 // listeners 10924 } 10925 10926 @Override 10927 @GuardedBy("mNotificationLock") 10928 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 10929 mListeners.unregisterService(removed.service, removed.userid); 10930 } 10931 10932 @Override 10933 public void onUserUnlocked(int user) { 10934 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); 10935 // force rebind the assistant, as it might be keeping its own state in user locked 10936 // storage 10937 rebindServices(true, user); 10938 } 10939 10940 @Override 10941 protected boolean allowRebindForParentUser() { 10942 return false; 10943 } 10944 10945 @Override 10946 protected String getRequiredPermission() { 10947 // only signature/privileged apps can be bound. 10948 return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE; 10949 } 10950 10951 protected List<String> getAllowedAssistantAdjustments() { 10952 synchronized (mLock) { 10953 List<String> types = new ArrayList<>(); 10954 types.addAll(mAllowedAdjustments); 10955 return types; 10956 } 10957 } 10958 10959 protected boolean isAdjustmentAllowed(String type) { 10960 synchronized (mLock) { 10961 return mAllowedAdjustments.contains(type); 10962 } 10963 } 10964 10965 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) { 10966 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 10967 ArrayList<String> keys = new ArrayList<>(records.size()); 10968 for (NotificationRecord r : records) { 10969 boolean sbnVisible = isVisibleToListener( 10970 r.getSbn(), r.getNotificationType(), info) 10971 && info.isSameUser(r.getUserId()); 10972 if (sbnVisible) { 10973 keys.add(r.getKey()); 10974 } 10975 } 10976 10977 if (!keys.isEmpty()) { 10978 mHandler.post(() -> notifySeen(info, keys)); 10979 } 10980 } 10981 } 10982 10983 protected void onPanelRevealed(int items) { 10984 // send to all currently bounds NASes since notifications from both users will appear in 10985 // the panel 10986 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 10987 mHandler.post(() -> { 10988 final INotificationListener assistant = (INotificationListener) info.service; 10989 try { 10990 assistant.onPanelRevealed(items); 10991 } catch (RemoteException ex) { 10992 Slog.e(TAG, "unable to notify assistant (panel revealed): " + info, ex); 10993 } 10994 }); 10995 } 10996 } 10997 10998 protected void onPanelHidden() { 10999 // send to all currently bounds NASes since notifications from both users will appear in 11000 // the panel 11001 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 11002 mHandler.post(() -> { 11003 final INotificationListener assistant = (INotificationListener) info.service; 11004 try { 11005 assistant.onPanelHidden(); 11006 } catch (RemoteException ex) { 11007 Slog.e(TAG, "unable to notify assistant (panel hidden): " + info, ex); 11008 } 11009 }); 11010 } 11011 } 11012 11013 boolean hasUserSet(int userId) { 11014 Boolean userSet = mIsUserChanged.get(userId); 11015 return (userSet != null && userSet); 11016 } 11017 11018 void setUserSet(int userId, boolean set) { 11019 mIsUserChanged.put(userId, set); 11020 } 11021 11022 private void notifySeen(final ManagedServiceInfo info, 11023 final ArrayList<String> keys) { 11024 final INotificationListener assistant = (INotificationListener) info.service; 11025 try { 11026 assistant.onNotificationsSeen(keys); 11027 } catch (RemoteException ex) { 11028 Slog.e(TAG, "unable to notify assistant (seen): " + info, ex); 11029 } 11030 } 11031 11032 @GuardedBy("mNotificationLock") 11033 private void onNotificationEnqueuedLocked(final NotificationRecord r) { 11034 final boolean debug = isVerboseLogEnabled(); 11035 if (debug) { 11036 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]"); 11037 } 11038 final StatusBarNotification sbn = r.getSbn(); 11039 11040 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 11041 boolean sbnVisible = isVisibleToListener( 11042 sbn, r.getNotificationType(), info) 11043 && info.isSameUser(r.getUserId()); 11044 if (sbnVisible) { 11045 TrimCache trimCache = new TrimCache(sbn); 11046 final INotificationListener assistant = (INotificationListener) info.service; 11047 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 11048 final StatusBarNotificationHolder sbnHolder = 11049 new StatusBarNotificationHolder(sbnToPost); 11050 try { 11051 if (debug) { 11052 Slog.v(TAG, 11053 "calling onNotificationEnqueuedWithChannel " + sbnHolder); 11054 } 11055 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 11056 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(), 11057 update); 11058 } catch (RemoteException ex) { 11059 Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); 11060 } 11061 } 11062 } 11063 } 11064 11065 @GuardedBy("mNotificationLock") 11066 void notifyAssistantVisibilityChangedLocked( 11067 final NotificationRecord r, 11068 final boolean isVisible) { 11069 final String key = r.getSbn().getKey(); 11070 if (DBG) { 11071 Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key); 11072 } 11073 notifyAssistantLocked( 11074 r.getSbn(), 11075 r.getNotificationType(), 11076 true /* sameUserOnly */, 11077 (assistant, sbnHolder) -> { 11078 try { 11079 assistant.onNotificationVisibilityChanged(key, isVisible); 11080 } catch (RemoteException ex) { 11081 Slog.e(TAG, "unable to notify assistant (visible): " + assistant, ex); 11082 } 11083 }); 11084 } 11085 11086 @GuardedBy("mNotificationLock") 11087 void notifyAssistantExpansionChangedLocked( 11088 final StatusBarNotification sbn, 11089 final int notificationType, 11090 final boolean isUserAction, 11091 final boolean isExpanded) { 11092 final String key = sbn.getKey(); 11093 notifyAssistantLocked( 11094 sbn, 11095 notificationType, 11096 true /* sameUserOnly */, 11097 (assistant, sbnHolder) -> { 11098 try { 11099 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded); 11100 } catch (RemoteException ex) { 11101 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 11102 } 11103 }); 11104 } 11105 11106 @GuardedBy("mNotificationLock") 11107 void notifyAssistantNotificationDirectReplyLocked( 11108 final NotificationRecord r) { 11109 final String key = r.getKey(); 11110 notifyAssistantLocked( 11111 r.getSbn(), 11112 r.getNotificationType(), 11113 true /* sameUserOnly */, 11114 (assistant, sbnHolder) -> { 11115 try { 11116 assistant.onNotificationDirectReply(key); 11117 } catch (RemoteException ex) { 11118 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 11119 } 11120 }); 11121 } 11122 11123 @GuardedBy("mNotificationLock") 11124 void notifyAssistantSuggestedReplySent( 11125 final StatusBarNotification sbn, int notificationType, 11126 CharSequence reply, boolean generatedByAssistant) { 11127 final String key = sbn.getKey(); 11128 notifyAssistantLocked( 11129 sbn, 11130 notificationType, 11131 true /* sameUserOnly */, 11132 (assistant, sbnHolder) -> { 11133 try { 11134 assistant.onSuggestedReplySent( 11135 key, 11136 reply, 11137 generatedByAssistant 11138 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 11139 : NotificationAssistantService.SOURCE_FROM_APP); 11140 } catch (RemoteException ex) { 11141 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 11142 } 11143 }); 11144 } 11145 11146 @GuardedBy("mNotificationLock") 11147 void notifyAssistantActionClicked( 11148 final NotificationRecord r, Notification.Action action, 11149 boolean generatedByAssistant) { 11150 final String key = r.getSbn().getKey(); 11151 notifyAssistantLocked( 11152 r.getSbn(), 11153 r.getNotificationType(), 11154 true /* sameUserOnly */, 11155 (assistant, sbnHolder) -> { 11156 try { 11157 assistant.onActionClicked( 11158 key, 11159 action, 11160 generatedByAssistant 11161 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 11162 : NotificationAssistantService.SOURCE_FROM_APP); 11163 } catch (RemoteException ex) { 11164 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 11165 } 11166 }); 11167 } 11168 11169 /** 11170 * asynchronously notify the assistant that a notification has been snoozed until a 11171 * context 11172 */ 11173 @GuardedBy("mNotificationLock") 11174 private void notifyAssistantSnoozedLocked( 11175 final NotificationRecord r, final String snoozeCriterionId) { 11176 notifyAssistantLocked( 11177 r.getSbn(), 11178 r.getNotificationType(), 11179 true /* sameUserOnly */, 11180 (assistant, sbnHolder) -> { 11181 try { 11182 assistant.onNotificationSnoozedUntilContext( 11183 sbnHolder, snoozeCriterionId); 11184 } catch (RemoteException ex) { 11185 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 11186 } 11187 }); 11188 } 11189 11190 @GuardedBy("mNotificationLock") 11191 void notifyAssistantNotificationClicked(final NotificationRecord r) { 11192 final String key = r.getSbn().getKey(); 11193 notifyAssistantLocked( 11194 r.getSbn(), 11195 r.getNotificationType(), 11196 true /* sameUserOnly */, 11197 (assistant, sbnHolder) -> { 11198 try { 11199 assistant.onNotificationClicked(key); 11200 } catch (RemoteException ex) { 11201 Slog.e(TAG, "unable to notify assistant (clicked): " + assistant, ex); 11202 } 11203 }); 11204 } 11205 11206 @GuardedBy("mNotificationLock") 11207 void notifyAssistantFeedbackReceived(final NotificationRecord r, Bundle feedback) { 11208 final StatusBarNotification sbn = r.getSbn(); 11209 11210 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 11211 boolean sbnVisible = isVisibleToListener( 11212 sbn, r.getNotificationType(), info) 11213 && info.isSameUser(r.getUserId()); 11214 if (sbnVisible) { 11215 final INotificationListener assistant = (INotificationListener) info.service; 11216 try { 11217 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 11218 assistant.onNotificationFeedbackReceived(sbn.getKey(), update, feedback); 11219 } catch (RemoteException ex) { 11220 Slog.e(TAG, "unable to notify assistant (feedback): " + assistant, ex); 11221 } 11222 } 11223 } 11224 } 11225 11226 /** 11227 * Notifies the assistant something about the specified notification, only assistant 11228 * that is visible to the notification will be notified. 11229 * 11230 * @param sbn the notification object that the update is about. 11231 * @param sameUserOnly should the update be sent to the assistant in the same user only. 11232 * @param callback the callback that provides the assistant to be notified, executed 11233 * in WorkerHandler. 11234 */ 11235 @GuardedBy("mNotificationLock") 11236 private void notifyAssistantLocked( 11237 final StatusBarNotification sbn, 11238 int notificationType, 11239 boolean sameUserOnly, 11240 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) { 11241 TrimCache trimCache = new TrimCache(sbn); 11242 // There should be only one, but it's a list, so while we enforce 11243 // singularity elsewhere, we keep it general here, to avoid surprises. 11244 11245 final boolean debug = isVerboseLogEnabled(); 11246 if (debug) { 11247 Slog.v(TAG, 11248 "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = [" 11249 + sameUserOnly + "], callback = [" + callback + "]"); 11250 } 11251 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 11252 boolean sbnVisible = isVisibleToListener(sbn, notificationType, info) 11253 && (!sameUserOnly || info.isSameUser(sbn.getUserId())); 11254 if (debug) { 11255 Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible); 11256 } 11257 if (!sbnVisible) { 11258 continue; 11259 } 11260 final INotificationListener assistant = (INotificationListener) info.service; 11261 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 11262 final StatusBarNotificationHolder sbnHolder = 11263 new StatusBarNotificationHolder(sbnToPost); 11264 mHandler.post(() -> callback.accept(assistant, sbnHolder)); 11265 } 11266 } 11267 11268 public boolean isEnabled() { 11269 return !getServices().isEmpty(); 11270 } 11271 11272 protected void resetDefaultAssistantsIfNecessary() { 11273 final List<UserInfo> activeUsers = mUm.getAliveUsers(); 11274 for (UserInfo userInfo : activeUsers) { 11275 int userId = userInfo.getUserHandle().getIdentifier(); 11276 if (!hasUserSet(userId)) { 11277 if (!isNASMigrationDone(userId)) { 11278 resetDefaultFromConfig(); 11279 setNASMigrationDone(userId); 11280 } 11281 Slog.d(TAG, "Approving default notification assistant for user " + userId); 11282 setDefaultAssistantForUser(userId); 11283 } 11284 } 11285 } 11286 11287 protected void resetDefaultFromConfig() { 11288 clearDefaults(); 11289 loadDefaultsFromConfig(); 11290 } 11291 11292 protected void clearDefaults() { 11293 mDefaultComponents.clear(); 11294 mDefaultPackages.clear(); 11295 } 11296 11297 @Override 11298 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, 11299 boolean isPrimary, boolean enabled, boolean userSet) { 11300 // Ensures that only one component is enabled at a time 11301 if (enabled) { 11302 List<ComponentName> allowedComponents = getAllowedComponents(userId); 11303 if (!allowedComponents.isEmpty()) { 11304 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents); 11305 if (currentComponent.flattenToString().equals(pkgOrComponent)) return; 11306 setNotificationAssistantAccessGrantedForUserInternal( 11307 currentComponent, userId, false, userSet); 11308 } 11309 } 11310 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet); 11311 } 11312 11313 private boolean isVerboseLogEnabled() { 11314 return Log.isLoggable("notification_assistant", Log.VERBOSE); 11315 } 11316 } 11317 11318 /** 11319 * Asynchronously notify all listeners about a posted (new or updated) notification. This 11320 * should be called from {@link PostNotificationRunnable} to "complete" the post (since SysUI is 11321 * one of the NLSes, and will display it to the user). 11322 * 11323 * <p>This method will call {@link PostNotificationTracker#finish} on the supplied tracker 11324 * when every {@link NotificationListenerService} has received the news. 11325 * 11326 * <p>Also takes care of removing a notification that has been visible to a listener before, 11327 * but isn't anymore. 11328 */ 11329 @GuardedBy("mNotificationLock") 11330 private void notifyListenersPostedAndLogLocked(NotificationRecord r, NotificationRecord old, 11331 @NonNull PostNotificationTracker tracker, 11332 @Nullable NotificationRecordLogger.NotificationReported report) { 11333 List<Runnable> listenerCalls = mListeners.prepareNotifyPostedLocked(r, old, true); 11334 mHandler.post(() -> { 11335 for (Runnable listenerCall : listenerCalls) { 11336 listenerCall.run(); 11337 } 11338 11339 long postDurationMillis = tracker.finish(); 11340 if (report != null) { 11341 report.post_duration_millis = postDurationMillis; 11342 mNotificationRecordLogger.logNotificationPosted(report); 11343 } 11344 }); 11345 11346 if (callstyleCallbackApi()) { 11347 notifyCallNotificationEventListenerOnPosted(r); 11348 } 11349 } 11350 11351 @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR) 11352 @GuardedBy("mNotificationLock") 11353 private void maybeNotifySystemUiListenerLifetimeExtendedListLocked( 11354 List<NotificationRecord> notificationList, int packageImportance) { 11355 for (int i = notificationList.size() - 1; i >= 0; --i) { 11356 NotificationRecord record = notificationList.get(i); 11357 maybeNotifySystemUiListenerLifetimeExtendedLocked(record, 11358 record.getSbn().getPackageName(), packageImportance); 11359 } 11360 } 11361 11362 @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR) 11363 @GuardedBy("mNotificationLock") 11364 private void maybeNotifySystemUiListenerLifetimeExtendedLocked(NotificationRecord record, 11365 String pkg, int packageImportance) { 11366 if (record != null && (record.getSbn().getNotification().flags 11367 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) { 11368 boolean isAppForeground = pkg != null && packageImportance == IMPORTANCE_FOREGROUND; 11369 11370 // Lifetime extended notifications don't need to alert on state change. 11371 record.setPostSilently(true); 11372 // We also set FLAG_ONLY_ALERT_ONCE to avoid the notification from HUN-ing again. 11373 record.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 11374 11375 mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(), 11376 record, isAppForeground, 11377 mPostNotificationTrackerFactory.newTracker(null))); 11378 } 11379 } 11380 11381 @FlaggedApi(FLAG_LIFETIME_EXTENSION_REFACTOR) 11382 private int getPackageImportanceWithIdentity(String pkg) { 11383 final long token = Binder.clearCallingIdentity(); 11384 final int packageImportance; 11385 try { 11386 packageImportance = mActivityManager.getPackageImportance(pkg); 11387 } finally { 11388 Binder.restoreCallingIdentity(token); 11389 } 11390 return packageImportance; 11391 } 11392 11393 public class NotificationListeners extends ManagedServices { 11394 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners"; 11395 static final String TAG_REQUESTED_LISTENERS = "request_listeners"; 11396 static final String TAG_REQUESTED_LISTENER = "listener"; 11397 static final String ATT_COMPONENT = "component"; 11398 static final String ATT_TYPES = "types"; 11399 static final String ATT_PKG = "pkg"; 11400 static final String ATT_UID = "uid"; 11401 static final String TAG_APPROVED = "allowed"; 11402 static final String TAG_DISALLOWED= "disallowed"; 11403 static final String XML_SEPARATOR = ","; 11404 static final String FLAG_SEPARATOR = "\\|"; 11405 11406 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 11407 11408 @GuardedBy("mTrustedListenerUids") 11409 private final ArraySet<Integer> mTrustedListenerUids = new ArraySet<>(); 11410 @GuardedBy("mRequestedNotificationListeners") 11411 private final ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter> 11412 mRequestedNotificationListeners = new ArrayMap<>(); 11413 private final boolean mIsHeadlessSystemUserMode; 11414 11415 public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, 11416 IPackageManager pm) { 11417 this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode()); 11418 } 11419 11420 @VisibleForTesting 11421 public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, 11422 IPackageManager pm, boolean isHeadlessSystemUserMode) { 11423 super(context, lock, userProfiles, pm); 11424 this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode; 11425 } 11426 11427 @Override 11428 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, 11429 boolean isPrimary, boolean enabled, boolean userSet) { 11430 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet); 11431 String pkgName = getPackageName(pkgOrComponent); 11432 if (redactSensitiveNotificationsFromUntrustedListeners()) { 11433 int uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId); 11434 if (!enabled && uid >= 0) { 11435 synchronized (mTrustedListenerUids) { 11436 mTrustedListenerUids.remove(uid); 11437 } 11438 } 11439 if (enabled && uid >= 0 && isAppTrustedNotificationListenerService(uid, pkgName)) { 11440 synchronized (mTrustedListenerUids) { 11441 mTrustedListenerUids.add(uid); 11442 } 11443 } 11444 } 11445 11446 mContext.sendBroadcastAsUser( 11447 new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED) 11448 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 11449 UserHandle.of(userId), null); 11450 } 11451 11452 @Override 11453 protected void loadDefaultsFromConfig() { 11454 String defaultListenerAccess = mContext.getResources().getString( 11455 R.string.config_defaultListenerAccessPackages); 11456 if (defaultListenerAccess != null) { 11457 String[] listeners = 11458 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR); 11459 for (int i = 0; i < listeners.length; i++) { 11460 if (TextUtils.isEmpty(listeners[i])) { 11461 continue; 11462 } 11463 int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; 11464 // In the headless system user mode, packages might not be installed for the 11465 // system user. Match packages for any user since apps can be installed only for 11466 // non-system users and would be considering uninstalled for the system user. 11467 if (mIsHeadlessSystemUserMode) { 11468 packageQueryFlags += MATCH_ANY_USER; 11469 } 11470 ArraySet<ComponentName> approvedListeners = 11471 this.queryPackageForServices(listeners[i], packageQueryFlags, 11472 USER_SYSTEM); 11473 for (int k = 0; k < approvedListeners.size(); k++) { 11474 ComponentName cn = approvedListeners.valueAt(k); 11475 addDefaultComponentOrPackage(cn.flattenToString()); 11476 } 11477 } 11478 } 11479 } 11480 11481 @Override 11482 protected int getBindFlags() { 11483 // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE 11484 // because too many 3P apps could be kept in memory as notification listeners and 11485 // cause extreme memory pressure. 11486 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation. 11487 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE 11488 | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT; 11489 } 11490 11491 @Override 11492 protected Config getConfig() { 11493 Config c = new Config(); 11494 c.caption = "notification listener"; 11495 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 11496 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS; 11497 c.secureSettingName = Secure.ENABLED_NOTIFICATION_LISTENERS; 11498 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 11499 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 11500 c.clientLabel = R.string.notification_listener_binding_label; 11501 return c; 11502 } 11503 11504 @Override 11505 protected IInterface asInterface(IBinder binder) { 11506 return INotificationListener.Stub.asInterface(binder); 11507 } 11508 11509 @Override 11510 protected boolean checkType(IInterface service) { 11511 return service instanceof INotificationListener; 11512 } 11513 11514 @Override 11515 public void onServiceAdded(ManagedServiceInfo info) { 11516 if (lifetimeExtensionRefactor()) { 11517 // Generally, only System or System UI should have the permissions to call 11518 // registerSystemService. 11519 // isCallerSystemOrPhone tells us whether the caller is System. We negate this, 11520 // to eliminate cases where the service was added by the system. This leaves 11521 // services registered by system server. 11522 // To identify system UI, we explicitly check the status bar permission for the 11523 // uid in the info object. 11524 // We can't use the calling uid here because it belongs to system server. 11525 // Note that this will also return true for the shell, but we deem this 11526 // acceptable, for the purposes of testing. 11527 info.isSystemUi = !isCallerSystemOrPhone() && getContext().checkPermission( 11528 android.Manifest.permission.STATUS_BAR_SERVICE, -1, info.uid) 11529 == PERMISSION_GRANTED; 11530 } 11531 final INotificationListener listener = (INotificationListener) info.service; 11532 final NotificationRankingUpdate update; 11533 synchronized (mNotificationLock) { 11534 update = makeRankingUpdateLocked(info); 11535 updateUriPermissionsForActiveNotificationsLocked(info, true); 11536 } 11537 if (redactSensitiveNotificationsFromUntrustedListeners() 11538 && isAppTrustedNotificationListenerService( 11539 info.uid, info.component.getPackageName())) { 11540 synchronized (mTrustedListenerUids) { 11541 mTrustedListenerUids.add(info.uid); 11542 } 11543 } 11544 try { 11545 listener.onListenerConnected(update); 11546 } catch (RemoteException e) { 11547 // we tried 11548 } 11549 } 11550 11551 @Override 11552 @GuardedBy("mNotificationLock") 11553 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 11554 updateUriPermissionsForActiveNotificationsLocked(removed, false); 11555 if (removeDisabledHints(removed)) { 11556 updateListenerHintsLocked(); 11557 updateEffectsSuppressorLocked(); 11558 } 11559 if (redactSensitiveNotificationsFromUntrustedListeners()) { 11560 synchronized (mTrustedListenerUids) { 11561 mTrustedListenerUids.remove(removed.uid); 11562 } 11563 } 11564 mLightTrimListeners.remove(removed); 11565 } 11566 11567 @Override 11568 public void onUserRemoved(int user) { 11569 super.onUserRemoved(user); 11570 synchronized (mRequestedNotificationListeners) { 11571 for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) { 11572 if (mRequestedNotificationListeners.keyAt(i).second == user) { 11573 mRequestedNotificationListeners.removeAt(i); 11574 } 11575 } 11576 } 11577 } 11578 11579 @Override 11580 protected boolean allowRebindForParentUser() { 11581 return true; 11582 } 11583 11584 @Override 11585 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) { 11586 super.onPackagesChanged(removingPackage, pkgList, uidList); 11587 11588 synchronized (mRequestedNotificationListeners) { 11589 // Since the default behavior is to allow everything, we don't need to explicitly 11590 // handle package add or update. they will be added to the xml file on next boot or 11591 // when the user tries to change the settings. 11592 if (removingPackage) { 11593 for (int i = 0; i < pkgList.length; i++) { 11594 String pkg = pkgList[i]; 11595 int userId = UserHandle.getUserId(uidList[i]); 11596 for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { 11597 Pair<ComponentName, Integer> key = 11598 mRequestedNotificationListeners.keyAt(j); 11599 if (key.second == userId && key.first.getPackageName().equals(pkg)) { 11600 mRequestedNotificationListeners.removeAt(j); 11601 } 11602 } 11603 } 11604 11605 // Clean up removed package from the disallowed packages list 11606 for (int i = 0; i < pkgList.length; i++) { 11607 String pkg = pkgList[i]; 11608 for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { 11609 NotificationListenerFilter nlf = 11610 mRequestedNotificationListeners.valueAt(j); 11611 VersionedPackage ai = new VersionedPackage(pkg, uidList[i]); 11612 nlf.removePackage(ai); 11613 } 11614 } 11615 } 11616 } 11617 } 11618 11619 @Override 11620 protected String getRequiredPermission() { 11621 return null; 11622 } 11623 11624 @Override 11625 protected boolean shouldReflectToSettings() { 11626 // androidx has a public method that reads the approved set of listeners from 11627 // Settings so we have to continue writing this list for this type of service 11628 return true; 11629 } 11630 11631 @Override 11632 protected void readExtraTag(String tag, TypedXmlPullParser parser) 11633 throws IOException, XmlPullParserException { 11634 if (TAG_REQUESTED_LISTENERS.equals(tag)) { 11635 final int listenersOuterDepth = parser.getDepth(); 11636 while (XmlUtils.nextElementWithin(parser, listenersOuterDepth)) { 11637 if (!TAG_REQUESTED_LISTENER.equals(parser.getName())) { 11638 continue; 11639 } 11640 final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID); 11641 final ComponentName cn = ComponentName.unflattenFromString( 11642 XmlUtils.readStringAttribute(parser, ATT_COMPONENT)); 11643 int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING 11644 | FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING; 11645 11646 ArraySet<VersionedPackage> disallowedPkgs = new ArraySet<>(); 11647 final int listenerOuterDepth = parser.getDepth(); 11648 while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) { 11649 if (TAG_APPROVED.equals(parser.getName())) { 11650 approved = XmlUtils.readIntAttribute(parser, ATT_TYPES); 11651 } else if (TAG_DISALLOWED.equals(parser.getName())) { 11652 String pkg = XmlUtils.readStringAttribute(parser, ATT_PKG); 11653 int uid = XmlUtils.readIntAttribute(parser, ATT_UID); 11654 if (!TextUtils.isEmpty(pkg)) { 11655 VersionedPackage ai = new VersionedPackage(pkg, uid); 11656 disallowedPkgs.add(ai); 11657 } 11658 } 11659 } 11660 NotificationListenerFilter nlf = 11661 new NotificationListenerFilter(approved, disallowedPkgs); 11662 synchronized (mRequestedNotificationListeners) { 11663 mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf); 11664 } 11665 } 11666 } 11667 } 11668 11669 @Override 11670 protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException { 11671 out.startTag(null, TAG_REQUESTED_LISTENERS); 11672 synchronized (mRequestedNotificationListeners) { 11673 for (Pair<ComponentName, Integer> listener : 11674 mRequestedNotificationListeners.keySet()) { 11675 NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener); 11676 out.startTag(null, TAG_REQUESTED_LISTENER); 11677 XmlUtils.writeStringAttribute( 11678 out, ATT_COMPONENT, listener.first.flattenToString()); 11679 XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second); 11680 11681 out.startTag(null, TAG_APPROVED); 11682 XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes()); 11683 out.endTag(null, TAG_APPROVED); 11684 11685 for (VersionedPackage ai : nlf.getDisallowedPackages()) { 11686 if (!TextUtils.isEmpty(ai.getPackageName())) { 11687 out.startTag(null, TAG_DISALLOWED); 11688 XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName()); 11689 XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode()); 11690 out.endTag(null, TAG_DISALLOWED); 11691 } 11692 } 11693 11694 out.endTag(null, TAG_REQUESTED_LISTENER); 11695 } 11696 } 11697 11698 out.endTag(null, TAG_REQUESTED_LISTENERS); 11699 } 11700 11701 @Nullable protected NotificationListenerFilter getNotificationListenerFilter( 11702 Pair<ComponentName, Integer> pair) { 11703 synchronized (mRequestedNotificationListeners) { 11704 return mRequestedNotificationListeners.get(pair); 11705 } 11706 } 11707 11708 protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair, 11709 NotificationListenerFilter nlf) { 11710 synchronized (mRequestedNotificationListeners) { 11711 mRequestedNotificationListeners.put(pair, nlf); 11712 } 11713 } 11714 11715 @Override 11716 protected void ensureFilters(ServiceInfo si, int userId) { 11717 Pair<ComponentName, Integer> listener = Pair.create(si.getComponentName(), userId); 11718 synchronized (mRequestedNotificationListeners) { 11719 NotificationListenerFilter existingNlf = 11720 mRequestedNotificationListeners.get(listener); 11721 if (si.metaData != null) { 11722 if (existingNlf == null) { 11723 // no stored filters for this listener; see if they provided a default 11724 if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) { 11725 String typeList = 11726 si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString(); 11727 if (typeList != null) { 11728 int types = getTypesFromStringList(typeList); 11729 NotificationListenerFilter nlf = 11730 new NotificationListenerFilter(types, new ArraySet<>()); 11731 mRequestedNotificationListeners.put(listener, nlf); 11732 } 11733 } 11734 } 11735 11736 // also check the types they never want bridged 11737 if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) { 11738 int neverBridge = getTypesFromStringList(si.metaData.get( 11739 META_DATA_DISABLED_FILTER_TYPES).toString()); 11740 if (neverBridge != 0) { 11741 NotificationListenerFilter nlf = 11742 mRequestedNotificationListeners.getOrDefault( 11743 listener, new NotificationListenerFilter()); 11744 nlf.setTypes(nlf.getTypes() & ~neverBridge); 11745 mRequestedNotificationListeners.put(listener, nlf); 11746 } 11747 } 11748 } 11749 } 11750 } 11751 11752 private int getTypesFromStringList(String typeList) { 11753 int types = 0; 11754 if (typeList != null) { 11755 String[] typeStrings = typeList.split(FLAG_SEPARATOR); 11756 for (int i = 0; i < typeStrings.length; i++) { 11757 final String typeString = typeStrings[i]; 11758 if (TextUtils.isEmpty(typeString)) { 11759 continue; 11760 } 11761 if (typeString.equalsIgnoreCase("ONGOING")) { 11762 types |= FLAG_FILTER_TYPE_ONGOING; 11763 } else if (typeString.equalsIgnoreCase("CONVERSATIONS")) { 11764 types |= FLAG_FILTER_TYPE_CONVERSATIONS; 11765 } else if (typeString.equalsIgnoreCase("SILENT")) { 11766 types |= FLAG_FILTER_TYPE_SILENT; 11767 } else if (typeString.equalsIgnoreCase("ALERTING")) { 11768 types |= FLAG_FILTER_TYPE_ALERTING; 11769 } else { 11770 try { 11771 types |= Integer.parseInt(typeString); 11772 } catch (NumberFormatException e) { 11773 // skip 11774 } 11775 } 11776 } 11777 } 11778 return types; 11779 } 11780 11781 @GuardedBy("mNotificationLock") 11782 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 11783 if (trim == TRIM_LIGHT) { 11784 mLightTrimListeners.add(info); 11785 } else { 11786 mLightTrimListeners.remove(info); 11787 } 11788 } 11789 11790 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 11791 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 11792 } 11793 11794 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { 11795 // send to all currently bounds NASes since notifications from both users will appear in 11796 // the status bar 11797 for (final ManagedServiceInfo info : getServices()) { 11798 mHandler.post(() -> { 11799 final INotificationListener listener = (INotificationListener) info.service; 11800 try { 11801 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons); 11802 } catch (RemoteException ex) { 11803 Slog.e(TAG, "unable to notify listener " 11804 + "(hideSilentStatusIcons): " + info, ex); 11805 } 11806 }); 11807 } 11808 } 11809 11810 /** 11811 * Asynchronously notify all listeners about a new or updated notification. Note that the 11812 * notification is new or updated from the point of view of the NLS, but might not be 11813 * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method 11814 * is also invoked after exiting lockdown mode. 11815 * 11816 * <p> 11817 * Also takes care of removing a notification that has been visible to a listener before, 11818 * but isn't anymore. 11819 */ 11820 @VisibleForTesting 11821 @GuardedBy("mNotificationLock") 11822 void notifyPostedLocked(NotificationRecord r, NotificationRecord old) { 11823 notifyPostedLocked(r, old, true); 11824 } 11825 11826 /** 11827 * Asynchronously notify all listeners about a new or updated notification. Note that the 11828 * notification is new or updated from the point of view of the NLS, but might not be 11829 * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method 11830 * is invoked after exiting lockdown mode. 11831 * 11832 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners 11833 * targeting <= O_MR1 11834 */ 11835 @VisibleForTesting 11836 @GuardedBy("mNotificationLock") 11837 void notifyPostedLocked(NotificationRecord r, NotificationRecord old, 11838 boolean notifyAllListeners) { 11839 for (Runnable listenerCall : prepareNotifyPostedLocked(r, old, notifyAllListeners)) { 11840 mHandler.post(listenerCall); 11841 } 11842 } 11843 11844 /** 11845 * "Prepares" to notify all listeners about the posted notification. 11846 * 11847 * <p>This method <em>does not invoke</em> the listeners; the caller should post each 11848 * returned {@link Runnable} on a suitable thread to do so. 11849 * 11850 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners 11851 * targeting <= O_MR1 11852 * @return A list of {@link Runnable} operations to notify all listeners about the posted 11853 * notification. 11854 */ 11855 @VisibleForTesting 11856 @GuardedBy("mNotificationLock") 11857 List<Runnable> prepareNotifyPostedLocked(NotificationRecord r, 11858 NotificationRecord old, boolean notifyAllListeners) { 11859 if (isInLockDownMode(r.getUser().getIdentifier())) { 11860 return new ArrayList<>(); 11861 } 11862 11863 ArrayList<Runnable> listenerCalls = new ArrayList<>(); 11864 try { 11865 // Lazily initialized snapshots of the notification. 11866 StatusBarNotification sbn = r.getSbn(); 11867 StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; 11868 TrimCache trimCache = new TrimCache(sbn); 11869 TrimCache redactedCache = null; 11870 StatusBarNotification redactedSbn = null; 11871 StatusBarNotification oldRedactedSbn = null; 11872 boolean isNewSensitive = hasSensitiveContent(r); 11873 boolean isOldSensitive = hasSensitiveContent(old); 11874 11875 for (final ManagedServiceInfo info : getServices()) { 11876 boolean isTrusted = isUidTrusted(info.uid); 11877 boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners() 11878 && isNewSensitive && !isTrusted; 11879 boolean sendOldRedacted = redactSensitiveNotificationsFromUntrustedListeners() 11880 && isOldSensitive && !isTrusted; 11881 boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info); 11882 boolean oldSbnVisible = (oldSbn != null) 11883 && isVisibleToListener(oldSbn, old.getNotificationType(), info); 11884 // This notification hasn't been and still isn't visible -> ignore. 11885 if (!oldSbnVisible && !sbnVisible) { 11886 continue; 11887 } 11888 // If the notification is hidden, don't notifyPosted listeners targeting < P. 11889 // Instead, those listeners will receive notifyPosted when the notification is 11890 // unhidden. 11891 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 11892 continue; 11893 } 11894 11895 if (lifetimeExtensionRefactor()) { 11896 if (sendRedacted && redactedSbn == null) { 11897 redactedSbn = redactStatusBarNotification(sbn); 11898 redactedCache = new TrimCache(redactedSbn); 11899 } 11900 final StatusBarNotification sbnToPost = sendRedacted 11901 ? redactedCache.ForListener(info) : trimCache.ForListener(info); 11902 11903 // Checks if this is a request to notify system UI about a notification that 11904 // has been lifetime extended. 11905 // (We only need to check old for the flag, because in both cancellation and 11906 // update cases, old should have the flag, whereas in update cases the 11907 // new will NOT have the flag.) 11908 // If it is such a request, and this is system UI, we send the post request 11909 // only to System UI, and break as we don't need to continue checking other 11910 // Managed Services. 11911 if (info.isSystemUi() && old != null && old.getNotification() != null 11912 && (old.getNotification().flags 11913 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) { 11914 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 11915 listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); 11916 break; 11917 } 11918 } 11919 11920 // If we shouldn't notify all listeners, this means the hidden state of 11921 // a notification was changed. Don't notifyPosted listeners targeting >= P. 11922 // Instead, those listeners will receive notifyRankingUpdate. 11923 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) { 11924 continue; 11925 } 11926 11927 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 11928 11929 // This notification became invisible -> remove the old one. 11930 if (oldSbnVisible && !sbnVisible) { 11931 if (sendOldRedacted && oldRedactedSbn == null) { 11932 oldRedactedSbn = redactStatusBarNotification(oldSbn); 11933 } 11934 final StatusBarNotification oldSbnLightClone = 11935 sendOldRedacted ? oldRedactedSbn.cloneLight() : oldSbn.cloneLight(); 11936 listenerCalls.add(() -> notifyRemoved( 11937 info, oldSbnLightClone, update, null, REASON_USER_STOPPED)); 11938 11939 continue; 11940 } 11941 // Grant access before listener is notified 11942 final int targetUserId = (info.userid == USER_ALL) 11943 ? USER_SYSTEM : info.userid; 11944 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId); 11945 11946 mPackageManagerInternal.grantImplicitAccess( 11947 targetUserId, null /* intent */, 11948 UserHandle.getAppId(info.uid), 11949 sbn.getUid(), 11950 false /* direct */, false /* retainOnUpdate */); 11951 11952 if (sendRedacted && redactedSbn == null) { 11953 redactedSbn = redactStatusBarNotification(sbn); 11954 redactedCache = new TrimCache(redactedSbn); 11955 } 11956 11957 final StatusBarNotification sbnToPost = sendRedacted 11958 ? redactedCache.ForListener(info) : trimCache.ForListener(info); 11959 listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); 11960 } 11961 } catch (Exception e) { 11962 Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e); 11963 } 11964 return listenerCalls; 11965 } 11966 11967 boolean isAppTrustedNotificationListenerService(int uid, String pkg) { 11968 if (!redactSensitiveNotificationsFromUntrustedListeners()) { 11969 return true; 11970 } 11971 11972 long token = Binder.clearCallingIdentity(); 11973 try { 11974 if (mPackageManager.checkUidPermission(RECEIVE_SENSITIVE_NOTIFICATIONS, uid) 11975 == PERMISSION_GRANTED || mPackageManagerInternal.isPlatformSigned(pkg) 11976 || mAppOps 11977 .noteOpNoThrow(OP_RECEIVE_SENSITIVE_NOTIFICATIONS, uid, pkg, null, null) 11978 == MODE_ALLOWED) { 11979 return true; 11980 } 11981 11982 // check if there is a CDM association with the listener 11983 // We don't listen for changes because if an association is lost, the app loses 11984 // NLS access 11985 List<AssociationInfo> cdmAssocs = new ArrayList<>(); 11986 if (mCompanionManager == null) { 11987 mCompanionManager = getCompanionManager(); 11988 } 11989 if (mCompanionManager != null) { 11990 cdmAssocs = 11991 mCompanionManager.getAllAssociationsForUser(UserHandle.getUserId(uid)); 11992 } 11993 for (int i = 0; i < cdmAssocs.size(); i++) { 11994 AssociationInfo assocInfo = cdmAssocs.get(i); 11995 if (!assocInfo.isRevoked() && pkg.equals(assocInfo.getPackageName()) 11996 && assocInfo.getUserId() == UserHandle.getUserId(uid)) { 11997 return true; 11998 } 11999 } 12000 } catch (RemoteException e) { 12001 Slog.e(TAG, "Failed to check trusted status of listener", e); 12002 } finally { 12003 Binder.restoreCallingIdentity(token); 12004 } 12005 return false; 12006 } 12007 12008 StatusBarNotification redactStatusBarNotification(StatusBarNotification sbn) { 12009 if (!redactSensitiveNotificationsFromUntrustedListeners()) { 12010 throw new RuntimeException("redactStatusBarNotification called while flag is off"); 12011 } 12012 12013 ApplicationInfo appInfo = sbn.getNotification().extras.getParcelable( 12014 EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class); 12015 String pkgLabel; 12016 if (appInfo != null) { 12017 pkgLabel = appInfo.loadLabel(mPackageManagerClient).toString(); 12018 } else { 12019 Slog.w(TAG, "StatusBarNotification " + sbn + " does not have ApplicationInfo." 12020 + " Did you pass in a 'cloneLight' notification?"); 12021 pkgLabel = sbn.getPackageName(); 12022 } 12023 String redactedText = mContext.getString(R.string.redacted_notification_message); 12024 Notification oldNotif = sbn.getNotification(); 12025 Notification oldClone = new Notification(); 12026 oldNotif.cloneInto(oldClone, false); 12027 Notification.Builder redactedNotifBuilder = 12028 new Notification.Builder(getContext(), oldClone); 12029 redactedNotifBuilder.setContentTitle(pkgLabel); 12030 redactedNotifBuilder.setContentText(redactedText); 12031 redactedNotifBuilder.setSubText(null); 12032 redactedNotifBuilder.setActions(); 12033 if (oldNotif.actions != null) { 12034 for (int i = 0; i < oldNotif.actions.length; i++) { 12035 Notification.Action act = 12036 new Notification.Action.Builder(oldNotif.actions[i]).build(); 12037 act.title = mContext.getString(R.string.redacted_notification_action_title); 12038 redactedNotifBuilder.addAction(act); 12039 } 12040 } 12041 12042 if (oldNotif.isStyle(MessagingStyle.class)) { 12043 Person empty = new Person.Builder().setName("").build(); 12044 MessagingStyle messageStyle = new MessagingStyle(empty); 12045 messageStyle.addMessage(new MessagingStyle.Message( 12046 redactedText, System.currentTimeMillis(), empty)); 12047 redactedNotifBuilder.setStyle(messageStyle); 12048 } 12049 if (redactSensitiveNotificationsBigTextStyle() 12050 && oldNotif.isStyle(Notification.BigTextStyle.class)) { 12051 Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(); 12052 bigTextStyle.bigText(mContext.getString(R.string.redacted_notification_message)); 12053 bigTextStyle.setBigContentTitle(""); 12054 bigTextStyle.setSummaryText(""); 12055 redactedNotifBuilder.setStyle(bigTextStyle); 12056 } 12057 12058 Notification redacted = redactedNotifBuilder.build(); 12059 // Notification extras can't always be overridden by a builder (configured by a system 12060 // property), so set them after building 12061 if (redacted.extras.containsKey(EXTRA_TITLE_BIG)) { 12062 redacted.extras.putString(EXTRA_TITLE_BIG, pkgLabel); 12063 } 12064 redacted.extras.remove(EXTRA_SUB_TEXT); 12065 redacted.extras.remove(EXTRA_TEXT_LINES); 12066 redacted.extras.remove(EXTRA_LARGE_ICON_BIG); 12067 return sbn.cloneShallow(redacted); 12068 } 12069 12070 boolean hasSensitiveContent(NotificationRecord r) { 12071 if (r == null || !redactSensitiveNotificationsFromUntrustedListeners()) { 12072 return false; 12073 } 12074 return r.hasSensitiveContent(); 12075 } 12076 12077 boolean isUidTrusted(int uid) { 12078 synchronized (mTrustedListenerUids) { 12079 return !redactSensitiveNotificationsFromUntrustedListeners() 12080 || mTrustedListenerUids.contains(uid); 12081 } 12082 } 12083 12084 /** 12085 * Synchronously grant or revoke permissions to Uris for all active and visible 12086 * notifications to just the NotificationListenerService provided. 12087 */ 12088 @GuardedBy("mNotificationLock") 12089 private void updateUriPermissionsForActiveNotificationsLocked( 12090 ManagedServiceInfo info, boolean grant) { 12091 try { 12092 for (final NotificationRecord r : mNotificationList) { 12093 // When granting permissions, ignore notifications which are invisible. 12094 // When revoking permissions, all notifications are invisible, so process all. 12095 if (grant && !isVisibleToListener(r.getSbn(), r.getNotificationType(), info)) { 12096 continue; 12097 } 12098 // If the notification is hidden, permissions are not required by the listener. 12099 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 12100 continue; 12101 } 12102 // Grant or revoke access synchronously 12103 final int targetUserId = (info.userid == USER_ALL) 12104 ? USER_SYSTEM : info.userid; 12105 if (grant) { 12106 // Grant permissions by passing arguments as if the notification is new. 12107 updateUriPermissions(/* newRecord */ r, /* oldRecord */ null, 12108 info.component.getPackageName(), targetUserId); 12109 } else { 12110 // Revoke permissions by passing arguments as if the notification was 12111 // removed, but set `onlyRevokeCurrentTarget` to avoid revoking permissions 12112 // granted to *other* targets by this notification's URIs. 12113 updateUriPermissions(/* newRecord */ null, /* oldRecord */ r, 12114 info.component.getPackageName(), targetUserId, 12115 /* onlyRevokeCurrentTarget */ true); 12116 } 12117 } 12118 } catch (Exception e) { 12119 Slog.e(TAG, "Could not " + (grant ? "grant" : "revoke") + " Uri permissions to " 12120 + info.component, e); 12121 } 12122 } 12123 12124 /** 12125 * asynchronously notify all listeners about a removed notification 12126 */ 12127 @GuardedBy("mNotificationLock") 12128 public void notifyRemovedLocked(NotificationRecord r, int reason, 12129 NotificationStats notificationStats) { 12130 if (isInLockDownMode(r.getUser().getIdentifier())) { 12131 return; 12132 } 12133 12134 final StatusBarNotification sbn = r.getSbn(); 12135 12136 // make a copy in case changes are made to the underlying Notification object 12137 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 12138 // notification 12139 final StatusBarNotification sbnLight = sbn.cloneLight(); 12140 StatusBarNotification redactedSbn = null; 12141 boolean hasSensitiveContent = hasSensitiveContent(r); 12142 for (final ManagedServiceInfo info : getServices()) { 12143 if (!isVisibleToListener(sbn, r.getNotificationType(), info)) { 12144 continue; 12145 } 12146 12147 // don't notifyRemoved for listeners targeting < P 12148 // if not for reason package suspended 12149 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED 12150 && info.targetSdkVersion < Build.VERSION_CODES.P) { 12151 continue; 12152 } 12153 12154 // don't notifyRemoved for listeners targeting >= P 12155 // if the reason is package suspended 12156 if (reason == REASON_PACKAGE_SUSPENDED 12157 && info.targetSdkVersion >= Build.VERSION_CODES.P) { 12158 continue; 12159 } 12160 12161 boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners() 12162 && hasSensitiveContent && !isUidTrusted(info.uid); 12163 if (sendRedacted && redactedSbn == null) { 12164 redactedSbn = redactStatusBarNotification(sbn); 12165 } 12166 12167 // Only assistants can get stats 12168 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service) 12169 ? notificationStats : null; 12170 final StatusBarNotification sbnToSend = sendRedacted ? redactedSbn : sbnLight; 12171 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 12172 mHandler.post(() -> notifyRemoved(info, sbnToSend, update, stats, reason)); 12173 } 12174 12175 // Revoke access after all listeners have been updated 12176 mHandler.post(() -> updateUriPermissions(null, r, null, USER_SYSTEM)); 12177 } 12178 12179 /** 12180 * Asynchronously notify all listeners about a reordering of notifications 12181 * unless changedHiddenNotifications is populated. 12182 * If changedHiddenNotifications is populated, there was a change in the hidden state 12183 * of the notifications. In this case, we only send updates to listeners that 12184 * target >= P. 12185 */ 12186 @GuardedBy("mNotificationLock") 12187 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { 12188 boolean isHiddenRankingUpdate = changedHiddenNotifications != null 12189 && changedHiddenNotifications.size() > 0; 12190 12191 // TODO (b/73052211): if the ranking update changed the notification type, 12192 // cancel notifications for NLSes that can't see them anymore 12193 for (final ManagedServiceInfo serviceInfo : getServices()) { 12194 if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener( 12195 serviceInfo, ActivityManager.getCurrentUser())) { 12196 continue; 12197 } 12198 12199 boolean notifyThisListener = false; 12200 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >= 12201 Build.VERSION_CODES.P) { 12202 for (NotificationRecord rec : changedHiddenNotifications) { 12203 if (isVisibleToListener( 12204 rec.getSbn(), rec.getNotificationType(), serviceInfo)) { 12205 notifyThisListener = true; 12206 break; 12207 } 12208 } 12209 } 12210 12211 if (notifyThisListener || !isHiddenRankingUpdate) { 12212 final NotificationRankingUpdate update = makeRankingUpdateLocked( 12213 serviceInfo); 12214 mHandler.post(() -> notifyRankingUpdate(serviceInfo, update)); 12215 } 12216 } 12217 } 12218 12219 @GuardedBy("mNotificationLock") 12220 public void notifyListenerHintsChangedLocked(final int hints) { 12221 for (final ManagedServiceInfo serviceInfo : getServices()) { 12222 if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener( 12223 serviceInfo, ActivityManager.getCurrentUser())) { 12224 continue; 12225 } 12226 mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints)); 12227 } 12228 } 12229 12230 /** 12231 * asynchronously notify relevant listeners their notification is hidden 12232 * NotificationListenerServices that target P+: 12233 * NotificationListenerService#notifyRankingUpdateLocked() 12234 * NotificationListenerServices that target <= P: 12235 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED. 12236 */ 12237 @GuardedBy("mNotificationLock") 12238 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) { 12239 if (changedNotifications == null || changedNotifications.size() == 0) { 12240 return; 12241 } 12242 12243 notifyRankingUpdateLocked(changedNotifications); 12244 12245 // for listeners that target < P, notifyRemoveLocked 12246 int numChangedNotifications = changedNotifications.size(); 12247 for (int i = 0; i < numChangedNotifications; i++) { 12248 NotificationRecord rec = changedNotifications.get(i); 12249 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats()); 12250 } 12251 } 12252 12253 /** 12254 * asynchronously notify relevant listeners their notification is unhidden 12255 * NotificationListenerServices that target P+: 12256 * NotificationListenerService#notifyRankingUpdateLocked() 12257 * NotificationListenerServices that target <= P: 12258 * NotificationListeners#notifyPostedLocked() 12259 */ 12260 @GuardedBy("mNotificationLock") 12261 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) { 12262 if (changedNotifications == null || changedNotifications.size() == 0) { 12263 return; 12264 } 12265 12266 notifyRankingUpdateLocked(changedNotifications); 12267 12268 // for listeners that target < P, notifyPostedLocked 12269 int numChangedNotifications = changedNotifications.size(); 12270 for (int i = 0; i < numChangedNotifications; i++) { 12271 NotificationRecord rec = changedNotifications.get(i); 12272 notifyPostedLocked(rec, rec, false); 12273 } 12274 } 12275 12276 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 12277 for (final ManagedServiceInfo serviceInfo : getServices()) { 12278 if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener( 12279 serviceInfo, ActivityManager.getCurrentUser())) { 12280 continue; 12281 } 12282 mHandler.post( 12283 () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter)); 12284 } 12285 } 12286 12287 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, 12288 final NotificationChannel channel, final int modificationType) { 12289 if (channel == null) { 12290 return; 12291 } 12292 for (final ManagedServiceInfo info : getServices()) { 12293 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId()) 12294 || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) { 12295 continue; 12296 } 12297 12298 BackgroundThread.getHandler().post(() -> { 12299 if (info.isSystem 12300 || hasCompanionDevice(info) 12301 || isServiceTokenValid(info.service)) { 12302 notifyNotificationChannelChanged( 12303 info, pkg, user, channel, modificationType); 12304 } 12305 }); 12306 } 12307 } 12308 12309 protected void notifyNotificationChannelGroupChanged( 12310 final String pkg, final UserHandle user, final NotificationChannelGroup group, 12311 final int modificationType) { 12312 if (group == null) { 12313 return; 12314 } 12315 for (final ManagedServiceInfo info : getServices()) { 12316 if (!info.enabledAndUserMatches(UserHandle.getCallingUserId()) 12317 || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) { 12318 continue; 12319 } 12320 12321 BackgroundThread.getHandler().post(() -> { 12322 if (info.isSystem() || hasCompanionDevice(info)) { 12323 notifyNotificationChannelGroupChanged( 12324 info, pkg, user, group, modificationType); 12325 } 12326 }); 12327 } 12328 } 12329 12330 private void notifyPosted(final ManagedServiceInfo info, 12331 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 12332 final INotificationListener listener = (INotificationListener) info.service; 12333 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 12334 try { 12335 listener.onNotificationPosted(sbnHolder, rankingUpdate); 12336 } catch (DeadObjectException ex) { 12337 Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex); 12338 } catch (RemoteException ex) { 12339 Slog.e(TAG, "unable to notify listener (posted): " + info, ex); 12340 } 12341 } 12342 12343 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 12344 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) { 12345 final INotificationListener listener = (INotificationListener) info.service; 12346 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 12347 try { 12348 if (!CompatChanges.isChangeEnabled(NOTIFICATION_CANCELLATION_REASONS, info.uid) 12349 && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) { 12350 reason = REASON_CHANNEL_BANNED; 12351 } 12352 // apps before T don't know about REASON_ASSISTANT, so replace it with the 12353 // previously-used case, REASON_LISTENER_CANCEL 12354 if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid) 12355 && reason == REASON_ASSISTANT_CANCEL) { 12356 reason = REASON_LISTENER_CANCEL; 12357 } 12358 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason); 12359 } catch (DeadObjectException ex) { 12360 Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex); 12361 } catch (RemoteException ex) { 12362 Slog.e(TAG, "unable to notify listener (removed): " + info, ex); 12363 } 12364 } 12365 12366 private void notifyRankingUpdate(ManagedServiceInfo info, 12367 NotificationRankingUpdate rankingUpdate) { 12368 final INotificationListener listener = (INotificationListener) info.service; 12369 try { 12370 listener.onNotificationRankingUpdate(rankingUpdate); 12371 } catch (DeadObjectException ex) { 12372 Slog.wtf(TAG, "unable to notify listener (ranking update): " + info, ex); 12373 } catch (RemoteException ex) { 12374 Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex); 12375 } 12376 } 12377 12378 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 12379 final INotificationListener listener = (INotificationListener) info.service; 12380 try { 12381 listener.onListenerHintsChanged(hints); 12382 } catch (RemoteException ex) { 12383 Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex); 12384 } 12385 } 12386 12387 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 12388 int interruptionFilter) { 12389 final INotificationListener listener = (INotificationListener) info.service; 12390 try { 12391 listener.onInterruptionFilterChanged(interruptionFilter); 12392 } catch (RemoteException ex) { 12393 Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex); 12394 } 12395 } 12396 12397 void notifyNotificationChannelChanged(ManagedServiceInfo info, 12398 final String pkg, final UserHandle user, final NotificationChannel channel, 12399 final int modificationType) { 12400 final INotificationListener listener = (INotificationListener) info.service; 12401 try { 12402 listener.onNotificationChannelModification(pkg, user, channel, modificationType); 12403 } catch (RemoteException ex) { 12404 Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex); 12405 } 12406 } 12407 12408 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, 12409 final String pkg, final UserHandle user, final NotificationChannelGroup group, 12410 final int modificationType) { 12411 final INotificationListener listener = (INotificationListener) info.getService(); 12412 try { 12413 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); 12414 } catch (RemoteException ex) { 12415 Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex); 12416 } 12417 } 12418 12419 public boolean isListenerPackage(String packageName) { 12420 if (packageName == null) { 12421 return false; 12422 } 12423 // TODO: clean up locking object later 12424 synchronized (mNotificationLock) { 12425 for (final ManagedServiceInfo serviceInfo : getServices()) { 12426 if (packageName.equals(serviceInfo.component.getPackageName())) { 12427 return true; 12428 } 12429 } 12430 } 12431 return false; 12432 } 12433 12434 // Returns whether there is a component with listener access granted that is associated 12435 // with the given package name / user ID. 12436 boolean hasAllowedListener(String packageName, int userId) { 12437 if (packageName == null) { 12438 return false; 12439 } 12440 12441 // Loop through allowed components to compare package names 12442 List<ComponentName> allowedComponents = getAllowedComponents(userId); 12443 for (int i = 0; i < allowedComponents.size(); i++) { 12444 if (allowedComponents.get(i).getPackageName().equals(packageName)) { 12445 return true; 12446 } 12447 } 12448 return false; 12449 } 12450 } 12451 12452 @GuardedBy("mNotificationLock") 12453 private void broadcastToCallNotificationEventCallbacks( 12454 final RemoteCallbackList<ICallNotificationEventCallback> callbackList, 12455 final NotificationRecord r, 12456 boolean isPosted) { 12457 if (callbackList != null) { 12458 int numCallbacks = callbackList.beginBroadcast(); 12459 try { 12460 for (int i = 0; i < numCallbacks; i++) { 12461 if (isPosted) { 12462 callbackList.getBroadcastItem(i) 12463 .onCallNotificationPosted(r.getSbn().getPackageName(), r.getUser()); 12464 } else { 12465 callbackList.getBroadcastItem(i) 12466 .onCallNotificationRemoved(r.getSbn().getPackageName(), 12467 r.getUser()); 12468 } 12469 } 12470 } catch (RemoteException e) { 12471 throw new RuntimeException(e); 12472 } 12473 callbackList.finishBroadcast(); 12474 } 12475 } 12476 12477 @GuardedBy("mNotificationLock") 12478 void notifyCallNotificationEventListenerOnPosted(final NotificationRecord r) { 12479 if (!r.getNotification().isStyle(Notification.CallStyle.class)) { 12480 return; 12481 } 12482 12483 synchronized (mCallNotificationEventCallbacks) { 12484 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 12485 callbacksForPackage = 12486 mCallNotificationEventCallbacks.get(r.getSbn().getPackageName()); 12487 if (callbacksForPackage == null) { 12488 return; 12489 } 12490 12491 if (!r.getUser().equals(UserHandle.ALL)) { 12492 broadcastToCallNotificationEventCallbacks( 12493 callbacksForPackage.get(r.getUser().getIdentifier()), r, true); 12494 // Also notify the listeners registered for USER_ALL 12495 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r, 12496 true); 12497 } else { 12498 // Notify listeners registered for any userId 12499 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList 12500 : callbacksForPackage.values()) { 12501 broadcastToCallNotificationEventCallbacks(callbackList, r, true); 12502 } 12503 } 12504 } 12505 } 12506 12507 @GuardedBy("mNotificationLock") 12508 void notifyCallNotificationEventListenerOnRemoved(final NotificationRecord r) { 12509 if (!r.getNotification().isStyle(Notification.CallStyle.class)) { 12510 return; 12511 } 12512 12513 synchronized (mCallNotificationEventCallbacks) { 12514 ArrayMap<Integer, RemoteCallbackList<ICallNotificationEventCallback>> 12515 callbacksForPackage = 12516 mCallNotificationEventCallbacks.get(r.getSbn().getPackageName()); 12517 if (callbacksForPackage == null) { 12518 return; 12519 } 12520 12521 if (!r.getUser().equals(UserHandle.ALL)) { 12522 broadcastToCallNotificationEventCallbacks( 12523 callbacksForPackage.get(r.getUser().getIdentifier()), r, false); 12524 // Also notify the listeners registered for USER_ALL 12525 broadcastToCallNotificationEventCallbacks(callbacksForPackage.get(USER_ALL), r, 12526 false); 12527 } else { 12528 // Notify listeners registered for any userId 12529 for (RemoteCallbackList<ICallNotificationEventCallback> callbackList 12530 : callbacksForPackage.values()) { 12531 broadcastToCallNotificationEventCallbacks(callbackList, r, false); 12532 } 12533 } 12534 } 12535 } 12536 12537 // TODO (b/194833441): remove when we've fully migrated to a permission 12538 class RoleObserver implements OnRoleHoldersChangedListener { 12539 // Role name : user id : list of approved packages 12540 private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps; 12541 12542 /** 12543 * Writes should be pretty rare (only when default browser changes) and reads are done 12544 * during activity start code-path, so we're optimizing for reads. This means this set is 12545 * immutable once written and we'll recreate the set every time there is a role change and 12546 * then assign that new set to the volatile below, so reads can be done without needing to 12547 * hold a lock. Every write is done on the main-thread, so write atomicity is guaranteed. 12548 * 12549 * Didn't use unmodifiable set to enforce immutability to avoid iterating via iterators. 12550 */ 12551 private volatile ArraySet<Integer> mTrampolineExemptUids = new ArraySet<>(); 12552 12553 private final RoleManager mRm; 12554 private final IPackageManager mPm; 12555 private final Executor mExecutor; 12556 private final Looper mMainLooper; 12557 12558 RoleObserver(Context context, @NonNull RoleManager roleManager, 12559 @NonNull IPackageManager pkgMgr, @NonNull Looper mainLooper) { 12560 mRm = roleManager; 12561 mPm = pkgMgr; 12562 mExecutor = context.getMainExecutor(); 12563 mMainLooper = mainLooper; 12564 } 12565 12566 /** Should be called from the main-thread. */ 12567 @MainThread 12568 public void init() { 12569 List<UserHandle> users = mUm.getUserHandles(/* excludeDying */ true); 12570 mNonBlockableDefaultApps = new ArrayMap<>(); 12571 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 12572 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>(); 12573 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList); 12574 for (int j = 0; j < users.size(); j++) { 12575 Integer userId = users.get(j).getIdentifier(); 12576 ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser( 12577 NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId))); 12578 ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>(); 12579 for (String pkg : approvedForUserId) { 12580 approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId))); 12581 } 12582 userToApprovedList.put(userId, approvedForUserId); 12583 mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids); 12584 } 12585 } 12586 updateTrampolineExemptUidsForUsers(users.toArray(new UserHandle[0])); 12587 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); 12588 } 12589 12590 void destroy() { 12591 mRm.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.ALL); 12592 } 12593 12594 @VisibleForTesting 12595 public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) { 12596 return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg); 12597 } 12598 12599 @VisibleForTesting 12600 public boolean isUidExemptFromTrampolineRestrictions(int uid) { 12601 return mTrampolineExemptUids.contains(uid); 12602 } 12603 12604 /** 12605 * Convert the assistant-role holder into settings. The rest of the system uses the 12606 * settings. 12607 * 12608 * @param roleName the name of the role whose holders are changed 12609 * @param user the user for this role holder change 12610 */ 12611 @Override 12612 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { 12613 onRoleHoldersChangedForNonBlockableDefaultApps(roleName, user); 12614 onRoleHoldersChangedForTrampolines(roleName, user); 12615 } 12616 12617 private void onRoleHoldersChangedForNonBlockableDefaultApps(@NonNull String roleName, 12618 @NonNull UserHandle user) { 12619 // we only care about a couple of the roles they'll tell us about 12620 boolean relevantChange = false; 12621 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 12622 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) { 12623 relevantChange = true; 12624 break; 12625 } 12626 } 12627 12628 if (!relevantChange) { 12629 return; 12630 } 12631 12632 ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user)); 12633 12634 // find the diff 12635 ArrayMap<Integer, ArraySet<String>> prevApprovedForRole = 12636 mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>()); 12637 ArraySet<String> previouslyApproved = 12638 prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>()); 12639 12640 ArraySet<String> toRemove = new ArraySet<>(); 12641 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 12642 12643 for (String previous : previouslyApproved) { 12644 if (!roleHolders.contains(previous)) { 12645 toRemove.add(previous); 12646 } 12647 } 12648 for (String nowApproved : roleHolders) { 12649 if (!previouslyApproved.contains(nowApproved)) { 12650 toAdd.add(new Pair(nowApproved, 12651 getUidForPackage(nowApproved, user.getIdentifier()))); 12652 } 12653 } 12654 12655 // store newly approved apps 12656 prevApprovedForRole.put(user.getIdentifier(), roleHolders); 12657 mNonBlockableDefaultApps.put(roleName, prevApprovedForRole); 12658 12659 // update what apps can be blocked 12660 mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd); 12661 12662 // RoleManager is the source of truth for this data so we don't need to trigger a 12663 // write of the notification policy xml for this change 12664 } 12665 12666 private void onRoleHoldersChangedForTrampolines(@NonNull String roleName, 12667 @NonNull UserHandle user) { 12668 if (!RoleManager.ROLE_BROWSER.equals(roleName)) { 12669 return; 12670 } 12671 updateTrampolineExemptUidsForUsers(user); 12672 } 12673 12674 private void updateTrampolineExemptUidsForUsers(UserHandle... users) { 12675 Preconditions.checkState(mMainLooper.isCurrentThread()); 12676 ArraySet<Integer> oldUids = mTrampolineExemptUids; 12677 ArraySet<Integer> newUids = new ArraySet<>(); 12678 // Add the uids from previous set for the users that we won't update. 12679 for (int i = 0, n = oldUids.size(); i < n; i++) { 12680 int uid = oldUids.valueAt(i); 12681 UserHandle user = UserHandle.of(UserHandle.getUserId(uid)); 12682 if (!ArrayUtils.contains(users, user)) { 12683 newUids.add(uid); 12684 } 12685 } 12686 // Now lookup the new uids for the users that we want to update. 12687 for (int i = 0, n = users.length; i < n; i++) { 12688 UserHandle user = users[i]; 12689 for (String pkg : mRm.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, user)) { 12690 int uid = getUidForPackage(pkg, user.getIdentifier()); 12691 if (uid != -1) { 12692 newUids.add(uid); 12693 } else { 12694 Slog.e(TAG, "Bad uid (-1) for browser package " + pkg); 12695 } 12696 } 12697 } 12698 mTrampolineExemptUids = newUids; 12699 } 12700 12701 private int getUidForPackage(String pkg, int userId) { 12702 try { 12703 return mPm.getPackageUid(pkg, MATCH_ALL, userId); 12704 } catch (RemoteException e) { 12705 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId); 12706 } 12707 return -1; 12708 } 12709 } 12710 12711 public static final class DumpFilter { 12712 public boolean filtered = false; 12713 public String pkgFilter; 12714 public boolean zen; 12715 public long since; 12716 public boolean stats; 12717 public boolean rvStats; 12718 public boolean redact = true; 12719 public boolean proto = false; 12720 public boolean criticalPriority = false; 12721 public boolean normalPriority = false; 12722 12723 @NonNull 12724 public static DumpFilter parseFromArguments(String[] args) { 12725 final DumpFilter filter = new DumpFilter(); 12726 for (int ai = 0; ai < args.length; ai++) { 12727 final String a = args[ai]; 12728 if ("--proto".equals(a)) { 12729 filter.proto = true; 12730 } else if ("--noredact".equals(a) || "--reveal".equals(a)) { 12731 filter.redact = false; 12732 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 12733 if (ai < args.length-1) { 12734 ai++; 12735 filter.pkgFilter = args[ai].trim().toLowerCase(); 12736 if (filter.pkgFilter.isEmpty()) { 12737 filter.pkgFilter = null; 12738 } else { 12739 filter.filtered = true; 12740 } 12741 } 12742 } else if ("--zen".equals(a) || "zen".equals(a)) { 12743 filter.filtered = true; 12744 filter.zen = true; 12745 } else if ("--stats".equals(a)) { 12746 filter.stats = true; 12747 if (ai < args.length-1) { 12748 ai++; 12749 filter.since = Long.parseLong(args[ai]); 12750 } else { 12751 filter.since = 0; 12752 } 12753 } else if ("--remote-view-stats".equals(a)) { 12754 filter.rvStats = true; 12755 if (ai < args.length-1) { 12756 ai++; 12757 filter.since = Long.parseLong(args[ai]); 12758 } else { 12759 filter.since = 0; 12760 } 12761 } else if (PRIORITY_ARG.equals(a)) { 12762 // Bugreport will call the service twice with priority arguments, first to dump 12763 // critical sections and then non critical ones. Set appropriate filters 12764 // to generate the desired data. 12765 if (ai < args.length - 1) { 12766 ai++; 12767 switch (args[ai]) { 12768 case PRIORITY_ARG_CRITICAL: 12769 filter.criticalPriority = true; 12770 break; 12771 case PRIORITY_ARG_NORMAL: 12772 filter.normalPriority = true; 12773 break; 12774 } 12775 } 12776 } 12777 } 12778 return filter; 12779 } 12780 12781 public boolean matches(StatusBarNotification sbn) { 12782 if (!filtered) return true; 12783 return zen ? true : sbn != null 12784 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 12785 } 12786 12787 public boolean matches(ComponentName component) { 12788 if (!filtered) return true; 12789 return zen ? true : component != null && matches(component.getPackageName()); 12790 } 12791 12792 public boolean matches(String pkg) { 12793 if (!filtered) return true; 12794 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 12795 } 12796 12797 @Override 12798 public String toString() { 12799 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 12800 } 12801 } 12802 12803 @VisibleForTesting 12804 void resetAssistantUserSet(int userId) { 12805 checkCallerIsSystemOrShell(); 12806 mAssistants.setUserSet(userId, false); 12807 handleSavePolicyFile(); 12808 } 12809 12810 @VisibleForTesting 12811 @Nullable 12812 ComponentName getApprovedAssistant(int userId) { 12813 checkCallerIsSystemOrShell(); 12814 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 12815 return CollectionUtils.firstOrNull(allowedComponents); 12816 } 12817 12818 /** 12819 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 12820 * binder without sending large amounts of data over a oneway transaction. 12821 */ 12822 private static final class StatusBarNotificationHolder 12823 extends IStatusBarNotificationHolder.Stub { 12824 private StatusBarNotification mValue; 12825 12826 public StatusBarNotificationHolder(StatusBarNotification value) { 12827 mValue = value; 12828 } 12829 12830 /** Get the held value and clear it. This function should only be called once per holder */ 12831 @Override 12832 public StatusBarNotification get() { 12833 StatusBarNotification value = mValue; 12834 mValue = null; 12835 return value; 12836 } 12837 } 12838 12839 private void writeSecureNotificationsPolicy(TypedXmlSerializer out) throws IOException { 12840 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 12841 out.attributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, 12842 mLockScreenAllowSecureNotifications); 12843 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 12844 } 12845 12846 // Creates a notification that informs the user about changes due to the migration to 12847 // use permissions for notifications. 12848 protected Notification createReviewPermissionsNotification() { 12849 int title = R.string.review_notification_settings_title; 12850 int content = R.string.review_notification_settings_text; 12851 12852 // Tapping on the notification leads to the settings screen for managing app notifications, 12853 // using the intent reserved for system services to indicate it comes from this notification 12854 Intent tapIntent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS_FOR_REVIEW); 12855 Intent remindIntent = new Intent(REVIEW_NOTIF_ACTION_REMIND); 12856 Intent dismissIntent = new Intent(REVIEW_NOTIF_ACTION_DISMISS); 12857 Intent swipeIntent = new Intent(REVIEW_NOTIF_ACTION_CANCELED); 12858 12859 // Both "remind me" and "dismiss" actions will be actions received by the BroadcastReceiver 12860 final Notification.Action remindMe = new Notification.Action.Builder(null, 12861 getContext().getResources().getString( 12862 R.string.review_notification_settings_remind_me_action), 12863 PendingIntent.getBroadcast( 12864 getContext(), 0, remindIntent, 12865 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 12866 .build(); 12867 final Notification.Action dismiss = new Notification.Action.Builder(null, 12868 getContext().getResources().getString( 12869 R.string.review_notification_settings_dismiss), 12870 PendingIntent.getBroadcast( 12871 getContext(), 0, dismissIntent, 12872 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 12873 .build(); 12874 12875 return new Notification.Builder(getContext(), SystemNotificationChannels.SYSTEM_CHANGES) 12876 .setSmallIcon(R.drawable.stat_sys_adb) 12877 .setContentTitle(getContext().getResources().getString(title)) 12878 .setContentText(getContext().getResources().getString(content)) 12879 .setContentIntent(PendingIntent.getActivity(getContext(), 0, tapIntent, 12880 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 12881 .setStyle(new Notification.BigTextStyle()) 12882 .setFlag(FLAG_NO_CLEAR, true) 12883 .setAutoCancel(true) 12884 .addAction(remindMe) 12885 .addAction(dismiss) 12886 .setDeleteIntent(PendingIntent.getBroadcast(getContext(), 0, swipeIntent, 12887 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 12888 .build(); 12889 } 12890 12891 protected void maybeShowInitialReviewPermissionsNotification() { 12892 if (!mShowReviewPermissionsNotification) { 12893 // if this notification is disabled by settings do not ever show it 12894 return; 12895 } 12896 12897 int currentState = Settings.Global.getInt(getContext().getContentResolver(), 12898 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 12899 REVIEW_NOTIF_STATE_UNKNOWN); 12900 12901 // now check the last known state of the notification -- this determination of whether the 12902 // user is in the correct target audience occurs elsewhere, and will have written the 12903 // REVIEW_NOTIF_STATE_SHOULD_SHOW to indicate it should be shown in the future. 12904 // 12905 // alternatively, if the user has rescheduled the notification (so it has been shown 12906 // again) but not yet interacted with the new notification, then show it again on boot, 12907 // as this state indicates that the user had the notification open before rebooting. 12908 // 12909 // sending the notification here does not record a new state for the notification; 12910 // that will be written by parts of the system further down the line if at any point 12911 // the user interacts with the notification. 12912 if (currentState == REVIEW_NOTIF_STATE_SHOULD_SHOW 12913 || currentState == REVIEW_NOTIF_STATE_RESHOWN) { 12914 NotificationManager nm = getContext().getSystemService(NotificationManager.class); 12915 nm.notify(TAG, 12916 SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS, 12917 createReviewPermissionsNotification()); 12918 } 12919 } 12920 12921 /** 12922 * Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too 12923 * aggressive and annoying the user. 12924 * 12925 * TODO(b/161957908): Remove dogfooder toast. 12926 */ 12927 private class NotificationTrampolineCallback implements BackgroundActivityStartCallback { 12928 @Override 12929 public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, 12930 String packageName) { 12931 checkArgument(!tokens.isEmpty()); 12932 for (IBinder token : tokens) { 12933 if (token != ALLOWLIST_TOKEN) { 12934 // We only block or warn if the start is exclusively due to notification 12935 return true; 12936 } 12937 } 12938 String logcatMessage = 12939 "Indirect notification activity start (trampoline) from " + packageName; 12940 if (blockTrampoline(uid)) { 12941 Slog.e(TAG, logcatMessage + " blocked"); 12942 return false; 12943 } else { 12944 Slog.w(TAG, logcatMessage + ", this should be avoided for performance reasons"); 12945 return true; 12946 } 12947 } 12948 12949 private boolean blockTrampoline(int uid) { 12950 if (mRoleObserver != null && mRoleObserver.isUidExemptFromTrampolineRestrictions(uid)) { 12951 return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK_FOR_EXEMPT_ROLES, 12952 uid); 12953 } 12954 return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); 12955 } 12956 12957 @Override 12958 public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) { 12959 // If the start is allowed via notification, we allow the app to close system dialogs 12960 // only if their targetSdk < S, otherwise they have no valid reason to do this since 12961 // trampolines are blocked. 12962 return tokens.contains(ALLOWLIST_TOKEN) 12963 && !CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); 12964 } 12965 } 12966 12967 interface PostNotificationTrackerFactory { 12968 default PostNotificationTracker newTracker(@Nullable WakeLock optionalWakelock) { 12969 return new PostNotificationTracker(optionalWakelock); 12970 } 12971 } 12972 12973 static class PostNotificationTracker { 12974 @ElapsedRealtimeLong private final long mStartTime; 12975 @Nullable private final WakeLock mWakeLock; 12976 private boolean mOngoing; 12977 12978 @VisibleForTesting 12979 PostNotificationTracker(@Nullable WakeLock wakeLock) { 12980 mStartTime = SystemClock.elapsedRealtime(); 12981 mWakeLock = wakeLock; 12982 mOngoing = true; 12983 if (DBG) { 12984 Slog.d(TAG, "PostNotification: Started"); 12985 } 12986 } 12987 12988 @ElapsedRealtimeLong 12989 long getStartTime() { 12990 return mStartTime; 12991 } 12992 12993 @VisibleForTesting 12994 boolean isOngoing() { 12995 return mOngoing; 12996 } 12997 12998 /** 12999 * Cancels the tracker (releasing the acquired WakeLock). Either {@link #finish} or 13000 * {@link #cancel} (exclusively) should be called on this object before it's discarded. 13001 */ 13002 void cancel() { 13003 if (!isOngoing()) { 13004 Log.wtfStack(TAG, "cancel() called on already-finished tracker"); 13005 return; 13006 } 13007 mOngoing = false; 13008 if (mWakeLock != null) { 13009 Binder.withCleanCallingIdentity(() -> mWakeLock.release()); 13010 } 13011 if (DBG) { 13012 long elapsedTime = SystemClock.elapsedRealtime() - mStartTime; 13013 Slog.d(TAG, TextUtils.formatSimple("PostNotification: Abandoned after %d ms", 13014 elapsedTime)); 13015 } 13016 } 13017 13018 /** 13019 * Finishes the tracker (releasing the acquired WakeLock) and returns the time elapsed since 13020 * the operation started, in milliseconds. Either {@link #finish} or {@link #cancel} 13021 * (exclusively) should be called on this object before it's discarded. 13022 */ 13023 @DurationMillisLong 13024 long finish() { 13025 long elapsedTime = SystemClock.elapsedRealtime() - mStartTime; 13026 if (!isOngoing()) { 13027 Log.wtfStack(TAG, "finish() called on already-finished tracker"); 13028 return elapsedTime; 13029 } 13030 mOngoing = false; 13031 if (mWakeLock != null) { 13032 Binder.withCleanCallingIdentity(() -> mWakeLock.release()); 13033 } 13034 if (DBG) { 13035 Slog.d(TAG, 13036 TextUtils.formatSimple("PostNotification: Finished in %d ms", elapsedTime)); 13037 } 13038 return elapsedTime; 13039 } 13040 } 13041 } 13042