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