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