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