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