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