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.CATEGORY_CALL; 21 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; 22 import static android.app.Notification.FLAG_BUBBLE; 23 import static android.app.Notification.FLAG_FOREGROUND_SERVICE; 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.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED; 28 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED; 29 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED; 30 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED; 31 import static android.app.NotificationManager.IMPORTANCE_LOW; 32 import static android.app.NotificationManager.IMPORTANCE_MIN; 33 import static android.app.NotificationManager.IMPORTANCE_NONE; 34 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 35 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET; 36 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 37 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 38 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 39 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 40 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 41 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 42 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 43 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 44 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 45 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; 46 import static android.content.Context.BIND_AUTO_CREATE; 47 import static android.content.Context.BIND_FOREGROUND_SERVICE; 48 import static android.content.Context.BIND_NOT_PERCEPTIBLE; 49 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; 50 import static android.content.pm.PackageManager.FEATURE_LEANBACK; 51 import static android.content.pm.PackageManager.FEATURE_TELEVISION; 52 import static android.content.pm.PackageManager.MATCH_ALL; 53 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; 54 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 55 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 56 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; 57 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; 58 import static android.os.UserHandle.USER_NULL; 59 import static android.os.UserHandle.USER_SYSTEM; 60 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 61 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 62 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 63 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; 64 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; 65 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; 66 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 67 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; 68 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 69 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; 70 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; 71 import static android.service.notification.NotificationListenerService.REASON_CLICK; 72 import static android.service.notification.NotificationListenerService.REASON_ERROR; 73 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; 74 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; 75 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; 76 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; 77 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; 78 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; 79 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF; 80 import static android.service.notification.NotificationListenerService.REASON_SNOOZED; 81 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; 82 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; 83 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; 84 import static android.service.notification.NotificationListenerService.TRIM_FULL; 85 import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 86 import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING; 87 import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE; 88 import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS; 89 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 90 91 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 92 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 93 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 94 import static com.android.server.notification.PreferencesHelper.DEFAULT_ALLOW_BUBBLE; 95 import static com.android.server.utils.PriorityDump.PRIORITY_ARG; 96 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; 97 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; 98 99 import android.Manifest; 100 import android.Manifest.permission; 101 import android.annotation.CallbackExecutor; 102 import android.annotation.NonNull; 103 import android.annotation.Nullable; 104 import android.app.ActivityManager; 105 import android.app.ActivityManagerInternal; 106 import android.app.AlarmManager; 107 import android.app.AppGlobals; 108 import android.app.AppOpsManager; 109 import android.app.AutomaticZenRule; 110 import android.app.IActivityManager; 111 import android.app.INotificationManager; 112 import android.app.ITransientNotification; 113 import android.app.IUriGrantsManager; 114 import android.app.Notification; 115 import android.app.NotificationChannel; 116 import android.app.NotificationChannelGroup; 117 import android.app.NotificationManager; 118 import android.app.NotificationManager.Policy; 119 import android.app.PendingIntent; 120 import android.app.Person; 121 import android.app.RemoteInput; 122 import android.app.StatusBarManager; 123 import android.app.UriGrantsManager; 124 import android.app.admin.DeviceAdminInfo; 125 import android.app.admin.DevicePolicyManagerInternal; 126 import android.app.backup.BackupManager; 127 import android.app.role.OnRoleHoldersChangedListener; 128 import android.app.role.RoleManager; 129 import android.app.usage.UsageEvents; 130 import android.app.usage.UsageStatsManagerInternal; 131 import android.companion.ICompanionDeviceManager; 132 import android.content.BroadcastReceiver; 133 import android.content.ComponentName; 134 import android.content.ContentProvider; 135 import android.content.ContentResolver; 136 import android.content.Context; 137 import android.content.Intent; 138 import android.content.IntentFilter; 139 import android.content.pm.ActivityInfo; 140 import android.content.pm.ApplicationInfo; 141 import android.content.pm.IPackageManager; 142 import android.content.pm.PackageManager; 143 import android.content.pm.PackageManager.NameNotFoundException; 144 import android.content.pm.PackageManagerInternal; 145 import android.content.pm.ParceledListSlice; 146 import android.content.pm.UserInfo; 147 import android.content.res.Resources; 148 import android.database.ContentObserver; 149 import android.media.AudioAttributes; 150 import android.media.AudioManager; 151 import android.media.AudioManagerInternal; 152 import android.media.IRingtonePlayer; 153 import android.metrics.LogMaker; 154 import android.net.Uri; 155 import android.os.Binder; 156 import android.os.Build; 157 import android.os.Bundle; 158 import android.os.Environment; 159 import android.os.Handler; 160 import android.os.HandlerThread; 161 import android.os.IBinder; 162 import android.os.IDeviceIdleController; 163 import android.os.IInterface; 164 import android.os.Looper; 165 import android.os.Message; 166 import android.os.ParcelFileDescriptor; 167 import android.os.Process; 168 import android.os.RemoteException; 169 import android.os.ResultReceiver; 170 import android.os.ServiceManager; 171 import android.os.ShellCallback; 172 import android.os.SystemClock; 173 import android.os.SystemProperties; 174 import android.os.UserHandle; 175 import android.os.UserManager; 176 import android.os.VibrationEffect; 177 import android.os.Vibrator; 178 import android.provider.DeviceConfig; 179 import android.provider.Settings; 180 import android.service.notification.Adjustment; 181 import android.service.notification.Condition; 182 import android.service.notification.IConditionProvider; 183 import android.service.notification.INotificationListener; 184 import android.service.notification.IStatusBarNotificationHolder; 185 import android.service.notification.ListenersDisablingEffectsProto; 186 import android.service.notification.NotificationAssistantService; 187 import android.service.notification.NotificationListenerService; 188 import android.service.notification.NotificationRankingUpdate; 189 import android.service.notification.NotificationRecordProto; 190 import android.service.notification.NotificationServiceDumpProto; 191 import android.service.notification.NotificationStats; 192 import android.service.notification.SnoozeCriterion; 193 import android.service.notification.StatusBarNotification; 194 import android.service.notification.ZenModeConfig; 195 import android.service.notification.ZenModeProto; 196 import android.telephony.PhoneStateListener; 197 import android.telephony.TelephonyManager; 198 import android.text.TextUtils; 199 import android.util.ArrayMap; 200 import android.util.ArraySet; 201 import android.util.AtomicFile; 202 import android.util.IntArray; 203 import android.util.Log; 204 import android.util.Pair; 205 import android.util.Slog; 206 import android.util.SparseArray; 207 import android.util.StatsLog; 208 import android.util.Xml; 209 import android.util.proto.ProtoOutputStream; 210 import android.view.accessibility.AccessibilityEvent; 211 import android.view.accessibility.AccessibilityManager; 212 import android.widget.Toast; 213 214 import com.android.internal.R; 215 import com.android.internal.annotations.GuardedBy; 216 import com.android.internal.annotations.VisibleForTesting; 217 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; 218 import com.android.internal.logging.MetricsLogger; 219 import com.android.internal.logging.nano.MetricsProto; 220 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 221 import com.android.internal.notification.SystemNotificationChannels; 222 import com.android.internal.os.BackgroundThread; 223 import com.android.internal.os.SomeArgs; 224 import com.android.internal.statusbar.NotificationVisibility; 225 import com.android.internal.util.ArrayUtils; 226 import com.android.internal.util.CollectionUtils; 227 import com.android.internal.util.DumpUtils; 228 import com.android.internal.util.FastXmlSerializer; 229 import com.android.internal.util.Preconditions; 230 import com.android.internal.util.XmlUtils; 231 import com.android.internal.util.function.TriPredicate; 232 import com.android.server.DeviceIdleController; 233 import com.android.server.EventLogTags; 234 import com.android.server.IoThread; 235 import com.android.server.LocalServices; 236 import com.android.server.SystemService; 237 import com.android.server.lights.LightsManager; 238 import com.android.server.lights.LogicalLight; 239 import com.android.server.notification.ManagedServices.ManagedServiceInfo; 240 import com.android.server.notification.ManagedServices.UserProfiles; 241 import com.android.server.pm.PackageManagerService; 242 import com.android.server.policy.PhoneWindowManager; 243 import com.android.server.statusbar.StatusBarManagerInternal; 244 import com.android.server.uri.UriGrantsManagerInternal; 245 import com.android.server.wm.WindowManagerInternal; 246 247 import libcore.io.IoUtils; 248 249 import org.json.JSONException; 250 import org.json.JSONObject; 251 import org.xmlpull.v1.XmlPullParser; 252 import org.xmlpull.v1.XmlPullParserException; 253 import org.xmlpull.v1.XmlSerializer; 254 255 import java.io.ByteArrayInputStream; 256 import java.io.ByteArrayOutputStream; 257 import java.io.File; 258 import java.io.FileDescriptor; 259 import java.io.FileNotFoundException; 260 import java.io.FileOutputStream; 261 import java.io.IOException; 262 import java.io.InputStream; 263 import java.io.OutputStream; 264 import java.io.PrintWriter; 265 import java.nio.charset.StandardCharsets; 266 import java.util.ArrayDeque; 267 import java.util.ArrayList; 268 import java.util.Arrays; 269 import java.util.Iterator; 270 import java.util.List; 271 import java.util.Map.Entry; 272 import java.util.Objects; 273 import java.util.Set; 274 import java.util.concurrent.Executor; 275 import java.util.concurrent.TimeUnit; 276 import java.util.function.BiConsumer; 277 278 /** {@hide} */ 279 public class NotificationManagerService extends SystemService { 280 static final String TAG = "NotificationService"; 281 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 282 public static final boolean ENABLE_CHILD_NOTIFICATIONS 283 = SystemProperties.getBoolean("debug.child_notifs", true); 284 285 // pullStats report request: undecorated remote view stats 286 public static final int REPORT_REMOTE_VIEWS = 0x01; 287 288 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean( 289 "debug.notification.interruptiveness", false); 290 291 static final int MAX_PACKAGE_NOTIFICATIONS = 25; 292 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f; 293 294 // message codes 295 static final int MESSAGE_DURATION_REACHED = 2; 296 // 3: removed to a different handler 297 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 298 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 299 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 300 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7; 301 static final int MESSAGE_ON_PACKAGE_CHANGED = 8; 302 303 // ranking thread messages 304 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 305 private static final int MESSAGE_RANKING_SORT = 1001; 306 307 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 308 static final int SHORT_DELAY = 2000; // 2 seconds 309 310 // 1 second past the ANR timeout. 311 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000; 312 313 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 314 315 static final long SNOOZE_UNTIL_UNSPECIFIED = -1; 316 317 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 318 319 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 320 321 static final boolean ENABLE_BLOCKED_TOASTS = true; 322 323 static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] { 324 Adjustment.KEY_CONTEXTUAL_ACTIONS, 325 Adjustment.KEY_TEXT_REPLIES}; 326 327 static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] { 328 RoleManager.ROLE_DIALER, 329 RoleManager.ROLE_EMERGENCY 330 }; 331 332 // When #matchesCallFilter is called from the ringer, wait at most 333 // 3s to resolve the contacts. This timeout is required since 334 // ContactsProvider might take a long time to start up. 335 // 336 // Return STARRED_CONTACT when the timeout is hit in order to avoid 337 // missed calls in ZEN mode "Important". 338 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 339 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 340 ValidateNotificationPeople.STARRED_CONTACT; 341 342 /** notification_enqueue status value for a newly enqueued notification. */ 343 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 344 345 /** notification_enqueue status value for an existing notification. */ 346 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 347 348 /** notification_enqueue status value for an ignored notification. */ 349 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 350 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds 351 352 private static final long DELAY_FOR_ASSISTANT_TIME = 100; 353 354 private static final String ACTION_NOTIFICATION_TIMEOUT = 355 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 356 private static final int REQUEST_CODE_TIMEOUT = 1; 357 private static final String SCHEME_TIMEOUT = "timeout"; 358 private static final String EXTRA_KEY = "key"; 359 360 private IActivityManager mAm; 361 private ActivityManager mActivityManager; 362 private IPackageManager mPackageManager; 363 private PackageManager mPackageManagerClient; 364 AudioManager mAudioManager; 365 AudioManagerInternal mAudioManagerInternal; 366 @Nullable StatusBarManagerInternal mStatusBar; 367 Vibrator mVibrator; 368 private WindowManagerInternal mWindowManagerInternal; 369 private AlarmManager mAlarmManager; 370 private ICompanionDeviceManager mCompanionManager; 371 private AccessibilityManager mAccessibilityManager; 372 private IDeviceIdleController mDeviceIdleController; 373 private IUriGrantsManager mUgm; 374 private UriGrantsManagerInternal mUgmInternal; 375 private RoleObserver mRoleObserver; 376 private UserManager mUm; 377 378 final IBinder mForegroundToken = new Binder(); 379 private WorkerHandler mHandler; 380 private final HandlerThread mRankingThread = new HandlerThread("ranker", 381 Process.THREAD_PRIORITY_BACKGROUND); 382 383 private LogicalLight mNotificationLight; 384 LogicalLight mAttentionLight; 385 386 private long[] mFallbackVibrationPattern; 387 private boolean mUseAttentionLight; 388 boolean mHasLight = true; 389 boolean mLightEnabled; 390 boolean mSystemReady; 391 392 private boolean mDisableNotificationEffects; 393 private int mCallState; 394 private String mSoundNotificationKey; 395 private String mVibrateNotificationKey; 396 397 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects = 398 new SparseArray<>(); 399 private List<ComponentName> mEffectsSuppressors = new ArrayList<>(); 400 private int mListenerHints; // right now, all hints are global 401 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 402 403 // for enabling and disabling notification pulse behavior 404 boolean mScreenOn = true; 405 protected boolean mInCallStateOffHook = false; 406 boolean mNotificationPulseEnabled; 407 408 private Uri mInCallNotificationUri; 409 private AudioAttributes mInCallNotificationAudioAttributes; 410 private float mInCallNotificationVolume; 411 private Binder mCallNotificationToken = null; 412 413 // used as a mutex for access to all active notifications & listeners 414 final Object mNotificationLock = new Object(); 415 @GuardedBy("mNotificationLock") 416 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>(); 417 @GuardedBy("mNotificationLock") 418 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>(); 419 @GuardedBy("mNotificationLock") 420 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>(); 421 @GuardedBy("mNotificationLock") 422 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); 423 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>(); 424 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 425 426 // The last key in this list owns the hardware. 427 ArrayList<String> mLights = new ArrayList<>(); 428 429 private AppOpsManager mAppOps; 430 private UsageStatsManagerInternal mAppUsageStats; 431 private DevicePolicyManagerInternal mDpm; 432 433 private Archive mArchive; 434 435 // Persistent storage for notification policy 436 private AtomicFile mPolicyFile; 437 438 private static final int DB_VERSION = 1; 439 440 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 441 private static final String ATTR_VERSION = "version"; 442 443 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG = 444 "allow-secure-notifications-on-lockscreen"; 445 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value"; 446 447 private RankingHelper mRankingHelper; 448 private PreferencesHelper mPreferencesHelper; 449 450 private final UserProfiles mUserProfiles = new UserProfiles(); 451 private NotificationListeners mListeners; 452 private NotificationAssistants mAssistants; 453 private ConditionProviders mConditionProviders; 454 private NotificationUsageStats mUsageStats; 455 private boolean mLockScreenAllowSecureNotifications = true; 456 457 private static final int MY_UID = Process.myUid(); 458 private static final int MY_PID = Process.myPid(); 459 private static final IBinder WHITELIST_TOKEN = new Binder(); 460 private RankingHandler mRankingHandler; 461 private long mLastOverRateLogTime; 462 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 463 464 private SnoozeHelper mSnoozeHelper; 465 private GroupHelper mGroupHelper; 466 private int mAutoGroupAtCount; 467 private boolean mIsTelevision; 468 private boolean mIsAutomotive; 469 private boolean mNotificationEffectsEnabledForAutomotive; 470 471 private MetricsLogger mMetricsLogger; 472 private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; 473 474 private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); 475 476 private static class Archive { 477 final int mBufferSize; 478 final ArrayDeque<StatusBarNotification> mBuffer; 479 Archive(int size)480 public Archive(int size) { 481 mBufferSize = size; 482 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize); 483 } 484 toString()485 public String toString() { 486 final StringBuilder sb = new StringBuilder(); 487 final int N = mBuffer.size(); 488 sb.append("Archive ("); 489 sb.append(N); 490 sb.append(" notification"); 491 sb.append((N==1)?")":"s)"); 492 return sb.toString(); 493 } 494 record(StatusBarNotification nr)495 public void record(StatusBarNotification nr) { 496 if (mBuffer.size() == mBufferSize) { 497 mBuffer.removeFirst(); 498 } 499 500 // We don't want to store the heavy bits of the notification in the archive, 501 // but other clients in the system process might be using the object, so we 502 // store a (lightened) copy. 503 mBuffer.addLast(nr.cloneLight()); 504 } 505 descendingIterator()506 public Iterator<StatusBarNotification> descendingIterator() { 507 return mBuffer.descendingIterator(); 508 } 509 getArray(int count)510 public StatusBarNotification[] getArray(int count) { 511 if (count == 0) count = mBufferSize; 512 final StatusBarNotification[] a 513 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 514 Iterator<StatusBarNotification> iter = descendingIterator(); 515 int i=0; 516 while (iter.hasNext() && i < count) { 517 a[i++] = iter.next(); 518 } 519 return a; 520 } 521 522 } 523 readDefaultApprovedServices(int userId)524 protected void readDefaultApprovedServices(int userId) { 525 String defaultListenerAccess = getContext().getResources().getString( 526 com.android.internal.R.string.config_defaultListenerAccessPackages); 527 if (defaultListenerAccess != null) { 528 for (String whitelisted : 529 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) { 530 // Gather all notification listener components for candidate pkgs. 531 Set<ComponentName> approvedListeners = 532 mListeners.queryPackageForServices(whitelisted, 533 MATCH_DIRECT_BOOT_AWARE 534 | MATCH_DIRECT_BOOT_UNAWARE, userId); 535 for (ComponentName cn : approvedListeners) { 536 try { 537 getBinderService().setNotificationListenerAccessGrantedForUser(cn, 538 userId, true); 539 } catch (RemoteException e) { 540 e.printStackTrace(); 541 } 542 } 543 } 544 } 545 546 String defaultDndAccess = getContext().getResources().getString( 547 com.android.internal.R.string.config_defaultDndAccessPackages); 548 if (defaultDndAccess != null) { 549 for (String whitelisted : 550 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) { 551 try { 552 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true); 553 } catch (RemoteException e) { 554 e.printStackTrace(); 555 } 556 } 557 } 558 559 setDefaultAssistantForUser(userId); 560 } 561 setDefaultAssistantForUser(int userId)562 protected void setDefaultAssistantForUser(int userId) { 563 List<ComponentName> validAssistants = new ArrayList<>( 564 mAssistants.queryPackageForServices( 565 null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId)); 566 567 List<String> candidateStrs = new ArrayList<>(); 568 candidateStrs.add(DeviceConfig.getProperty( 569 DeviceConfig.NAMESPACE_SYSTEMUI, 570 SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)); 571 candidateStrs.add(getContext().getResources().getString( 572 com.android.internal.R.string.config_defaultAssistantAccessComponent)); 573 574 for (String candidateStr : candidateStrs) { 575 if (TextUtils.isEmpty(candidateStr)) { 576 continue; 577 } 578 ComponentName candidate = ComponentName.unflattenFromString(candidateStr); 579 if (candidate != null && validAssistants.contains(candidate)) { 580 setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true); 581 Slog.d(TAG, String.format("Set default NAS to be %s in %d", candidateStr, userId)); 582 return; 583 } else { 584 Slog.w(TAG, "Invalid default NAS config is found: " + candidateStr); 585 } 586 } 587 } 588 readPolicyXml(InputStream stream, boolean forRestore, int userId)589 void readPolicyXml(InputStream stream, boolean forRestore, int userId) 590 throws XmlPullParserException, NumberFormatException, IOException { 591 final XmlPullParser parser = Xml.newPullParser(); 592 parser.setInput(stream, StandardCharsets.UTF_8.name()); 593 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY); 594 boolean migratedManagedServices = false; 595 boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId); 596 int outerDepth = parser.getDepth(); 597 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 598 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) { 599 mZenModeHelper.readXml(parser, forRestore, userId); 600 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){ 601 mPreferencesHelper.readXml(parser, forRestore, userId); 602 } 603 if (mListeners.getConfig().xmlTag.equals(parser.getName())) { 604 if (ineligibleForManagedServices) { 605 continue; 606 } 607 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 608 migratedManagedServices = true; 609 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) { 610 if (ineligibleForManagedServices) { 611 continue; 612 } 613 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId); 614 migratedManagedServices = true; 615 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) { 616 if (ineligibleForManagedServices) { 617 continue; 618 } 619 mConditionProviders.readXml( 620 parser, mAllowedManagedServicePackages, forRestore, userId); 621 migratedManagedServices = true; 622 } 623 if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) { 624 if (forRestore && userId != UserHandle.USER_SYSTEM) { 625 continue; 626 } 627 mLockScreenAllowSecureNotifications = 628 safeBoolean(parser.getAttributeValue(null, 629 LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true); 630 } 631 } 632 633 if (!migratedManagedServices) { 634 mListeners.migrateToXml(); 635 mAssistants.migrateToXml(); 636 mConditionProviders.migrateToXml(); 637 handleSavePolicyFile(); 638 } 639 640 mAssistants.resetDefaultAssistantsIfNecessary(); 641 } 642 643 @VisibleForTesting loadPolicyFile()644 protected void loadPolicyFile() { 645 if (DBG) Slog.d(TAG, "loadPolicyFile"); 646 synchronized (mPolicyFile) { 647 InputStream infile = null; 648 try { 649 infile = mPolicyFile.openRead(); 650 readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL); 651 } catch (FileNotFoundException e) { 652 // No data yet 653 // Load default managed services approvals 654 readDefaultApprovedServices(USER_SYSTEM); 655 } catch (IOException e) { 656 Log.wtf(TAG, "Unable to read notification policy", e); 657 } catch (NumberFormatException e) { 658 Log.wtf(TAG, "Unable to parse notification policy", e); 659 } catch (XmlPullParserException e) { 660 Log.wtf(TAG, "Unable to parse notification policy", e); 661 } finally { 662 IoUtils.closeQuietly(infile); 663 } 664 } 665 } 666 667 @VisibleForTesting handleSavePolicyFile()668 protected void handleSavePolicyFile() { 669 if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) { 670 IoThread.getHandler().post(mSavePolicyFile); 671 } 672 } 673 674 private final class SavePolicyFileRunnable implements Runnable { 675 @Override run()676 public void run() { 677 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 678 synchronized (mPolicyFile) { 679 final FileOutputStream stream; 680 try { 681 stream = mPolicyFile.startWrite(); 682 } catch (IOException e) { 683 Slog.w(TAG, "Failed to save policy file", e); 684 return; 685 } 686 687 try { 688 writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL); 689 mPolicyFile.finishWrite(stream); 690 } catch (IOException e) { 691 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 692 mPolicyFile.failWrite(stream); 693 } 694 } 695 BackupManager.dataChanged(getContext().getPackageName()); 696 } 697 } 698 writePolicyXml(OutputStream stream, boolean forBackup, int userId)699 private void writePolicyXml(OutputStream stream, boolean forBackup, int userId) 700 throws IOException { 701 final XmlSerializer out = new FastXmlSerializer(); 702 out.setOutput(stream, StandardCharsets.UTF_8.name()); 703 out.startDocument(null, true); 704 out.startTag(null, TAG_NOTIFICATION_POLICY); 705 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 706 mZenModeHelper.writeXml(out, forBackup, null, userId); 707 mPreferencesHelper.writeXml(out, forBackup, userId); 708 mListeners.writeXml(out, forBackup, userId); 709 mAssistants.writeXml(out, forBackup, userId); 710 mConditionProviders.writeXml(out, forBackup, userId); 711 if (!forBackup || userId == UserHandle.USER_SYSTEM) { 712 writeSecureNotificationsPolicy(out); 713 } 714 out.endTag(null, TAG_NOTIFICATION_POLICY); 715 out.endDocument(); 716 } 717 718 private static final class ToastRecord 719 { 720 final int pid; 721 final String pkg; 722 final ITransientNotification callback; 723 int duration; 724 int displayId; 725 Binder token; 726 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration, Binder token, int displayId)727 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration, 728 Binder token, int displayId) { 729 this.pid = pid; 730 this.pkg = pkg; 731 this.callback = callback; 732 this.duration = duration; 733 this.token = token; 734 this.displayId = displayId; 735 } 736 update(int duration)737 void update(int duration) { 738 this.duration = duration; 739 } 740 dump(PrintWriter pw, String prefix, DumpFilter filter)741 void dump(PrintWriter pw, String prefix, DumpFilter filter) { 742 if (filter != null && !filter.matches(pkg)) return; 743 pw.println(prefix + this); 744 } 745 746 @Override toString()747 public final String toString() 748 { 749 return "ToastRecord{" 750 + Integer.toHexString(System.identityHashCode(this)) 751 + " pkg=" + pkg 752 + " callback=" + callback 753 + " duration=" + duration; 754 } 755 } 756 757 @VisibleForTesting 758 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 759 760 @Override 761 public void onSetDisabled(int status) { 762 synchronized (mNotificationLock) { 763 mDisableNotificationEffects = 764 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 765 if (disableNotificationEffects(null) != null) { 766 // cancel whatever's going on 767 long identity = Binder.clearCallingIdentity(); 768 try { 769 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 770 if (player != null) { 771 player.stopAsync(); 772 } 773 } catch (RemoteException e) { 774 } finally { 775 Binder.restoreCallingIdentity(identity); 776 } 777 778 identity = Binder.clearCallingIdentity(); 779 try { 780 mVibrator.cancel(); 781 } finally { 782 Binder.restoreCallingIdentity(identity); 783 } 784 } 785 } 786 } 787 788 @Override 789 public void onClearAll(int callingUid, int callingPid, int userId) { 790 synchronized (mNotificationLock) { 791 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null, 792 /*includeCurrentProfiles*/ true); 793 } 794 } 795 796 @Override 797 public void onNotificationClick(int callingUid, int callingPid, String key, 798 NotificationVisibility nv) { 799 exitIdle(); 800 synchronized (mNotificationLock) { 801 NotificationRecord r = mNotificationsByKey.get(key); 802 if (r == null) { 803 Slog.w(TAG, "No notification with key: " + key); 804 return; 805 } 806 final long now = System.currentTimeMillis(); 807 MetricsLogger.action(r.getItemLogMaker() 808 .setType(MetricsEvent.TYPE_ACTION) 809 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 810 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); 811 EventLogTags.writeNotificationClicked(key, 812 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 813 nv.rank, nv.count); 814 815 StatusBarNotification sbn = r.sbn; 816 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 817 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 818 FLAG_FOREGROUND_SERVICE, false, r.getUserId(), 819 REASON_CLICK, nv.rank, nv.count, null); 820 nv.recycle(); 821 reportUserInteraction(r); 822 } 823 } 824 825 @Override 826 public void onNotificationActionClick(int callingUid, int callingPid, String key, 827 int actionIndex, Notification.Action action, NotificationVisibility nv, 828 boolean generatedByAssistant) { 829 exitIdle(); 830 synchronized (mNotificationLock) { 831 NotificationRecord r = mNotificationsByKey.get(key); 832 if (r == null) { 833 Slog.w(TAG, "No notification with key: " + key); 834 return; 835 } 836 final long now = System.currentTimeMillis(); 837 MetricsLogger.action(r.getLogMaker(now) 838 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) 839 .setType(MetricsEvent.TYPE_ACTION) 840 .setSubtype(actionIndex) 841 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) 842 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count) 843 .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART, 844 action.isContextual() ? 1 : 0) 845 .addTaggedData( 846 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 847 generatedByAssistant ? 1 : 0) 848 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 849 nv.location.toMetricsEventEnum())); 850 851 EventLogTags.writeNotificationActionClicked(key, actionIndex, 852 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 853 nv.rank, nv.count); 854 nv.recycle(); 855 reportUserInteraction(r); 856 mAssistants.notifyAssistantActionClicked( 857 r.sbn, actionIndex, action, generatedByAssistant); 858 } 859 } 860 861 @Override 862 public void onNotificationClear(int callingUid, int callingPid, 863 String pkg, String tag, int id, int userId, String key, 864 @NotificationStats.DismissalSurface int dismissalSurface, 865 @NotificationStats.DismissalSentiment int dismissalSentiment, 866 NotificationVisibility nv) { 867 synchronized (mNotificationLock) { 868 NotificationRecord r = mNotificationsByKey.get(key); 869 if (r != null) { 870 r.recordDismissalSurface(dismissalSurface); 871 r.recordDismissalSentiment(dismissalSentiment); 872 } 873 } 874 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 875 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE, 876 true, userId, REASON_CANCEL, nv.rank, nv.count,null); 877 nv.recycle(); 878 } 879 880 @Override 881 public void onPanelRevealed(boolean clearEffects, int items) { 882 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL); 883 MetricsLogger.histogram(getContext(), "note_load", items); 884 EventLogTags.writeNotificationPanelRevealed(items); 885 if (clearEffects) { 886 clearEffects(); 887 } 888 } 889 890 @Override 891 public void onPanelHidden() { 892 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL); 893 EventLogTags.writeNotificationPanelHidden(); 894 } 895 896 @Override 897 public void clearEffects() { 898 synchronized (mNotificationLock) { 899 if (DBG) Slog.d(TAG, "clearEffects"); 900 clearSoundLocked(); 901 clearVibrateLocked(); 902 clearLightsLocked(); 903 } 904 } 905 906 @Override 907 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, 908 int id, int uid, int initialPid, String message, int userId) { 909 final boolean fgService; 910 synchronized (mNotificationLock) { 911 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 912 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; 913 } 914 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 915 REASON_ERROR, null); 916 if (fgService) { 917 // Still crash for foreground services, preventing the not-crash behaviour abused 918 // by apps to give us a garbage notification and silently start a fg service. 919 Binder.withCleanCallingIdentity( 920 () -> mAm.crashApplication(uid, initialPid, pkg, -1, 921 "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " 922 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " 923 + message, true /* force */)); 924 } 925 } 926 927 @Override 928 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 929 NotificationVisibility[] noLongerVisibleKeys) { 930 synchronized (mNotificationLock) { 931 for (NotificationVisibility nv : newlyVisibleKeys) { 932 NotificationRecord r = mNotificationsByKey.get(nv.key); 933 if (r == null) continue; 934 if (!r.isSeen()) { 935 // Report to usage stats that notification was made visible 936 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key); 937 reportSeen(r); 938 } 939 r.setVisibility(true, nv.rank, nv.count); 940 boolean isHun = (nv.location 941 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP); 942 // hasBeenVisiblyExpanded must be called after updating the expansion state of 943 // the NotificationRecord to ensure the expansion state is up-to-date. 944 if (isHun || r.hasBeenVisiblyExpanded()) { 945 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum()); 946 } 947 maybeRecordInterruptionLocked(r); 948 nv.recycle(); 949 } 950 // Note that we might receive this event after notifications 951 // have already left the system, e.g. after dismissing from the 952 // shade. Hence not finding notifications in 953 // mNotificationsByKey is not an exceptional condition. 954 for (NotificationVisibility nv : noLongerVisibleKeys) { 955 NotificationRecord r = mNotificationsByKey.get(nv.key); 956 if (r == null) continue; 957 r.setVisibility(false, nv.rank, nv.count); 958 nv.recycle(); 959 } 960 } 961 } 962 963 @Override 964 public void onNotificationExpansionChanged(String key, 965 boolean userAction, boolean expanded, int notificationLocation) { 966 synchronized (mNotificationLock) { 967 NotificationRecord r = mNotificationsByKey.get(key); 968 if (r != null) { 969 r.stats.onExpansionChanged(userAction, expanded); 970 // hasBeenVisiblyExpanded must be called after updating the expansion state of 971 // the NotificationRecord to ensure the expansion state is up-to-date. 972 if (r.hasBeenVisiblyExpanded()) { 973 logSmartSuggestionsVisible(r, notificationLocation); 974 } 975 if (userAction) { 976 MetricsLogger.action(r.getItemLogMaker() 977 .setType(expanded ? MetricsEvent.TYPE_DETAIL 978 : MetricsEvent.TYPE_COLLAPSE)); 979 } 980 if (expanded && userAction) { 981 r.recordExpanded(); 982 reportUserInteraction(r); 983 } 984 mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded); 985 } 986 } 987 } 988 989 @Override 990 public void onNotificationDirectReplied(String key) { 991 exitIdle(); 992 synchronized (mNotificationLock) { 993 NotificationRecord r = mNotificationsByKey.get(key); 994 if (r != null) { 995 r.recordDirectReplied(); 996 mMetricsLogger.write(r.getLogMaker() 997 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION) 998 .setType(MetricsEvent.TYPE_ACTION)); 999 reportUserInteraction(r); 1000 mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn); 1001 } 1002 } 1003 } 1004 1005 @Override 1006 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, 1007 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) { 1008 synchronized (mNotificationLock) { 1009 NotificationRecord r = mNotificationsByKey.get(key); 1010 if (r != null) { 1011 r.setNumSmartRepliesAdded(smartReplyCount); 1012 r.setNumSmartActionsAdded(smartActionCount); 1013 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 1014 r.setEditChoicesBeforeSending(editBeforeSending); 1015 } 1016 } 1017 } 1018 1019 @Override 1020 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply, 1021 int notificationLocation, boolean modifiedBeforeSending) { 1022 1023 synchronized (mNotificationLock) { 1024 NotificationRecord r = mNotificationsByKey.get(key); 1025 if (r != null) { 1026 LogMaker logMaker = r.getLogMaker() 1027 .setCategory(MetricsEvent.SMART_REPLY_ACTION) 1028 .setSubtype(replyIndex) 1029 .addTaggedData( 1030 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1031 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1032 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, 1033 notificationLocation) 1034 .addTaggedData( 1035 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1036 r.getEditChoicesBeforeSending() ? 1 : 0) 1037 .addTaggedData( 1038 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING, 1039 modifiedBeforeSending ? 1 : 0); 1040 mMetricsLogger.write(logMaker); 1041 // Treat clicking on a smart reply as a user interaction. 1042 reportUserInteraction(r); 1043 mAssistants.notifyAssistantSuggestedReplySent( 1044 r.sbn, reply, r.getSuggestionsGeneratedByAssistant()); 1045 } 1046 } 1047 } 1048 1049 @Override 1050 public void onNotificationSettingsViewed(String key) { 1051 synchronized (mNotificationLock) { 1052 NotificationRecord r = mNotificationsByKey.get(key); 1053 if (r != null) { 1054 r.recordViewedSettings(); 1055 } 1056 } 1057 } 1058 1059 @Override 1060 public void onNotificationBubbleChanged(String key, boolean isBubble) { 1061 synchronized (mNotificationLock) { 1062 NotificationRecord r = mNotificationsByKey.get(key); 1063 if (r != null) { 1064 final StatusBarNotification n = r.sbn; 1065 final int callingUid = n.getUid(); 1066 final String pkg = n.getPackageName(); 1067 if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid, 1068 null /* oldEntry */)) { 1069 r.getNotification().flags |= FLAG_BUBBLE; 1070 } else { 1071 r.getNotification().flags &= ~FLAG_BUBBLE; 1072 } 1073 } 1074 } 1075 } 1076 }; 1077 1078 @VisibleForTesting logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)1079 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) { 1080 // If the newly visible notification has smart suggestions 1081 // then log that the user has seen them. 1082 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0) 1083 && !r.hasSeenSmartReplies()) { 1084 r.setSeenSmartReplies(true); 1085 LogMaker logMaker = r.getLogMaker() 1086 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE) 1087 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT, 1088 r.getNumSmartRepliesAdded()) 1089 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT, 1090 r.getNumSmartActionsAdded()) 1091 .addTaggedData( 1092 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, 1093 r.getSuggestionsGeneratedByAssistant() ? 1 : 0) 1094 // The fields in the NotificationVisibility.NotificationLocation enum map 1095 // directly to the fields in the MetricsEvent.NotificationLocation enum. 1096 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation) 1097 .addTaggedData( 1098 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING, 1099 r.getEditChoicesBeforeSending() ? 1 : 0); 1100 mMetricsLogger.write(logMaker); 1101 } 1102 } 1103 1104 @GuardedBy("mNotificationLock") clearSoundLocked()1105 private void clearSoundLocked() { 1106 mSoundNotificationKey = null; 1107 long identity = Binder.clearCallingIdentity(); 1108 try { 1109 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 1110 if (player != null) { 1111 player.stopAsync(); 1112 } 1113 } catch (RemoteException e) { 1114 } finally { 1115 Binder.restoreCallingIdentity(identity); 1116 } 1117 } 1118 1119 @GuardedBy("mNotificationLock") clearVibrateLocked()1120 private void clearVibrateLocked() { 1121 mVibrateNotificationKey = null; 1122 long identity = Binder.clearCallingIdentity(); 1123 try { 1124 mVibrator.cancel(); 1125 } finally { 1126 Binder.restoreCallingIdentity(identity); 1127 } 1128 } 1129 1130 @GuardedBy("mNotificationLock") clearLightsLocked()1131 private void clearLightsLocked() { 1132 // light 1133 mLights.clear(); 1134 updateLightsLocked(); 1135 } 1136 1137 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { 1138 @Override 1139 public void onReceive(Context context, Intent intent) { 1140 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 1141 // update system notification channels 1142 SystemNotificationChannels.createAll(context); 1143 mZenModeHelper.updateDefaultZenRules(); 1144 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser()); 1145 } 1146 } 1147 }; 1148 1149 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() { 1150 @Override 1151 public void onReceive(Context context, Intent intent) { 1152 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) { 1153 try { 1154 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); 1155 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); 1156 int restoredFromSdkInt = intent.getIntExtra( 1157 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0); 1158 mListeners.onSettingRestored( 1159 element, newValue, restoredFromSdkInt, getSendingUserId()); 1160 mConditionProviders.onSettingRestored( 1161 element, newValue, restoredFromSdkInt, getSendingUserId()); 1162 } catch (Exception e) { 1163 Slog.wtf(TAG, "Cannot restore managed services from settings", e); 1164 } 1165 } 1166 } 1167 }; 1168 1169 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() { 1170 @Override 1171 public void onReceive(Context context, Intent intent) { 1172 String action = intent.getAction(); 1173 if (action == null) { 1174 return; 1175 } 1176 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) { 1177 final NotificationRecord record; 1178 synchronized (mNotificationLock) { 1179 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY)); 1180 } 1181 if (record != null) { 1182 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(), 1183 record.sbn.getPackageName(), record.sbn.getTag(), 1184 record.sbn.getId(), 0, 1185 FLAG_FOREGROUND_SERVICE, true, record.getUserId(), 1186 REASON_TIMEOUT, null); 1187 } 1188 } 1189 } 1190 }; 1191 1192 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 1193 @Override 1194 public void onReceive(Context context, Intent intent) { 1195 String action = intent.getAction(); 1196 if (action == null) { 1197 return; 1198 } 1199 1200 boolean queryRestart = false; 1201 boolean queryRemove = false; 1202 boolean packageChanged = false; 1203 boolean cancelNotifications = true; 1204 boolean hideNotifications = false; 1205 boolean unhideNotifications = false; 1206 int reason = REASON_PACKAGE_CHANGED; 1207 1208 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1209 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 1210 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1211 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 1212 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 1213 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) 1214 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED) 1215 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED) 1216 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 1217 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1218 UserHandle.USER_ALL); 1219 String pkgList[] = null; 1220 int uidList[] = null; 1221 boolean removingPackage = queryRemove && 1222 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 1223 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage); 1224 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1225 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1226 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1227 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 1228 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1229 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1230 cancelNotifications = false; 1231 hideNotifications = true; 1232 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { 1233 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1234 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1235 cancelNotifications = false; 1236 unhideNotifications = true; 1237 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) { 1238 final int distractionRestrictions = 1239 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS, 1240 PackageManager.RESTRICTION_NONE); 1241 if ((distractionRestrictions 1242 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) { 1243 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1244 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1245 cancelNotifications = false; 1246 hideNotifications = true; 1247 } else { 1248 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1249 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1250 cancelNotifications = false; 1251 unhideNotifications = true; 1252 } 1253 1254 } else if (queryRestart) { 1255 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 1256 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 1257 } else { 1258 Uri uri = intent.getData(); 1259 if (uri == null) { 1260 return; 1261 } 1262 String pkgName = uri.getSchemeSpecificPart(); 1263 if (pkgName == null) { 1264 return; 1265 } 1266 if (packageChanged) { 1267 // We cancel notifications for packages which have just been disabled 1268 try { 1269 final int enabled = mPackageManager.getApplicationEnabledSetting( 1270 pkgName, 1271 changeUserId != UserHandle.USER_ALL ? changeUserId : 1272 USER_SYSTEM); 1273 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 1274 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 1275 cancelNotifications = false; 1276 } 1277 } catch (IllegalArgumentException e) { 1278 // Package doesn't exist; probably racing with uninstall. 1279 // cancelNotifications is already true, so nothing to do here. 1280 if (DBG) { 1281 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 1282 } 1283 } catch (RemoteException e) { 1284 // Failed to talk to PackageManagerService Should never happen! 1285 } 1286 } 1287 pkgList = new String[]{pkgName}; 1288 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 1289 } 1290 if (pkgList != null && (pkgList.length > 0)) { 1291 if (cancelNotifications) { 1292 for (String pkgName : pkgList) { 1293 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, 1294 !queryRestart, changeUserId, reason, null); 1295 } 1296 } else if (hideNotifications) { 1297 hideNotificationsForPackages(pkgList); 1298 } else if (unhideNotifications) { 1299 unhideNotificationsForPackages(pkgList); 1300 } 1301 } 1302 1303 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList); 1304 } 1305 } 1306 }; 1307 1308 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 1309 @Override 1310 public void onReceive(Context context, Intent intent) { 1311 String action = intent.getAction(); 1312 1313 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1314 // Keep track of screen on/off state, but do not turn off the notification light 1315 // until user passes through the lock screen or views the notification. 1316 mScreenOn = true; 1317 updateNotificationPulse(); 1318 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1319 mScreenOn = false; 1320 updateNotificationPulse(); 1321 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 1322 mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK 1323 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 1324 updateNotificationPulse(); 1325 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 1326 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1327 if (userHandle >= 0) { 1328 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle, 1329 REASON_USER_STOPPED, null); 1330 } 1331 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 1332 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1333 if (userHandle >= 0) { 1334 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle, 1335 REASON_PROFILE_TURNED_OFF, null); 1336 } 1337 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1338 // turn off LED when user passes through lock screen 1339 mNotificationLight.turnOff(); 1340 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 1341 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1342 mUserProfiles.updateCache(context); 1343 if (!mUserProfiles.isManagedProfile(userId)) { 1344 // reload per-user settings 1345 mSettingsObserver.update(null); 1346 // Refresh managed services 1347 mConditionProviders.onUserSwitched(userId); 1348 mListeners.onUserSwitched(userId); 1349 mZenModeHelper.onUserSwitched(userId); 1350 mPreferencesHelper.onUserSwitched(userId); 1351 } 1352 // assistant is the only thing that cares about managed profiles specifically 1353 mAssistants.onUserSwitched(userId); 1354 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 1355 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1356 if (userId != USER_NULL) { 1357 mUserProfiles.updateCache(context); 1358 if (!mUserProfiles.isManagedProfile(userId)) { 1359 readDefaultApprovedServices(userId); 1360 } 1361 } 1362 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 1363 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1364 mUserProfiles.updateCache(context); 1365 mZenModeHelper.onUserRemoved(userId); 1366 mPreferencesHelper.onUserRemoved(userId); 1367 mListeners.onUserRemoved(userId); 1368 mConditionProviders.onUserRemoved(userId); 1369 mAssistants.onUserRemoved(userId); 1370 handleSavePolicyFile(); 1371 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { 1372 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); 1373 mUserProfiles.updateCache(context); 1374 mAssistants.onUserUnlocked(userId); 1375 if (!mUserProfiles.isManagedProfile(userId)) { 1376 mConditionProviders.onUserUnlocked(userId); 1377 mListeners.onUserUnlocked(userId); 1378 mZenModeHelper.onUserUnlocked(userId); 1379 mPreferencesHelper.onUserUnlocked(userId); 1380 } 1381 } 1382 } 1383 }; 1384 1385 private final class SettingsObserver extends ContentObserver { 1386 private final Uri NOTIFICATION_BADGING_URI 1387 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING); 1388 private final Uri NOTIFICATION_BUBBLES_URI_GLOBAL 1389 = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_BUBBLES); 1390 private final Uri NOTIFICATION_BUBBLES_URI_SECURE 1391 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES); 1392 private final Uri NOTIFICATION_LIGHT_PULSE_URI 1393 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 1394 private final Uri NOTIFICATION_RATE_LIMIT_URI 1395 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); 1396 SettingsObserver(Handler handler)1397 SettingsObserver(Handler handler) { 1398 super(handler); 1399 } 1400 observe()1401 void observe() { 1402 ContentResolver resolver = getContext().getContentResolver(); 1403 resolver.registerContentObserver(NOTIFICATION_BADGING_URI, 1404 false, this, UserHandle.USER_ALL); 1405 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 1406 false, this, UserHandle.USER_ALL); 1407 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, 1408 false, this, UserHandle.USER_ALL); 1409 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_GLOBAL, 1410 false, this, UserHandle.USER_ALL); 1411 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_SECURE, 1412 false, this, UserHandle.USER_ALL); 1413 update(null); 1414 } 1415 onChange(boolean selfChange, Uri uri)1416 @Override public void onChange(boolean selfChange, Uri uri) { 1417 update(uri); 1418 } 1419 update(Uri uri)1420 public void update(Uri uri) { 1421 ContentResolver resolver = getContext().getContentResolver(); 1422 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 1423 boolean pulseEnabled = Settings.System.getIntForUser(resolver, 1424 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) 1425 != 0; 1426 if (mNotificationPulseEnabled != pulseEnabled) { 1427 mNotificationPulseEnabled = pulseEnabled; 1428 updateNotificationPulse(); 1429 } 1430 } 1431 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) { 1432 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver, 1433 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate); 1434 } 1435 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { 1436 mPreferencesHelper.updateBadgingEnabled(); 1437 } 1438 // In QPR we moved the setting to Global rather than Secure so that the setting 1439 // applied to work profiles. Unfortunately we need to maintain both to pass CTS without 1440 // a change to CTS outside of a normal letter release. 1441 if (uri == null || NOTIFICATION_BUBBLES_URI_GLOBAL.equals(uri)) { 1442 syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_GLOBAL); 1443 mPreferencesHelper.updateBubblesEnabled(); 1444 } 1445 if (NOTIFICATION_BUBBLES_URI_SECURE.equals(uri)) { 1446 syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_SECURE); 1447 } 1448 } 1449 syncBubbleSettings(ContentResolver resolver, Uri settingToFollow)1450 private void syncBubbleSettings(ContentResolver resolver, Uri settingToFollow) { 1451 boolean followSecureSetting = settingToFollow.equals(NOTIFICATION_BUBBLES_URI_SECURE); 1452 1453 int secureSettingValue = Settings.Secure.getInt(resolver, 1454 Settings.Secure.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0); 1455 int globalSettingValue = Settings.Global.getInt(resolver, 1456 Settings.Global.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0); 1457 1458 if (globalSettingValue == secureSettingValue) { 1459 return; 1460 } 1461 1462 if (followSecureSetting) { 1463 // Global => secure 1464 Settings.Global.putInt(resolver, 1465 Settings.Global.NOTIFICATION_BUBBLES, 1466 secureSettingValue); 1467 } else { 1468 // Secure => Global 1469 Settings.Secure.putInt(resolver, 1470 Settings.Secure.NOTIFICATION_BUBBLES, 1471 globalSettingValue); 1472 } 1473 } 1474 } 1475 1476 private SettingsObserver mSettingsObserver; 1477 protected ZenModeHelper mZenModeHelper; 1478 getLongArray(Resources r, int resid, int maxlen, long[] def)1479 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 1480 int[] ar = r.getIntArray(resid); 1481 if (ar == null) { 1482 return def; 1483 } 1484 final int len = ar.length > maxlen ? maxlen : ar.length; 1485 long[] out = new long[len]; 1486 for (int i=0; i<len; i++) { 1487 out[i] = ar[i]; 1488 } 1489 return out; 1490 } 1491 NotificationManagerService(Context context)1492 public NotificationManagerService(Context context) { 1493 super(context); 1494 Notification.processWhitelistToken = WHITELIST_TOKEN; 1495 } 1496 1497 // TODO - replace these methods with a single VisibleForTesting constructor 1498 @VisibleForTesting setAudioManager(AudioManager audioMananger)1499 void setAudioManager(AudioManager audioMananger) { 1500 mAudioManager = audioMananger; 1501 } 1502 1503 @VisibleForTesting setHints(int hints)1504 void setHints(int hints) { 1505 mListenerHints = hints; 1506 } 1507 1508 @VisibleForTesting setVibrator(Vibrator vibrator)1509 void setVibrator(Vibrator vibrator) { 1510 mVibrator = vibrator; 1511 } 1512 1513 @VisibleForTesting setLights(LogicalLight light)1514 void setLights(LogicalLight light) { 1515 mNotificationLight = light; 1516 mAttentionLight = light; 1517 mNotificationPulseEnabled = true; 1518 } 1519 1520 @VisibleForTesting setScreenOn(boolean on)1521 void setScreenOn(boolean on) { 1522 mScreenOn = on; 1523 } 1524 1525 @VisibleForTesting getNotificationRecordCount()1526 int getNotificationRecordCount() { 1527 synchronized (mNotificationLock) { 1528 int count = mNotificationList.size() + mNotificationsByKey.size() 1529 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size(); 1530 // subtract duplicates 1531 for (NotificationRecord posted : mNotificationList) { 1532 if (mNotificationsByKey.containsKey(posted.getKey())) { 1533 count--; 1534 } 1535 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) { 1536 count--; 1537 } 1538 } 1539 1540 return count; 1541 } 1542 } 1543 1544 @VisibleForTesting clearNotifications()1545 void clearNotifications() { 1546 mEnqueuedNotifications.clear(); 1547 mNotificationList.clear(); 1548 mNotificationsByKey.clear(); 1549 mSummaryByGroupKey.clear(); 1550 } 1551 1552 @VisibleForTesting addNotification(NotificationRecord r)1553 void addNotification(NotificationRecord r) { 1554 mNotificationList.add(r); 1555 mNotificationsByKey.put(r.sbn.getKey(), r); 1556 if (r.sbn.isGroup()) { 1557 mSummaryByGroupKey.put(r.getGroupKey(), r); 1558 } 1559 } 1560 1561 @VisibleForTesting addEnqueuedNotification(NotificationRecord r)1562 void addEnqueuedNotification(NotificationRecord r) { 1563 mEnqueuedNotifications.add(r); 1564 } 1565 1566 @VisibleForTesting getNotificationRecord(String key)1567 NotificationRecord getNotificationRecord(String key) { 1568 return mNotificationsByKey.get(key); 1569 } 1570 1571 1572 @VisibleForTesting setSystemReady(boolean systemReady)1573 void setSystemReady(boolean systemReady) { 1574 mSystemReady = systemReady; 1575 } 1576 1577 @VisibleForTesting setHandler(WorkerHandler handler)1578 void setHandler(WorkerHandler handler) { 1579 mHandler = handler; 1580 } 1581 1582 @VisibleForTesting setFallbackVibrationPattern(long[] vibrationPattern)1583 void setFallbackVibrationPattern(long[] vibrationPattern) { 1584 mFallbackVibrationPattern = vibrationPattern; 1585 } 1586 1587 @VisibleForTesting setPackageManager(IPackageManager packageManager)1588 void setPackageManager(IPackageManager packageManager) { 1589 mPackageManager = packageManager; 1590 } 1591 1592 @VisibleForTesting setRankingHelper(RankingHelper rankingHelper)1593 void setRankingHelper(RankingHelper rankingHelper) { 1594 mRankingHelper = rankingHelper; 1595 } 1596 1597 @VisibleForTesting setPreferencesHelper(PreferencesHelper prefHelper)1598 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; } 1599 1600 @VisibleForTesting setRankingHandler(RankingHandler rankingHandler)1601 void setRankingHandler(RankingHandler rankingHandler) { 1602 mRankingHandler = rankingHandler; 1603 } 1604 1605 @VisibleForTesting setZenHelper(ZenModeHelper zenHelper)1606 void setZenHelper(ZenModeHelper zenHelper) { 1607 mZenModeHelper = zenHelper; 1608 } 1609 1610 @VisibleForTesting setIsAutomotive(boolean isAutomotive)1611 void setIsAutomotive(boolean isAutomotive) { 1612 mIsAutomotive = isAutomotive; 1613 } 1614 1615 @VisibleForTesting setNotificationEffectsEnabledForAutomotive(boolean isEnabled)1616 void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) { 1617 mNotificationEffectsEnabledForAutomotive = isEnabled; 1618 } 1619 1620 @VisibleForTesting setIsTelevision(boolean isTelevision)1621 void setIsTelevision(boolean isTelevision) { 1622 mIsTelevision = isTelevision; 1623 } 1624 1625 @VisibleForTesting setUsageStats(NotificationUsageStats us)1626 void setUsageStats(NotificationUsageStats us) { 1627 mUsageStats = us; 1628 } 1629 1630 @VisibleForTesting setAccessibilityManager(AccessibilityManager am)1631 void setAccessibilityManager(AccessibilityManager am) { 1632 mAccessibilityManager = am; 1633 } 1634 1635 // TODO: All tests should use this init instead of the one-off setters above. 1636 @VisibleForTesting init(Looper looper, 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, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, TelephonyManager telephonyManager)1637 void init(Looper looper, IPackageManager packageManager, 1638 PackageManager packageManagerClient, 1639 LightsManager lightsManager, NotificationListeners notificationListeners, 1640 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, 1641 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, 1642 NotificationUsageStats usageStats, AtomicFile policyFile, 1643 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, 1644 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, 1645 IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, 1646 UserManager userManager, TelephonyManager telephonyManager) { 1647 Resources resources = getContext().getResources(); 1648 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), 1649 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, 1650 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); 1651 1652 mAccessibilityManager = 1653 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 1654 mAm = am; 1655 mUgm = ugm; 1656 mUgmInternal = ugmInternal; 1657 mPackageManager = packageManager; 1658 mPackageManagerClient = packageManagerClient; 1659 mAppOps = appOps; 1660 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 1661 mAppUsageStats = appUsageStats; 1662 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 1663 mCompanionManager = companionManager; 1664 mActivityManager = activityManager; 1665 mDeviceIdleController = IDeviceIdleController.Stub.asInterface( 1666 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); 1667 mDpm = dpm; 1668 mUm = userManager; 1669 1670 mHandler = new WorkerHandler(looper); 1671 mRankingThread.start(); 1672 String[] extractorNames; 1673 try { 1674 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 1675 } catch (Resources.NotFoundException e) { 1676 extractorNames = new String[0]; 1677 } 1678 mUsageStats = usageStats; 1679 mMetricsLogger = new MetricsLogger(); 1680 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper()); 1681 mConditionProviders = conditionProviders; 1682 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); 1683 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 1684 @Override 1685 public void onConfigChanged() { 1686 handleSavePolicyFile(); 1687 } 1688 1689 @Override 1690 void onZenModeChanged() { 1691 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 1692 getContext().sendBroadcastAsUser( 1693 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 1694 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 1695 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); 1696 synchronized (mNotificationLock) { 1697 updateInterruptionFilterLocked(); 1698 } 1699 mRankingHandler.requestSort(); 1700 } 1701 1702 @Override 1703 void onPolicyChanged() { 1704 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 1705 mRankingHandler.requestSort(); 1706 } 1707 }); 1708 mPreferencesHelper = new PreferencesHelper(getContext(), 1709 mPackageManagerClient, 1710 mRankingHandler, 1711 mZenModeHelper); 1712 mRankingHelper = new RankingHelper(getContext(), 1713 mRankingHandler, 1714 mPreferencesHelper, 1715 mZenModeHelper, 1716 mUsageStats, 1717 extractorNames); 1718 mSnoozeHelper = snoozeHelper; 1719 mGroupHelper = groupHelper; 1720 1721 // This is a ManagedServices object that keeps track of the listeners. 1722 mListeners = notificationListeners; 1723 1724 // This is a MangedServices object that keeps track of the assistant. 1725 mAssistants = notificationAssistants; 1726 1727 // Needs to be set before loadPolicyFile 1728 mAllowedManagedServicePackages = this::canUseManagedServices; 1729 1730 mPolicyFile = policyFile; 1731 loadPolicyFile(); 1732 1733 mStatusBar = getLocalService(StatusBarManagerInternal.class); 1734 if (mStatusBar != null) { 1735 mStatusBar.setNotificationDelegate(mNotificationDelegate); 1736 } 1737 1738 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 1739 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION); 1740 1741 mFallbackVibrationPattern = getLongArray(resources, 1742 R.array.config_notificationFallbackVibePattern, 1743 VIBRATE_PATTERN_MAXLEN, 1744 DEFAULT_VIBRATE_PATTERN); 1745 mInCallNotificationUri = Uri.parse("file://" + 1746 resources.getString(R.string.config_inCallNotificationSound)); 1747 mInCallNotificationAudioAttributes = new AudioAttributes.Builder() 1748 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 1749 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) 1750 .build(); 1751 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume); 1752 1753 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); 1754 mHasLight = 1755 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed); 1756 1757 // Don't start allowing notifications until the setup wizard has run once. 1758 // After that, including subsequent boots, init with notifications turned on. 1759 // This works on the first boot because the setup wizard will toggle this 1760 // flag at least once and we'll go back to 0 after that. 1761 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 1762 Settings.Global.DEVICE_PROVISIONED, 0)) { 1763 mDisableNotificationEffects = true; 1764 } 1765 mZenModeHelper.initZenMode(); 1766 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1767 1768 mUserProfiles.updateCache(getContext()); 1769 1770 telephonyManager.listen(new PhoneStateListener() { 1771 @Override 1772 public void onCallStateChanged(int state, String incomingNumber) { 1773 if (mCallState == state) return; 1774 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 1775 mCallState = state; 1776 } 1777 }, PhoneStateListener.LISTEN_CALL_STATE); 1778 1779 mSettingsObserver = new SettingsObserver(mHandler); 1780 1781 mArchive = new Archive(resources.getInteger( 1782 R.integer.config_notificationServiceArchiveSize)); 1783 1784 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK) 1785 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION); 1786 1787 mIsAutomotive = 1788 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0); 1789 mNotificationEffectsEnabledForAutomotive = 1790 resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive); 1791 1792 mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray( 1793 com.android.internal.R.array.config_nonBlockableNotificationPackages)); 1794 1795 mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( 1796 com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); 1797 } 1798 1799 @Override onStart()1800 public void onStart() { 1801 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() { 1802 @Override 1803 public void repost(int userId, NotificationRecord r) { 1804 try { 1805 if (DBG) { 1806 Slog.d(TAG, "Reposting " + r.getKey()); 1807 } 1808 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(), 1809 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(), 1810 r.sbn.getNotification(), userId); 1811 } catch (Exception e) { 1812 Slog.e(TAG, "Cannot un-snooze notification", e); 1813 } 1814 } 1815 }, mUserProfiles); 1816 1817 final File systemDir = new File(Environment.getDataDirectory(), "system"); 1818 1819 init(Looper.myLooper(), 1820 AppGlobals.getPackageManager(), getContext().getPackageManager(), 1821 getLocalService(LightsManager.class), 1822 new NotificationListeners(AppGlobals.getPackageManager()), 1823 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles, 1824 AppGlobals.getPackageManager()), 1825 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()), 1826 null, snoozeHelper, new NotificationUsageStats(getContext()), 1827 new AtomicFile(new File( 1828 systemDir, "notification_policy.xml"), "notification-policy"), 1829 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE), 1830 getGroupHelper(), ActivityManager.getService(), 1831 LocalServices.getService(UsageStatsManagerInternal.class), 1832 LocalServices.getService(DevicePolicyManagerInternal.class), 1833 UriGrantsManager.getService(), 1834 LocalServices.getService(UriGrantsManagerInternal.class), 1835 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE), 1836 getContext().getSystemService(UserManager.class), 1837 getContext().getSystemService(TelephonyManager.class)); 1838 1839 // register for various Intents 1840 IntentFilter filter = new IntentFilter(); 1841 filter.addAction(Intent.ACTION_SCREEN_ON); 1842 filter.addAction(Intent.ACTION_SCREEN_OFF); 1843 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 1844 filter.addAction(Intent.ACTION_USER_PRESENT); 1845 filter.addAction(Intent.ACTION_USER_STOPPED); 1846 filter.addAction(Intent.ACTION_USER_SWITCHED); 1847 filter.addAction(Intent.ACTION_USER_ADDED); 1848 filter.addAction(Intent.ACTION_USER_REMOVED); 1849 filter.addAction(Intent.ACTION_USER_UNLOCKED); 1850 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 1851 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null); 1852 1853 IntentFilter pkgFilter = new IntentFilter(); 1854 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1855 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1856 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1857 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1858 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1859 pkgFilter.addDataScheme("package"); 1860 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 1861 null); 1862 1863 IntentFilter suspendedPkgFilter = new IntentFilter(); 1864 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 1865 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); 1866 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 1867 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, 1868 suspendedPkgFilter, null, null); 1869 1870 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1871 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 1872 null); 1873 1874 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT); 1875 timeoutFilter.addDataScheme(SCHEME_TIMEOUT); 1876 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter); 1877 1878 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED); 1879 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter); 1880 1881 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED); 1882 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter); 1883 1884 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, 1885 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); 1886 publishLocalService(NotificationManagerInternal.class, mInternalService); 1887 } 1888 registerDeviceConfigChange()1889 private void registerDeviceConfigChange() { 1890 DeviceConfig.addOnPropertiesChangedListener( 1891 DeviceConfig.NAMESPACE_SYSTEMUI, 1892 getContext().getMainExecutor(), 1893 (properties) -> { 1894 if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) { 1895 return; 1896 } 1897 if (properties.getKeyset() 1898 .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) { 1899 mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE); 1900 mAssistants.resetDefaultAssistantsIfNecessary(); 1901 } 1902 }); 1903 } 1904 1905 getGroupHelper()1906 private GroupHelper getGroupHelper() { 1907 mAutoGroupAtCount = 1908 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount); 1909 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() { 1910 @Override 1911 public void addAutoGroup(String key) { 1912 synchronized (mNotificationLock) { 1913 addAutogroupKeyLocked(key); 1914 } 1915 } 1916 1917 @Override 1918 public void removeAutoGroup(String key) { 1919 synchronized (mNotificationLock) { 1920 removeAutogroupKeyLocked(key); 1921 } 1922 } 1923 1924 @Override 1925 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) { 1926 createAutoGroupSummary(userId, pkg, triggeringKey); 1927 } 1928 1929 @Override 1930 public void removeAutoGroupSummary(int userId, String pkg) { 1931 synchronized (mNotificationLock) { 1932 clearAutogroupSummaryLocked(userId, pkg); 1933 } 1934 } 1935 }); 1936 } 1937 1938 private void sendRegisteredOnlyBroadcast(String action) { 1939 Intent intent = new Intent(action); 1940 getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 1941 UserHandle.ALL, null); 1942 // explicitly send the broadcast to all DND packages, even if they aren't currently running 1943 intent.setFlags(0); 1944 final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages(); 1945 for (String pkg : dndApprovedPackages) { 1946 intent.setPackage(pkg); 1947 getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 1948 } 1949 } 1950 1951 @Override 1952 public void onBootPhase(int phase) { 1953 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1954 // no beeping until we're basically done booting 1955 mSystemReady = true; 1956 1957 // Grab our optional AudioService 1958 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1959 mAudioManagerInternal = getLocalService(AudioManagerInternal.class); 1960 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 1961 mZenModeHelper.onSystemReady(); 1962 mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class), 1963 mPackageManager, getContext().getMainExecutor()); 1964 mRoleObserver.init(); 1965 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1966 // This observer will force an update when observe is called, causing us to 1967 // bind to listener services. 1968 mSettingsObserver.observe(); 1969 mListeners.onBootPhaseAppsCanStart(); 1970 mAssistants.onBootPhaseAppsCanStart(); 1971 mConditionProviders.onBootPhaseAppsCanStart(); 1972 registerDeviceConfigChange(); 1973 } 1974 } 1975 1976 @GuardedBy("mNotificationLock") 1977 private void updateListenerHintsLocked() { 1978 final int hints = calculateHints(); 1979 if (hints == mListenerHints) return; 1980 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size()); 1981 mListenerHints = hints; 1982 scheduleListenerHintsChanged(hints); 1983 } 1984 1985 @GuardedBy("mNotificationLock") 1986 private void updateEffectsSuppressorLocked() { 1987 final long updatedSuppressedEffects = calculateSuppressedEffects(); 1988 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; 1989 final List<ComponentName> suppressors = getSuppressors(); 1990 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects); 1991 mEffectsSuppressors = suppressors; 1992 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); 1993 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 1994 } 1995 1996 private void exitIdle() { 1997 try { 1998 if (mDeviceIdleController != null) { 1999 mDeviceIdleController.exitIdle("notification interaction"); 2000 } 2001 } catch (RemoteException e) { 2002 } 2003 } 2004 2005 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel, 2006 boolean fromListener) { 2007 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) { 2008 // cancel 2009 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, 2010 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED, 2011 null); 2012 if (isUidSystemOrPhone(uid)) { 2013 IntArray profileIds = mUserProfiles.getCurrentProfileIds(); 2014 int N = profileIds.size(); 2015 for (int i = 0; i < N; i++) { 2016 int profileId = profileIds.get(i); 2017 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, 2018 profileId, REASON_CHANNEL_BANNED, 2019 null); 2020 } 2021 } 2022 } 2023 final NotificationChannel preUpdate = 2024 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true); 2025 2026 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true); 2027 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel); 2028 2029 if (!fromListener) { 2030 final NotificationChannel modifiedChannel = 2031 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false); 2032 mListeners.notifyNotificationChannelChanged( 2033 pkg, UserHandle.getUserHandleForUid(uid), 2034 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); 2035 } 2036 2037 handleSavePolicyFile(); 2038 } 2039 2040 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate, 2041 NotificationChannel update) { 2042 try { 2043 if ((preUpdate.getImportance() == IMPORTANCE_NONE 2044 && update.getImportance() != IMPORTANCE_NONE) 2045 || (preUpdate.getImportance() != IMPORTANCE_NONE 2046 && update.getImportance() == IMPORTANCE_NONE)) { 2047 getContext().sendBroadcastAsUser( 2048 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED) 2049 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID, 2050 update.getId()) 2051 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 2052 update.getImportance() == IMPORTANCE_NONE) 2053 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 2054 .setPackage(pkg), 2055 UserHandle.of(UserHandle.getUserId(uid)), null); 2056 } 2057 } catch (SecurityException e) { 2058 Slog.w(TAG, "Can't notify app about channel change", e); 2059 } 2060 } 2061 2062 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, 2063 boolean fromApp, boolean fromListener) { 2064 Preconditions.checkNotNull(group); 2065 Preconditions.checkNotNull(pkg); 2066 2067 final NotificationChannelGroup preUpdate = 2068 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid); 2069 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group, 2070 fromApp); 2071 if (!fromApp) { 2072 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group); 2073 } 2074 if (!fromListener) { 2075 mListeners.notifyNotificationChannelGroupChanged(pkg, 2076 UserHandle.of(UserHandle.getCallingUserId()), group, 2077 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 2078 } 2079 } 2080 2081 private void maybeNotifyChannelGroupOwner(String pkg, int uid, 2082 NotificationChannelGroup preUpdate, NotificationChannelGroup update) { 2083 try { 2084 if (preUpdate.isBlocked() != update.isBlocked()) { 2085 getContext().sendBroadcastAsUser( 2086 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED) 2087 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID, 2088 update.getId()) 2089 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, 2090 update.isBlocked()) 2091 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 2092 .setPackage(pkg), 2093 UserHandle.of(UserHandle.getUserId(uid)), null); 2094 } 2095 } catch (SecurityException e) { 2096 Slog.w(TAG, "Can't notify app about group change", e); 2097 } 2098 } 2099 2100 private ArrayList<ComponentName> getSuppressors() { 2101 ArrayList<ComponentName> names = new ArrayList<ComponentName>(); 2102 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 2103 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 2104 2105 for (ComponentName info : serviceInfoList) { 2106 names.add(info); 2107 } 2108 } 2109 2110 return names; 2111 } 2112 2113 private boolean removeDisabledHints(ManagedServiceInfo info) { 2114 return removeDisabledHints(info, 0); 2115 } 2116 2117 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) { 2118 boolean removed = false; 2119 2120 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 2121 final int hint = mListenersDisablingEffects.keyAt(i); 2122 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 2123 2124 if (hints == 0 || (hint & hints) == hint) { 2125 removed |= listeners.remove(info.component); 2126 } 2127 } 2128 2129 return removed; 2130 } 2131 2132 private void addDisabledHints(ManagedServiceInfo info, int hints) { 2133 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2134 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS); 2135 } 2136 2137 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 2138 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 2139 } 2140 2141 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 2142 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS); 2143 } 2144 } 2145 2146 private void addDisabledHint(ManagedServiceInfo info, int hint) { 2147 if (mListenersDisablingEffects.indexOfKey(hint) < 0) { 2148 mListenersDisablingEffects.put(hint, new ArraySet<>()); 2149 } 2150 2151 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint); 2152 hintListeners.add(info.component); 2153 } 2154 2155 private int calculateHints() { 2156 int hints = 0; 2157 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 2158 int hint = mListenersDisablingEffects.keyAt(i); 2159 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); 2160 2161 if (!serviceInfoList.isEmpty()) { 2162 hints |= hint; 2163 } 2164 } 2165 2166 return hints; 2167 } 2168 2169 private long calculateSuppressedEffects() { 2170 int hints = calculateHints(); 2171 long suppressedEffects = 0; 2172 2173 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2174 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL; 2175 } 2176 2177 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 2178 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS; 2179 } 2180 2181 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 2182 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS; 2183 } 2184 2185 return suppressedEffects; 2186 } 2187 2188 @GuardedBy("mNotificationLock") 2189 private void updateInterruptionFilterLocked() { 2190 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 2191 if (interruptionFilter == mInterruptionFilter) return; 2192 mInterruptionFilter = interruptionFilter; 2193 scheduleInterruptionFilterChanged(interruptionFilter); 2194 } 2195 2196 @VisibleForTesting 2197 INotificationManager getBinderService() { 2198 return INotificationManager.Stub.asInterface(mService); 2199 } 2200 2201 /** 2202 * Report to usage stats that the notification was seen. 2203 * @param r notification record 2204 */ 2205 @GuardedBy("mNotificationLock") 2206 protected void reportSeen(NotificationRecord r) { 2207 if (!r.isProxied()) { 2208 mAppUsageStats.reportEvent(r.sbn.getPackageName(), 2209 getRealUserId(r.sbn.getUserId()), 2210 UsageEvents.Event.NOTIFICATION_SEEN); 2211 } 2212 } 2213 2214 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy, 2215 int targetSdkVersion) { 2216 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) { 2217 return incomingPolicy.suppressedVisualEffects; 2218 } 2219 final int[] effectsIntroducedInP = { 2220 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT, 2221 SUPPRESSED_EFFECT_LIGHTS, 2222 SUPPRESSED_EFFECT_PEEK, 2223 SUPPRESSED_EFFECT_STATUS_BAR, 2224 SUPPRESSED_EFFECT_BADGE, 2225 SUPPRESSED_EFFECT_AMBIENT, 2226 SUPPRESSED_EFFECT_NOTIFICATION_LIST 2227 }; 2228 2229 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects; 2230 if (targetSdkVersion < Build.VERSION_CODES.P) { 2231 // unset higher order bits introduced in P, maintain the user's higher order bits 2232 for (int i = 0; i < effectsIntroducedInP.length ; i++) { 2233 newSuppressedVisualEffects &= ~effectsIntroducedInP[i]; 2234 newSuppressedVisualEffects |= 2235 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]); 2236 } 2237 // set higher order bits according to lower order bits 2238 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 2239 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 2240 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 2241 } 2242 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 2243 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 2244 } 2245 } else { 2246 boolean hasNewEffects = (newSuppressedVisualEffects 2247 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0; 2248 // if any of the new effects introduced in P are set 2249 if (hasNewEffects) { 2250 // clear out the deprecated effects 2251 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON 2252 | SUPPRESSED_EFFECT_SCREEN_OFF); 2253 2254 // set the deprecated effects according to the new more specific effects 2255 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) { 2256 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON; 2257 } 2258 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0 2259 && (newSuppressedVisualEffects 2260 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0 2261 && (newSuppressedVisualEffects 2262 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) { 2263 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF; 2264 } 2265 } else { 2266 // set higher order bits according to lower order bits 2267 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) { 2268 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS; 2269 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 2270 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT; 2271 } 2272 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) { 2273 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK; 2274 } 2275 } 2276 } 2277 2278 return newSuppressedVisualEffects; 2279 } 2280 2281 @GuardedBy("mNotificationLock") 2282 protected void maybeRecordInterruptionLocked(NotificationRecord r) { 2283 if (r.isInterruptive() && !r.hasRecordedInterruption()) { 2284 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(), 2285 r.getChannel().getId(), 2286 getRealUserId(r.sbn.getUserId())); 2287 r.setRecordedInterruption(true); 2288 } 2289 } 2290 2291 /** 2292 * Report to usage stats that the user interacted with the notification. 2293 * @param r notification record 2294 */ 2295 protected void reportUserInteraction(NotificationRecord r) { 2296 mAppUsageStats.reportEvent(r.sbn.getPackageName(), 2297 getRealUserId(r.sbn.getUserId()), 2298 UsageEvents.Event.USER_INTERACTION); 2299 } 2300 2301 private int getRealUserId(int userId) { 2302 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId; 2303 } 2304 2305 @VisibleForTesting 2306 NotificationManagerInternal getInternalService() { 2307 return mInternalService; 2308 } 2309 2310 @VisibleForTesting 2311 final IBinder mService = new INotificationManager.Stub() { 2312 // Toasts 2313 // ============================================================================ 2314 2315 @Override 2316 public void enqueueToast(String pkg, ITransientNotification callback, int duration, 2317 int displayId) 2318 { 2319 if (DBG) { 2320 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 2321 + " duration=" + duration + " displayId=" + displayId); 2322 } 2323 2324 if (pkg == null || callback == null) { 2325 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback); 2326 return ; 2327 } 2328 2329 final int callingUid = Binder.getCallingUid(); 2330 final boolean isSystemToast = isCallerSystemOrPhone() 2331 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); 2332 final boolean isPackageSuspended = isPackagePaused(pkg); 2333 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, 2334 callingUid); 2335 2336 long callingIdentity = Binder.clearCallingIdentity(); 2337 try { 2338 final boolean appIsForeground = mActivityManager.getUidImportance(callingUid) 2339 == IMPORTANCE_FOREGROUND; 2340 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage 2341 && !appIsForeground) || isPackageSuspended)) { 2342 Slog.e(TAG, "Suppressing toast from package " + pkg 2343 + (isPackageSuspended ? " due to package suspended." 2344 : " by user request.")); 2345 return; 2346 } 2347 } finally { 2348 Binder.restoreCallingIdentity(callingIdentity); 2349 } 2350 2351 synchronized (mToastQueue) { 2352 int callingPid = Binder.getCallingPid(); 2353 long callingId = Binder.clearCallingIdentity(); 2354 try { 2355 ToastRecord record; 2356 int index = indexOfToastLocked(pkg, callback); 2357 // If it's already in the queue, we update it in place, we don't 2358 // move it to the end of the queue. 2359 if (index >= 0) { 2360 record = mToastQueue.get(index); 2361 record.update(duration); 2362 } else { 2363 // Limit the number of toasts that any given package except the android 2364 // package can enqueue. Prevents DOS attacks and deals with leaks. 2365 if (!isSystemToast) { 2366 int count = 0; 2367 final int N = mToastQueue.size(); 2368 for (int i=0; i<N; i++) { 2369 final ToastRecord r = mToastQueue.get(i); 2370 if (r.pkg.equals(pkg)) { 2371 count++; 2372 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2373 Slog.e(TAG, "Package has already posted " + count 2374 + " toasts. Not showing more. Package=" + pkg); 2375 return; 2376 } 2377 } 2378 } 2379 } 2380 2381 Binder token = new Binder(); 2382 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId); 2383 record = new ToastRecord(callingPid, pkg, callback, duration, token, 2384 displayId); 2385 mToastQueue.add(record); 2386 index = mToastQueue.size() - 1; 2387 keepProcessAliveIfNeededLocked(callingPid); 2388 } 2389 // If it's at index 0, it's the current toast. It doesn't matter if it's 2390 // new or just been updated. Call back and tell it to show itself. 2391 // If the callback fails, this will remove it from the list, so don't 2392 // assume that it's valid after this. 2393 if (index == 0) { 2394 showNextToastLocked(); 2395 } 2396 } finally { 2397 Binder.restoreCallingIdentity(callingId); 2398 } 2399 } 2400 } 2401 2402 @Override 2403 public void cancelToast(String pkg, ITransientNotification callback) { 2404 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 2405 2406 if (pkg == null || callback == null) { 2407 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 2408 return ; 2409 } 2410 2411 synchronized (mToastQueue) { 2412 long callingId = Binder.clearCallingIdentity(); 2413 try { 2414 int index = indexOfToastLocked(pkg, callback); 2415 if (index >= 0) { 2416 cancelToastLocked(index); 2417 } else { 2418 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 2419 + " callback=" + callback); 2420 } 2421 } finally { 2422 Binder.restoreCallingIdentity(callingId); 2423 } 2424 } 2425 } 2426 2427 @Override 2428 public void finishToken(String pkg, ITransientNotification callback) { 2429 synchronized (mToastQueue) { 2430 long callingId = Binder.clearCallingIdentity(); 2431 try { 2432 int index = indexOfToastLocked(pkg, callback); 2433 if (index >= 0) { 2434 ToastRecord record = mToastQueue.get(index); 2435 finishTokenLocked(record.token, record.displayId); 2436 } else { 2437 Slog.w(TAG, "Toast already killed. pkg=" + pkg 2438 + " callback=" + callback); 2439 } 2440 } finally { 2441 Binder.restoreCallingIdentity(callingId); 2442 } 2443 } 2444 } 2445 2446 @Override 2447 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 2448 Notification notification, int userId) throws RemoteException { 2449 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 2450 Binder.getCallingPid(), tag, id, notification, userId); 2451 } 2452 2453 @Override 2454 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 2455 checkCallerIsSystemOrSameApp(pkg); 2456 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2457 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 2458 // Don't allow client applications to cancel foreground service notis or autobundled 2459 // summaries. 2460 final int mustNotHaveFlags = isCallingUidSystem() ? 0 : 2461 (FLAG_FOREGROUND_SERVICE | FLAG_AUTOGROUP_SUMMARY); 2462 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 2463 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); 2464 } 2465 2466 @Override 2467 public void cancelAllNotifications(String pkg, int userId) { 2468 checkCallerIsSystemOrSameApp(pkg); 2469 2470 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2471 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 2472 2473 // Calling from user space, don't allow the canceling of actively 2474 // running foreground services. 2475 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 2476 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId, 2477 REASON_APP_CANCEL_ALL, null); 2478 } 2479 2480 @Override 2481 public void silenceNotificationSound() { 2482 checkCallerIsSystem(); 2483 2484 mNotificationDelegate.clearEffects(); 2485 } 2486 2487 @Override 2488 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 2489 enforceSystemOrSystemUI("setNotificationsEnabledForPackage"); 2490 2491 synchronized (mNotificationLock) { 2492 boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid) 2493 != NotificationManager.IMPORTANCE_NONE; 2494 2495 if (wasEnabled == enabled) { 2496 return; 2497 } 2498 } 2499 2500 mPreferencesHelper.setEnabled(pkg, uid, enabled); 2501 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) 2502 .setType(MetricsEvent.TYPE_ACTION) 2503 .setPackageName(pkg) 2504 .setSubtype(enabled ? 1 : 0)); 2505 // Now, cancel any outstanding notifications that are part of a just-disabled app 2506 if (!enabled) { 2507 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true, 2508 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null); 2509 } 2510 2511 try { 2512 getContext().sendBroadcastAsUser( 2513 new Intent(ACTION_APP_BLOCK_STATE_CHANGED) 2514 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled) 2515 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 2516 .setPackage(pkg), 2517 UserHandle.of(UserHandle.getUserId(uid)), null); 2518 } catch (SecurityException e) { 2519 Slog.w(TAG, "Can't notify app about app block change", e); 2520 } 2521 2522 handleSavePolicyFile(); 2523 } 2524 2525 /** 2526 * Updates the enabled state for notifications for the given package (and uid). 2527 * Additionally, this method marks the app importance as locked by the user, which means 2528 * that notifications from the app will <b>not</b> be considered for showing a 2529 * blocking helper. 2530 * 2531 * @param pkg package that owns the notifications to update 2532 * @param uid uid of the app providing notifications 2533 * @param enabled whether notifications should be enabled for the app 2534 * 2535 * @see #setNotificationsEnabledForPackage(String, int, boolean) 2536 */ 2537 @Override 2538 public void setNotificationsEnabledWithImportanceLockForPackage( 2539 String pkg, int uid, boolean enabled) { 2540 setNotificationsEnabledForPackage(pkg, uid, enabled); 2541 2542 mPreferencesHelper.setAppImportanceLocked(pkg, uid); 2543 } 2544 2545 /** 2546 * Use this when you just want to know if notifications are OK for this package. 2547 */ 2548 @Override 2549 public boolean areNotificationsEnabled(String pkg) { 2550 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()); 2551 } 2552 2553 /** 2554 * Use this when you just want to know if notifications are OK for this package. 2555 */ 2556 @Override 2557 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 2558 enforceSystemOrSystemUIOrSamePackage(pkg, 2559 "Caller not system or systemui or same package"); 2560 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 2561 getContext().enforceCallingPermission( 2562 android.Manifest.permission.INTERACT_ACROSS_USERS, 2563 "canNotifyAsPackage for uid " + uid); 2564 } 2565 2566 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; 2567 } 2568 2569 @Override 2570 public boolean areBubblesAllowed(String pkg) { 2571 return areBubblesAllowedForPackage(pkg, Binder.getCallingUid()); 2572 } 2573 2574 @Override 2575 public boolean areBubblesAllowedForPackage(String pkg, int uid) { 2576 enforceSystemOrSystemUIOrSamePackage(pkg, 2577 "Caller not system or systemui or same package"); 2578 2579 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { 2580 getContext().enforceCallingPermission( 2581 android.Manifest.permission.INTERACT_ACROSS_USERS, 2582 "canNotifyAsPackage for uid " + uid); 2583 } 2584 2585 return mPreferencesHelper.areBubblesAllowed(pkg, uid); 2586 } 2587 2588 @Override 2589 public void setBubblesAllowed(String pkg, int uid, boolean allowed) { 2590 enforceSystemOrSystemUI("Caller not system or systemui"); 2591 mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed); 2592 handleSavePolicyFile(); 2593 } 2594 2595 @Override 2596 public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) { 2597 enforceSystemOrSystemUI("Caller not system or systemui"); 2598 int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid); 2599 return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0; 2600 } 2601 2602 @Override 2603 public boolean shouldHideSilentStatusIcons(String callingPkg) { 2604 checkCallerIsSameApp(callingPkg); 2605 2606 if (isCallerSystemOrPhone() 2607 || mListeners.isListenerPackage(callingPkg)) { 2608 return mPreferencesHelper.shouldHideSilentStatusIcons(); 2609 } else { 2610 throw new SecurityException("Only available for notification listeners"); 2611 } 2612 } 2613 2614 @Override 2615 public void setHideSilentStatusIcons(boolean hide) { 2616 checkCallerIsSystem(); 2617 2618 mPreferencesHelper.setHideSilentStatusIcons(hide); 2619 handleSavePolicyFile(); 2620 2621 mListeners.onStatusBarIconsBehaviorChanged(hide); 2622 } 2623 2624 @Override 2625 public int getPackageImportance(String pkg) { 2626 checkCallerIsSystemOrSameApp(pkg); 2627 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid()); 2628 } 2629 2630 @Override 2631 public boolean canShowBadge(String pkg, int uid) { 2632 checkCallerIsSystem(); 2633 return mPreferencesHelper.canShowBadge(pkg, uid); 2634 } 2635 2636 @Override 2637 public void setShowBadge(String pkg, int uid, boolean showBadge) { 2638 checkCallerIsSystem(); 2639 mPreferencesHelper.setShowBadge(pkg, uid, showBadge); 2640 handleSavePolicyFile(); 2641 } 2642 2643 @Override 2644 public void setNotificationDelegate(String callingPkg, String delegate) { 2645 checkCallerIsSameApp(callingPkg); 2646 final int callingUid = Binder.getCallingUid(); 2647 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 2648 if (delegate == null) { 2649 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid()); 2650 handleSavePolicyFile(); 2651 } else { 2652 try { 2653 ApplicationInfo info = 2654 mPackageManager.getApplicationInfo(delegate, 2655 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 2656 user.getIdentifier()); 2657 if (info != null) { 2658 mPreferencesHelper.setNotificationDelegate( 2659 callingPkg, callingUid, delegate, info.uid); 2660 handleSavePolicyFile(); 2661 } 2662 } catch (RemoteException e) { 2663 e.rethrowFromSystemServer(); 2664 } 2665 } 2666 } 2667 2668 @Override 2669 public String getNotificationDelegate(String callingPkg) { 2670 // callable by Settings also 2671 checkCallerIsSystemOrSameApp(callingPkg); 2672 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid()); 2673 } 2674 2675 @Override 2676 public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) { 2677 checkCallerIsSameApp(callingPkg); 2678 final int callingUid = Binder.getCallingUid(); 2679 UserHandle user = UserHandle.getUserHandleForUid(callingUid); 2680 if (user.getIdentifier() != userId) { 2681 getContext().enforceCallingPermission( 2682 android.Manifest.permission.INTERACT_ACROSS_USERS, 2683 "canNotifyAsPackage for user " + userId); 2684 } 2685 if (callingPkg.equals(targetPkg)) { 2686 return true; 2687 } 2688 try { 2689 ApplicationInfo info = 2690 mPackageManager.getApplicationInfo(targetPkg, 2691 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, 2692 userId); 2693 if (info != null) { 2694 return mPreferencesHelper.isDelegateAllowed( 2695 targetPkg, info.uid, callingPkg, callingUid); 2696 } 2697 } catch (RemoteException e) { 2698 // :( 2699 } 2700 return false; 2701 } 2702 2703 @Override 2704 public void updateNotificationChannelGroupForPackage(String pkg, int uid, 2705 NotificationChannelGroup group) throws RemoteException { 2706 enforceSystemOrSystemUI("Caller not system or systemui"); 2707 createNotificationChannelGroup(pkg, uid, group, false, false); 2708 handleSavePolicyFile(); 2709 } 2710 2711 @Override 2712 public void createNotificationChannelGroups(String pkg, 2713 ParceledListSlice channelGroupList) throws RemoteException { 2714 checkCallerIsSystemOrSameApp(pkg); 2715 List<NotificationChannelGroup> groups = channelGroupList.getList(); 2716 final int groupSize = groups.size(); 2717 for (int i = 0; i < groupSize; i++) { 2718 final NotificationChannelGroup group = groups.get(i); 2719 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false); 2720 } 2721 handleSavePolicyFile(); 2722 } 2723 2724 private void createNotificationChannelsImpl(String pkg, int uid, 2725 ParceledListSlice channelsList) { 2726 List<NotificationChannel> channels = channelsList.getList(); 2727 final int channelsSize = channels.size(); 2728 boolean needsPolicyFileChange = false; 2729 for (int i = 0; i < channelsSize; i++) { 2730 final NotificationChannel channel = channels.get(i); 2731 Preconditions.checkNotNull(channel, "channel in list is null"); 2732 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid, 2733 channel, true /* fromTargetApp */, 2734 mConditionProviders.isPackageOrComponentAllowed( 2735 pkg, UserHandle.getUserId(uid))); 2736 if (needsPolicyFileChange) { 2737 mListeners.notifyNotificationChannelChanged(pkg, 2738 UserHandle.getUserHandleForUid(uid), 2739 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), 2740 false), 2741 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 2742 } 2743 } 2744 if (needsPolicyFileChange) { 2745 handleSavePolicyFile(); 2746 } 2747 } 2748 2749 @Override 2750 public void createNotificationChannels(String pkg, 2751 ParceledListSlice channelsList) throws RemoteException { 2752 checkCallerIsSystemOrSameApp(pkg); 2753 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList); 2754 } 2755 2756 @Override 2757 public void createNotificationChannelsForPackage(String pkg, int uid, 2758 ParceledListSlice channelsList) throws RemoteException { 2759 checkCallerIsSystem(); 2760 createNotificationChannelsImpl(pkg, uid, channelsList); 2761 } 2762 2763 @Override 2764 public NotificationChannel getNotificationChannel(String callingPkg, int userId, 2765 String targetPkg, String channelId) { 2766 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 2767 || isCallingUidSystem()) { 2768 int targetUid = -1; 2769 try { 2770 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 2771 } catch (NameNotFoundException e) { 2772 /* ignore */ 2773 } 2774 return mPreferencesHelper.getNotificationChannel( 2775 targetPkg, targetUid, channelId, false /* includeDeleted */); 2776 } 2777 throw new SecurityException("Pkg " + callingPkg 2778 + " cannot read channels for " + targetPkg + " in " + userId); 2779 } 2780 2781 @Override 2782 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, 2783 String channelId, boolean includeDeleted) { 2784 checkCallerIsSystem(); 2785 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted); 2786 } 2787 2788 @Override 2789 public void deleteNotificationChannel(String pkg, String channelId) { 2790 checkCallerIsSystemOrSameApp(pkg); 2791 final int callingUid = Binder.getCallingUid(); 2792 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 2793 throw new IllegalArgumentException("Cannot delete default channel"); 2794 } 2795 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, 2796 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); 2797 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId); 2798 mListeners.notifyNotificationChannelChanged(pkg, 2799 UserHandle.getUserHandleForUid(callingUid), 2800 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true), 2801 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 2802 handleSavePolicyFile(); 2803 } 2804 2805 @Override 2806 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) { 2807 checkCallerIsSystemOrSameApp(pkg); 2808 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 2809 pkg, Binder.getCallingUid(), groupId, false); 2810 } 2811 2812 @Override 2813 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups( 2814 String pkg) { 2815 checkCallerIsSystemOrSameApp(pkg); 2816 return mPreferencesHelper.getNotificationChannelGroups( 2817 pkg, Binder.getCallingUid(), false, false, true); 2818 } 2819 2820 @Override 2821 public void deleteNotificationChannelGroup(String pkg, String groupId) { 2822 checkCallerIsSystemOrSameApp(pkg); 2823 2824 final int callingUid = Binder.getCallingUid(); 2825 NotificationChannelGroup groupToDelete = 2826 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid); 2827 if (groupToDelete != null) { 2828 List<NotificationChannel> deletedChannels = 2829 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); 2830 for (int i = 0; i < deletedChannels.size(); i++) { 2831 final NotificationChannel deletedChannel = deletedChannels.get(i); 2832 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, 2833 true, 2834 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, 2835 null); 2836 mListeners.notifyNotificationChannelChanged(pkg, 2837 UserHandle.getUserHandleForUid(callingUid), 2838 deletedChannel, 2839 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 2840 } 2841 mListeners.notifyNotificationChannelGroupChanged( 2842 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, 2843 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 2844 handleSavePolicyFile(); 2845 } 2846 } 2847 2848 @Override 2849 public void updateNotificationChannelForPackage(String pkg, int uid, 2850 NotificationChannel channel) { 2851 enforceSystemOrSystemUI("Caller not system or systemui"); 2852 Preconditions.checkNotNull(channel); 2853 updateNotificationChannelInt(pkg, uid, channel, false); 2854 } 2855 2856 @Override 2857 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg, 2858 int uid, boolean includeDeleted) { 2859 enforceSystemOrSystemUI("getNotificationChannelsForPackage"); 2860 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted); 2861 } 2862 2863 @Override 2864 public int getNumNotificationChannelsForPackage(String pkg, int uid, 2865 boolean includeDeleted) { 2866 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage"); 2867 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted) 2868 .getList().size(); 2869 } 2870 2871 @Override 2872 public boolean onlyHasDefaultChannel(String pkg, int uid) { 2873 enforceSystemOrSystemUI("onlyHasDefaultChannel"); 2874 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid); 2875 } 2876 2877 @Override 2878 public int getDeletedChannelCount(String pkg, int uid) { 2879 enforceSystemOrSystemUI("getDeletedChannelCount"); 2880 return mPreferencesHelper.getDeletedChannelCount(pkg, uid); 2881 } 2882 2883 @Override 2884 public int getBlockedChannelCount(String pkg, int uid) { 2885 enforceSystemOrSystemUI("getBlockedChannelCount"); 2886 return mPreferencesHelper.getBlockedChannelCount(pkg, uid); 2887 } 2888 2889 @Override 2890 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage( 2891 String pkg, int uid, boolean includeDeleted) { 2892 enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage"); 2893 return mPreferencesHelper.getNotificationChannelGroups( 2894 pkg, uid, includeDeleted, true, false); 2895 } 2896 2897 @Override 2898 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage( 2899 String pkg, int uid, String groupId, boolean includeDeleted) { 2900 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage"); 2901 return mPreferencesHelper.getNotificationChannelGroupWithChannels( 2902 pkg, uid, groupId, includeDeleted); 2903 } 2904 2905 @Override 2906 public NotificationChannelGroup getNotificationChannelGroupForPackage( 2907 String groupId, String pkg, int uid) { 2908 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage"); 2909 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid); 2910 } 2911 2912 @Override 2913 public ParceledListSlice<NotificationChannel> getNotificationChannels( 2914 String callingPkg, String targetPkg, int userId) { 2915 if (canNotifyAsPackage(callingPkg, targetPkg, userId) 2916 || isCallingUidSystem()) { 2917 int targetUid = -1; 2918 try { 2919 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 2920 } catch (NameNotFoundException e) { 2921 /* ignore */ 2922 } 2923 return mPreferencesHelper.getNotificationChannels( 2924 targetPkg, targetUid, false /* includeDeleted */); 2925 } 2926 throw new SecurityException("Pkg " + callingPkg 2927 + " cannot read channels for " + targetPkg + " in " + userId); 2928 } 2929 2930 @Override 2931 public int getBlockedAppCount(int userId) { 2932 checkCallerIsSystem(); 2933 return mPreferencesHelper.getBlockedAppCount(userId); 2934 } 2935 2936 @Override 2937 public int getAppsBypassingDndCount(int userId) { 2938 checkCallerIsSystem(); 2939 return mPreferencesHelper.getAppsBypassingDndCount(userId); 2940 } 2941 2942 @Override 2943 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( 2944 String pkg, int userId) { 2945 checkCallerIsSystem(); 2946 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId); 2947 } 2948 2949 @Override 2950 public boolean areChannelsBypassingDnd() { 2951 return mPreferencesHelper.areChannelsBypassingDnd(); 2952 } 2953 2954 @Override 2955 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException { 2956 checkCallerIsSystem(); 2957 2958 // Cancel posted notifications 2959 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true, 2960 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); 2961 2962 final String[] packages = new String[] {packageName}; 2963 final int[] uids = new int[] {uid}; 2964 2965 // Listener & assistant 2966 mListeners.onPackagesChanged(true, packages, uids); 2967 mAssistants.onPackagesChanged(true, packages, uids); 2968 2969 // Zen 2970 mConditionProviders.onPackagesChanged(true, packages, uids); 2971 2972 // Snoozing 2973 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName); 2974 2975 // Reset notification preferences 2976 if (!fromApp) { 2977 mPreferencesHelper.clearData(packageName, uid); 2978 } 2979 2980 handleSavePolicyFile(); 2981 } 2982 2983 @Override 2984 public List<String> getAllowedAssistantAdjustments(String pkg) { 2985 checkCallerIsSystemOrSameApp(pkg); 2986 2987 if (!isCallerSystemOrPhone() 2988 && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) { 2989 throw new SecurityException("Not currently an assistant"); 2990 } 2991 2992 return mAssistants.getAllowedAssistantAdjustments(); 2993 } 2994 2995 @Override 2996 public void allowAssistantAdjustment(String adjustmentType) { 2997 checkCallerIsSystemOrSystemUiOrShell(); 2998 mAssistants.allowAdjustmentType(adjustmentType); 2999 3000 handleSavePolicyFile(); 3001 } 3002 3003 @Override 3004 public void disallowAssistantAdjustment(String adjustmentType) { 3005 checkCallerIsSystemOrSystemUiOrShell(); 3006 mAssistants.disallowAdjustmentType(adjustmentType); 3007 3008 handleSavePolicyFile(); 3009 } 3010 3011 /** 3012 * System-only API for getting a list of current (i.e. not cleared) notifications. 3013 * 3014 * Requires ACCESS_NOTIFICATIONS which is signature|system. 3015 * @returns A list of all the notifications, in natural order. 3016 */ 3017 @Override 3018 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 3019 // enforce() will ensure the calling uid has the correct permission 3020 getContext().enforceCallingOrSelfPermission( 3021 android.Manifest.permission.ACCESS_NOTIFICATIONS, 3022 "NotificationManagerService.getActiveNotifications"); 3023 3024 StatusBarNotification[] tmp = null; 3025 int uid = Binder.getCallingUid(); 3026 3027 // noteOp will check to make sure the callingPkg matches the uid 3028 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 3029 == AppOpsManager.MODE_ALLOWED) { 3030 synchronized (mNotificationLock) { 3031 tmp = new StatusBarNotification[mNotificationList.size()]; 3032 final int N = mNotificationList.size(); 3033 for (int i=0; i<N; i++) { 3034 tmp[i] = mNotificationList.get(i).sbn; 3035 } 3036 } 3037 } 3038 return tmp; 3039 } 3040 3041 /** 3042 * Public API for getting a list of current notifications for the calling package/uid. 3043 * 3044 * Note that since notification posting is done asynchronously, this will not return 3045 * notifications that are in the process of being posted. 3046 * 3047 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as 3048 * an app's notification delegate via 3049 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}. 3050 * 3051 * @returns A list of all the package's notifications, in natural order. 3052 */ 3053 @Override 3054 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 3055 int incomingUserId) { 3056 checkCallerIsSystemOrSameApp(pkg); 3057 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 3058 Binder.getCallingUid(), incomingUserId, true, false, 3059 "getAppActiveNotifications", pkg); 3060 synchronized (mNotificationLock) { 3061 final ArrayMap<String, StatusBarNotification> map 3062 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); 3063 final int N = mNotificationList.size(); 3064 for (int i = 0; i < N; i++) { 3065 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 3066 mNotificationList.get(i).sbn); 3067 if (sbn != null) { 3068 map.put(sbn.getKey(), sbn); 3069 } 3070 } 3071 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) { 3072 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn); 3073 if (sbn != null) { 3074 map.put(sbn.getKey(), sbn); 3075 } 3076 } 3077 final int M = mEnqueuedNotifications.size(); 3078 for (int i = 0; i < M; i++) { 3079 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 3080 mEnqueuedNotifications.get(i).sbn); 3081 if (sbn != null) { 3082 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here 3083 } 3084 } 3085 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); 3086 list.addAll(map.values()); 3087 return new ParceledListSlice<StatusBarNotification>(list); 3088 } 3089 } 3090 3091 private StatusBarNotification sanitizeSbn(String pkg, int userId, 3092 StatusBarNotification sbn) { 3093 if (sbn.getUserId() == userId) { 3094 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) { 3095 // We could pass back a cloneLight() but clients might get confused and 3096 // try to send this thing back to notify() again, which would not work 3097 // very well. 3098 return new StatusBarNotification( 3099 sbn.getPackageName(), 3100 sbn.getOpPkg(), 3101 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 3102 sbn.getNotification().clone(), 3103 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); 3104 } 3105 } 3106 return null; 3107 } 3108 3109 /** 3110 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 3111 * 3112 * Requires ACCESS_NOTIFICATIONS which is signature|system. 3113 */ 3114 @Override 3115 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 3116 // enforce() will ensure the calling uid has the correct permission 3117 getContext().enforceCallingOrSelfPermission( 3118 android.Manifest.permission.ACCESS_NOTIFICATIONS, 3119 "NotificationManagerService.getHistoricalNotifications"); 3120 3121 StatusBarNotification[] tmp = null; 3122 int uid = Binder.getCallingUid(); 3123 3124 // noteOp will check to make sure the callingPkg matches the uid 3125 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 3126 == AppOpsManager.MODE_ALLOWED) { 3127 synchronized (mArchive) { 3128 tmp = mArchive.getArray(count); 3129 } 3130 } 3131 return tmp; 3132 } 3133 3134 /** 3135 * Register a listener binder directly with the notification manager. 3136 * 3137 * Only works with system callers. Apps should extend 3138 * {@link android.service.notification.NotificationListenerService}. 3139 */ 3140 @Override 3141 public void registerListener(final INotificationListener listener, 3142 final ComponentName component, final int userid) { 3143 enforceSystemOrSystemUI("INotificationManager.registerListener"); 3144 mListeners.registerService(listener, component, userid); 3145 } 3146 3147 /** 3148 * Remove a listener binder directly 3149 */ 3150 @Override 3151 public void unregisterListener(INotificationListener token, int userid) { 3152 mListeners.unregisterService(token, userid); 3153 } 3154 3155 /** 3156 * Allow an INotificationListener to simulate a "clear all" operation. 3157 * 3158 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 3159 * 3160 * @param token The binder for the listener, to check that the caller is allowed 3161 */ 3162 @Override 3163 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 3164 final int callingUid = Binder.getCallingUid(); 3165 final int callingPid = Binder.getCallingPid(); 3166 long identity = Binder.clearCallingIdentity(); 3167 try { 3168 synchronized (mNotificationLock) { 3169 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3170 3171 if (keys != null) { 3172 final int N = keys.length; 3173 for (int i = 0; i < N; i++) { 3174 NotificationRecord r = mNotificationsByKey.get(keys[i]); 3175 if (r == null) continue; 3176 final int userId = r.sbn.getUserId(); 3177 if (userId != info.userid && userId != UserHandle.USER_ALL && 3178 !mUserProfiles.isCurrentProfile(userId)) { 3179 throw new SecurityException("Disallowed call from listener: " 3180 + info.service); 3181 } 3182 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 3183 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 3184 userId); 3185 } 3186 } else { 3187 cancelAllLocked(callingUid, callingPid, info.userid, 3188 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 3189 } 3190 } 3191 } finally { 3192 Binder.restoreCallingIdentity(identity); 3193 } 3194 } 3195 3196 /** 3197 * Handle request from an approved listener to re-enable itself. 3198 * 3199 * @param component The componenet to be re-enabled, caller must match package. 3200 */ 3201 @Override 3202 public void requestBindListener(ComponentName component) { 3203 checkCallerIsSystemOrSameApp(component.getPackageName()); 3204 long identity = Binder.clearCallingIdentity(); 3205 try { 3206 ManagedServices manager = 3207 mAssistants.isComponentEnabledForCurrentProfiles(component) 3208 ? mAssistants 3209 : mListeners; 3210 manager.setComponentState(component, true); 3211 } finally { 3212 Binder.restoreCallingIdentity(identity); 3213 } 3214 } 3215 3216 @Override 3217 public void requestUnbindListener(INotificationListener token) { 3218 long identity = Binder.clearCallingIdentity(); 3219 try { 3220 // allow bound services to disable themselves 3221 synchronized (mNotificationLock) { 3222 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3223 info.getOwner().setComponentState(info.component, false); 3224 } 3225 } finally { 3226 Binder.restoreCallingIdentity(identity); 3227 } 3228 } 3229 3230 @Override 3231 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 3232 long identity = Binder.clearCallingIdentity(); 3233 try { 3234 synchronized (mNotificationLock) { 3235 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3236 if (keys == null) { 3237 return; 3238 } 3239 ArrayList<NotificationRecord> seen = new ArrayList<>(); 3240 final int n = keys.length; 3241 for (int i = 0; i < n; i++) { 3242 NotificationRecord r = mNotificationsByKey.get(keys[i]); 3243 if (r == null) continue; 3244 final int userId = r.sbn.getUserId(); 3245 if (userId != info.userid && userId != UserHandle.USER_ALL 3246 && !mUserProfiles.isCurrentProfile(userId)) { 3247 throw new SecurityException("Disallowed call from listener: " 3248 + info.service); 3249 } 3250 seen.add(r); 3251 if (!r.isSeen()) { 3252 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 3253 reportSeen(r); 3254 r.setSeen(); 3255 maybeRecordInterruptionLocked(r); 3256 } 3257 } 3258 if (!seen.isEmpty()) { 3259 mAssistants.onNotificationsSeenLocked(seen); 3260 } 3261 } 3262 } finally { 3263 Binder.restoreCallingIdentity(identity); 3264 } 3265 } 3266 3267 /** 3268 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 3269 * 3270 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 3271 * 3272 * @param info The binder for the listener, to check that the caller is allowed 3273 */ 3274 @GuardedBy("mNotificationLock") 3275 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 3276 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 3277 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 3278 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE, 3279 true, 3280 userId, REASON_LISTENER_CANCEL, info); 3281 } 3282 3283 /** 3284 * Allow an INotificationListener to snooze a single notification until a context. 3285 * 3286 * @param token The binder for the listener, to check that the caller is allowed 3287 */ 3288 @Override 3289 public void snoozeNotificationUntilContextFromListener(INotificationListener token, 3290 String key, String snoozeCriterionId) { 3291 long identity = Binder.clearCallingIdentity(); 3292 try { 3293 synchronized (mNotificationLock) { 3294 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3295 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); 3296 } 3297 } finally { 3298 Binder.restoreCallingIdentity(identity); 3299 } 3300 } 3301 3302 /** 3303 * Allow an INotificationListener to snooze a single notification until a time. 3304 * 3305 * @param token The binder for the listener, to check that the caller is allowed 3306 */ 3307 @Override 3308 public void snoozeNotificationUntilFromListener(INotificationListener token, String key, 3309 long duration) { 3310 long identity = Binder.clearCallingIdentity(); 3311 try { 3312 synchronized (mNotificationLock) { 3313 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3314 snoozeNotificationInt(key, duration, null, info); 3315 } 3316 } finally { 3317 Binder.restoreCallingIdentity(identity); 3318 } 3319 } 3320 3321 /** 3322 * Allows the notification assistant to un-snooze a single notification. 3323 * 3324 * @param token The binder for the assistant, to check that the caller is allowed 3325 */ 3326 @Override 3327 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { 3328 long identity = Binder.clearCallingIdentity(); 3329 try { 3330 synchronized (mNotificationLock) { 3331 final ManagedServiceInfo info = 3332 mAssistants.checkServiceTokenLocked(token); 3333 unsnoozeNotificationInt(key, info); 3334 } 3335 } finally { 3336 Binder.restoreCallingIdentity(identity); 3337 } 3338 } 3339 3340 /** 3341 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 3342 * 3343 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 3344 * 3345 * @param token The binder for the listener, to check that the caller is allowed 3346 */ 3347 @Override 3348 public void cancelNotificationFromListener(INotificationListener token, String pkg, 3349 String tag, int id) { 3350 final int callingUid = Binder.getCallingUid(); 3351 final int callingPid = Binder.getCallingPid(); 3352 long identity = Binder.clearCallingIdentity(); 3353 try { 3354 synchronized (mNotificationLock) { 3355 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3356 if (info.supportsProfiles()) { 3357 Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 3358 + "from " + info.component 3359 + " use cancelNotification(key) instead."); 3360 } else { 3361 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 3362 pkg, tag, id, info.userid); 3363 } 3364 } 3365 } finally { 3366 Binder.restoreCallingIdentity(identity); 3367 } 3368 } 3369 3370 /** 3371 * Allow an INotificationListener to request the list of outstanding notifications seen by 3372 * the current user. Useful when starting up, after which point the listener callbacks 3373 * should be used. 3374 * 3375 * @param token The binder for the listener, to check that the caller is allowed 3376 * @param keys An array of notification keys to fetch, or null to fetch everything 3377 * @returns The return value will contain the notifications specified in keys, in that 3378 * order, or if keys is null, all the notifications, in natural order. 3379 */ 3380 @Override 3381 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 3382 INotificationListener token, String[] keys, int trim) { 3383 synchronized (mNotificationLock) { 3384 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3385 final boolean getKeys = keys != null; 3386 final int N = getKeys ? keys.length : mNotificationList.size(); 3387 final ArrayList<StatusBarNotification> list 3388 = new ArrayList<StatusBarNotification>(N); 3389 for (int i=0; i<N; i++) { 3390 final NotificationRecord r = getKeys 3391 ? mNotificationsByKey.get(keys[i]) 3392 : mNotificationList.get(i); 3393 if (r == null) continue; 3394 StatusBarNotification sbn = r.sbn; 3395 if (!isVisibleToListener(sbn, info)) continue; 3396 StatusBarNotification sbnToSend = 3397 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 3398 list.add(sbnToSend); 3399 } 3400 return new ParceledListSlice<StatusBarNotification>(list); 3401 } 3402 } 3403 3404 /** 3405 * Allow an INotificationListener to request the list of outstanding snoozed notifications 3406 * seen by the current user. Useful when starting up, after which point the listener 3407 * callbacks should be used. 3408 * 3409 * @param token The binder for the listener, to check that the caller is allowed 3410 * @returns The return value will contain the notifications specified in keys, in that 3411 * order, or if keys is null, all the notifications, in natural order. 3412 */ 3413 @Override 3414 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener( 3415 INotificationListener token, int trim) { 3416 synchronized (mNotificationLock) { 3417 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3418 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed(); 3419 final int N = snoozedRecords.size(); 3420 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 3421 for (int i=0; i < N; i++) { 3422 final NotificationRecord r = snoozedRecords.get(i); 3423 if (r == null) continue; 3424 StatusBarNotification sbn = r.sbn; 3425 if (!isVisibleToListener(sbn, info)) continue; 3426 StatusBarNotification sbnToSend = 3427 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 3428 list.add(sbnToSend); 3429 } 3430 return new ParceledListSlice<>(list); 3431 } 3432 } 3433 3434 @Override 3435 public void clearRequestedListenerHints(INotificationListener token) { 3436 final long identity = Binder.clearCallingIdentity(); 3437 try { 3438 synchronized (mNotificationLock) { 3439 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3440 removeDisabledHints(info); 3441 updateListenerHintsLocked(); 3442 updateEffectsSuppressorLocked(); 3443 } 3444 } finally { 3445 Binder.restoreCallingIdentity(identity); 3446 } 3447 } 3448 3449 @Override 3450 public void requestHintsFromListener(INotificationListener token, int hints) { 3451 final long identity = Binder.clearCallingIdentity(); 3452 try { 3453 synchronized (mNotificationLock) { 3454 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3455 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS 3456 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS 3457 | HINT_HOST_DISABLE_CALL_EFFECTS; 3458 final boolean disableEffects = (hints & disableEffectsMask) != 0; 3459 if (disableEffects) { 3460 addDisabledHints(info, hints); 3461 } else { 3462 removeDisabledHints(info, hints); 3463 } 3464 updateListenerHintsLocked(); 3465 updateEffectsSuppressorLocked(); 3466 } 3467 } finally { 3468 Binder.restoreCallingIdentity(identity); 3469 } 3470 } 3471 3472 @Override 3473 public int getHintsFromListener(INotificationListener token) { 3474 synchronized (mNotificationLock) { 3475 return mListenerHints; 3476 } 3477 } 3478 3479 @Override 3480 public void requestInterruptionFilterFromListener(INotificationListener token, 3481 int interruptionFilter) throws RemoteException { 3482 final long identity = Binder.clearCallingIdentity(); 3483 try { 3484 synchronized (mNotificationLock) { 3485 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3486 mZenModeHelper.requestFromListener(info.component, interruptionFilter); 3487 updateInterruptionFilterLocked(); 3488 } 3489 } finally { 3490 Binder.restoreCallingIdentity(identity); 3491 } 3492 } 3493 3494 @Override 3495 public int getInterruptionFilterFromListener(INotificationListener token) 3496 throws RemoteException { 3497 synchronized (mNotificationLight) { 3498 return mInterruptionFilter; 3499 } 3500 } 3501 3502 @Override 3503 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 3504 throws RemoteException { 3505 synchronized (mNotificationLock) { 3506 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 3507 if (info == null) return; 3508 mListeners.setOnNotificationPostedTrimLocked(info, trim); 3509 } 3510 } 3511 3512 @Override 3513 public int getZenMode() { 3514 return mZenModeHelper.getZenMode(); 3515 } 3516 3517 @Override 3518 public ZenModeConfig getZenModeConfig() { 3519 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig"); 3520 return mZenModeHelper.getConfig(); 3521 } 3522 3523 @Override 3524 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { 3525 enforceSystemOrSystemUI("INotificationManager.setZenMode"); 3526 final long identity = Binder.clearCallingIdentity(); 3527 try { 3528 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason); 3529 } finally { 3530 Binder.restoreCallingIdentity(identity); 3531 } 3532 } 3533 3534 @Override 3535 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException { 3536 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); 3537 return mZenModeHelper.getZenRules(); 3538 } 3539 3540 @Override 3541 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 3542 Preconditions.checkNotNull(id, "Id is null"); 3543 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); 3544 return mZenModeHelper.getAutomaticZenRule(id); 3545 } 3546 3547 @Override 3548 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) { 3549 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 3550 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 3551 if (automaticZenRule.getOwner() == null 3552 && automaticZenRule.getConfigurationActivity() == null) { 3553 throw new NullPointerException( 3554 "Rule must have a conditionproviderservice and/or configuration activity"); 3555 } 3556 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 3557 if (automaticZenRule.getZenPolicy() != null 3558 && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { 3559 throw new IllegalArgumentException("ZenPolicy is only applicable to " 3560 + "INTERRUPTION_FILTER_PRIORITY filters"); 3561 } 3562 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 3563 3564 return mZenModeHelper.addAutomaticZenRule(automaticZenRule, 3565 "addAutomaticZenRule"); 3566 } 3567 3568 @Override 3569 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) 3570 throws RemoteException { 3571 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 3572 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 3573 if (automaticZenRule.getOwner() == null 3574 && automaticZenRule.getConfigurationActivity() == null) { 3575 throw new NullPointerException( 3576 "Rule must have a conditionproviderservice and/or configuration activity"); 3577 } 3578 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 3579 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 3580 3581 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule, 3582 "updateAutomaticZenRule"); 3583 } 3584 3585 @Override 3586 public boolean removeAutomaticZenRule(String id) throws RemoteException { 3587 Preconditions.checkNotNull(id, "Id is null"); 3588 // Verify that they can modify zen rules. 3589 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 3590 3591 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule"); 3592 } 3593 3594 @Override 3595 public boolean removeAutomaticZenRules(String packageName) throws RemoteException { 3596 Preconditions.checkNotNull(packageName, "Package name is null"); 3597 enforceSystemOrSystemUI("removeAutomaticZenRules"); 3598 3599 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules"); 3600 } 3601 3602 @Override 3603 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 3604 Preconditions.checkNotNull(owner, "Owner is null"); 3605 enforceSystemOrSystemUI("getRuleInstanceCount"); 3606 3607 return mZenModeHelper.getCurrentInstanceCount(owner); 3608 } 3609 3610 @Override 3611 public void setAutomaticZenRuleState(String id, Condition condition) { 3612 Preconditions.checkNotNull(id, "id is null"); 3613 Preconditions.checkNotNull(condition, "Condition is null"); 3614 3615 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState"); 3616 3617 mZenModeHelper.setAutomaticZenRuleState(id, condition); 3618 } 3619 3620 @Override 3621 public void setInterruptionFilter(String pkg, int filter) throws RemoteException { 3622 enforcePolicyAccess(pkg, "setInterruptionFilter"); 3623 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 3624 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 3625 final long identity = Binder.clearCallingIdentity(); 3626 try { 3627 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter"); 3628 } finally { 3629 Binder.restoreCallingIdentity(identity); 3630 } 3631 } 3632 3633 @Override 3634 public void notifyConditions(final String pkg, IConditionProvider provider, 3635 final Condition[] conditions) { 3636 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 3637 checkCallerIsSystemOrSameApp(pkg); 3638 mHandler.post(new Runnable() { 3639 @Override 3640 public void run() { 3641 mConditionProviders.notifyConditions(pkg, info, conditions); 3642 } 3643 }); 3644 } 3645 3646 @Override 3647 public void requestUnbindProvider(IConditionProvider provider) { 3648 long identity = Binder.clearCallingIdentity(); 3649 try { 3650 // allow bound services to disable themselves 3651 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 3652 info.getOwner().setComponentState(info.component, false); 3653 } finally { 3654 Binder.restoreCallingIdentity(identity); 3655 } 3656 } 3657 3658 @Override 3659 public void requestBindProvider(ComponentName component) { 3660 checkCallerIsSystemOrSameApp(component.getPackageName()); 3661 long identity = Binder.clearCallingIdentity(); 3662 try { 3663 mConditionProviders.setComponentState(component, true); 3664 } finally { 3665 Binder.restoreCallingIdentity(identity); 3666 } 3667 } 3668 3669 private void enforceSystemOrSystemUI(String message) { 3670 if (isCallerSystemOrPhone()) return; 3671 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 3672 message); 3673 } 3674 3675 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) { 3676 try { 3677 checkCallerIsSystemOrSameApp(pkg); 3678 } catch (SecurityException e) { 3679 getContext().enforceCallingPermission( 3680 android.Manifest.permission.STATUS_BAR_SERVICE, 3681 message); 3682 } 3683 } 3684 3685 private void enforcePolicyAccess(int uid, String method) { 3686 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 3687 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 3688 return; 3689 } 3690 boolean accessAllowed = false; 3691 String[] packages = mPackageManagerClient.getPackagesForUid(uid); 3692 final int packageCount = packages.length; 3693 for (int i = 0; i < packageCount; i++) { 3694 if (mConditionProviders.isPackageOrComponentAllowed( 3695 packages[i], UserHandle.getUserId(uid))) { 3696 accessAllowed = true; 3697 } 3698 } 3699 if (!accessAllowed) { 3700 Slog.w(TAG, "Notification policy access denied calling " + method); 3701 throw new SecurityException("Notification policy access denied"); 3702 } 3703 } 3704 3705 private void enforcePolicyAccess(String pkg, String method) { 3706 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 3707 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 3708 return; 3709 } 3710 checkCallerIsSameApp(pkg); 3711 if (!checkPolicyAccess(pkg)) { 3712 Slog.w(TAG, "Notification policy access denied calling " + method); 3713 throw new SecurityException("Notification policy access denied"); 3714 } 3715 } 3716 3717 private boolean checkPackagePolicyAccess(String pkg) { 3718 return mConditionProviders.isPackageOrComponentAllowed( 3719 pkg, getCallingUserHandle().getIdentifier()); 3720 } 3721 3722 private boolean checkPolicyAccess(String pkg) { 3723 try { 3724 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg, 3725 UserHandle.getCallingUserId()); 3726 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission( 3727 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, 3728 -1, true)) { 3729 return true; 3730 } 3731 } catch (NameNotFoundException e) { 3732 return false; 3733 } 3734 return checkPackagePolicyAccess(pkg) 3735 || mListeners.isComponentEnabledForPackage(pkg) 3736 || (mDpm != null && 3737 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(), 3738 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)); 3739 } 3740 3741 @Override 3742 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3743 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; 3744 final DumpFilter filter = DumpFilter.parseFromArguments(args); 3745 final long token = Binder.clearCallingIdentity(); 3746 try { 3747 if (filter.stats) { 3748 dumpJson(pw, filter); 3749 } else if (filter.rvStats) { 3750 dumpRemoteViewStats(pw, filter); 3751 } else if (filter.proto) { 3752 dumpProto(fd, filter); 3753 } else if (filter.criticalPriority) { 3754 dumpNotificationRecords(pw, filter); 3755 } else { 3756 dumpImpl(pw, filter); 3757 } 3758 } finally { 3759 Binder.restoreCallingIdentity(token); 3760 } 3761 } 3762 3763 @Override 3764 public ComponentName getEffectsSuppressor() { 3765 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null; 3766 } 3767 3768 @Override 3769 public boolean matchesCallFilter(Bundle extras) { 3770 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 3771 return mZenModeHelper.matchesCallFilter( 3772 Binder.getCallingUserHandle(), 3773 extras, 3774 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 3775 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 3776 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); 3777 } 3778 3779 @Override 3780 public boolean isSystemConditionProviderEnabled(String path) { 3781 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled"); 3782 return mConditionProviders.isSystemProviderEnabled(path); 3783 } 3784 3785 // Backup/restore interface 3786 @Override 3787 public byte[] getBackupPayload(int user) { 3788 checkCallerIsSystem(); 3789 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 3790 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 3791 try { 3792 writePolicyXml(baos, true /*forBackup*/, user); 3793 return baos.toByteArray(); 3794 } catch (IOException e) { 3795 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 3796 } 3797 return null; 3798 } 3799 3800 @Override 3801 public void applyRestore(byte[] payload, int user) { 3802 checkCallerIsSystem(); 3803 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 3804 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 3805 if (payload == null) { 3806 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 3807 return; 3808 } 3809 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 3810 try { 3811 readPolicyXml(bais, true /*forRestore*/, user); 3812 handleSavePolicyFile(); 3813 } catch (NumberFormatException | XmlPullParserException | IOException e) { 3814 Slog.w(TAG, "applyRestore: error reading payload", e); 3815 } 3816 } 3817 3818 @Override 3819 public boolean isNotificationPolicyAccessGranted(String pkg) { 3820 return checkPolicyAccess(pkg); 3821 } 3822 3823 @Override 3824 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {; 3825 enforceSystemOrSystemUIOrSamePackage(pkg, 3826 "request policy access status for another package"); 3827 return checkPolicyAccess(pkg); 3828 } 3829 3830 @Override 3831 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 3832 throws RemoteException { 3833 setNotificationPolicyAccessGrantedForUser( 3834 pkg, getCallingUserHandle().getIdentifier(), granted); 3835 } 3836 3837 @Override 3838 public void setNotificationPolicyAccessGrantedForUser( 3839 String pkg, int userId, boolean granted) { 3840 checkCallerIsSystemOrShell(); 3841 final long identity = Binder.clearCallingIdentity(); 3842 try { 3843 if (mAllowedManagedServicePackages.test( 3844 pkg, userId, mConditionProviders.getRequiredPermission())) { 3845 mConditionProviders.setPackageOrComponentEnabled( 3846 pkg, userId, true, granted); 3847 3848 getContext().sendBroadcastAsUser(new Intent( 3849 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 3850 .setPackage(pkg) 3851 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 3852 UserHandle.of(userId), null); 3853 handleSavePolicyFile(); 3854 } 3855 } finally { 3856 Binder.restoreCallingIdentity(identity); 3857 } 3858 } 3859 3860 @Override 3861 public Policy getNotificationPolicy(String pkg) { 3862 final long identity = Binder.clearCallingIdentity(); 3863 try { 3864 return mZenModeHelper.getNotificationPolicy(); 3865 } finally { 3866 Binder.restoreCallingIdentity(identity); 3867 } 3868 } 3869 3870 @Override 3871 public Policy getConsolidatedNotificationPolicy() { 3872 final long identity = Binder.clearCallingIdentity(); 3873 try { 3874 return mZenModeHelper.getConsolidatedNotificationPolicy(); 3875 } finally { 3876 Binder.restoreCallingIdentity(identity); 3877 } 3878 } 3879 3880 /** 3881 * Sets the notification policy. Apps that target API levels below 3882 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to 3883 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS}, 3884 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and 3885 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd 3886 */ 3887 @Override 3888 public void setNotificationPolicy(String pkg, Policy policy) { 3889 enforcePolicyAccess(pkg, "setNotificationPolicy"); 3890 final long identity = Binder.clearCallingIdentity(); 3891 try { 3892 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg, 3893 0, UserHandle.getUserId(MY_UID)); 3894 Policy currPolicy = mZenModeHelper.getNotificationPolicy(); 3895 3896 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) { 3897 int priorityCategories = policy.priorityCategories; 3898 // ignore alarm and media values from new policy 3899 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS; 3900 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA; 3901 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM; 3902 // use user-designated values 3903 priorityCategories |= currPolicy.priorityCategories 3904 & Policy.PRIORITY_CATEGORY_ALARMS; 3905 priorityCategories |= currPolicy.priorityCategories 3906 & Policy.PRIORITY_CATEGORY_MEDIA; 3907 priorityCategories |= currPolicy.priorityCategories 3908 & Policy.PRIORITY_CATEGORY_SYSTEM; 3909 3910 policy = new Policy(priorityCategories, 3911 policy.priorityCallSenders, policy.priorityMessageSenders, 3912 policy.suppressedVisualEffects); 3913 } 3914 int newVisualEffects = calculateSuppressedVisualEffects( 3915 policy, currPolicy, applicationInfo.targetSdkVersion); 3916 policy = new Policy(policy.priorityCategories, 3917 policy.priorityCallSenders, policy.priorityMessageSenders, 3918 newVisualEffects); 3919 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy); 3920 mZenModeHelper.setNotificationPolicy(policy); 3921 } catch (RemoteException e) { 3922 } finally { 3923 Binder.restoreCallingIdentity(identity); 3924 } 3925 } 3926 3927 @Override 3928 public List<String> getEnabledNotificationListenerPackages() { 3929 checkCallerIsSystem(); 3930 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier()); 3931 } 3932 3933 @Override 3934 public List<ComponentName> getEnabledNotificationListeners(int userId) { 3935 checkCallerIsSystem(); 3936 return mListeners.getAllowedComponents(userId); 3937 } 3938 3939 @Override 3940 public ComponentName getAllowedNotificationAssistantForUser(int userId) { 3941 checkCallerIsSystemOrSystemUiOrShell(); 3942 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 3943 if (allowedComponents.size() > 1) { 3944 throw new IllegalStateException( 3945 "At most one NotificationAssistant: " + allowedComponents.size()); 3946 } 3947 return CollectionUtils.firstOrNull(allowedComponents); 3948 } 3949 3950 @Override 3951 public ComponentName getAllowedNotificationAssistant() { 3952 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier()); 3953 } 3954 3955 @Override 3956 public boolean isNotificationListenerAccessGranted(ComponentName listener) { 3957 Preconditions.checkNotNull(listener); 3958 checkCallerIsSystemOrSameApp(listener.getPackageName()); 3959 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 3960 getCallingUserHandle().getIdentifier()); 3961 } 3962 3963 @Override 3964 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener, 3965 int userId) { 3966 Preconditions.checkNotNull(listener); 3967 checkCallerIsSystem(); 3968 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(), 3969 userId); 3970 } 3971 3972 @Override 3973 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { 3974 Preconditions.checkNotNull(assistant); 3975 checkCallerIsSystemOrSameApp(assistant.getPackageName()); 3976 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(), 3977 getCallingUserHandle().getIdentifier()); 3978 } 3979 3980 @Override 3981 public void setNotificationListenerAccessGranted(ComponentName listener, 3982 boolean granted) throws RemoteException { 3983 setNotificationListenerAccessGrantedForUser( 3984 listener, getCallingUserHandle().getIdentifier(), granted); 3985 } 3986 3987 @Override 3988 public void setNotificationAssistantAccessGranted(ComponentName assistant, 3989 boolean granted) { 3990 setNotificationAssistantAccessGrantedForUser( 3991 assistant, getCallingUserHandle().getIdentifier(), granted); 3992 } 3993 3994 @Override 3995 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, 3996 boolean granted) { 3997 Preconditions.checkNotNull(listener); 3998 checkCallerIsSystemOrShell(); 3999 final long identity = Binder.clearCallingIdentity(); 4000 try { 4001 if (mAllowedManagedServicePackages.test( 4002 listener.getPackageName(), userId, mListeners.getRequiredPermission())) { 4003 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(), 4004 userId, false, granted); 4005 mListeners.setPackageOrComponentEnabled(listener.flattenToString(), 4006 userId, true, granted); 4007 4008 getContext().sendBroadcastAsUser(new Intent( 4009 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4010 .setPackage(listener.getPackageName()) 4011 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 4012 UserHandle.of(userId), null); 4013 4014 handleSavePolicyFile(); 4015 } 4016 } finally { 4017 Binder.restoreCallingIdentity(identity); 4018 } 4019 } 4020 4021 @Override 4022 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, 4023 int userId, boolean granted) { 4024 checkCallerIsSystemOrSystemUiOrShell(); 4025 for (UserInfo ui : mUm.getEnabledProfiles(userId)) { 4026 mAssistants.setUserSet(ui.id, true); 4027 } 4028 final long identity = Binder.clearCallingIdentity(); 4029 try { 4030 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted); 4031 } finally { 4032 Binder.restoreCallingIdentity(identity); 4033 } 4034 } 4035 4036 @Override 4037 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token, 4038 Adjustment adjustment) { 4039 boolean foundEnqueued = false; 4040 final long identity = Binder.clearCallingIdentity(); 4041 try { 4042 synchronized (mNotificationLock) { 4043 mAssistants.checkServiceTokenLocked(token); 4044 int N = mEnqueuedNotifications.size(); 4045 for (int i = 0; i < N; i++) { 4046 final NotificationRecord r = mEnqueuedNotifications.get(i); 4047 if (Objects.equals(adjustment.getKey(), r.getKey()) 4048 && Objects.equals(adjustment.getUser(), r.getUserId()) 4049 && mAssistants.isSameUser(token, r.getUserId())) { 4050 applyAdjustment(r, adjustment); 4051 r.applyAdjustments(); 4052 // importance is checked at the beginning of the 4053 // PostNotificationRunnable, before the signal extractors are run, so 4054 // calculate the final importance here 4055 r.calculateImportance(); 4056 foundEnqueued = true; 4057 break; 4058 } 4059 } 4060 if (!foundEnqueued) { 4061 applyAdjustmentFromAssistant(token, adjustment); 4062 } 4063 } 4064 } finally { 4065 Binder.restoreCallingIdentity(identity); 4066 } 4067 } 4068 4069 @Override 4070 public void applyAdjustmentFromAssistant(INotificationListener token, 4071 Adjustment adjustment) { 4072 List<Adjustment> adjustments = new ArrayList<>(); 4073 adjustments.add(adjustment); 4074 applyAdjustmentsFromAssistant(token, adjustments); 4075 } 4076 4077 @Override 4078 public void applyAdjustmentsFromAssistant(INotificationListener token, 4079 List<Adjustment> adjustments) { 4080 4081 boolean needsSort = false; 4082 final long identity = Binder.clearCallingIdentity(); 4083 try { 4084 synchronized (mNotificationLock) { 4085 mAssistants.checkServiceTokenLocked(token); 4086 for (Adjustment adjustment : adjustments) { 4087 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey()); 4088 if (r != null && mAssistants.isSameUser(token, r.getUserId())) { 4089 applyAdjustment(r, adjustment); 4090 // If the assistant has blocked the notification, cancel it 4091 // This will trigger a sort, so we don't have to explicitly ask for 4092 // one here. 4093 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE) 4094 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE) 4095 == IMPORTANCE_NONE) { 4096 cancelNotificationsFromListener(token, new String[]{r.getKey()}); 4097 } else { 4098 needsSort = true; 4099 } 4100 } 4101 } 4102 } 4103 if (needsSort) { 4104 mRankingHandler.requestSort(); 4105 } 4106 } finally { 4107 Binder.restoreCallingIdentity(identity); 4108 } 4109 } 4110 4111 @Override 4112 public void updateNotificationChannelGroupFromPrivilegedListener( 4113 INotificationListener token, String pkg, UserHandle user, 4114 NotificationChannelGroup group) throws RemoteException { 4115 Preconditions.checkNotNull(user); 4116 verifyPrivilegedListener(token, user, false); 4117 createNotificationChannelGroup( 4118 pkg, getUidForPackageAndUser(pkg, user), group, false, true); 4119 handleSavePolicyFile(); 4120 } 4121 4122 @Override 4123 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, 4124 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { 4125 Preconditions.checkNotNull(channel); 4126 Preconditions.checkNotNull(pkg); 4127 Preconditions.checkNotNull(user); 4128 4129 verifyPrivilegedListener(token, user, false); 4130 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); 4131 } 4132 4133 @Override 4134 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( 4135 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 4136 Preconditions.checkNotNull(pkg); 4137 Preconditions.checkNotNull(user); 4138 verifyPrivilegedListener(token, user, true); 4139 4140 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), 4141 false /* includeDeleted */); 4142 } 4143 4144 @Override 4145 public ParceledListSlice<NotificationChannelGroup> 4146 getNotificationChannelGroupsFromPrivilegedListener( 4147 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 4148 Preconditions.checkNotNull(pkg); 4149 Preconditions.checkNotNull(user); 4150 verifyPrivilegedListener(token, user, true); 4151 4152 List<NotificationChannelGroup> groups = new ArrayList<>(); 4153 groups.addAll(mPreferencesHelper.getNotificationChannelGroups( 4154 pkg, getUidForPackageAndUser(pkg, user))); 4155 return new ParceledListSlice<>(groups); 4156 } 4157 4158 @Override 4159 public void setPrivateNotificationsAllowed(boolean allow) { 4160 if (PackageManager.PERMISSION_GRANTED 4161 != getContext().checkCallingPermission( 4162 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 4163 throw new SecurityException( 4164 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 4165 } 4166 if (allow != mLockScreenAllowSecureNotifications) { 4167 mLockScreenAllowSecureNotifications = allow; 4168 handleSavePolicyFile(); 4169 } 4170 } 4171 4172 @Override 4173 public boolean getPrivateNotificationsAllowed() { 4174 if (PackageManager.PERMISSION_GRANTED 4175 != getContext().checkCallingPermission( 4176 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { 4177 throw new SecurityException( 4178 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); 4179 } 4180 return mLockScreenAllowSecureNotifications; 4181 } 4182 4183 @Override 4184 public boolean isPackagePaused(String pkg) { 4185 Preconditions.checkNotNull(pkg); 4186 checkCallerIsSameApp(pkg); 4187 4188 return isPackagePausedOrSuspended(pkg, Binder.getCallingUid()); 4189 } 4190 4191 private void verifyPrivilegedListener(INotificationListener token, UserHandle user, 4192 boolean assistantAllowed) { 4193 ManagedServiceInfo info; 4194 synchronized (mNotificationLock) { 4195 info = mListeners.checkServiceTokenLocked(token); 4196 } 4197 if (!hasCompanionDevice(info)) { 4198 synchronized (mNotificationLock) { 4199 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) { 4200 throw new SecurityException(info + " does not have access"); 4201 } 4202 } 4203 } 4204 if (!info.enabledAndUserMatches(user.getIdentifier())) { 4205 throw new SecurityException(info + " does not have access"); 4206 } 4207 } 4208 4209 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { 4210 int uid = 0; 4211 long identity = Binder.clearCallingIdentity(); 4212 try { 4213 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); 4214 } finally { 4215 Binder.restoreCallingIdentity(identity); 4216 } 4217 return uid; 4218 } 4219 4220 @Override 4221 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 4222 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 4223 throws RemoteException { 4224 new NotificationShellCmd(NotificationManagerService.this) 4225 .exec(this, in, out, err, args, callback, resultReceiver); 4226 } 4227 4228 /** 4229 * Get stats committed after startNs 4230 * 4231 * @param startNs Report stats committed after this time in nanoseconds. 4232 * @param report Indicatess which section to include in the stats. 4233 * @param doAgg Whether to aggregate the stats or keep them separated. 4234 * @param out List of protos of individual commits or one representing the 4235 * aggregate. 4236 * @return the report time in nanoseconds, or 0 on error. 4237 */ 4238 @Override 4239 public long pullStats(long startNs, int report, boolean doAgg, 4240 List<ParcelFileDescriptor> out) { 4241 checkCallerIsSystemOrShell(); 4242 long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS); 4243 4244 final long identity = Binder.clearCallingIdentity(); 4245 try { 4246 switch (report) { 4247 case REPORT_REMOTE_VIEWS: 4248 Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: " 4249 + startMs + " wtih " + doAgg); 4250 PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg); 4251 if (stats != null) { 4252 out.add(stats.toParcelFileDescriptor(report)); 4253 Slog.e(TAG, "exiting pullStats with: " + out.size()); 4254 long endNs = TimeUnit.NANOSECONDS 4255 .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS); 4256 return endNs; 4257 } 4258 Slog.e(TAG, "null stats for: " + report); 4259 } 4260 } catch (IOException e) { 4261 4262 Slog.e(TAG, "exiting pullStats: on error", e); 4263 return 0; 4264 } finally { 4265 Binder.restoreCallingIdentity(identity); 4266 } 4267 Slog.e(TAG, "exiting pullStats: bad request"); 4268 return 0; 4269 } 4270 }; 4271 4272 @VisibleForTesting 4273 protected void setNotificationAssistantAccessGrantedForUserInternal( 4274 ComponentName assistant, int baseUserId, boolean granted) { 4275 List<UserInfo> users = mUm.getEnabledProfiles(baseUserId); 4276 if (users != null) { 4277 for (UserInfo user : users) { 4278 int userId = user.id; 4279 if (assistant == null) { 4280 ComponentName allowedAssistant = CollectionUtils.firstOrNull( 4281 mAssistants.getAllowedComponents(userId)); 4282 if (allowedAssistant != null) { 4283 setNotificationAssistantAccessGrantedForUserInternal( 4284 allowedAssistant, userId, false); 4285 } 4286 continue; 4287 } 4288 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), 4289 userId, mAssistants.getRequiredPermission())) { 4290 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(), 4291 userId, false, granted); 4292 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(), 4293 userId, true, granted); 4294 4295 getContext().sendBroadcastAsUser( 4296 new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4297 .setPackage(assistant.getPackageName()) 4298 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 4299 UserHandle.of(userId), null); 4300 4301 handleSavePolicyFile(); 4302 } 4303 } 4304 } 4305 } 4306 4307 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) { 4308 if (r == null) { 4309 return; 4310 } 4311 if (adjustment.getSignals() != null) { 4312 final Bundle adjustments = adjustment.getSignals(); 4313 Bundle.setDefusable(adjustments, true); 4314 List<String> toRemove = new ArrayList<>(); 4315 for (String potentialKey : adjustments.keySet()) { 4316 if (!mAssistants.isAdjustmentAllowed(potentialKey)) { 4317 toRemove.add(potentialKey); 4318 } 4319 } 4320 for (String removeKey : toRemove) { 4321 adjustments.remove(removeKey); 4322 } 4323 r.addAdjustment(adjustment); 4324 } 4325 } 4326 4327 @GuardedBy("mNotificationLock") 4328 void addAutogroupKeyLocked(String key) { 4329 NotificationRecord r = mNotificationsByKey.get(key); 4330 if (r == null) { 4331 return; 4332 } 4333 if (r.sbn.getOverrideGroupKey() == null) { 4334 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY); 4335 EventLogTags.writeNotificationAutogrouped(key); 4336 mRankingHandler.requestSort(); 4337 } 4338 } 4339 4340 @GuardedBy("mNotificationLock") 4341 void removeAutogroupKeyLocked(String key) { 4342 NotificationRecord r = mNotificationsByKey.get(key); 4343 if (r == null) { 4344 return; 4345 } 4346 if (r.sbn.getOverrideGroupKey() != null) { 4347 addAutoGroupAdjustment(r, null); 4348 EventLogTags.writeNotificationUnautogrouped(key); 4349 mRankingHandler.requestSort(); 4350 } 4351 } 4352 4353 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) { 4354 Bundle signals = new Bundle(); 4355 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey); 4356 Adjustment adjustment = 4357 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId()); 4358 r.addAdjustment(adjustment); 4359 } 4360 4361 // Clears the 'fake' auto-group summary. 4362 @GuardedBy("mNotificationLock") 4363 private void clearAutogroupSummaryLocked(int userId, String pkg) { 4364 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 4365 if (summaries != null && summaries.containsKey(pkg)) { 4366 // Clear summary. 4367 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg)); 4368 if (removed != null) { 4369 boolean wasPosted = removeFromNotificationListsLocked(removed); 4370 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null); 4371 } 4372 } 4373 } 4374 4375 @GuardedBy("mNotificationLock") 4376 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) { 4377 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId()); 4378 return summaries != null && summaries.containsKey(sbn.getPackageName()); 4379 } 4380 4381 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit. 4382 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) { 4383 NotificationRecord summaryRecord = null; 4384 synchronized (mNotificationLock) { 4385 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey); 4386 if (notificationRecord == null) { 4387 // The notification could have been cancelled again already. A successive 4388 // adjustment will post a summary if needed. 4389 return; 4390 } 4391 final StatusBarNotification adjustedSbn = notificationRecord.sbn; 4392 userId = adjustedSbn.getUser().getIdentifier(); 4393 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 4394 if (summaries == null) { 4395 summaries = new ArrayMap<>(); 4396 } 4397 mAutobundledSummaries.put(userId, summaries); 4398 if (!summaries.containsKey(pkg)) { 4399 // Add summary 4400 final ApplicationInfo appInfo = 4401 adjustedSbn.getNotification().extras.getParcelable( 4402 Notification.EXTRA_BUILDER_APPLICATION_INFO); 4403 final Bundle extras = new Bundle(); 4404 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo); 4405 final String channelId = notificationRecord.getChannel().getId(); 4406 final Notification summaryNotification = 4407 new Notification.Builder(getContext(), channelId) 4408 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon()) 4409 .setGroupSummary(true) 4410 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) 4411 .setGroup(GroupHelper.AUTOGROUP_KEY) 4412 .setFlag(FLAG_AUTOGROUP_SUMMARY, true) 4413 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 4414 .setColor(adjustedSbn.getNotification().color) 4415 .setLocalOnly(true) 4416 .build(); 4417 summaryNotification.extras.putAll(extras); 4418 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); 4419 if (appIntent != null) { 4420 summaryNotification.contentIntent = PendingIntent.getActivityAsUser( 4421 getContext(), 0, appIntent, 0, null, UserHandle.of(userId)); 4422 } 4423 final StatusBarNotification summarySbn = 4424 new StatusBarNotification(adjustedSbn.getPackageName(), 4425 adjustedSbn.getOpPkg(), 4426 Integer.MAX_VALUE, 4427 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(), 4428 adjustedSbn.getInitialPid(), summaryNotification, 4429 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY, 4430 System.currentTimeMillis()); 4431 summaryRecord = new NotificationRecord(getContext(), summarySbn, 4432 notificationRecord.getChannel()); 4433 summaryRecord.setIsAppImportanceLocked( 4434 notificationRecord.getIsAppImportanceLocked()); 4435 summaries.put(pkg, summarySbn.getKey()); 4436 } 4437 } 4438 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID, 4439 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) { 4440 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord)); 4441 } 4442 } 4443 4444 private String disableNotificationEffects(NotificationRecord record) { 4445 if (mDisableNotificationEffects) { 4446 return "booleanState"; 4447 } 4448 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 4449 return "listenerHints"; 4450 } 4451 if (record != null && record.getAudioAttributes() != null) { 4452 if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 4453 if (record.getAudioAttributes().getUsage() 4454 != AudioAttributes.USAGE_VOICE_COMMUNICATION) { 4455 return "listenerNoti"; 4456 } 4457 } 4458 if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 4459 if (record.getAudioAttributes().getUsage() 4460 == AudioAttributes.USAGE_VOICE_COMMUNICATION) { 4461 return "listenerCall"; 4462 } 4463 } 4464 } 4465 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 4466 return "callState"; 4467 } 4468 return null; 4469 }; 4470 4471 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) { 4472 JSONObject dump = new JSONObject(); 4473 try { 4474 dump.put("service", "Notification Manager"); 4475 dump.put("bans", mPreferencesHelper.dumpBansJson(filter)); 4476 dump.put("ranking", mPreferencesHelper.dumpJson(filter)); 4477 dump.put("stats", mUsageStats.dumpJson(filter)); 4478 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter)); 4479 } catch (JSONException e) { 4480 e.printStackTrace(); 4481 } 4482 pw.println(dump); 4483 } 4484 4485 private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) { 4486 PulledStats stats = mUsageStats.remoteViewStats(filter.since, true); 4487 if (stats == null) { 4488 pw.println("no remote view stats reported."); 4489 return; 4490 } 4491 stats.dump(REPORT_REMOTE_VIEWS, pw, filter); 4492 } 4493 4494 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) { 4495 final ProtoOutputStream proto = new ProtoOutputStream(fd); 4496 synchronized (mNotificationLock) { 4497 int N = mNotificationList.size(); 4498 for (int i = 0; i < N; i++) { 4499 final NotificationRecord nr = mNotificationList.get(i); 4500 if (filter.filtered && !filter.matches(nr.sbn)) continue; 4501 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 4502 NotificationRecordProto.POSTED); 4503 } 4504 N = mEnqueuedNotifications.size(); 4505 for (int i = 0; i < N; i++) { 4506 final NotificationRecord nr = mEnqueuedNotifications.get(i); 4507 if (filter.filtered && !filter.matches(nr.sbn)) continue; 4508 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 4509 NotificationRecordProto.ENQUEUED); 4510 } 4511 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed(); 4512 N = snoozed.size(); 4513 for (int i = 0; i < N; i++) { 4514 final NotificationRecord nr = snoozed.get(i); 4515 if (filter.filtered && !filter.matches(nr.sbn)) continue; 4516 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact, 4517 NotificationRecordProto.SNOOZED); 4518 } 4519 4520 long zenLog = proto.start(NotificationServiceDumpProto.ZEN); 4521 mZenModeHelper.dump(proto); 4522 for (ComponentName suppressor : mEffectsSuppressors) { 4523 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS); 4524 } 4525 proto.end(zenLog); 4526 4527 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS); 4528 mListeners.dump(proto, filter); 4529 proto.end(listenersToken); 4530 4531 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints); 4532 4533 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) { 4534 long effectsToken = proto.start( 4535 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS); 4536 4537 proto.write( 4538 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i)); 4539 final ArraySet<ComponentName> listeners = 4540 mListenersDisablingEffects.valueAt(i); 4541 for (int j = 0; j < listeners.size(); j++) { 4542 final ComponentName componentName = listeners.valueAt(j); 4543 componentName.writeToProto(proto, 4544 ListenersDisablingEffectsProto.LISTENER_COMPONENTS); 4545 } 4546 4547 proto.end(effectsToken); 4548 } 4549 4550 long assistantsToken = proto.start( 4551 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS); 4552 mAssistants.dump(proto, filter); 4553 proto.end(assistantsToken); 4554 4555 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS); 4556 mConditionProviders.dump(proto, filter); 4557 proto.end(conditionsToken); 4558 4559 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG); 4560 mRankingHelper.dump(proto, filter); 4561 mPreferencesHelper.dump(proto, filter); 4562 proto.end(rankingToken); 4563 } 4564 4565 proto.flush(); 4566 } 4567 4568 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) { 4569 synchronized (mNotificationLock) { 4570 int N; 4571 N = mNotificationList.size(); 4572 if (N > 0) { 4573 pw.println(" Notification List:"); 4574 for (int i = 0; i < N; i++) { 4575 final NotificationRecord nr = mNotificationList.get(i); 4576 if (filter.filtered && !filter.matches(nr.sbn)) continue; 4577 nr.dump(pw, " ", getContext(), filter.redact); 4578 } 4579 pw.println(" "); 4580 } 4581 } 4582 } 4583 4584 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) { 4585 pw.print("Current Notification Manager state"); 4586 if (filter.filtered) { 4587 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 4588 } 4589 pw.println(':'); 4590 int N; 4591 final boolean zenOnly = filter.filtered && filter.zen; 4592 4593 if (!zenOnly) { 4594 synchronized (mToastQueue) { 4595 N = mToastQueue.size(); 4596 if (N > 0) { 4597 pw.println(" Toast Queue:"); 4598 for (int i=0; i<N; i++) { 4599 mToastQueue.get(i).dump(pw, " ", filter); 4600 } 4601 pw.println(" "); 4602 } 4603 } 4604 } 4605 4606 synchronized (mNotificationLock) { 4607 if (!zenOnly) { 4608 // Priority filters are only set when called via bugreport. If set 4609 // skip sections that are part of the critical section. 4610 if (!filter.normalPriority) { 4611 dumpNotificationRecords(pw, filter); 4612 } 4613 if (!filter.filtered) { 4614 N = mLights.size(); 4615 if (N > 0) { 4616 pw.println(" Lights List:"); 4617 for (int i=0; i<N; i++) { 4618 if (i == N - 1) { 4619 pw.print(" > "); 4620 } else { 4621 pw.print(" "); 4622 } 4623 pw.println(mLights.get(i)); 4624 } 4625 pw.println(" "); 4626 } 4627 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 4628 pw.println(" mHasLight=" + mHasLight); 4629 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 4630 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 4631 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 4632 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 4633 pw.println(" mCallState=" + callStateToString(mCallState)); 4634 pw.println(" mSystemReady=" + mSystemReady); 4635 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate); 4636 } 4637 pw.println(" mArchive=" + mArchive.toString()); 4638 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 4639 int j=0; 4640 while (iter.hasNext()) { 4641 final StatusBarNotification sbn = iter.next(); 4642 if (filter != null && !filter.matches(sbn)) continue; 4643 pw.println(" " + sbn); 4644 if (++j >= 5) { 4645 if (iter.hasNext()) pw.println(" ..."); 4646 break; 4647 } 4648 } 4649 4650 if (!zenOnly) { 4651 N = mEnqueuedNotifications.size(); 4652 if (N > 0) { 4653 pw.println(" Enqueued Notification List:"); 4654 for (int i = 0; i < N; i++) { 4655 final NotificationRecord nr = mEnqueuedNotifications.get(i); 4656 if (filter.filtered && !filter.matches(nr.sbn)) continue; 4657 nr.dump(pw, " ", getContext(), filter.redact); 4658 } 4659 pw.println(" "); 4660 } 4661 4662 mSnoozeHelper.dump(pw, filter); 4663 } 4664 } 4665 4666 if (!zenOnly) { 4667 pw.println("\n Ranking Config:"); 4668 mRankingHelper.dump(pw, " ", filter); 4669 4670 pw.println("\n Notification Preferences:"); 4671 mPreferencesHelper.dump(pw, " ", filter); 4672 4673 pw.println("\n Notification listeners:"); 4674 mListeners.dump(pw, filter); 4675 pw.print(" mListenerHints: "); pw.println(mListenerHints); 4676 pw.print(" mListenersDisablingEffects: ("); 4677 N = mListenersDisablingEffects.size(); 4678 for (int i = 0; i < N; i++) { 4679 final int hint = mListenersDisablingEffects.keyAt(i); 4680 if (i > 0) pw.print(';'); 4681 pw.print("hint[" + hint + "]:"); 4682 4683 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); 4684 final int listenerSize = listeners.size(); 4685 4686 for (int j = 0; j < listenerSize; j++) { 4687 if (j > 0) pw.print(','); 4688 final ComponentName listener = listeners.valueAt(j); 4689 if (listener != null) { 4690 pw.print(listener); 4691 } 4692 } 4693 } 4694 pw.println(')'); 4695 pw.println("\n Notification assistant services:"); 4696 mAssistants.dump(pw, filter); 4697 } 4698 4699 if (!filter.filtered || zenOnly) { 4700 pw.println("\n Zen Mode:"); 4701 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 4702 mZenModeHelper.dump(pw, " "); 4703 4704 pw.println("\n Zen Log:"); 4705 ZenLog.dump(pw, " "); 4706 } 4707 4708 pw.println("\n Condition providers:"); 4709 mConditionProviders.dump(pw, filter); 4710 4711 pw.println("\n Group summaries:"); 4712 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 4713 NotificationRecord r = entry.getValue(); 4714 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 4715 if (mNotificationsByKey.get(r.getKey()) != r) { 4716 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 4717 r.dump(pw, " ", getContext(), filter.redact); 4718 } 4719 } 4720 4721 if (!zenOnly) { 4722 pw.println("\n Usage Stats:"); 4723 mUsageStats.dump(pw, " ", filter); 4724 } 4725 } 4726 } 4727 4728 /** 4729 * The private API only accessible to the system process. 4730 */ 4731 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 4732 @Override 4733 public NotificationChannel getNotificationChannel(String pkg, int uid, String 4734 channelId) { 4735 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false); 4736 } 4737 4738 @Override 4739 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 4740 String tag, int id, Notification notification, int userId) { 4741 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 4742 userId); 4743 } 4744 4745 @Override 4746 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 4747 int userId) { 4748 checkCallerIsSystem(); 4749 mHandler.post(() -> { 4750 synchronized (mNotificationLock) { 4751 // strip flag from all enqueued notifications. listeners will be informed 4752 // in post runnable. 4753 List<NotificationRecord> enqueued = findNotificationsByListLocked( 4754 mEnqueuedNotifications, pkg, null, notificationId, userId); 4755 for (int i = 0; i < enqueued.size(); i++) { 4756 removeForegroundServiceFlagLocked(enqueued.get(i)); 4757 } 4758 4759 // if posted notification exists, strip its flag and tell listeners 4760 NotificationRecord r = findNotificationByListLocked( 4761 mNotificationList, pkg, null, notificationId, userId); 4762 if (r != null) { 4763 removeForegroundServiceFlagLocked(r); 4764 mRankingHelper.sort(mNotificationList); 4765 mListeners.notifyPostedLocked(r, r); 4766 } 4767 } 4768 }); 4769 } 4770 4771 @GuardedBy("mNotificationLock") 4772 private void removeForegroundServiceFlagLocked(NotificationRecord r) { 4773 if (r == null) { 4774 return; 4775 } 4776 StatusBarNotification sbn = r.sbn; 4777 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 4778 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove 4779 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received 4780 // initially *and* force remove FLAG_FOREGROUND_SERVICE. 4781 sbn.getNotification().flags = 4782 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE); 4783 } 4784 }; 4785 4786 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 4787 final int callingPid, final String tag, final int id, final Notification notification, 4788 int incomingUserId) { 4789 if (DBG) { 4790 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 4791 + " notification=" + notification); 4792 } 4793 4794 if (pkg == null || notification == null) { 4795 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 4796 + " id=" + id + " notification=" + notification); 4797 } 4798 4799 final int userId = ActivityManager.handleIncomingUser(callingPid, 4800 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 4801 final UserHandle user = UserHandle.of(userId); 4802 4803 // Can throw a SecurityException if the calling uid doesn't have permission to post 4804 // as "pkg" 4805 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId); 4806 4807 checkRestrictedCategories(notification); 4808 4809 // Fix the notification as best we can. 4810 try { 4811 fixNotification(notification, pkg, userId); 4812 4813 } catch (NameNotFoundException e) { 4814 Slog.e(TAG, "Cannot create a context for sending app", e); 4815 return; 4816 } 4817 4818 mUsageStats.registerEnqueuedByApp(pkg); 4819 4820 // setup local book-keeping 4821 String channelId = notification.getChannelId(); 4822 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) { 4823 channelId = (new Notification.TvExtender(notification)).getChannelId(); 4824 } 4825 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg, 4826 notificationUid, channelId, false /* includeDeleted */); 4827 if (channel == null) { 4828 final String noChannelStr = "No Channel found for " 4829 + "pkg=" + pkg 4830 + ", channelId=" + channelId 4831 + ", id=" + id 4832 + ", tag=" + tag 4833 + ", opPkg=" + opPkg 4834 + ", callingUid=" + callingUid 4835 + ", userId=" + userId 4836 + ", incomingUserId=" + incomingUserId 4837 + ", notificationUid=" + notificationUid 4838 + ", notification=" + notification; 4839 Slog.e(TAG, noChannelStr); 4840 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid) 4841 == NotificationManager.IMPORTANCE_NONE; 4842 4843 if (!appNotificationsOff) { 4844 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" + 4845 "Failed to post notification on channel \"" + channelId + "\"\n" + 4846 "See log for more details"); 4847 } 4848 return; 4849 } 4850 4851 final StatusBarNotification n = new StatusBarNotification( 4852 pkg, opPkg, id, tag, notificationUid, callingPid, notification, 4853 user, null, System.currentTimeMillis()); 4854 final NotificationRecord r = new NotificationRecord(getContext(), n, channel); 4855 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid)); 4856 4857 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 4858 final boolean fgServiceShown = channel.isFgServiceShown(); 4859 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0 4860 || !fgServiceShown) 4861 && (r.getImportance() == IMPORTANCE_MIN 4862 || r.getImportance() == IMPORTANCE_NONE)) { 4863 // Increase the importance of foreground service notifications unless the user had 4864 // an opinion otherwise (and the channel hasn't yet shown a fg service). 4865 if (TextUtils.isEmpty(channelId) 4866 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 4867 r.setSystemImportance(IMPORTANCE_LOW); 4868 } else { 4869 channel.setImportance(IMPORTANCE_LOW); 4870 r.setSystemImportance(IMPORTANCE_LOW); 4871 if (!fgServiceShown) { 4872 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); 4873 channel.setFgServiceShown(true); 4874 } 4875 mPreferencesHelper.updateNotificationChannel( 4876 pkg, notificationUid, channel, false); 4877 r.updateNotificationChannel(channel); 4878 } 4879 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId) 4880 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 4881 channel.setFgServiceShown(true); 4882 r.updateNotificationChannel(channel); 4883 } 4884 } 4885 4886 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, 4887 r.sbn.getOverrideGroupKey() != null)) { 4888 return; 4889 } 4890 4891 // Whitelist pending intents. 4892 if (notification.allPendingIntents != null) { 4893 final int intentCount = notification.allPendingIntents.size(); 4894 if (intentCount > 0) { 4895 final ActivityManagerInternal am = LocalServices 4896 .getService(ActivityManagerInternal.class); 4897 final long duration = LocalServices.getService( 4898 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration(); 4899 for (int i = 0; i < intentCount; i++) { 4900 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); 4901 if (pendingIntent != null) { 4902 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), 4903 WHITELIST_TOKEN, duration); 4904 am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(), 4905 WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER 4906 | FLAG_SERVICE_SENDER)); 4907 } 4908 } 4909 } 4910 } 4911 4912 mHandler.post(new EnqueueNotificationRunnable(userId, r)); 4913 } 4914 4915 @VisibleForTesting 4916 protected void fixNotification(Notification notification, String pkg, int userId) 4917 throws NameNotFoundException { 4918 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( 4919 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 4920 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId); 4921 Notification.addFieldsFromContext(ai, notification); 4922 4923 int canColorize = mPackageManagerClient.checkPermission( 4924 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg); 4925 if (canColorize == PERMISSION_GRANTED) { 4926 notification.flags |= Notification.FLAG_CAN_COLORIZE; 4927 } else { 4928 notification.flags &= ~Notification.FLAG_CAN_COLORIZE; 4929 } 4930 4931 if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) { 4932 int fullscreenIntentPermission = mPackageManagerClient.checkPermission( 4933 android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg); 4934 if (fullscreenIntentPermission != PERMISSION_GRANTED) { 4935 notification.fullScreenIntent = null; 4936 Slog.w(TAG, "Package " + pkg + 4937 ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission"); 4938 } 4939 } 4940 } 4941 4942 /** 4943 * Updates the flags for this notification to reflect whether it is a bubble or not. 4944 */ 4945 private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId, 4946 NotificationRecord oldRecord) { 4947 Notification notification = r.getNotification(); 4948 if (isNotificationAppropriateToBubble(r, pkg, userId, oldRecord)) { 4949 notification.flags |= FLAG_BUBBLE; 4950 } else { 4951 notification.flags &= ~FLAG_BUBBLE; 4952 } 4953 // Is the app in the foreground? 4954 final boolean appIsForeground = 4955 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; 4956 Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); 4957 if (!appIsForeground && metadata != null) { 4958 // Remove any flags that only work when foregrounded 4959 int flags = metadata.getFlags(); 4960 flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 4961 flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 4962 metadata.setFlags(flags); 4963 } 4964 } 4965 4966 /** 4967 * @return whether the provided notification record is allowed to be represented as a bubble, 4968 * accounting for user choice & policy. 4969 */ 4970 private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId, 4971 NotificationRecord oldRecord) { 4972 Notification notification = r.getNotification(); 4973 if (!canBubble(r, pkg, userId)) { 4974 // no log: canBubble has its own 4975 return false; 4976 } 4977 4978 if (mActivityManager.isLowRamDevice()) { 4979 logBubbleError(r.getKey(), "low ram device"); 4980 return false; 4981 } 4982 4983 if (mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND) { 4984 // If the app is foreground it always gets to bubble 4985 return true; 4986 } 4987 4988 if (oldRecord != null && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0) { 4989 // This is an update to an active bubble 4990 return true; 4991 } 4992 4993 // At this point the bubble must fulfill communication policy 4994 4995 // Communication always needs a person 4996 ArrayList<Person> peopleList = notification.extras != null 4997 ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST) 4998 : null; 4999 // Message style requires a person & it's not included in the list 5000 boolean isMessageStyle = Notification.MessagingStyle.class.equals( 5001 notification.getNotificationStyle()); 5002 if (!isMessageStyle && (peopleList == null || peopleList.isEmpty())) { 5003 logBubbleError(r.getKey(), "if not foreground, must have a person and be " 5004 + "Notification.MessageStyle or Notification.CATEGORY_CALL"); 5005 return false; 5006 } 5007 5008 // Communication is a message or a call 5009 boolean isCall = CATEGORY_CALL.equals(notification.category); 5010 boolean hasForegroundService = (notification.flags & FLAG_FOREGROUND_SERVICE) != 0; 5011 if (isMessageStyle) { 5012 if (hasValidRemoteInput(notification)) { 5013 return true; 5014 } 5015 logBubbleError(r.getKey(), "messages require valid remote input"); 5016 return false; 5017 } else if (isCall) { 5018 if (hasForegroundService) { 5019 return true; 5020 } 5021 logBubbleError(r.getKey(), "calls require foreground service"); 5022 return false; 5023 } 5024 logBubbleError(r.getKey(), "if not foreground, must be " 5025 + "Notification.MessageStyle or Notification.CATEGORY_CALL"); 5026 return false; 5027 } 5028 5029 /** 5030 * @return whether the user has enabled the provided notification to bubble, does not account 5031 * for policy. 5032 */ 5033 private boolean canBubble(NotificationRecord r, String pkg, int userId) { 5034 Notification notification = r.getNotification(); 5035 Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); 5036 if (metadata == null) { 5037 // no log: no need to inform dev if they didn't attach bubble metadata 5038 return false; 5039 } 5040 if (!canLaunchInActivityView(getContext(), metadata.getIntent(), pkg)) { 5041 // no log: method has the failure log 5042 return false; 5043 } 5044 if (!mPreferencesHelper.bubblesEnabled()) { 5045 logBubbleError(r.getKey(), "bubbles disabled for user: " + userId); 5046 return false; 5047 } 5048 if (!mPreferencesHelper.areBubblesAllowed(pkg, userId)) { 5049 logBubbleError(r.getKey(), 5050 "bubbles for package: " + pkg + " disabled for user: " + userId); 5051 return false; 5052 } 5053 if (!r.getChannel().canBubble()) { 5054 logBubbleError(r.getKey(), 5055 "bubbles for channel " + r.getChannel().getId() + " disabled"); 5056 return false; 5057 } 5058 return true; 5059 } 5060 5061 private boolean hasValidRemoteInput(Notification n) { 5062 // Also check for inline reply 5063 Notification.Action[] actions = n.actions; 5064 if (actions != null) { 5065 // Get the remote inputs 5066 for (int i = 0; i < actions.length; i++) { 5067 Notification.Action action = actions[i]; 5068 RemoteInput[] inputs = action.getRemoteInputs(); 5069 if (inputs != null && inputs.length > 0) { 5070 return true; 5071 } 5072 } 5073 } 5074 return false; 5075 } 5076 5077 private void logBubbleError(String key, String failureMessage) { 5078 if (DBG) { 5079 Log.w(TAG, "Bubble notification: " + key + " failed: " + failureMessage); 5080 } 5081 } 5082 /** 5083 * Whether an intent is properly configured to display in an {@link android.app.ActivityView}. 5084 * 5085 * @param context the context to use. 5086 * @param pendingIntent the pending intent of the bubble. 5087 * @param packageName the notification package name for this bubble. 5088 */ 5089 // Keep checks in sync with BubbleController#canLaunchInActivityView. 5090 @VisibleForTesting 5091 protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent, 5092 String packageName) { 5093 if (pendingIntent == null) { 5094 Log.w(TAG, "Unable to create bubble -- no intent"); 5095 return false; 5096 } 5097 5098 // Need escalated privileges to get the intent. 5099 final long token = Binder.clearCallingIdentity(); 5100 Intent intent; 5101 try { 5102 intent = pendingIntent.getIntent(); 5103 } finally { 5104 Binder.restoreCallingIdentity(token); 5105 } 5106 5107 ActivityInfo info = intent != null 5108 ? intent.resolveActivityInfo(context.getPackageManager(), 0) 5109 : null; 5110 if (info == null) { 5111 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, 5112 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING); 5113 Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: " 5114 + intent); 5115 return false; 5116 } 5117 if (!ActivityInfo.isResizeableMode(info.resizeMode)) { 5118 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, 5119 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE); 5120 Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: " 5121 + intent); 5122 return false; 5123 } 5124 if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) { 5125 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, 5126 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS); 5127 Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always " 5128 + "for intent: " + intent); 5129 return false; 5130 } 5131 if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) { 5132 Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: " 5133 + intent); 5134 return false; 5135 } 5136 return true; 5137 } 5138 5139 private void doChannelWarningToast(CharSequence toastText) { 5140 Binder.withCleanCallingIdentity(() -> { 5141 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0; 5142 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(), 5143 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0; 5144 if (warningEnabled) { 5145 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText, 5146 Toast.LENGTH_SHORT); 5147 toast.show(); 5148 } 5149 }); 5150 } 5151 5152 @VisibleForTesting 5153 int resolveNotificationUid(String callingPkg, String targetPkg, 5154 int callingUid, int userId) { 5155 if (userId == UserHandle.USER_ALL) { 5156 userId = USER_SYSTEM; 5157 } 5158 // posted from app A on behalf of app A 5159 if (isCallerSameApp(targetPkg, callingUid, userId) 5160 && (TextUtils.equals(callingPkg, targetPkg) 5161 || isCallerSameApp(callingPkg, callingUid, userId))) { 5162 return callingUid; 5163 } 5164 5165 int targetUid = -1; 5166 try { 5167 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); 5168 } catch (NameNotFoundException e) { 5169 /* ignore */ 5170 } 5171 // posted from app A on behalf of app B 5172 if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid) 5173 || mPreferencesHelper.isDelegateAllowed( 5174 targetPkg, targetUid, callingPkg, callingUid))) { 5175 return targetUid; 5176 } 5177 5178 throw new SecurityException("Caller " + callingPkg + ":" + callingUid 5179 + " cannot post for pkg " + targetPkg + " in user " + userId); 5180 } 5181 5182 /** 5183 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking. 5184 * 5185 * Has side effects. 5186 */ 5187 private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag, 5188 NotificationRecord r, boolean isAutogroup) { 5189 final String pkg = r.sbn.getPackageName(); 5190 final boolean isSystemNotification = 5191 isUidSystemOrPhone(uid) || ("android".equals(pkg)); 5192 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 5193 5194 // Limit the number of notifications that any given package except the android 5195 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 5196 if (!isSystemNotification && !isNotificationFromListener) { 5197 synchronized (mNotificationLock) { 5198 final int callingUid = Binder.getCallingUid(); 5199 if (mNotificationsByKey.get(r.sbn.getKey()) == null 5200 && isCallerInstantApp(callingUid, userId)) { 5201 // Ephemeral apps have some special constraints for notifications. 5202 // They are not allowed to create new notifications however they are allowed to 5203 // update notifications created by the system (e.g. a foreground service 5204 // notification). 5205 throw new SecurityException("Instant app " + pkg 5206 + " cannot create notifications"); 5207 } 5208 5209 // rate limit updates that aren't completed progress notifications 5210 if (mNotificationsByKey.get(r.sbn.getKey()) != null 5211 && !r.getNotification().hasCompletedProgress() 5212 && !isAutogroup) { 5213 5214 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); 5215 if (appEnqueueRate > mMaxPackageEnqueueRate) { 5216 mUsageStats.registerOverRateQuota(pkg); 5217 final long now = SystemClock.elapsedRealtime(); 5218 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { 5219 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate 5220 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg); 5221 mLastOverRateLogTime = now; 5222 } 5223 return false; 5224 } 5225 } 5226 5227 // limit the number of outstanding notificationrecords an app can have 5228 int count = getNotificationCountLocked(pkg, userId, id, tag); 5229 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 5230 mUsageStats.registerOverCountQuota(pkg); 5231 Slog.e(TAG, "Package has already posted or enqueued " + count 5232 + " notifications. Not showing more. package=" + pkg); 5233 return false; 5234 } 5235 } 5236 } 5237 5238 // snoozed apps 5239 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) { 5240 MetricsLogger.action(r.getLogMaker() 5241 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE) 5242 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)); 5243 if (DBG) { 5244 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); 5245 } 5246 mSnoozeHelper.update(userId, r); 5247 handleSavePolicyFile(); 5248 return false; 5249 } 5250 5251 5252 // blocked apps 5253 if (isBlocked(r, mUsageStats)) { 5254 return false; 5255 } 5256 5257 return true; 5258 } 5259 5260 @GuardedBy("mNotificationLock") 5261 protected int getNotificationCountLocked(String pkg, int userId, int excludedId, 5262 String excludedTag) { 5263 int count = 0; 5264 final int N = mNotificationList.size(); 5265 for (int i = 0; i < N; i++) { 5266 final NotificationRecord existing = mNotificationList.get(i); 5267 if (existing.sbn.getPackageName().equals(pkg) 5268 && existing.sbn.getUserId() == userId) { 5269 if (existing.sbn.getId() == excludedId 5270 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) { 5271 continue; 5272 } 5273 count++; 5274 } 5275 } 5276 final int M = mEnqueuedNotifications.size(); 5277 for (int i = 0; i < M; i++) { 5278 final NotificationRecord existing = mEnqueuedNotifications.get(i); 5279 if (existing.sbn.getPackageName().equals(pkg) 5280 && existing.sbn.getUserId() == userId) { 5281 count++; 5282 } 5283 } 5284 return count; 5285 } 5286 5287 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) { 5288 if (isBlocked(r)) { 5289 Slog.e(TAG, "Suppressing notification from package by user request."); 5290 usageStats.registerBlocked(r); 5291 return true; 5292 } 5293 return false; 5294 } 5295 5296 private boolean isBlocked(NotificationRecord r) { 5297 final String pkg = r.sbn.getPackageName(); 5298 final int callingUid = r.sbn.getUid(); 5299 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup()) 5300 || mPreferencesHelper.getImportance(pkg, callingUid) 5301 == NotificationManager.IMPORTANCE_NONE 5302 || r.getImportance() == NotificationManager.IMPORTANCE_NONE; 5303 } 5304 5305 protected class SnoozeNotificationRunnable implements Runnable { 5306 private final String mKey; 5307 private final long mDuration; 5308 private final String mSnoozeCriterionId; 5309 5310 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) { 5311 mKey = key; 5312 mDuration = duration; 5313 mSnoozeCriterionId = snoozeCriterionId; 5314 } 5315 5316 @Override 5317 public void run() { 5318 synchronized (mNotificationLock) { 5319 final NotificationRecord r = findNotificationByKeyLocked(mKey); 5320 if (r != null) { 5321 snoozeLocked(r); 5322 } 5323 } 5324 } 5325 5326 @GuardedBy("mNotificationLock") 5327 void snoozeLocked(NotificationRecord r) { 5328 if (r.sbn.isGroup()) { 5329 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked( 5330 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId()); 5331 if (r.getNotification().isGroupSummary()) { 5332 // snooze summary and all children 5333 for (int i = 0; i < groupNotifications.size(); i++) { 5334 snoozeNotificationLocked(groupNotifications.get(i)); 5335 } 5336 } else { 5337 // if there is a valid summary for this group, and we are snoozing the only 5338 // child, also snooze the summary 5339 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) { 5340 if (groupNotifications.size() != 2) { 5341 snoozeNotificationLocked(r); 5342 } else { 5343 // snooze summary and the one child 5344 for (int i = 0; i < groupNotifications.size(); i++) { 5345 snoozeNotificationLocked(groupNotifications.get(i)); 5346 } 5347 } 5348 } else { 5349 snoozeNotificationLocked(r); 5350 } 5351 } 5352 } else { 5353 // just snooze the one notification 5354 snoozeNotificationLocked(r); 5355 } 5356 } 5357 5358 @GuardedBy("mNotificationLock") 5359 void snoozeNotificationLocked(NotificationRecord r) { 5360 MetricsLogger.action(r.getLogMaker() 5361 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED) 5362 .setType(MetricsEvent.TYPE_CLOSE) 5363 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, 5364 mDuration) 5365 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA, 5366 mSnoozeCriterionId == null ? 0 : 1)); 5367 reportUserInteraction(r); 5368 boolean wasPosted = removeFromNotificationListsLocked(r); 5369 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null); 5370 updateLightsLocked(); 5371 if (mSnoozeCriterionId != null) { 5372 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId); 5373 mSnoozeHelper.snooze(r); 5374 } else { 5375 mSnoozeHelper.snooze(r, mDuration); 5376 } 5377 r.recordSnoozed(); 5378 handleSavePolicyFile(); 5379 } 5380 } 5381 5382 protected class CancelNotificationRunnable implements Runnable { 5383 private final int mCallingUid; 5384 private final int mCallingPid; 5385 private final String mPkg; 5386 private final String mTag; 5387 private final int mId; 5388 private final int mMustHaveFlags; 5389 private final int mMustNotHaveFlags; 5390 private final boolean mSendDelete; 5391 private final int mUserId; 5392 private final int mReason; 5393 private final int mRank; 5394 private final int mCount; 5395 private final ManagedServiceInfo mListener; 5396 5397 CancelNotificationRunnable(final int callingUid, final int callingPid, 5398 final String pkg, final String tag, final int id, 5399 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 5400 final int userId, final int reason, int rank, int count, 5401 final ManagedServiceInfo listener) { 5402 this.mCallingUid = callingUid; 5403 this.mCallingPid = callingPid; 5404 this.mPkg = pkg; 5405 this.mTag = tag; 5406 this.mId = id; 5407 this.mMustHaveFlags = mustHaveFlags; 5408 this.mMustNotHaveFlags = mustNotHaveFlags; 5409 this.mSendDelete = sendDelete; 5410 this.mUserId = userId; 5411 this.mReason = reason; 5412 this.mRank = rank; 5413 this.mCount = count; 5414 this.mListener = listener; 5415 } 5416 5417 @Override 5418 public void run() { 5419 String listenerName = mListener == null ? null : mListener.component.toShortString(); 5420 if (DBG) { 5421 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag, 5422 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName); 5423 } 5424 5425 synchronized (mNotificationLock) { 5426 // If the notification is currently enqueued, repost this runnable so it has a 5427 // chance to notify listeners 5428 if ((findNotificationByListLocked(mEnqueuedNotifications, mPkg, mTag, mId, mUserId)) 5429 != null) { 5430 mHandler.post(this); 5431 return; 5432 } 5433 // Look for the notification in the posted list, since we already checked enqueued. 5434 NotificationRecord r = 5435 findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); 5436 if (r != null) { 5437 // The notification was found, check if it should be removed. 5438 5439 // Ideally we'd do this in the caller of this method. However, that would 5440 // require the caller to also find the notification. 5441 if (mReason == REASON_CLICK) { 5442 mUsageStats.registerClickedByUser(r); 5443 } 5444 5445 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { 5446 return; 5447 } 5448 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { 5449 return; 5450 } 5451 5452 // Bubbled children get to stick around if the summary was manually cancelled 5453 // (user removed) from systemui. 5454 FlagChecker childrenFlagChecker = null; 5455 if (mReason == REASON_CANCEL 5456 || mReason == REASON_CLICK 5457 || mReason == REASON_CANCEL_ALL) { 5458 childrenFlagChecker = (flags) -> { 5459 if ((flags & FLAG_BUBBLE) != 0) { 5460 return false; 5461 } 5462 return true; 5463 }; 5464 } 5465 5466 // Cancel the notification. 5467 boolean wasPosted = removeFromNotificationListsLocked(r); 5468 cancelNotificationLocked( 5469 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName); 5470 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName, 5471 mSendDelete, childrenFlagChecker); 5472 updateLightsLocked(); 5473 } else { 5474 // No notification was found, assume that it is snoozed and cancel it. 5475 if (mReason != REASON_SNOOZED) { 5476 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId); 5477 if (wasSnoozed) { 5478 handleSavePolicyFile(); 5479 } 5480 } 5481 } 5482 } 5483 } 5484 } 5485 5486 protected class EnqueueNotificationRunnable implements Runnable { 5487 private final NotificationRecord r; 5488 private final int userId; 5489 5490 EnqueueNotificationRunnable(int userId, NotificationRecord r) { 5491 this.userId = userId; 5492 this.r = r; 5493 }; 5494 5495 @Override 5496 public void run() { 5497 synchronized (mNotificationLock) { 5498 mEnqueuedNotifications.add(r); 5499 scheduleTimeoutLocked(r); 5500 5501 final StatusBarNotification n = r.sbn; 5502 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 5503 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 5504 if (old != null) { 5505 // Retain ranking information from previous record 5506 r.copyRankingInformation(old); 5507 } 5508 5509 final int callingUid = n.getUid(); 5510 final int callingPid = n.getInitialPid(); 5511 final Notification notification = n.getNotification(); 5512 final String pkg = n.getPackageName(); 5513 final int id = n.getId(); 5514 final String tag = n.getTag(); 5515 5516 // We need to fix the notification up a little for bubbles 5517 flagNotificationForBubbles(r, pkg, callingUid, old); 5518 5519 // Handle grouped notifications and bail out early if we 5520 // can to avoid extracting signals. 5521 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 5522 5523 // if this is a group child, unsnooze parent summary 5524 if (n.isGroup() && notification.isGroupChild()) { 5525 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey()); 5526 } 5527 5528 // This conditional is a dirty hack to limit the logging done on 5529 // behalf of the download manager without affecting other apps. 5530 if (!pkg.equals("com.android.providers.downloads") 5531 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 5532 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 5533 if (old != null) { 5534 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 5535 } 5536 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 5537 pkg, id, tag, userId, notification.toString(), 5538 enqueueStatus); 5539 } 5540 5541 // tell the assistant service about the notification 5542 if (mAssistants.isEnabled()) { 5543 mAssistants.onNotificationEnqueuedLocked(r); 5544 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()), 5545 DELAY_FOR_ASSISTANT_TIME); 5546 } else { 5547 mHandler.post(new PostNotificationRunnable(r.getKey())); 5548 } 5549 } 5550 } 5551 } 5552 5553 @GuardedBy("mNotificationLock") 5554 boolean isPackagePausedOrSuspended(String pkg, int uid) { 5555 boolean isPaused; 5556 5557 final PackageManagerInternal pmi = LocalServices.getService( 5558 PackageManagerInternal.class); 5559 int flags = pmi.getDistractingPackageRestrictions( 5560 pkg, Binder.getCallingUserHandle().getIdentifier()); 5561 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0); 5562 5563 isPaused |= isPackageSuspendedForUser(pkg, uid); 5564 5565 return isPaused; 5566 } 5567 5568 protected class PostNotificationRunnable implements Runnable { 5569 private final String key; 5570 5571 PostNotificationRunnable(String key) { 5572 this.key = key; 5573 } 5574 5575 @Override 5576 public void run() { 5577 synchronized (mNotificationLock) { 5578 try { 5579 NotificationRecord r = null; 5580 int N = mEnqueuedNotifications.size(); 5581 for (int i = 0; i < N; i++) { 5582 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 5583 if (Objects.equals(key, enqueued.getKey())) { 5584 r = enqueued; 5585 break; 5586 } 5587 } 5588 if (r == null) { 5589 Slog.i(TAG, "Cannot find enqueued record for key: " + key); 5590 return; 5591 } 5592 5593 if (isBlocked(r)) { 5594 Slog.i(TAG, "notification blocked by assistant request"); 5595 return; 5596 } 5597 5598 final boolean isPackageSuspended = 5599 isPackagePausedOrSuspended(r.sbn.getPackageName(), r.getUid()); 5600 r.setHidden(isPackageSuspended); 5601 if (isPackageSuspended) { 5602 mUsageStats.registerSuspendedByAdmin(r); 5603 } 5604 NotificationRecord old = mNotificationsByKey.get(key); 5605 final StatusBarNotification n = r.sbn; 5606 final Notification notification = n.getNotification(); 5607 int index = indexOfNotificationLocked(n.getKey()); 5608 if (index < 0) { 5609 mNotificationList.add(r); 5610 mUsageStats.registerPostedByApp(r); 5611 r.setInterruptive(isVisuallyInterruptive(null, r)); 5612 } else { 5613 old = mNotificationList.get(index); 5614 mNotificationList.set(index, r); 5615 mUsageStats.registerUpdatedByApp(r, old); 5616 // Make sure we don't lose the foreground service state. 5617 notification.flags |= 5618 old.getNotification().flags & FLAG_FOREGROUND_SERVICE; 5619 r.isUpdate = true; 5620 final boolean isInterruptive = isVisuallyInterruptive(old, r); 5621 r.setTextChanged(isInterruptive); 5622 r.setInterruptive(isInterruptive); 5623 } 5624 5625 mNotificationsByKey.put(n.getKey(), r); 5626 5627 // Ensure if this is a foreground service that the proper additional 5628 // flags are set. 5629 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) { 5630 notification.flags |= FLAG_ONGOING_EVENT 5631 | FLAG_NO_CLEAR; 5632 } 5633 5634 mRankingHelper.extractSignals(r); 5635 mRankingHelper.sort(mNotificationList); 5636 5637 if (!r.isHidden()) { 5638 buzzBeepBlinkLocked(r); 5639 } 5640 5641 if (notification.getSmallIcon() != null) { 5642 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 5643 mListeners.notifyPostedLocked(r, old); 5644 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) 5645 && !isCritical(r)) { 5646 mHandler.post(new Runnable() { 5647 @Override 5648 public void run() { 5649 mGroupHelper.onNotificationPosted( 5650 n, hasAutoGroupSummaryLocked(n)); 5651 } 5652 }); 5653 } 5654 } else { 5655 Slog.e(TAG, "Not posting notification without small icon: " + notification); 5656 if (old != null && !old.isCanceled) { 5657 mListeners.notifyRemovedLocked(r, 5658 NotificationListenerService.REASON_ERROR, r.getStats()); 5659 mHandler.post(new Runnable() { 5660 @Override 5661 public void run() { 5662 mGroupHelper.onNotificationRemoved(n); 5663 } 5664 }); 5665 } 5666 // ATTENTION: in a future release we will bail out here 5667 // so that we do not play sounds, show lights, etc. for invalid 5668 // notifications 5669 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 5670 + n.getPackageName()); 5671 } 5672 5673 maybeRecordInterruptionLocked(r); 5674 } finally { 5675 int N = mEnqueuedNotifications.size(); 5676 for (int i = 0; i < N; i++) { 5677 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 5678 if (Objects.equals(key, enqueued.getKey())) { 5679 mEnqueuedNotifications.remove(i); 5680 break; 5681 } 5682 } 5683 } 5684 } 5685 } 5686 } 5687 5688 /** 5689 * If the notification differs enough visually, consider it a new interruptive notification. 5690 */ 5691 @GuardedBy("mNotificationLock") 5692 @VisibleForTesting 5693 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) { 5694 // Ignore summary updates because we don't display most of the information. 5695 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) { 5696 if (DEBUG_INTERRUPTIVENESS) { 5697 Slog.v(TAG, "INTERRUPTIVENESS: " 5698 + r.getKey() + " is not interruptive: summary"); 5699 } 5700 return false; 5701 } 5702 5703 if (old == null) { 5704 if (DEBUG_INTERRUPTIVENESS) { 5705 Slog.v(TAG, "INTERRUPTIVENESS: " 5706 + r.getKey() + " is interruptive: new notification"); 5707 } 5708 return true; 5709 } 5710 5711 if (r == null) { 5712 if (DEBUG_INTERRUPTIVENESS) { 5713 Slog.v(TAG, "INTERRUPTIVENESS: " 5714 + r.getKey() + " is not interruptive: null"); 5715 } 5716 return false; 5717 } 5718 5719 Notification oldN = old.sbn.getNotification(); 5720 Notification newN = r.sbn.getNotification(); 5721 if (oldN.extras == null || newN.extras == null) { 5722 if (DEBUG_INTERRUPTIVENESS) { 5723 Slog.v(TAG, "INTERRUPTIVENESS: " 5724 + r.getKey() + " is not interruptive: no extras"); 5725 } 5726 return false; 5727 } 5728 5729 // Ignore visual interruptions from foreground services because users 5730 // consider them one 'session'. Count them for everything else. 5731 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { 5732 if (DEBUG_INTERRUPTIVENESS) { 5733 Slog.v(TAG, "INTERRUPTIVENESS: " 5734 + r.getKey() + " is not interruptive: foreground service"); 5735 } 5736 return false; 5737 } 5738 5739 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); 5740 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); 5741 if (!Objects.equals(oldTitle, newTitle)) { 5742 if (DEBUG_INTERRUPTIVENESS) { 5743 Slog.v(TAG, "INTERRUPTIVENESS: " 5744 + r.getKey() + " is interruptive: changed title"); 5745 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)", 5746 oldTitle, oldTitle.getClass(), oldTitle.hashCode())); 5747 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)", 5748 newTitle, newTitle.getClass(), newTitle.hashCode())); 5749 } 5750 return true; 5751 } 5752 5753 // Do not compare Spannables (will always return false); compare unstyled Strings 5754 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT)); 5755 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT)); 5756 if (!Objects.equals(oldText, newText)) { 5757 if (DEBUG_INTERRUPTIVENESS) { 5758 Slog.v(TAG, "INTERRUPTIVENESS: " 5759 + r.getKey() + " is interruptive: changed text"); 5760 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)", 5761 oldText, oldText.getClass(), oldText.hashCode())); 5762 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)", 5763 newText, newText.getClass(), newText.hashCode())); 5764 } 5765 return true; 5766 } 5767 5768 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) { 5769 if (DEBUG_INTERRUPTIVENESS) { 5770 Slog.v(TAG, "INTERRUPTIVENESS: " 5771 + r.getKey() + " is interruptive: completed progress"); 5772 } 5773 return true; 5774 } 5775 5776 // Fields below are invisible to bubbles. 5777 if (r.canBubble()) { 5778 if (DEBUG_INTERRUPTIVENESS) { 5779 Slog.v(TAG, "INTERRUPTIVENESS: " 5780 + r.getKey() + " is not interruptive: bubble"); 5781 } 5782 return false; 5783 } 5784 5785 // Actions 5786 if (Notification.areActionsVisiblyDifferent(oldN, newN)) { 5787 if (DEBUG_INTERRUPTIVENESS) { 5788 Slog.v(TAG, "INTERRUPTIVENESS: " 5789 + r.getKey() + " is interruptive: changed actions"); 5790 } 5791 return true; 5792 } 5793 5794 try { 5795 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN); 5796 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN); 5797 5798 // Style based comparisons 5799 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) { 5800 if (DEBUG_INTERRUPTIVENESS) { 5801 Slog.v(TAG, "INTERRUPTIVENESS: " 5802 + r.getKey() + " is interruptive: styles differ"); 5803 } 5804 return true; 5805 } 5806 5807 // Remote views 5808 if (Notification.areRemoteViewsChanged(oldB, newB)) { 5809 if (DEBUG_INTERRUPTIVENESS) { 5810 Slog.v(TAG, "INTERRUPTIVENESS: " 5811 + r.getKey() + " is interruptive: remoteviews differ"); 5812 } 5813 return true; 5814 } 5815 } catch (Exception e) { 5816 Slog.w(TAG, "error recovering builder", e); 5817 } 5818 return false; 5819 } 5820 5821 /** 5822 * Check if the notification is classified as critical. 5823 * 5824 * @param record the record to test for criticality 5825 * @return {@code true} if notification is considered critical 5826 * 5827 * @see CriticalNotificationExtractor for criteria 5828 */ 5829 private boolean isCritical(NotificationRecord record) { 5830 // 0 is the most critical 5831 return record.getCriticality() < CriticalNotificationExtractor.NORMAL; 5832 } 5833 5834 /** 5835 * Ensures that grouped notification receive their special treatment. 5836 * 5837 * <p>Cancels group children if the new notification causes a group to lose 5838 * its summary.</p> 5839 * 5840 * <p>Updates mSummaryByGroupKey.</p> 5841 */ 5842 @GuardedBy("mNotificationLock") 5843 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 5844 int callingUid, int callingPid) { 5845 StatusBarNotification sbn = r.sbn; 5846 Notification n = sbn.getNotification(); 5847 if (n.isGroupSummary() && !sbn.isAppGroup()) { 5848 // notifications without a group shouldn't be a summary, otherwise autobundling can 5849 // lead to bugs 5850 n.flags &= ~Notification.FLAG_GROUP_SUMMARY; 5851 } 5852 5853 String group = sbn.getGroupKey(); 5854 boolean isSummary = n.isGroupSummary(); 5855 5856 Notification oldN = old != null ? old.sbn.getNotification() : null; 5857 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 5858 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 5859 5860 if (oldIsSummary) { 5861 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 5862 if (removedSummary != old) { 5863 String removedKey = 5864 removedSummary != null ? removedSummary.getKey() : "<null>"; 5865 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 5866 ", removed=" + removedKey); 5867 } 5868 } 5869 if (isSummary) { 5870 mSummaryByGroupKey.put(group, r); 5871 } 5872 5873 // Clear out group children of the old notification if the update 5874 // causes the group summary to go away. This happens when the old 5875 // notification was a summary and the new one isn't, or when the old 5876 // notification was a summary and its group key changed. 5877 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 5878 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */, 5879 null); 5880 } 5881 } 5882 5883 @VisibleForTesting 5884 @GuardedBy("mNotificationLock") 5885 void scheduleTimeoutLocked(NotificationRecord record) { 5886 if (record.getNotification().getTimeoutAfter() > 0) { 5887 final PendingIntent pi = PendingIntent.getBroadcast(getContext(), 5888 REQUEST_CODE_TIMEOUT, 5889 new Intent(ACTION_NOTIFICATION_TIMEOUT) 5890 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT) 5891 .appendPath(record.getKey()).build()) 5892 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 5893 .putExtra(EXTRA_KEY, record.getKey()), 5894 PendingIntent.FLAG_UPDATE_CURRENT); 5895 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 5896 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi); 5897 } 5898 } 5899 5900 @VisibleForTesting 5901 @GuardedBy("mNotificationLock") 5902 void buzzBeepBlinkLocked(NotificationRecord record) { 5903 if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) { 5904 return; 5905 } 5906 boolean buzz = false; 5907 boolean beep = false; 5908 boolean blink = false; 5909 5910 final Notification notification = record.sbn.getNotification(); 5911 final String key = record.getKey(); 5912 5913 // Should this notification make noise, vibe, or use the LED? 5914 final boolean aboveThreshold = 5915 mIsAutomotive 5916 ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT 5917 : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT; 5918 5919 // Remember if this notification already owns the notification channels. 5920 boolean wasBeep = key != null && key.equals(mSoundNotificationKey); 5921 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey); 5922 // These are set inside the conditional if the notification is allowed to make noise. 5923 boolean hasValidVibrate = false; 5924 boolean hasValidSound = false; 5925 boolean sentAccessibilityEvent = false; 5926 // If the notification will appear in the status bar, it should send an accessibility 5927 // event 5928 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { 5929 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 5930 sentAccessibilityEvent = true; 5931 } 5932 5933 if (aboveThreshold && isNotificationForCurrentUser(record)) { 5934 5935 if (mSystemReady && mAudioManager != null) { 5936 Uri soundUri = record.getSound(); 5937 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri); 5938 long[] vibration = record.getVibration(); 5939 // Demote sound to vibration if vibration missing & phone in vibration mode. 5940 if (vibration == null 5941 && hasValidSound 5942 && (mAudioManager.getRingerModeInternal() 5943 == AudioManager.RINGER_MODE_VIBRATE) 5944 && mAudioManager.getStreamVolume( 5945 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) { 5946 vibration = mFallbackVibrationPattern; 5947 } 5948 hasValidVibrate = vibration != null; 5949 5950 boolean hasAudibleAlert = hasValidSound || hasValidVibrate; 5951 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { 5952 if (!sentAccessibilityEvent) { 5953 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 5954 sentAccessibilityEvent = true; 5955 } 5956 if (DBG) Slog.v(TAG, "Interrupting!"); 5957 if (hasValidSound) { 5958 if (isInCall()) { 5959 playInCallNotification(); 5960 beep = true; 5961 } else { 5962 beep = playSound(record, soundUri); 5963 } 5964 if(beep) { 5965 mSoundNotificationKey = key; 5966 } 5967 } 5968 5969 final boolean ringerModeSilent = 5970 mAudioManager.getRingerModeInternal() 5971 == AudioManager.RINGER_MODE_SILENT; 5972 if (!isInCall() && hasValidVibrate && !ringerModeSilent) { 5973 buzz = playVibration(record, vibration, hasValidSound); 5974 if(buzz) { 5975 mVibrateNotificationKey = key; 5976 } 5977 } 5978 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) { 5979 hasValidSound = false; 5980 } 5981 } 5982 } 5983 // If a notification is updated to remove the actively playing sound or vibrate, 5984 // cancel that feedback now 5985 if (wasBeep && !hasValidSound) { 5986 clearSoundLocked(); 5987 } 5988 if (wasBuzz && !hasValidVibrate) { 5989 clearVibrateLocked(); 5990 } 5991 5992 // light 5993 // release the light 5994 boolean wasShowLights = mLights.remove(key); 5995 if (canShowLightsLocked(record, aboveThreshold)) { 5996 mLights.add(key); 5997 updateLightsLocked(); 5998 if (mUseAttentionLight) { 5999 mAttentionLight.pulse(); 6000 } 6001 blink = true; 6002 } else if (wasShowLights) { 6003 updateLightsLocked(); 6004 } 6005 if (buzz || beep || blink) { 6006 // Ignore summary updates because we don't display most of the information. 6007 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) { 6008 if (DEBUG_INTERRUPTIVENESS) { 6009 Slog.v(TAG, "INTERRUPTIVENESS: " 6010 + record.getKey() + " is not interruptive: summary"); 6011 } 6012 } else if (record.canBubble()) { 6013 if (DEBUG_INTERRUPTIVENESS) { 6014 Slog.v(TAG, "INTERRUPTIVENESS: " 6015 + record.getKey() + " is not interruptive: bubble"); 6016 } 6017 } else { 6018 record.setInterruptive(true); 6019 if (DEBUG_INTERRUPTIVENESS) { 6020 Slog.v(TAG, "INTERRUPTIVENESS: " 6021 + record.getKey() + " is interruptive: alerted"); 6022 } 6023 } 6024 MetricsLogger.action(record.getLogMaker() 6025 .setCategory(MetricsEvent.NOTIFICATION_ALERT) 6026 .setType(MetricsEvent.TYPE_OPEN) 6027 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0))); 6028 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 6029 } 6030 record.setAudiblyAlerted(buzz || beep); 6031 } 6032 6033 @GuardedBy("mNotificationLock") 6034 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) { 6035 // device lacks light 6036 if (!mHasLight) { 6037 return false; 6038 } 6039 // user turned lights off globally 6040 if (!mNotificationPulseEnabled) { 6041 return false; 6042 } 6043 // the notification/channel has no light 6044 if (record.getLight() == null) { 6045 return false; 6046 } 6047 // unimportant notification 6048 if (!aboveThreshold) { 6049 return false; 6050 } 6051 // suppressed due to DND 6052 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) { 6053 return false; 6054 } 6055 // Suppressed because it's a silent update 6056 final Notification notification = record.getNotification(); 6057 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) { 6058 return false; 6059 } 6060 // Suppressed because another notification in its group handles alerting 6061 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) { 6062 return false; 6063 } 6064 // not if in call or the screen's on 6065 if (isInCall() || mScreenOn) { 6066 return false; 6067 } 6068 // check current user 6069 if (!isNotificationForCurrentUser(record)) { 6070 return false; 6071 } 6072 6073 return true; 6074 } 6075 6076 @GuardedBy("mNotificationLock") 6077 boolean shouldMuteNotificationLocked(final NotificationRecord record) { 6078 // Suppressed because it's a silent update 6079 final Notification notification = record.getNotification(); 6080 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) { 6081 return true; 6082 } 6083 6084 // muted by listener 6085 final String disableEffects = disableNotificationEffects(record); 6086 if (disableEffects != null) { 6087 ZenLog.traceDisableEffects(record, disableEffects); 6088 return true; 6089 } 6090 6091 // suppressed due to DND 6092 if (record.isIntercepted()) { 6093 return true; 6094 } 6095 6096 // Suppressed because another notification in its group handles alerting 6097 if (record.sbn.isGroup()) { 6098 if (notification.suppressAlertingDueToGrouping()) { 6099 return true; 6100 } 6101 } 6102 6103 // Suppressed for being too recently noisy 6104 final String pkg = record.sbn.getPackageName(); 6105 if (mUsageStats.isAlertRateLimited(pkg)) { 6106 Slog.e(TAG, "Muting recently noisy " + record.getKey()); 6107 return true; 6108 } 6109 6110 return false; 6111 } 6112 6113 private boolean playSound(final NotificationRecord record, Uri soundUri) { 6114 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; 6115 // play notifications if there is no user of exclusive audio focus 6116 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or 6117 // VIBRATE ringer mode) 6118 if (!mAudioManager.isAudioFocusExclusive() 6119 && (mAudioManager.getStreamVolume( 6120 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) { 6121 final long identity = Binder.clearCallingIdentity(); 6122 try { 6123 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 6124 if (player != null) { 6125 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 6126 + " with attributes " + record.getAudioAttributes()); 6127 player.playAsync(soundUri, record.sbn.getUser(), looping, 6128 record.getAudioAttributes()); 6129 return true; 6130 } 6131 } catch (RemoteException e) { 6132 } finally { 6133 Binder.restoreCallingIdentity(identity); 6134 } 6135 } 6136 return false; 6137 } 6138 6139 private boolean playVibration(final NotificationRecord record, long[] vibration, 6140 boolean delayVibForSound) { 6141 // Escalate privileges so we can use the vibrator even if the 6142 // notifying app does not have the VIBRATE permission. 6143 long identity = Binder.clearCallingIdentity(); 6144 try { 6145 final VibrationEffect effect; 6146 try { 6147 final boolean insistent = 6148 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; 6149 effect = VibrationEffect.createWaveform( 6150 vibration, insistent ? 0 : -1 /*repeatIndex*/); 6151 } catch (IllegalArgumentException e) { 6152 Slog.e(TAG, "Error creating vibration waveform with pattern: " + 6153 Arrays.toString(vibration)); 6154 return false; 6155 } 6156 if (delayVibForSound) { 6157 new Thread(() -> { 6158 // delay the vibration by the same amount as the notification sound 6159 final int waitMs = mAudioManager.getFocusRampTimeMs( 6160 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 6161 record.getAudioAttributes()); 6162 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms"); 6163 try { 6164 Thread.sleep(waitMs); 6165 } catch (InterruptedException e) { } 6166 6167 // Notifications might be canceled before it actually vibrates due to waitMs, 6168 // so need to check the notification still valide for vibrate. 6169 synchronized (mNotificationLock) { 6170 if (mNotificationsByKey.get(record.getKey()) != null) { 6171 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 6172 effect, "Notification (delayed)", record.getAudioAttributes()); 6173 } else { 6174 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey()); 6175 } 6176 } 6177 }).start(); 6178 } else { 6179 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(), 6180 effect, "Notification", record.getAudioAttributes()); 6181 } 6182 return true; 6183 } finally{ 6184 Binder.restoreCallingIdentity(identity); 6185 } 6186 } 6187 6188 private boolean isNotificationForCurrentUser(NotificationRecord record) { 6189 final int currentUser; 6190 final long token = Binder.clearCallingIdentity(); 6191 try { 6192 currentUser = ActivityManager.getCurrentUser(); 6193 } finally { 6194 Binder.restoreCallingIdentity(token); 6195 } 6196 return (record.getUserId() == UserHandle.USER_ALL || 6197 record.getUserId() == currentUser || 6198 mUserProfiles.isCurrentProfile(record.getUserId())); 6199 } 6200 6201 protected void playInCallNotification() { 6202 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL 6203 && Settings.Secure.getInt(getContext().getContentResolver(), 6204 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) { 6205 new Thread() { 6206 @Override 6207 public void run() { 6208 final long identity = Binder.clearCallingIdentity(); 6209 try { 6210 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 6211 if (player != null) { 6212 if (mCallNotificationToken != null) { 6213 player.stop(mCallNotificationToken); 6214 } 6215 mCallNotificationToken = new Binder(); 6216 player.play(mCallNotificationToken, mInCallNotificationUri, 6217 mInCallNotificationAudioAttributes, 6218 mInCallNotificationVolume, false); 6219 } 6220 } catch (RemoteException e) { 6221 } finally { 6222 Binder.restoreCallingIdentity(identity); 6223 } 6224 } 6225 }.start(); 6226 } 6227 } 6228 6229 @GuardedBy("mToastQueue") 6230 void showNextToastLocked() { 6231 ToastRecord record = mToastQueue.get(0); 6232 while (record != null) { 6233 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 6234 try { 6235 record.callback.show(record.token); 6236 scheduleDurationReachedLocked(record); 6237 return; 6238 } catch (RemoteException e) { 6239 Slog.w(TAG, "Object died trying to show notification " + record.callback 6240 + " in package " + record.pkg); 6241 // remove it from the list and let the process die 6242 int index = mToastQueue.indexOf(record); 6243 if (index >= 0) { 6244 mToastQueue.remove(index); 6245 } 6246 keepProcessAliveIfNeededLocked(record.pid); 6247 if (mToastQueue.size() > 0) { 6248 record = mToastQueue.get(0); 6249 } else { 6250 record = null; 6251 } 6252 } 6253 } 6254 } 6255 6256 @GuardedBy("mToastQueue") 6257 void cancelToastLocked(int index) { 6258 ToastRecord record = mToastQueue.get(index); 6259 try { 6260 record.callback.hide(); 6261 } catch (RemoteException e) { 6262 Slog.w(TAG, "Object died trying to hide notification " + record.callback 6263 + " in package " + record.pkg); 6264 // don't worry about this, we're about to remove it from 6265 // the list anyway 6266 } 6267 6268 ToastRecord lastToast = mToastQueue.remove(index); 6269 6270 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */, 6271 lastToast.displayId); 6272 // We passed 'false' for 'removeWindows' so that the client has time to stop 6273 // rendering (as hide above is a one-way message), otherwise we could crash 6274 // a client which was actively using a surface made from the token. However 6275 // we need to schedule a timeout to make sure the token is eventually killed 6276 // one way or another. 6277 scheduleKillTokenTimeout(lastToast); 6278 6279 keepProcessAliveIfNeededLocked(record.pid); 6280 if (mToastQueue.size() > 0) { 6281 // Show the next one. If the callback fails, this will remove 6282 // it from the list, so don't assume that the list hasn't changed 6283 // after this point. 6284 showNextToastLocked(); 6285 } 6286 } 6287 6288 void finishTokenLocked(IBinder t, int displayId) { 6289 mHandler.removeCallbacksAndMessages(t); 6290 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any 6291 // remaining surfaces as either the client has called finishToken indicating 6292 // it has successfully removed the views, or the client has timed out 6293 // at which point anything goes. 6294 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId); 6295 } 6296 6297 @GuardedBy("mToastQueue") 6298 private void scheduleDurationReachedLocked(ToastRecord r) 6299 { 6300 mHandler.removeCallbacksAndMessages(r); 6301 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r); 6302 int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 6303 // Accessibility users may need longer timeout duration. This api compares original delay 6304 // with user's preference and return longer one. It returns original delay if there's no 6305 // preference. 6306 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay, 6307 AccessibilityManager.FLAG_CONTENT_TEXT); 6308 mHandler.sendMessageDelayed(m, delay); 6309 } 6310 6311 private void handleDurationReached(ToastRecord record) 6312 { 6313 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 6314 synchronized (mToastQueue) { 6315 int index = indexOfToastLocked(record.pkg, record.callback); 6316 if (index >= 0) { 6317 cancelToastLocked(index); 6318 } 6319 } 6320 } 6321 6322 @GuardedBy("mToastQueue") 6323 private void scheduleKillTokenTimeout(ToastRecord r) 6324 { 6325 mHandler.removeCallbacksAndMessages(r); 6326 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r); 6327 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT); 6328 } 6329 6330 private void handleKillTokenTimeout(ToastRecord record) 6331 { 6332 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token); 6333 synchronized (mToastQueue) { 6334 finishTokenLocked(record.token, record.displayId); 6335 } 6336 } 6337 6338 @GuardedBy("mToastQueue") 6339 int indexOfToastLocked(String pkg, ITransientNotification callback) 6340 { 6341 IBinder cbak = callback.asBinder(); 6342 ArrayList<ToastRecord> list = mToastQueue; 6343 int len = list.size(); 6344 for (int i=0; i<len; i++) { 6345 ToastRecord r = list.get(i); 6346 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 6347 return i; 6348 } 6349 } 6350 return -1; 6351 } 6352 6353 @GuardedBy("mToastQueue") 6354 void keepProcessAliveIfNeededLocked(int pid) 6355 { 6356 int toastCount = 0; // toasts from this pid 6357 ArrayList<ToastRecord> list = mToastQueue; 6358 int N = list.size(); 6359 for (int i=0; i<N; i++) { 6360 ToastRecord r = list.get(i); 6361 if (r.pid == pid) { 6362 toastCount++; 6363 } 6364 } 6365 try { 6366 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast"); 6367 } catch (RemoteException e) { 6368 // Shouldn't happen. 6369 } 6370 } 6371 6372 private void handleRankingReconsideration(Message message) { 6373 if (!(message.obj instanceof RankingReconsideration)) return; 6374 RankingReconsideration recon = (RankingReconsideration) message.obj; 6375 recon.run(); 6376 boolean changed; 6377 synchronized (mNotificationLock) { 6378 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 6379 if (record == null) { 6380 return; 6381 } 6382 int indexBefore = findNotificationRecordIndexLocked(record); 6383 boolean interceptBefore = record.isIntercepted(); 6384 int visibilityBefore = record.getPackageVisibilityOverride(); 6385 boolean interruptiveBefore = record.isInterruptive(); 6386 6387 recon.applyChangesLocked(record); 6388 applyZenModeLocked(record); 6389 mRankingHelper.sort(mNotificationList); 6390 boolean indexChanged = indexBefore != findNotificationRecordIndexLocked(record); 6391 boolean interceptChanged = interceptBefore != record.isIntercepted(); 6392 boolean visibilityChanged = visibilityBefore != record.getPackageVisibilityOverride(); 6393 6394 // Broadcast isInterruptive changes for bubbles. 6395 boolean interruptiveChanged = 6396 record.canBubble() && (interruptiveBefore != record.isInterruptive()); 6397 6398 changed = indexChanged || interceptChanged || visibilityChanged || interruptiveChanged; 6399 if (interceptBefore && !record.isIntercepted() 6400 && record.isNewEnoughForAlerting(System.currentTimeMillis())) { 6401 buzzBeepBlinkLocked(record); 6402 } 6403 } 6404 if (changed) { 6405 mHandler.scheduleSendRankingUpdate(); 6406 } 6407 } 6408 6409 void handleRankingSort() { 6410 if (mRankingHelper == null) return; 6411 synchronized (mNotificationLock) { 6412 final int N = mNotificationList.size(); 6413 // Any field that can change via one of the extractors needs to be added here. 6414 ArrayList<String> orderBefore = new ArrayList<>(N); 6415 int[] visibilities = new int[N]; 6416 boolean[] showBadges = new boolean[N]; 6417 boolean[] allowBubbles = new boolean[N]; 6418 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N); 6419 ArrayList<String> groupKeyBefore = new ArrayList<>(N); 6420 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N); 6421 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N); 6422 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N); 6423 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N); 6424 ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N); 6425 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N); 6426 int[] importancesBefore = new int[N]; 6427 for (int i = 0; i < N; i++) { 6428 final NotificationRecord r = mNotificationList.get(i); 6429 orderBefore.add(r.getKey()); 6430 visibilities[i] = r.getPackageVisibilityOverride(); 6431 showBadges[i] = r.canShowBadge(); 6432 allowBubbles[i] = r.canBubble(); 6433 channelBefore.add(r.getChannel()); 6434 groupKeyBefore.add(r.getGroupKey()); 6435 overridePeopleBefore.add(r.getPeopleOverride()); 6436 snoozeCriteriaBefore.add(r.getSnoozeCriteria()); 6437 userSentimentBefore.add(r.getUserSentiment()); 6438 suppressVisuallyBefore.add(r.getSuppressedVisualEffects()); 6439 systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions()); 6440 smartRepliesBefore.add(r.getSmartReplies()); 6441 importancesBefore[i] = r.getImportance(); 6442 mRankingHelper.extractSignals(r); 6443 } 6444 mRankingHelper.sort(mNotificationList); 6445 for (int i = 0; i < N; i++) { 6446 final NotificationRecord r = mNotificationList.get(i); 6447 if (!orderBefore.get(i).equals(r.getKey()) 6448 || visibilities[i] != r.getPackageVisibilityOverride() 6449 || showBadges[i] != r.canShowBadge() 6450 || allowBubbles[i] != r.canBubble() 6451 || !Objects.equals(channelBefore.get(i), r.getChannel()) 6452 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey()) 6453 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride()) 6454 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria()) 6455 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment()) 6456 || !Objects.equals(suppressVisuallyBefore.get(i), 6457 r.getSuppressedVisualEffects()) 6458 || !Objects.equals(systemSmartActionsBefore.get(i), 6459 r.getSystemGeneratedSmartActions()) 6460 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies()) 6461 || importancesBefore[i] != r.getImportance()) { 6462 mHandler.scheduleSendRankingUpdate(); 6463 return; 6464 } 6465 } 6466 } 6467 } 6468 6469 @GuardedBy("mNotificationLock") 6470 private void recordCallerLocked(NotificationRecord record) { 6471 if (mZenModeHelper.isCall(record)) { 6472 mZenModeHelper.recordCaller(record); 6473 } 6474 } 6475 6476 // let zen mode evaluate this record 6477 @GuardedBy("mNotificationLock") 6478 private void applyZenModeLocked(NotificationRecord record) { 6479 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 6480 if (record.isIntercepted()) { 6481 record.setSuppressedVisualEffects( 6482 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects); 6483 } else { 6484 record.setSuppressedVisualEffects(0); 6485 } 6486 } 6487 6488 @GuardedBy("mNotificationLock") 6489 private int findNotificationRecordIndexLocked(NotificationRecord target) { 6490 return mRankingHelper.indexOf(mNotificationList, target); 6491 } 6492 6493 private void handleSendRankingUpdate() { 6494 synchronized (mNotificationLock) { 6495 mListeners.notifyRankingUpdateLocked(null); 6496 } 6497 } 6498 6499 private void scheduleListenerHintsChanged(int state) { 6500 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 6501 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 6502 } 6503 6504 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 6505 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 6506 mHandler.obtainMessage( 6507 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 6508 listenerInterruptionFilter, 6509 0).sendToTarget(); 6510 } 6511 6512 private void handleListenerHintsChanged(int hints) { 6513 synchronized (mNotificationLock) { 6514 mListeners.notifyListenerHintsChangedLocked(hints); 6515 } 6516 } 6517 6518 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 6519 synchronized (mNotificationLock) { 6520 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 6521 } 6522 } 6523 6524 private void handleOnPackageChanged(boolean removingPackage, int changeUserId, 6525 String[] pkgList, int[] uidList) { 6526 boolean preferencesChanged = removingPackage; 6527 mListeners.onPackagesChanged(removingPackage, pkgList, uidList); 6528 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList); 6529 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); 6530 preferencesChanged |= mPreferencesHelper.onPackagesChanged( 6531 removingPackage, changeUserId, pkgList, uidList); 6532 if (preferencesChanged) { 6533 handleSavePolicyFile(); 6534 } 6535 } 6536 6537 protected class WorkerHandler extends Handler 6538 { 6539 public WorkerHandler(Looper looper) { 6540 super(looper); 6541 } 6542 6543 @Override 6544 public void handleMessage(Message msg) 6545 { 6546 switch (msg.what) 6547 { 6548 case MESSAGE_DURATION_REACHED: 6549 handleDurationReached((ToastRecord) msg.obj); 6550 break; 6551 case MESSAGE_FINISH_TOKEN_TIMEOUT: 6552 handleKillTokenTimeout((ToastRecord) msg.obj); 6553 break; 6554 case MESSAGE_SEND_RANKING_UPDATE: 6555 handleSendRankingUpdate(); 6556 break; 6557 case MESSAGE_LISTENER_HINTS_CHANGED: 6558 handleListenerHintsChanged(msg.arg1); 6559 break; 6560 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 6561 handleListenerInterruptionFilterChanged(msg.arg1); 6562 break; 6563 case MESSAGE_ON_PACKAGE_CHANGED: 6564 SomeArgs args = (SomeArgs) msg.obj; 6565 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2, 6566 (int[]) args.arg3); 6567 args.recycle(); 6568 break; 6569 } 6570 } 6571 6572 protected void scheduleSendRankingUpdate() { 6573 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 6574 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); 6575 sendMessage(m); 6576 } 6577 } 6578 6579 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) { 6580 if (!hasCallbacks(cancelRunnable)) { 6581 sendMessage(Message.obtain(this, cancelRunnable)); 6582 } 6583 } 6584 6585 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId, 6586 String[] pkgList, int[] uidList) { 6587 SomeArgs args = SomeArgs.obtain(); 6588 args.arg1 = removingPackage; 6589 args.argi1 = changeUserId; 6590 args.arg2 = pkgList; 6591 args.arg3 = uidList; 6592 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args)); 6593 } 6594 } 6595 6596 private final class RankingHandlerWorker extends Handler implements RankingHandler 6597 { 6598 public RankingHandlerWorker(Looper looper) { 6599 super(looper); 6600 } 6601 6602 @Override 6603 public void handleMessage(Message msg) { 6604 switch (msg.what) { 6605 case MESSAGE_RECONSIDER_RANKING: 6606 handleRankingReconsideration(msg); 6607 break; 6608 case MESSAGE_RANKING_SORT: 6609 handleRankingSort(); 6610 break; 6611 } 6612 } 6613 6614 public void requestSort() { 6615 removeMessages(MESSAGE_RANKING_SORT); 6616 Message msg = Message.obtain(); 6617 msg.what = MESSAGE_RANKING_SORT; 6618 sendMessage(msg); 6619 } 6620 6621 public void requestReconsideration(RankingReconsideration recon) { 6622 Message m = Message.obtain(this, 6623 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 6624 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 6625 sendMessageDelayed(m, delay); 6626 } 6627 } 6628 6629 // Notifications 6630 // ============================================================================ 6631 static int clamp(int x, int low, int high) { 6632 return (x < low) ? low : ((x > high) ? high : x); 6633 } 6634 6635 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 6636 if (!mAccessibilityManager.isEnabled()) { 6637 return; 6638 } 6639 6640 AccessibilityEvent event = 6641 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 6642 event.setPackageName(packageName); 6643 event.setClassName(Notification.class.getName()); 6644 event.setParcelableData(notification); 6645 CharSequence tickerText = notification.tickerText; 6646 if (!TextUtils.isEmpty(tickerText)) { 6647 event.getText().add(tickerText); 6648 } 6649 6650 mAccessibilityManager.sendAccessibilityEvent(event); 6651 } 6652 6653 /** 6654 * Removes all NotificationsRecords with the same key as the given notification record 6655 * from both lists. Do not call this method while iterating over either list. 6656 */ 6657 @GuardedBy("mNotificationLock") 6658 private boolean removeFromNotificationListsLocked(NotificationRecord r) { 6659 // Remove from both lists, either list could have a separate Record for what is 6660 // effectively the same notification. 6661 boolean wasPosted = false; 6662 NotificationRecord recordInList = null; 6663 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) 6664 != null) { 6665 mNotificationList.remove(recordInList); 6666 mNotificationsByKey.remove(recordInList.sbn.getKey()); 6667 wasPosted = true; 6668 } 6669 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) 6670 != null) { 6671 mEnqueuedNotifications.remove(recordInList); 6672 } 6673 return wasPosted; 6674 } 6675 6676 @GuardedBy("mNotificationLock") 6677 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, 6678 boolean wasPosted, String listenerName) { 6679 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName); 6680 } 6681 6682 @GuardedBy("mNotificationLock") 6683 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, 6684 int rank, int count, boolean wasPosted, String listenerName) { 6685 final String canceledKey = r.getKey(); 6686 6687 // Record caller. 6688 recordCallerLocked(r); 6689 6690 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) { 6691 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER); 6692 } 6693 6694 // tell the app 6695 if (sendDelete) { 6696 final PendingIntent deleteIntent = r.getNotification().deleteIntent; 6697 if (deleteIntent != null) { 6698 try { 6699 // make sure deleteIntent cannot be used to start activities from background 6700 LocalServices.getService(ActivityManagerInternal.class) 6701 .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(), 6702 WHITELIST_TOKEN); 6703 deleteIntent.send(); 6704 } catch (PendingIntent.CanceledException ex) { 6705 // do nothing - there's no relevant way to recover, and 6706 // no reason to let this propagate 6707 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 6708 } 6709 } 6710 } 6711 6712 // Only cancel these if this notification actually got to be posted. 6713 if (wasPosted) { 6714 // status bar 6715 if (r.getNotification().getSmallIcon() != null) { 6716 if (reason != REASON_SNOOZED) { 6717 r.isCanceled = true; 6718 } 6719 mListeners.notifyRemovedLocked(r, reason, r.getStats()); 6720 mHandler.post(new Runnable() { 6721 @Override 6722 public void run() { 6723 mGroupHelper.onNotificationRemoved(r.sbn); 6724 } 6725 }); 6726 } 6727 6728 // sound 6729 if (canceledKey.equals(mSoundNotificationKey)) { 6730 mSoundNotificationKey = null; 6731 final long identity = Binder.clearCallingIdentity(); 6732 try { 6733 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 6734 if (player != null) { 6735 player.stopAsync(); 6736 } 6737 } catch (RemoteException e) { 6738 } finally { 6739 Binder.restoreCallingIdentity(identity); 6740 } 6741 } 6742 6743 // vibrate 6744 if (canceledKey.equals(mVibrateNotificationKey)) { 6745 mVibrateNotificationKey = null; 6746 long identity = Binder.clearCallingIdentity(); 6747 try { 6748 mVibrator.cancel(); 6749 } 6750 finally { 6751 Binder.restoreCallingIdentity(identity); 6752 } 6753 } 6754 6755 // light 6756 mLights.remove(canceledKey); 6757 } 6758 6759 // Record usage stats 6760 // TODO: add unbundling stats? 6761 switch (reason) { 6762 case REASON_CANCEL: 6763 case REASON_CANCEL_ALL: 6764 case REASON_LISTENER_CANCEL: 6765 case REASON_LISTENER_CANCEL_ALL: 6766 mUsageStats.registerDismissedByUser(r); 6767 break; 6768 case REASON_APP_CANCEL: 6769 case REASON_APP_CANCEL_ALL: 6770 mUsageStats.registerRemovedByApp(r); 6771 break; 6772 } 6773 6774 String groupKey = r.getGroupKey(); 6775 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 6776 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) { 6777 mSummaryByGroupKey.remove(groupKey); 6778 } 6779 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId()); 6780 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) { 6781 summaries.remove(r.sbn.getPackageName()); 6782 } 6783 6784 // Save it for users of getHistoricalNotifications() 6785 mArchive.record(r.sbn); 6786 6787 final long now = System.currentTimeMillis(); 6788 final LogMaker logMaker = r.getItemLogMaker() 6789 .setType(MetricsEvent.TYPE_DISMISS) 6790 .setSubtype(reason); 6791 if (rank != -1 && count != -1) { 6792 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank) 6793 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count); 6794 } 6795 MetricsLogger.action(logMaker); 6796 EventLogTags.writeNotificationCanceled(canceledKey, reason, 6797 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), 6798 rank, count, listenerName); 6799 } 6800 6801 @VisibleForTesting 6802 void updateUriPermissions(@Nullable NotificationRecord newRecord, 6803 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) { 6804 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey(); 6805 if (DBG) Slog.d(TAG, key + ": updating permissions"); 6806 6807 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null; 6808 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null; 6809 6810 // Shortcut when no Uris involved 6811 if (newUris == null && oldUris == null) { 6812 return; 6813 } 6814 6815 // Inherit any existing owner 6816 IBinder permissionOwner = null; 6817 if (newRecord != null && permissionOwner == null) { 6818 permissionOwner = newRecord.permissionOwner; 6819 } 6820 if (oldRecord != null && permissionOwner == null) { 6821 permissionOwner = oldRecord.permissionOwner; 6822 } 6823 6824 // If we have Uris to grant, but no owner yet, go create one 6825 if (newUris != null && permissionOwner == null) { 6826 if (DBG) Slog.d(TAG, key + ": creating owner"); 6827 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key); 6828 } 6829 6830 // If we have no Uris to grant, but an existing owner, go destroy it 6831 if (newUris == null && permissionOwner != null) { 6832 final long ident = Binder.clearCallingIdentity(); 6833 try { 6834 if (DBG) Slog.d(TAG, key + ": destroying owner"); 6835 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0, 6836 UserHandle.getUserId(oldRecord.getUid())); 6837 permissionOwner = null; 6838 } finally { 6839 Binder.restoreCallingIdentity(ident); 6840 } 6841 } 6842 6843 // Grant access to new Uris 6844 if (newUris != null && permissionOwner != null) { 6845 for (int i = 0; i < newUris.size(); i++) { 6846 final Uri uri = newUris.valueAt(i); 6847 if (oldUris == null || !oldUris.contains(uri)) { 6848 if (DBG) Slog.d(TAG, key + ": granting " + uri); 6849 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg, 6850 targetUserId); 6851 } 6852 } 6853 } 6854 6855 // Revoke access to old Uris 6856 if (oldUris != null && permissionOwner != null) { 6857 for (int i = 0; i < oldUris.size(); i++) { 6858 final Uri uri = oldUris.valueAt(i); 6859 if (newUris == null || !newUris.contains(uri)) { 6860 if (DBG) Slog.d(TAG, key + ": revoking " + uri); 6861 revokeUriPermission(permissionOwner, uri, oldRecord.getUid()); 6862 } 6863 } 6864 } 6865 6866 if (newRecord != null) { 6867 newRecord.permissionOwner = permissionOwner; 6868 } 6869 } 6870 6871 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg, 6872 int targetUserId) { 6873 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 6874 6875 final long ident = Binder.clearCallingIdentity(); 6876 try { 6877 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg, 6878 ContentProvider.getUriWithoutUserId(uri), 6879 Intent.FLAG_GRANT_READ_URI_PERMISSION, 6880 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)), 6881 targetUserId); 6882 } catch (RemoteException ignored) { 6883 // Ignored because we're in same process 6884 } finally { 6885 Binder.restoreCallingIdentity(ident); 6886 } 6887 } 6888 6889 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) { 6890 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; 6891 6892 final long ident = Binder.clearCallingIdentity(); 6893 try { 6894 mUgmInternal.revokeUriPermissionFromOwner( 6895 owner, 6896 ContentProvider.getUriWithoutUserId(uri), 6897 Intent.FLAG_GRANT_READ_URI_PERMISSION, 6898 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid))); 6899 } finally { 6900 Binder.restoreCallingIdentity(ident); 6901 } 6902 } 6903 6904 /** 6905 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 6906 * and none of the {@code mustNotHaveFlags}. 6907 */ 6908 void cancelNotification(final int callingUid, final int callingPid, 6909 final String pkg, final String tag, final int id, 6910 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 6911 final int userId, final int reason, final ManagedServiceInfo listener) { 6912 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags, 6913 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener); 6914 } 6915 6916 /** 6917 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 6918 * and none of the {@code mustNotHaveFlags}. 6919 */ 6920 void cancelNotification(final int callingUid, final int callingPid, 6921 final String pkg, final String tag, final int id, 6922 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 6923 final int userId, final int reason, int rank, int count, 6924 final ManagedServiceInfo listener) { 6925 // In enqueueNotificationInternal notifications are added by scheduling the 6926 // work on the worker handler. Hence, we also schedule the cancel on this 6927 // handler to avoid a scenario where an add notification call followed by a 6928 // remove notification call ends up in not removing the notification. 6929 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid, 6930 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank, 6931 count, listener)); 6932 } 6933 6934 /** 6935 * Determine whether the userId applies to the notification in question, either because 6936 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 6937 */ 6938 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 6939 return 6940 // looking for USER_ALL notifications? match everything 6941 userId == UserHandle.USER_ALL 6942 // a notification sent to USER_ALL matches any query 6943 || r.getUserId() == UserHandle.USER_ALL 6944 // an exact user match 6945 || r.getUserId() == userId; 6946 } 6947 6948 /** 6949 * Determine whether the userId applies to the notification in question, either because 6950 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 6951 * because it matches one of the users profiles. 6952 */ 6953 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 6954 return notificationMatchesUserId(r, userId) 6955 || mUserProfiles.isCurrentProfile(r.getUserId()); 6956 } 6957 6958 /** 6959 * Cancels all notifications from a given package that have all of the 6960 * {@code mustHaveFlags}. 6961 */ 6962 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId, 6963 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason, 6964 ManagedServiceInfo listener) { 6965 mHandler.post(new Runnable() { 6966 @Override 6967 public void run() { 6968 String listenerName = listener == null ? null : listener.component.toShortString(); 6969 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 6970 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 6971 listenerName); 6972 6973 // Why does this parameter exist? Do we actually want to execute the above if doit 6974 // is false? 6975 if (!doit) { 6976 return; 6977 } 6978 6979 synchronized (mNotificationLock) { 6980 FlagChecker flagChecker = (int flags) -> { 6981 if ((flags & mustHaveFlags) != mustHaveFlags) { 6982 return false; 6983 } 6984 if ((flags & mustNotHaveFlags) != 0) { 6985 return false; 6986 } 6987 return true; 6988 }; 6989 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid, 6990 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 6991 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 6992 listenerName, true /* wasPosted */); 6993 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid, 6994 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, 6995 flagChecker, false /*includeCurrentProfiles*/, userId, 6996 false /*sendDelete*/, reason, listenerName, false /* wasPosted */); 6997 mSnoozeHelper.cancel(userId, pkg); 6998 } 6999 } 7000 }); 7001 } 7002 7003 private interface FlagChecker { 7004 // Returns false if these flags do not pass the defined flag test. 7005 public boolean apply(int flags); 7006 } 7007 7008 @GuardedBy("mNotificationLock") 7009 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList, 7010 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch, 7011 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, 7012 boolean sendDelete, int reason, String listenerName, boolean wasPosted) { 7013 ArrayList<NotificationRecord> canceledNotifications = null; 7014 for (int i = notificationList.size() - 1; i >= 0; --i) { 7015 NotificationRecord r = notificationList.get(i); 7016 if (includeCurrentProfiles) { 7017 if (!notificationMatchesCurrentProfiles(r, userId)) { 7018 continue; 7019 } 7020 } else if (!notificationMatchesUserId(r, userId)) { 7021 continue; 7022 } 7023 // Don't remove notifications to all, if there's no package name specified 7024 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) { 7025 continue; 7026 } 7027 if (!flagChecker.apply(r.getFlags())) { 7028 continue; 7029 } 7030 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 7031 continue; 7032 } 7033 if (channelId != null && !channelId.equals(r.getChannel().getId())) { 7034 continue; 7035 } 7036 if (canceledNotifications == null) { 7037 canceledNotifications = new ArrayList<>(); 7038 } 7039 notificationList.remove(i); 7040 mNotificationsByKey.remove(r.getKey()); 7041 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); 7042 canceledNotifications.add(r); 7043 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); 7044 } 7045 if (canceledNotifications != null) { 7046 final int M = canceledNotifications.size(); 7047 for (int i = 0; i < M; i++) { 7048 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 7049 listenerName, false /* sendDelete */, flagChecker); 7050 } 7051 updateLightsLocked(); 7052 } 7053 } 7054 7055 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId, 7056 ManagedServiceInfo listener) { 7057 String listenerName = listener == null ? null : listener.component.toShortString(); 7058 if (duration <= 0 && snoozeCriterionId == null || key == null) { 7059 return; 7060 } 7061 7062 if (DBG) { 7063 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration, 7064 snoozeCriterionId, listenerName)); 7065 } 7066 // Needs to post so that it can cancel notifications not yet enqueued. 7067 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); 7068 } 7069 7070 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) { 7071 String listenerName = listener == null ? null : listener.component.toShortString(); 7072 if (DBG) { 7073 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); 7074 } 7075 mSnoozeHelper.repost(key); 7076 handleSavePolicyFile(); 7077 } 7078 7079 @GuardedBy("mNotificationLock") 7080 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 7081 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 7082 mHandler.post(new Runnable() { 7083 @Override 7084 public void run() { 7085 synchronized (mNotificationLock) { 7086 String listenerName = 7087 listener == null ? null : listener.component.toShortString(); 7088 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 7089 null, userId, 0, 0, reason, listenerName); 7090 7091 FlagChecker flagChecker = (int flags) -> { 7092 int flagsToCheck = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 7093 if (REASON_LISTENER_CANCEL_ALL == reason) { 7094 flagsToCheck |= FLAG_BUBBLE; 7095 } 7096 if ((flags & flagsToCheck) != 0) { 7097 return false; 7098 } 7099 return true; 7100 }; 7101 7102 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid, 7103 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker, 7104 includeCurrentProfiles, userId, true /*sendDelete*/, reason, 7105 listenerName, true); 7106 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid, 7107 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null, 7108 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/, 7109 reason, listenerName, false); 7110 mSnoozeHelper.cancel(userId, includeCurrentProfiles); 7111 } 7112 } 7113 }); 7114 } 7115 7116 // Warning: The caller is responsible for invoking updateLightsLocked(). 7117 @GuardedBy("mNotificationLock") 7118 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 7119 String listenerName, boolean sendDelete, FlagChecker flagChecker) { 7120 Notification n = r.getNotification(); 7121 if (!n.isGroupSummary()) { 7122 return; 7123 } 7124 7125 String pkg = r.sbn.getPackageName(); 7126 7127 if (pkg == null) { 7128 if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey()); 7129 return; 7130 } 7131 7132 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName, 7133 sendDelete, true, flagChecker); 7134 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid, 7135 listenerName, sendDelete, false, flagChecker); 7136 } 7137 7138 @GuardedBy("mNotificationLock") 7139 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList, 7140 NotificationRecord parentNotification, int callingUid, int callingPid, 7141 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) { 7142 final String pkg = parentNotification.sbn.getPackageName(); 7143 final int userId = parentNotification.getUserId(); 7144 final int reason = REASON_GROUP_SUMMARY_CANCELED; 7145 for (int i = notificationList.size() - 1; i >= 0; i--) { 7146 final NotificationRecord childR = notificationList.get(i); 7147 final StatusBarNotification childSbn = childR.sbn; 7148 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 7149 childR.getGroupKey().equals(parentNotification.getGroupKey()) 7150 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0 7151 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) { 7152 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 7153 childSbn.getTag(), userId, 0, 0, reason, listenerName); 7154 notificationList.remove(i); 7155 mNotificationsByKey.remove(childR.getKey()); 7156 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName); 7157 } 7158 } 7159 } 7160 7161 @GuardedBy("mNotificationLock") 7162 void updateLightsLocked() 7163 { 7164 // handle notification lights 7165 NotificationRecord ledNotification = null; 7166 while (ledNotification == null && !mLights.isEmpty()) { 7167 final String owner = mLights.get(mLights.size() - 1); 7168 ledNotification = mNotificationsByKey.get(owner); 7169 if (ledNotification == null) { 7170 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 7171 mLights.remove(owner); 7172 } 7173 } 7174 7175 // Don't flash while we are in a call or screen is on 7176 if (ledNotification == null || isInCall() || mScreenOn) { 7177 mNotificationLight.turnOff(); 7178 } else { 7179 NotificationRecord.Light light = ledNotification.getLight(); 7180 if (light != null && mNotificationPulseEnabled) { 7181 // pulse repeatedly 7182 mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED, 7183 light.onMs, light.offMs); 7184 } 7185 } 7186 } 7187 7188 @GuardedBy("mNotificationLock") 7189 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg, 7190 String groupKey, int userId) { 7191 List<NotificationRecord> records = new ArrayList<>(); 7192 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId)); 7193 records.addAll( 7194 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId)); 7195 return records; 7196 } 7197 7198 7199 @GuardedBy("mNotificationLock") 7200 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( 7201 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) { 7202 List<NotificationRecord> records = new ArrayList<>(); 7203 final int len = list.size(); 7204 for (int i = 0; i < len; i++) { 7205 NotificationRecord r = list.get(i); 7206 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey) 7207 && r.sbn.getPackageName().equals(pkg)) { 7208 records.add(r); 7209 } 7210 } 7211 return records; 7212 } 7213 7214 // Searches both enqueued and posted notifications by key. 7215 // TODO: need to combine a bunch of these getters with slightly different behavior. 7216 // TODO: Should enqueuing just add to mNotificationsByKey instead? 7217 @GuardedBy("mNotificationLock") 7218 private NotificationRecord findNotificationByKeyLocked(String key) { 7219 NotificationRecord r; 7220 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) { 7221 return r; 7222 } 7223 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) { 7224 return r; 7225 } 7226 return null; 7227 } 7228 7229 @GuardedBy("mNotificationLock") 7230 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) { 7231 NotificationRecord r; 7232 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) { 7233 return r; 7234 } 7235 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId)) 7236 != null) { 7237 return r; 7238 } 7239 return null; 7240 } 7241 7242 @GuardedBy("mNotificationLock") 7243 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, 7244 String pkg, String tag, int id, int userId) { 7245 final int len = list.size(); 7246 for (int i = 0; i < len; i++) { 7247 NotificationRecord r = list.get(i); 7248 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 7249 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 7250 return r; 7251 } 7252 } 7253 return null; 7254 } 7255 7256 @GuardedBy("mNotificationLock") 7257 private List<NotificationRecord> findNotificationsByListLocked( 7258 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { 7259 List<NotificationRecord> matching = new ArrayList<>(); 7260 final int len = list.size(); 7261 for (int i = 0; i < len; i++) { 7262 NotificationRecord r = list.get(i); 7263 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 7264 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 7265 matching.add(r); 7266 } 7267 } 7268 return matching; 7269 } 7270 7271 @GuardedBy("mNotificationLock") 7272 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, 7273 String key) { 7274 final int N = list.size(); 7275 for (int i = 0; i < N; i++) { 7276 if (key.equals(list.get(i).getKey())) { 7277 return list.get(i); 7278 } 7279 } 7280 return null; 7281 } 7282 7283 @GuardedBy("mNotificationLock") 7284 int indexOfNotificationLocked(String key) { 7285 final int N = mNotificationList.size(); 7286 for (int i = 0; i < N; i++) { 7287 if (key.equals(mNotificationList.get(i).getKey())) { 7288 return i; 7289 } 7290 } 7291 return -1; 7292 } 7293 7294 @VisibleForTesting 7295 protected void hideNotificationsForPackages(String[] pkgs) { 7296 synchronized (mNotificationLock) { 7297 List<String> pkgList = Arrays.asList(pkgs); 7298 List<NotificationRecord> changedNotifications = new ArrayList<>(); 7299 int numNotifications = mNotificationList.size(); 7300 for (int i = 0; i < numNotifications; i++) { 7301 NotificationRecord rec = mNotificationList.get(i); 7302 if (pkgList.contains(rec.sbn.getPackageName())) { 7303 rec.setHidden(true); 7304 changedNotifications.add(rec); 7305 } 7306 } 7307 7308 mListeners.notifyHiddenLocked(changedNotifications); 7309 } 7310 } 7311 7312 @VisibleForTesting 7313 protected void unhideNotificationsForPackages(String[] pkgs) { 7314 synchronized (mNotificationLock) { 7315 List<String> pkgList = Arrays.asList(pkgs); 7316 List<NotificationRecord> changedNotifications = new ArrayList<>(); 7317 int numNotifications = mNotificationList.size(); 7318 for (int i = 0; i < numNotifications; i++) { 7319 NotificationRecord rec = mNotificationList.get(i); 7320 if (pkgList.contains(rec.sbn.getPackageName())) { 7321 rec.setHidden(false); 7322 changedNotifications.add(rec); 7323 } 7324 } 7325 7326 mListeners.notifyUnhiddenLocked(changedNotifications); 7327 } 7328 } 7329 7330 private void updateNotificationPulse() { 7331 synchronized (mNotificationLock) { 7332 updateLightsLocked(); 7333 } 7334 } 7335 7336 protected boolean isCallingUidSystem() { 7337 final int uid = Binder.getCallingUid(); 7338 return uid == Process.SYSTEM_UID; 7339 } 7340 7341 protected boolean isUidSystemOrPhone(int uid) { 7342 final int appid = UserHandle.getAppId(uid); 7343 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 7344 } 7345 7346 // TODO: Most calls should probably move to isCallerSystem. 7347 protected boolean isCallerSystemOrPhone() { 7348 return isUidSystemOrPhone(Binder.getCallingUid()); 7349 } 7350 7351 private void checkCallerIsSystemOrShell() { 7352 if (Binder.getCallingUid() == Process.SHELL_UID) { 7353 return; 7354 } 7355 checkCallerIsSystem(); 7356 } 7357 7358 private void checkCallerIsSystem() { 7359 if (isCallerSystemOrPhone()) { 7360 return; 7361 } 7362 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 7363 } 7364 7365 private void checkCallerIsSystemOrSystemUiOrShell() { 7366 if (Binder.getCallingUid() == Process.SHELL_UID) { 7367 return; 7368 } 7369 if (isCallerSystemOrPhone()) { 7370 return; 7371 } 7372 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null); 7373 } 7374 7375 private void checkCallerIsSystemOrSameApp(String pkg) { 7376 if (isCallerSystemOrPhone()) { 7377 return; 7378 } 7379 checkCallerIsSameApp(pkg); 7380 } 7381 7382 private boolean isCallerAndroid(String callingPkg, int uid) { 7383 return isUidSystemOrPhone(uid) && callingPkg != null 7384 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg); 7385 } 7386 7387 /** 7388 * Check if the notification is of a category type that is restricted to system use only, 7389 * if so throw SecurityException 7390 */ 7391 private void checkRestrictedCategories(final Notification notification) { 7392 try { 7393 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) { 7394 return; 7395 } 7396 } catch (RemoteException re) { 7397 if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category " 7398 + "restrictions check thus the check will be done anyway"); 7399 } 7400 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category) 7401 || Notification.CATEGORY_CAR_WARNING.equals(notification.category) 7402 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) { 7403 checkCallerIsSystem(); 7404 } 7405 } 7406 7407 @VisibleForTesting 7408 boolean isCallerInstantApp(int callingUid, int userId) { 7409 // System is always allowed to act for ephemeral apps. 7410 if (isUidSystemOrPhone(callingUid)) { 7411 return false; 7412 } 7413 7414 if (userId == UserHandle.USER_ALL) { 7415 userId = USER_SYSTEM; 7416 } 7417 7418 try { 7419 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid); 7420 if (pkgs == null) { 7421 throw new SecurityException("Unknown uid " + callingUid); 7422 } 7423 final String pkg = pkgs[0]; 7424 mAppOps.checkPackage(callingUid, pkg); 7425 7426 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId); 7427 if (ai == null) { 7428 throw new SecurityException("Unknown package " + pkg); 7429 } 7430 return ai.isInstantApp(); 7431 } catch (RemoteException re) { 7432 throw new SecurityException("Unknown uid " + callingUid, re); 7433 } 7434 } 7435 7436 private void checkCallerIsSameApp(String pkg) { 7437 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId()); 7438 } 7439 7440 private void checkCallerIsSameApp(String pkg, int uid, int userId) { 7441 try { 7442 ApplicationInfo ai = mPackageManager.getApplicationInfo( 7443 pkg, 0, userId); 7444 if (ai == null) { 7445 throw new SecurityException("Unknown package " + pkg); 7446 } 7447 if (!UserHandle.isSameApp(ai.uid, uid)) { 7448 throw new SecurityException("Calling uid " + uid + " gave package " 7449 + pkg + " which is owned by uid " + ai.uid); 7450 } 7451 } catch (RemoteException re) { 7452 throw new SecurityException("Unknown package " + pkg + "\n" + re); 7453 } 7454 } 7455 7456 private boolean isCallerSameApp(String pkg) { 7457 try { 7458 checkCallerIsSameApp(pkg); 7459 return true; 7460 } catch (SecurityException e) { 7461 return false; 7462 } 7463 } 7464 7465 private boolean isCallerSameApp(String pkg, int uid, int userId) { 7466 try { 7467 checkCallerIsSameApp(pkg, uid, userId); 7468 return true; 7469 } catch (SecurityException e) { 7470 return false; 7471 } 7472 } 7473 7474 private static String callStateToString(int state) { 7475 switch (state) { 7476 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 7477 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 7478 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 7479 default: return "CALL_STATE_UNKNOWN_" + state; 7480 } 7481 } 7482 7483 /** 7484 * Generates a NotificationRankingUpdate from 'sbns', considering only 7485 * notifications visible to the given listener. 7486 */ 7487 @GuardedBy("mNotificationLock") 7488 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 7489 final int N = mNotificationList.size(); 7490 final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>(); 7491 7492 for (int i = 0; i < N; i++) { 7493 NotificationRecord record = mNotificationList.get(i); 7494 if (!isVisibleToListener(record.sbn, info)) { 7495 continue; 7496 } 7497 final String key = record.sbn.getKey(); 7498 final NotificationListenerService.Ranking ranking = 7499 new NotificationListenerService.Ranking(); 7500 ranking.populate( 7501 key, 7502 rankings.size(), 7503 !record.isIntercepted(), 7504 record.getPackageVisibilityOverride(), 7505 record.getSuppressedVisualEffects(), 7506 record.getImportance(), 7507 record.getImportanceExplanation(), 7508 record.sbn.getOverrideGroupKey(), 7509 record.getChannel(), 7510 record.getPeopleOverride(), 7511 record.getSnoozeCriteria(), 7512 record.canShowBadge(), 7513 record.getUserSentiment(), 7514 record.isHidden(), 7515 record.getLastAudiblyAlertedMs(), 7516 record.getSound() != null || record.getVibration() != null, 7517 record.getSystemGeneratedSmartActions(), 7518 record.getSmartReplies(), 7519 record.canBubble(), 7520 record.isInterruptive() 7521 ); 7522 rankings.add(ranking); 7523 } 7524 7525 return new NotificationRankingUpdate( 7526 rankings.toArray(new NotificationListenerService.Ranking[0])); 7527 } 7528 7529 boolean hasCompanionDevice(ManagedServiceInfo info) { 7530 if (mCompanionManager == null) { 7531 mCompanionManager = getCompanionManager(); 7532 } 7533 // Companion mgr doesn't exist on all device types 7534 if (mCompanionManager == null) { 7535 return false; 7536 } 7537 long identity = Binder.clearCallingIdentity(); 7538 try { 7539 List<String> associations = mCompanionManager.getAssociations( 7540 info.component.getPackageName(), info.userid); 7541 if (!ArrayUtils.isEmpty(associations)) { 7542 return true; 7543 } 7544 } catch (SecurityException se) { 7545 // Not a privileged listener 7546 } catch (RemoteException re) { 7547 Slog.e(TAG, "Cannot reach companion device service", re); 7548 } catch (Exception e) { 7549 Slog.e(TAG, "Cannot verify listener " + info, e); 7550 } finally { 7551 Binder.restoreCallingIdentity(identity); 7552 } 7553 return false; 7554 } 7555 7556 protected ICompanionDeviceManager getCompanionManager() { 7557 return ICompanionDeviceManager.Stub.asInterface( 7558 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); 7559 } 7560 7561 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 7562 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 7563 return false; 7564 } 7565 // TODO: remove this for older listeners. 7566 return true; 7567 } 7568 7569 private boolean isPackageSuspendedForUser(String pkg, int uid) { 7570 final long identity = Binder.clearCallingIdentity(); 7571 int userId = UserHandle.getUserId(uid); 7572 try { 7573 return mPackageManager.isPackageSuspendedForUser(pkg, userId); 7574 } catch (RemoteException re) { 7575 throw new SecurityException("Could not talk to package manager service"); 7576 } catch (IllegalArgumentException ex) { 7577 // Package not found. 7578 return false; 7579 } finally { 7580 Binder.restoreCallingIdentity(identity); 7581 } 7582 } 7583 7584 @VisibleForTesting 7585 boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) { 7586 boolean canUseManagedServices = !mActivityManager.isLowRamDevice() 7587 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH); 7588 7589 for (String whitelisted : getContext().getResources().getStringArray( 7590 R.array.config_allowedManagedServicesOnLowRamDevices)) { 7591 if (whitelisted.equals(pkg)) { 7592 canUseManagedServices = true; 7593 } 7594 } 7595 7596 if (requiredPermission != null) { 7597 try { 7598 if (mPackageManager.checkPermission(requiredPermission, pkg, userId) 7599 != PackageManager.PERMISSION_GRANTED) { 7600 canUseManagedServices = false; 7601 } 7602 } catch (RemoteException e) { 7603 Slog.e(TAG, "can't talk to pm", e); 7604 } 7605 } 7606 7607 return canUseManagedServices; 7608 } 7609 7610 private class TrimCache { 7611 StatusBarNotification heavy; 7612 StatusBarNotification sbnClone; 7613 StatusBarNotification sbnCloneLight; 7614 7615 TrimCache(StatusBarNotification sbn) { 7616 heavy = sbn; 7617 } 7618 7619 StatusBarNotification ForListener(ManagedServiceInfo info) { 7620 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 7621 if (sbnCloneLight == null) { 7622 sbnCloneLight = heavy.cloneLight(); 7623 } 7624 return sbnCloneLight; 7625 } else { 7626 if (sbnClone == null) { 7627 sbnClone = heavy.clone(); 7628 } 7629 return sbnClone; 7630 } 7631 } 7632 } 7633 7634 private boolean isInCall() { 7635 if (mInCallStateOffHook) { 7636 return true; 7637 } 7638 int audioMode = mAudioManager.getMode(); 7639 if (audioMode == AudioManager.MODE_IN_CALL 7640 || audioMode == AudioManager.MODE_IN_COMMUNICATION) { 7641 return true; 7642 } 7643 return false; 7644 } 7645 7646 public class NotificationAssistants extends ManagedServices { 7647 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants"; 7648 7649 private static final String ATT_USER_SET = "user_set"; 7650 private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "q_allowed_adjustments"; 7651 private static final String ATT_TYPES = "types"; 7652 7653 private final Object mLock = new Object(); 7654 7655 @GuardedBy("mLock") 7656 private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>(); 7657 private Set<String> mAllowedAdjustments = new ArraySet<>(); 7658 7659 public NotificationAssistants(Context context, Object lock, UserProfiles up, 7660 IPackageManager pm) { 7661 super(context, lock, up, pm); 7662 7663 // Add all default allowed adjustment types. Will be overwritten by values in xml, 7664 // if they exist 7665 for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) { 7666 mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]); 7667 } 7668 } 7669 7670 @Override 7671 protected Config getConfig() { 7672 Config c = new Config(); 7673 c.caption = "notification assistant"; 7674 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; 7675 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS; 7676 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; 7677 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; 7678 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 7679 c.clientLabel = R.string.notification_ranker_binding_label; 7680 return c; 7681 } 7682 7683 @Override 7684 protected IInterface asInterface(IBinder binder) { 7685 return INotificationListener.Stub.asInterface(binder); 7686 } 7687 7688 @Override 7689 protected boolean checkType(IInterface service) { 7690 return service instanceof INotificationListener; 7691 } 7692 7693 @Override 7694 protected void onServiceAdded(ManagedServiceInfo info) { 7695 mListeners.registerGuestService(info); 7696 } 7697 7698 @Override 7699 @GuardedBy("mNotificationLock") 7700 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 7701 mListeners.unregisterService(removed.service, removed.userid); 7702 } 7703 7704 @Override 7705 public void onUserUnlocked(int user) { 7706 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); 7707 // force rebind the assistant, as it might be keeping its own state in user locked 7708 // storage 7709 rebindServices(true, user); 7710 } 7711 7712 @Override 7713 protected String getRequiredPermission() { 7714 // only signature/privileged apps can be bound. 7715 return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE; 7716 } 7717 7718 @Override 7719 protected void writeExtraXmlTags(XmlSerializer out) throws IOException { 7720 synchronized (mLock) { 7721 out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES); 7722 out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments)); 7723 out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES); 7724 } 7725 } 7726 7727 @Override 7728 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException { 7729 if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) { 7730 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES); 7731 synchronized (mLock) { 7732 mAllowedAdjustments.clear(); 7733 if (!TextUtils.isEmpty(types)) { 7734 mAllowedAdjustments.addAll(Arrays.asList(types.split(","))); 7735 } 7736 } 7737 } 7738 } 7739 7740 protected void allowAdjustmentType(String type) { 7741 synchronized (mLock) { 7742 mAllowedAdjustments.add(type); 7743 } 7744 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 7745 mHandler.post(() -> notifyCapabilitiesChanged(info)); 7746 } 7747 } 7748 7749 protected void disallowAdjustmentType(String type) { 7750 synchronized (mLock) { 7751 mAllowedAdjustments.remove(type); 7752 } 7753 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 7754 mHandler.post(() -> notifyCapabilitiesChanged(info)); 7755 } 7756 } 7757 7758 protected List<String> getAllowedAssistantAdjustments() { 7759 synchronized (mLock) { 7760 List<String> types = new ArrayList<>(); 7761 types.addAll(mAllowedAdjustments); 7762 return types; 7763 } 7764 } 7765 7766 protected boolean isAdjustmentAllowed(String type) { 7767 synchronized (mLock) { 7768 return mAllowedAdjustments.contains(type); 7769 } 7770 } 7771 7772 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) { 7773 // There should be only one, but it's a list, so while we enforce 7774 // singularity elsewhere, we keep it general here, to avoid surprises. 7775 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 7776 ArrayList<String> keys = new ArrayList<>(records.size()); 7777 for (NotificationRecord r : records) { 7778 boolean sbnVisible = isVisibleToListener(r.sbn, info) 7779 && info.isSameUser(r.getUserId()); 7780 if (sbnVisible) { 7781 keys.add(r.getKey()); 7782 } 7783 } 7784 7785 if (!keys.isEmpty()) { 7786 mHandler.post(() -> notifySeen(info, keys)); 7787 } 7788 } 7789 } 7790 7791 boolean hasUserSet(int userId) { 7792 synchronized (mLock) { 7793 return mUserSetMap.getOrDefault(userId, false); 7794 } 7795 } 7796 7797 void setUserSet(int userId, boolean set) { 7798 synchronized (mLock) { 7799 mUserSetMap.put(userId, set); 7800 } 7801 } 7802 7803 @Override 7804 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException { 7805 out.attribute(null, ATT_USER_SET, Boolean.toString(hasUserSet(userId))); 7806 } 7807 7808 @Override 7809 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId) 7810 throws IOException { 7811 boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false); 7812 setUserSet(userId, userSet); 7813 } 7814 7815 private void notifyCapabilitiesChanged(final ManagedServiceInfo info) { 7816 final INotificationListener assistant = (INotificationListener) info.service; 7817 try { 7818 assistant.onAllowedAdjustmentsChanged(); 7819 } catch (RemoteException ex) { 7820 Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex); 7821 } 7822 } 7823 7824 private void notifySeen(final ManagedServiceInfo info, 7825 final ArrayList<String> keys) { 7826 final INotificationListener assistant = (INotificationListener) info.service; 7827 try { 7828 assistant.onNotificationsSeen(keys); 7829 } catch (RemoteException ex) { 7830 Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex); 7831 } 7832 } 7833 7834 @GuardedBy("mNotificationLock") 7835 private void onNotificationEnqueuedLocked(final NotificationRecord r) { 7836 final boolean debug = isVerboseLogEnabled(); 7837 if (debug) { 7838 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]"); 7839 } 7840 final StatusBarNotification sbn = r.sbn; 7841 notifyAssistantLocked( 7842 sbn, 7843 true /* sameUserOnly */, 7844 (assistant, sbnHolder) -> { 7845 try { 7846 if (debug) { 7847 Slog.v(TAG, 7848 "calling onNotificationEnqueuedWithChannel " + sbnHolder); 7849 } 7850 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel()); 7851 } catch (RemoteException ex) { 7852 Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); 7853 } 7854 }); 7855 } 7856 7857 @GuardedBy("mNotificationLock") 7858 void notifyAssistantExpansionChangedLocked( 7859 final StatusBarNotification sbn, 7860 final boolean isUserAction, 7861 final boolean isExpanded) { 7862 final String key = sbn.getKey(); 7863 notifyAssistantLocked( 7864 sbn, 7865 false /* sameUserOnly */, 7866 (assistant, sbnHolder) -> { 7867 try { 7868 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded); 7869 } catch (RemoteException ex) { 7870 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 7871 } 7872 }); 7873 } 7874 7875 @GuardedBy("mNotificationLock") 7876 void notifyAssistantNotificationDirectReplyLocked( 7877 final StatusBarNotification sbn) { 7878 final String key = sbn.getKey(); 7879 notifyAssistantLocked( 7880 sbn, 7881 false /* sameUserOnly */, 7882 (assistant, sbnHolder) -> { 7883 try { 7884 assistant.onNotificationDirectReply(key); 7885 } catch (RemoteException ex) { 7886 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); 7887 } 7888 }); 7889 } 7890 7891 @GuardedBy("mNotificationLock") 7892 void notifyAssistantSuggestedReplySent( 7893 final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) { 7894 final String key = sbn.getKey(); 7895 notifyAssistantLocked( 7896 sbn, 7897 false /* sameUserOnly */, 7898 (assistant, sbnHolder) -> { 7899 try { 7900 assistant.onSuggestedReplySent( 7901 key, 7902 reply, 7903 generatedByAssistant 7904 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 7905 : NotificationAssistantService.SOURCE_FROM_APP); 7906 } catch (RemoteException ex) { 7907 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 7908 } 7909 }); 7910 } 7911 7912 @GuardedBy("mNotificationLock") 7913 void notifyAssistantActionClicked( 7914 final StatusBarNotification sbn, int actionIndex, Notification.Action action, 7915 boolean generatedByAssistant) { 7916 final String key = sbn.getKey(); 7917 notifyAssistantLocked( 7918 sbn, 7919 false /* sameUserOnly */, 7920 (assistant, sbnHolder) -> { 7921 try { 7922 assistant.onActionClicked( 7923 key, 7924 action, 7925 generatedByAssistant 7926 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT 7927 : NotificationAssistantService.SOURCE_FROM_APP); 7928 } catch (RemoteException ex) { 7929 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 7930 } 7931 }); 7932 } 7933 7934 /** 7935 * asynchronously notify the assistant that a notification has been snoozed until a 7936 * context 7937 */ 7938 @GuardedBy("mNotificationLock") 7939 private void notifyAssistantSnoozedLocked( 7940 final StatusBarNotification sbn, final String snoozeCriterionId) { 7941 notifyAssistantLocked( 7942 sbn, 7943 false /* sameUserOnly */, 7944 (assistant, sbnHolder) -> { 7945 try { 7946 assistant.onNotificationSnoozedUntilContext( 7947 sbnHolder, snoozeCriterionId); 7948 } catch (RemoteException ex) { 7949 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 7950 } 7951 }); 7952 } 7953 7954 /** 7955 * Notifies the assistant something about the specified notification, only assistant 7956 * that is visible to the notification will be notified. 7957 * 7958 * @param sbn the notification object that the update is about. 7959 * @param sameUserOnly should the update be sent to the assistant in the same user only. 7960 * @param callback the callback that provides the assistant to be notified, executed 7961 * in WorkerHandler. 7962 */ 7963 @GuardedBy("mNotificationLock") 7964 private void notifyAssistantLocked( 7965 final StatusBarNotification sbn, 7966 boolean sameUserOnly, 7967 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) { 7968 TrimCache trimCache = new TrimCache(sbn); 7969 // There should be only one, but it's a list, so while we enforce 7970 // singularity elsewhere, we keep it general here, to avoid surprises. 7971 7972 final boolean debug = isVerboseLogEnabled(); 7973 if (debug) { 7974 Slog.v(TAG, 7975 "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = [" 7976 + sameUserOnly + "], callback = [" + callback + "]"); 7977 } 7978 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 7979 boolean sbnVisible = isVisibleToListener(sbn, info) 7980 && (!sameUserOnly || info.isSameUser(sbn.getUserId())); 7981 if (debug) { 7982 Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible); 7983 } 7984 if (!sbnVisible) { 7985 continue; 7986 } 7987 final INotificationListener assistant = (INotificationListener) info.service; 7988 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 7989 final StatusBarNotificationHolder sbnHolder = 7990 new StatusBarNotificationHolder(sbnToPost); 7991 mHandler.post(() -> callback.accept(assistant, sbnHolder)); 7992 } 7993 } 7994 7995 public boolean isEnabled() { 7996 return !getServices().isEmpty(); 7997 } 7998 7999 protected void resetDefaultAssistantsIfNecessary() { 8000 final List<UserInfo> activeUsers = mUm.getUsers(true); 8001 for (UserInfo userInfo : activeUsers) { 8002 int userId = userInfo.getUserHandle().getIdentifier(); 8003 if (!hasUserSet(userId)) { 8004 Slog.d(TAG, "Approving default notification assistant for user " + userId); 8005 setDefaultAssistantForUser(userId); 8006 } 8007 } 8008 } 8009 8010 @Override 8011 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, 8012 boolean isPrimary, boolean enabled) { 8013 // Ensures that only one component is enabled at a time 8014 if (enabled) { 8015 List<ComponentName> allowedComponents = getAllowedComponents(userId); 8016 if (!allowedComponents.isEmpty()) { 8017 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents); 8018 if (currentComponent.flattenToString().equals(pkgOrComponent)) return; 8019 setNotificationAssistantAccessGrantedForUserInternal( 8020 currentComponent, userId, false); 8021 } 8022 } 8023 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled); 8024 } 8025 8026 @Override 8027 public void dump(PrintWriter pw, DumpFilter filter) { 8028 super.dump(pw, filter); 8029 pw.println(" Has user set:"); 8030 synchronized (mLock) { 8031 Set<Integer> userIds = mUserSetMap.keySet(); 8032 for (int userId : userIds) { 8033 pw.println(" userId=" + userId + " value=" + mUserSetMap.get(userId)); 8034 } 8035 } 8036 } 8037 8038 private boolean isVerboseLogEnabled() { 8039 return Log.isLoggable("notification_assistant", Log.VERBOSE); 8040 } 8041 } 8042 8043 public class NotificationListeners extends ManagedServices { 8044 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners"; 8045 8046 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 8047 8048 public NotificationListeners(IPackageManager pm) { 8049 super(getContext(), mNotificationLock, mUserProfiles, pm); 8050 8051 } 8052 8053 @Override 8054 protected int getBindFlags() { 8055 // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE 8056 // because too many 3P apps could be kept in memory as notification listeners and 8057 // cause extreme memory pressure. 8058 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation. 8059 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE 8060 | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT; 8061 } 8062 8063 @Override 8064 protected Config getConfig() { 8065 Config c = new Config(); 8066 c.caption = "notification listener"; 8067 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 8068 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS; 8069 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 8070 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 8071 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 8072 c.clientLabel = R.string.notification_listener_binding_label; 8073 return c; 8074 } 8075 8076 @Override 8077 protected IInterface asInterface(IBinder binder) { 8078 return INotificationListener.Stub.asInterface(binder); 8079 } 8080 8081 @Override 8082 protected boolean checkType(IInterface service) { 8083 return service instanceof INotificationListener; 8084 } 8085 8086 @Override 8087 public void onServiceAdded(ManagedServiceInfo info) { 8088 final INotificationListener listener = (INotificationListener) info.service; 8089 final NotificationRankingUpdate update; 8090 synchronized (mNotificationLock) { 8091 update = makeRankingUpdateLocked(info); 8092 } 8093 try { 8094 listener.onListenerConnected(update); 8095 } catch (RemoteException e) { 8096 // we tried 8097 } 8098 } 8099 8100 @Override 8101 @GuardedBy("mNotificationLock") 8102 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 8103 if (removeDisabledHints(removed)) { 8104 updateListenerHintsLocked(); 8105 updateEffectsSuppressorLocked(); 8106 } 8107 mLightTrimListeners.remove(removed); 8108 } 8109 8110 @Override 8111 protected String getRequiredPermission() { 8112 return null; 8113 } 8114 8115 @GuardedBy("mNotificationLock") 8116 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 8117 if (trim == TRIM_LIGHT) { 8118 mLightTrimListeners.add(info); 8119 } else { 8120 mLightTrimListeners.remove(info); 8121 } 8122 } 8123 8124 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 8125 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 8126 } 8127 8128 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { 8129 for (final ManagedServiceInfo info : getServices()) { 8130 mHandler.post(() -> { 8131 final INotificationListener listener = (INotificationListener) info.service; 8132 try { 8133 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons); 8134 } catch (RemoteException ex) { 8135 Slog.e(TAG, "unable to notify listener " 8136 + "(hideSilentStatusIcons): " + listener, ex); 8137 } 8138 }); 8139 } 8140 } 8141 8142 /** 8143 * asynchronously notify all listeners about a new notification 8144 * 8145 * <p> 8146 * Also takes care of removing a notification that has been visible to a listener before, 8147 * but isn't anymore. 8148 */ 8149 @GuardedBy("mNotificationLock") 8150 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) { 8151 notifyPostedLocked(r, old, true); 8152 } 8153 8154 /** 8155 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners 8156 * targetting <= O_MR1 8157 */ 8158 @GuardedBy("mNotificationLock") 8159 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old, 8160 boolean notifyAllListeners) { 8161 // Lazily initialized snapshots of the notification. 8162 StatusBarNotification sbn = r.sbn; 8163 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 8164 TrimCache trimCache = new TrimCache(sbn); 8165 8166 for (final ManagedServiceInfo info : getServices()) { 8167 boolean sbnVisible = isVisibleToListener(sbn, info); 8168 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 8169 // This notification hasn't been and still isn't visible -> ignore. 8170 if (!oldSbnVisible && !sbnVisible) { 8171 continue; 8172 } 8173 // If the notification is hidden, don't notifyPosted listeners targeting < P. 8174 // Instead, those listeners will receive notifyPosted when the notification is 8175 // unhidden. 8176 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { 8177 continue; 8178 } 8179 8180 // If we shouldn't notify all listeners, this means the hidden state of 8181 // a notification was changed. Don't notifyPosted listeners targeting >= P. 8182 // Instead, those listeners will receive notifyRankingUpdate. 8183 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) { 8184 continue; 8185 } 8186 8187 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 8188 8189 // This notification became invisible -> remove the old one. 8190 if (oldSbnVisible && !sbnVisible) { 8191 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 8192 mHandler.post(new Runnable() { 8193 @Override 8194 public void run() { 8195 notifyRemoved( 8196 info, oldSbnLightClone, update, null, REASON_USER_STOPPED); 8197 } 8198 }); 8199 continue; 8200 } 8201 8202 // Grant access before listener is notified 8203 final int targetUserId = (info.userid == UserHandle.USER_ALL) 8204 ? UserHandle.USER_SYSTEM : info.userid; 8205 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId); 8206 8207 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 8208 mHandler.post(new Runnable() { 8209 @Override 8210 public void run() { 8211 notifyPosted(info, sbnToPost, update); 8212 } 8213 }); 8214 } 8215 } 8216 8217 /** 8218 * asynchronously notify all listeners about a removed notification 8219 */ 8220 @GuardedBy("mNotificationLock") 8221 public void notifyRemovedLocked(NotificationRecord r, int reason, 8222 NotificationStats notificationStats) { 8223 final StatusBarNotification sbn = r.sbn; 8224 8225 // make a copy in case changes are made to the underlying Notification object 8226 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 8227 // notification 8228 final StatusBarNotification sbnLight = sbn.cloneLight(); 8229 for (final ManagedServiceInfo info : getServices()) { 8230 if (!isVisibleToListener(sbn, info)) { 8231 continue; 8232 } 8233 8234 // don't notifyRemoved for listeners targeting < P 8235 // if not for reason package suspended 8236 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED 8237 && info.targetSdkVersion < Build.VERSION_CODES.P) { 8238 continue; 8239 } 8240 8241 // don't notifyRemoved for listeners targeting >= P 8242 // if the reason is package suspended 8243 if (reason == REASON_PACKAGE_SUSPENDED 8244 && info.targetSdkVersion >= Build.VERSION_CODES.P) { 8245 continue; 8246 } 8247 8248 // Only assistants can get stats 8249 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service) 8250 ? notificationStats : null; 8251 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 8252 mHandler.post(new Runnable() { 8253 @Override 8254 public void run() { 8255 notifyRemoved(info, sbnLight, update, stats, reason); 8256 } 8257 }); 8258 } 8259 8260 // Revoke access after all listeners have been updated 8261 mHandler.post(() -> { 8262 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM); 8263 }); 8264 } 8265 8266 /** 8267 * Asynchronously notify all listeners about a reordering of notifications 8268 * unless changedHiddenNotifications is populated. 8269 * If changedHiddenNotifications is populated, there was a change in the hidden state 8270 * of the notifications. In this case, we only send updates to listeners that 8271 * target >= P. 8272 */ 8273 @GuardedBy("mNotificationLock") 8274 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { 8275 boolean isHiddenRankingUpdate = changedHiddenNotifications != null 8276 && changedHiddenNotifications.size() > 0; 8277 8278 for (final ManagedServiceInfo serviceInfo : getServices()) { 8279 if (!serviceInfo.isEnabledForCurrentProfiles()) { 8280 continue; 8281 } 8282 8283 boolean notifyThisListener = false; 8284 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >= 8285 Build.VERSION_CODES.P) { 8286 for (NotificationRecord rec : changedHiddenNotifications) { 8287 if (isVisibleToListener(rec.sbn, serviceInfo)) { 8288 notifyThisListener = true; 8289 break; 8290 } 8291 } 8292 } 8293 8294 if (notifyThisListener || !isHiddenRankingUpdate) { 8295 final NotificationRankingUpdate update = makeRankingUpdateLocked( 8296 serviceInfo); 8297 8298 mHandler.post(new Runnable() { 8299 @Override 8300 public void run() { 8301 notifyRankingUpdate(serviceInfo, update); 8302 } 8303 }); 8304 } 8305 } 8306 } 8307 8308 @GuardedBy("mNotificationLock") 8309 public void notifyListenerHintsChangedLocked(final int hints) { 8310 for (final ManagedServiceInfo serviceInfo : getServices()) { 8311 if (!serviceInfo.isEnabledForCurrentProfiles()) { 8312 continue; 8313 } 8314 mHandler.post(new Runnable() { 8315 @Override 8316 public void run() { 8317 notifyListenerHintsChanged(serviceInfo, hints); 8318 } 8319 }); 8320 } 8321 } 8322 8323 /** 8324 * asynchronously notify relevant listeners their notification is hidden 8325 * NotificationListenerServices that target P+: 8326 * NotificationListenerService#notifyRankingUpdateLocked() 8327 * NotificationListenerServices that target <= P: 8328 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED. 8329 */ 8330 @GuardedBy("mNotificationLock") 8331 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) { 8332 if (changedNotifications == null || changedNotifications.size() == 0) { 8333 return; 8334 } 8335 8336 notifyRankingUpdateLocked(changedNotifications); 8337 8338 // for listeners that target < P, notifyRemoveLocked 8339 int numChangedNotifications = changedNotifications.size(); 8340 for (int i = 0; i < numChangedNotifications; i++) { 8341 NotificationRecord rec = changedNotifications.get(i); 8342 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats()); 8343 } 8344 } 8345 8346 /** 8347 * asynchronously notify relevant listeners their notification is unhidden 8348 * NotificationListenerServices that target P+: 8349 * NotificationListenerService#notifyRankingUpdateLocked() 8350 * NotificationListenerServices that target <= P: 8351 * NotificationListeners#notifyPostedLocked() 8352 */ 8353 @GuardedBy("mNotificationLock") 8354 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) { 8355 if (changedNotifications == null || changedNotifications.size() == 0) { 8356 return; 8357 } 8358 8359 notifyRankingUpdateLocked(changedNotifications); 8360 8361 // for listeners that target < P, notifyPostedLocked 8362 int numChangedNotifications = changedNotifications.size(); 8363 for (int i = 0; i < numChangedNotifications; i++) { 8364 NotificationRecord rec = changedNotifications.get(i); 8365 mListeners.notifyPostedLocked(rec, rec, false); 8366 } 8367 } 8368 8369 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 8370 for (final ManagedServiceInfo serviceInfo : getServices()) { 8371 if (!serviceInfo.isEnabledForCurrentProfiles()) { 8372 continue; 8373 } 8374 mHandler.post(new Runnable() { 8375 @Override 8376 public void run() { 8377 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 8378 } 8379 }); 8380 } 8381 } 8382 8383 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, 8384 final NotificationChannel channel, final int modificationType) { 8385 if (channel == null) { 8386 return; 8387 } 8388 for (final ManagedServiceInfo serviceInfo : getServices()) { 8389 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { 8390 continue; 8391 } 8392 8393 BackgroundThread.getHandler().post(() -> { 8394 if (hasCompanionDevice(serviceInfo)) { 8395 notifyNotificationChannelChanged( 8396 serviceInfo, pkg, user, channel, modificationType); 8397 } 8398 }); 8399 } 8400 } 8401 8402 protected void notifyNotificationChannelGroupChanged( 8403 final String pkg, final UserHandle user, final NotificationChannelGroup group, 8404 final int modificationType) { 8405 if (group == null) { 8406 return; 8407 } 8408 for (final ManagedServiceInfo serviceInfo : getServices()) { 8409 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { 8410 continue; 8411 } 8412 8413 BackgroundThread.getHandler().post(() -> { 8414 if (hasCompanionDevice(serviceInfo)) { 8415 notifyNotificationChannelGroupChanged( 8416 serviceInfo, pkg, user, group, modificationType); 8417 } 8418 }); 8419 } 8420 } 8421 8422 private void notifyPosted(final ManagedServiceInfo info, 8423 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 8424 final INotificationListener listener = (INotificationListener) info.service; 8425 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 8426 try { 8427 listener.onNotificationPosted(sbnHolder, rankingUpdate); 8428 } catch (RemoteException ex) { 8429 Slog.e(TAG, "unable to notify listener (posted): " + listener, ex); 8430 } 8431 } 8432 8433 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 8434 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) { 8435 if (!info.enabledAndUserMatches(sbn.getUserId())) { 8436 return; 8437 } 8438 final INotificationListener listener = (INotificationListener) info.service; 8439 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 8440 try { 8441 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason); 8442 } catch (RemoteException ex) { 8443 Slog.e(TAG, "unable to notify listener (removed): " + listener, ex); 8444 } 8445 } 8446 8447 private void notifyRankingUpdate(ManagedServiceInfo info, 8448 NotificationRankingUpdate rankingUpdate) { 8449 final INotificationListener listener = (INotificationListener) info.service; 8450 try { 8451 listener.onNotificationRankingUpdate(rankingUpdate); 8452 } catch (RemoteException ex) { 8453 Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 8454 } 8455 } 8456 8457 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 8458 final INotificationListener listener = (INotificationListener) info.service; 8459 try { 8460 listener.onListenerHintsChanged(hints); 8461 } catch (RemoteException ex) { 8462 Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 8463 } 8464 } 8465 8466 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 8467 int interruptionFilter) { 8468 final INotificationListener listener = (INotificationListener) info.service; 8469 try { 8470 listener.onInterruptionFilterChanged(interruptionFilter); 8471 } catch (RemoteException ex) { 8472 Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 8473 } 8474 } 8475 8476 void notifyNotificationChannelChanged(ManagedServiceInfo info, 8477 final String pkg, final UserHandle user, final NotificationChannel channel, 8478 final int modificationType) { 8479 final INotificationListener listener = (INotificationListener) info.service; 8480 try { 8481 listener.onNotificationChannelModification(pkg, user, channel, modificationType); 8482 } catch (RemoteException ex) { 8483 Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex); 8484 } 8485 } 8486 8487 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, 8488 final String pkg, final UserHandle user, final NotificationChannelGroup group, 8489 final int modificationType) { 8490 final INotificationListener listener = (INotificationListener) info.service; 8491 try { 8492 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); 8493 } catch (RemoteException ex) { 8494 Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex); 8495 } 8496 } 8497 8498 public boolean isListenerPackage(String packageName) { 8499 if (packageName == null) { 8500 return false; 8501 } 8502 // TODO: clean up locking object later 8503 synchronized (mNotificationLock) { 8504 for (final ManagedServiceInfo serviceInfo : getServices()) { 8505 if (packageName.equals(serviceInfo.component.getPackageName())) { 8506 return true; 8507 } 8508 } 8509 } 8510 return false; 8511 } 8512 } 8513 8514 class RoleObserver implements OnRoleHoldersChangedListener { 8515 // Role name : user id : list of approved packages 8516 private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps; 8517 8518 private final RoleManager mRm; 8519 private final IPackageManager mPm; 8520 private final Executor mExecutor; 8521 8522 RoleObserver(@NonNull RoleManager roleManager, 8523 @NonNull IPackageManager pkgMgr, 8524 @NonNull @CallbackExecutor Executor executor) { 8525 mRm = roleManager; 8526 mPm = pkgMgr; 8527 mExecutor = executor; 8528 } 8529 8530 public void init() { 8531 List<UserInfo> users = mUm.getUsers(); 8532 mNonBlockableDefaultApps = new ArrayMap<>(); 8533 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 8534 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>(); 8535 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList); 8536 for (int j = 0; j < users.size(); j++) { 8537 Integer userId = users.get(j).getUserHandle().getIdentifier(); 8538 ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser( 8539 NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId))); 8540 ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>(); 8541 for (String pkg : approvedForUserId) { 8542 approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId))); 8543 } 8544 userToApprovedList.put(userId, approvedForUserId); 8545 mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids); 8546 } 8547 } 8548 8549 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); 8550 } 8551 8552 @VisibleForTesting 8553 public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) { 8554 return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg); 8555 } 8556 8557 /** 8558 * Convert the assistant-role holder into settings. The rest of the system uses the 8559 * settings. 8560 * 8561 * @param roleName the name of the role whose holders are changed 8562 * @param user the user for this role holder change 8563 */ 8564 @Override 8565 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { 8566 // we only care about a couple of the roles they'll tell us about 8567 boolean relevantChange = false; 8568 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { 8569 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) { 8570 relevantChange = true; 8571 break; 8572 } 8573 } 8574 8575 if (!relevantChange) { 8576 return; 8577 } 8578 8579 ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user)); 8580 8581 // find the diff 8582 ArrayMap<Integer, ArraySet<String>> prevApprovedForRole = 8583 mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>()); 8584 ArraySet<String> previouslyApproved = 8585 prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>()); 8586 8587 ArraySet<String> toRemove = new ArraySet<>(); 8588 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 8589 8590 for (String previous : previouslyApproved) { 8591 if (!roleHolders.contains(previous)) { 8592 toRemove.add(previous); 8593 } 8594 } 8595 for (String nowApproved : roleHolders) { 8596 if (!previouslyApproved.contains(nowApproved)) { 8597 toAdd.add(new Pair(nowApproved, 8598 getUidForPackage(nowApproved, user.getIdentifier()))); 8599 } 8600 } 8601 8602 // store newly approved apps 8603 prevApprovedForRole.put(user.getIdentifier(), roleHolders); 8604 mNonBlockableDefaultApps.put(roleName, prevApprovedForRole); 8605 8606 // update what apps can be blocked 8607 mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd); 8608 8609 // RoleManager is the source of truth for this data so we don't need to trigger a 8610 // write of the notification policy xml for this change 8611 } 8612 8613 private int getUidForPackage(String pkg, int userId) { 8614 try { 8615 return mPm.getPackageUid(pkg, MATCH_ALL, userId); 8616 } catch (RemoteException e) { 8617 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId); 8618 } 8619 return -1; 8620 } 8621 } 8622 8623 public static final class DumpFilter { 8624 public boolean filtered = false; 8625 public String pkgFilter; 8626 public boolean zen; 8627 public long since; 8628 public boolean stats; 8629 public boolean rvStats; 8630 public boolean redact = true; 8631 public boolean proto = false; 8632 public boolean criticalPriority = false; 8633 public boolean normalPriority = false; 8634 8635 @NonNull 8636 public static DumpFilter parseFromArguments(String[] args) { 8637 final DumpFilter filter = new DumpFilter(); 8638 for (int ai = 0; ai < args.length; ai++) { 8639 final String a = args[ai]; 8640 if ("--proto".equals(a)) { 8641 filter.proto = true; 8642 } else if ("--noredact".equals(a) || "--reveal".equals(a)) { 8643 filter.redact = false; 8644 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 8645 if (ai < args.length-1) { 8646 ai++; 8647 filter.pkgFilter = args[ai].trim().toLowerCase(); 8648 if (filter.pkgFilter.isEmpty()) { 8649 filter.pkgFilter = null; 8650 } else { 8651 filter.filtered = true; 8652 } 8653 } 8654 } else if ("--zen".equals(a) || "zen".equals(a)) { 8655 filter.filtered = true; 8656 filter.zen = true; 8657 } else if ("--stats".equals(a)) { 8658 filter.stats = true; 8659 if (ai < args.length-1) { 8660 ai++; 8661 filter.since = Long.parseLong(args[ai]); 8662 } else { 8663 filter.since = 0; 8664 } 8665 } else if ("--remote-view-stats".equals(a)) { 8666 filter.rvStats = true; 8667 if (ai < args.length-1) { 8668 ai++; 8669 filter.since = Long.parseLong(args[ai]); 8670 } else { 8671 filter.since = 0; 8672 } 8673 } else if (PRIORITY_ARG.equals(a)) { 8674 // Bugreport will call the service twice with priority arguments, first to dump 8675 // critical sections and then non critical ones. Set approriate filters 8676 // to generate the desired data. 8677 if (ai < args.length - 1) { 8678 ai++; 8679 switch (args[ai]) { 8680 case PRIORITY_ARG_CRITICAL: 8681 filter.criticalPriority = true; 8682 break; 8683 case PRIORITY_ARG_NORMAL: 8684 filter.normalPriority = true; 8685 break; 8686 } 8687 } 8688 } 8689 } 8690 return filter; 8691 } 8692 8693 public boolean matches(StatusBarNotification sbn) { 8694 if (!filtered) return true; 8695 return zen ? true : sbn != null 8696 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 8697 } 8698 8699 public boolean matches(ComponentName component) { 8700 if (!filtered) return true; 8701 return zen ? true : component != null && matches(component.getPackageName()); 8702 } 8703 8704 public boolean matches(String pkg) { 8705 if (!filtered) return true; 8706 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 8707 } 8708 8709 @Override 8710 public String toString() { 8711 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 8712 } 8713 } 8714 8715 @VisibleForTesting 8716 void resetAssistantUserSet(int userId) { 8717 checkCallerIsSystemOrShell(); 8718 mAssistants.setUserSet(userId, false); 8719 handleSavePolicyFile(); 8720 } 8721 8722 @VisibleForTesting 8723 @Nullable 8724 ComponentName getApprovedAssistant(int userId) { 8725 checkCallerIsSystemOrShell(); 8726 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); 8727 return CollectionUtils.firstOrNull(allowedComponents); 8728 } 8729 8730 @VisibleForTesting 8731 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) { 8732 checkCallerIsSystemOrShell(); 8733 // only use for testing: mimic receive broadcast that package is (un)suspended 8734 // but does not actually (un)suspend the package 8735 final Bundle extras = new Bundle(); 8736 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, 8737 new String[]{pkg}); 8738 8739 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED 8740 : Intent.ACTION_PACKAGES_UNSUSPENDED; 8741 final Intent intent = new Intent(action); 8742 intent.putExtras(extras); 8743 8744 mPackageIntentReceiver.onReceive(getContext(), intent); 8745 } 8746 8747 @VisibleForTesting 8748 protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) { 8749 checkCallerIsSystemOrShell(); 8750 // only use for testing: mimic receive broadcast that package is (un)distracting 8751 // but does not actually register that info with packagemanager 8752 final Bundle extras = new Bundle(); 8753 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); 8754 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); 8755 8756 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 8757 intent.putExtras(extras); 8758 8759 mPackageIntentReceiver.onReceive(getContext(), intent); 8760 } 8761 8762 /** 8763 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 8764 * binder without sending large amounts of data over a oneway transaction. 8765 */ 8766 private static final class StatusBarNotificationHolder 8767 extends IStatusBarNotificationHolder.Stub { 8768 private StatusBarNotification mValue; 8769 8770 public StatusBarNotificationHolder(StatusBarNotification value) { 8771 mValue = value; 8772 } 8773 8774 /** Get the held value and clear it. This function should only be called once per holder */ 8775 @Override 8776 public StatusBarNotification get() { 8777 StatusBarNotification value = mValue; 8778 mValue = null; 8779 return value; 8780 } 8781 } 8782 8783 private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException { 8784 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 8785 out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, 8786 Boolean.toString(mLockScreenAllowSecureNotifications)); 8787 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG); 8788 } 8789 8790 private static boolean safeBoolean(String val, boolean defValue) { 8791 if (TextUtils.isEmpty(val)) return defValue; 8792 return Boolean.parseBoolean(val); 8793 } 8794 } 8795