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