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