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