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