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