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