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