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