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