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