NotificationManagerService.java revision bcec2b0cebd873f8b80c11c8653326fc638af860
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.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 20import static android.service.notification.NotificationListenerService.TRIM_FULL; 21import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 22import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 23import static org.xmlpull.v1.XmlPullParser.END_TAG; 24import static org.xmlpull.v1.XmlPullParser.START_TAG; 25 26import android.app.ActivityManager; 27import android.app.ActivityManagerNative; 28import android.app.AppGlobals; 29import android.app.AppOpsManager; 30import android.app.IActivityManager; 31import android.app.INotificationManager; 32import android.app.INotificationManagerCallback; 33import android.app.ITransientNotification; 34import android.app.Notification; 35import android.app.NotificationManager; 36import android.app.NotificationManager.Policy; 37import android.app.PendingIntent; 38import android.app.StatusBarManager; 39import android.app.usage.UsageEvents; 40import android.app.usage.UsageStatsManagerInternal; 41import android.content.BroadcastReceiver; 42import android.content.ComponentName; 43import android.content.ContentResolver; 44import android.content.Context; 45import android.content.Intent; 46import android.content.IntentFilter; 47import android.content.pm.ApplicationInfo; 48import android.content.pm.IPackageManager; 49import android.content.pm.PackageInfo; 50import android.content.pm.PackageManager; 51import android.content.pm.PackageManager.NameNotFoundException; 52import android.content.pm.ParceledListSlice; 53import android.content.res.Resources; 54import android.database.ContentObserver; 55import android.media.AudioAttributes; 56import android.media.AudioManager; 57import android.media.AudioManagerInternal; 58import android.media.AudioSystem; 59import android.media.IRingtonePlayer; 60import android.net.Uri; 61import android.os.Binder; 62import android.os.Build; 63import android.os.Bundle; 64import android.os.Environment; 65import android.os.Handler; 66import android.os.HandlerThread; 67import android.os.IBinder; 68import android.os.IInterface; 69import android.os.Looper; 70import android.os.Message; 71import android.os.Process; 72import android.os.RemoteException; 73import android.os.SystemProperties; 74import android.os.UserHandle; 75import android.os.Vibrator; 76import android.provider.Settings; 77import android.service.notification.Condition; 78import android.service.notification.IConditionListener; 79import android.service.notification.IConditionProvider; 80import android.service.notification.INotificationListener; 81import android.service.notification.IStatusBarNotificationHolder; 82import android.service.notification.NotificationListenerService; 83import android.service.notification.NotificationRankingUpdate; 84import android.service.notification.StatusBarNotification; 85import android.service.notification.ZenModeConfig; 86import android.telephony.PhoneStateListener; 87import android.telephony.TelephonyManager; 88import android.text.TextUtils; 89import android.util.ArrayMap; 90import android.util.ArraySet; 91import android.util.AtomicFile; 92import android.util.Log; 93import android.util.Slog; 94import android.util.Xml; 95import android.view.accessibility.AccessibilityEvent; 96import android.view.accessibility.AccessibilityManager; 97import android.widget.Toast; 98 99import com.android.internal.R; 100import com.android.internal.util.FastXmlSerializer; 101import com.android.server.EventLogTags; 102import com.android.server.LocalServices; 103import com.android.server.SystemService; 104import com.android.server.lights.Light; 105import com.android.server.lights.LightsManager; 106import com.android.server.notification.ManagedServices.ManagedServiceInfo; 107import com.android.server.notification.ManagedServices.UserProfiles; 108import com.android.server.statusbar.StatusBarManagerInternal; 109 110import libcore.io.IoUtils; 111 112import org.xmlpull.v1.XmlPullParser; 113import org.xmlpull.v1.XmlPullParserException; 114import org.xmlpull.v1.XmlSerializer; 115 116import java.io.File; 117import java.io.FileDescriptor; 118import java.io.FileInputStream; 119import java.io.FileNotFoundException; 120import java.io.FileOutputStream; 121import java.io.IOException; 122import java.io.PrintWriter; 123import java.nio.charset.StandardCharsets; 124import java.util.ArrayDeque; 125import java.util.ArrayList; 126import java.util.HashSet; 127import java.util.Iterator; 128import java.util.Map.Entry; 129import java.util.NoSuchElementException; 130import java.util.Objects; 131 132/** {@hide} */ 133public class NotificationManagerService extends SystemService { 134 static final String TAG = "NotificationService"; 135 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 136 public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE 137 && SystemProperties.getBoolean("debug.child_notifs", false); 138 139 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 140 141 // message codes 142 static final int MESSAGE_TIMEOUT = 2; 143 static final int MESSAGE_SAVE_POLICY_FILE = 3; 144 static final int MESSAGE_RECONSIDER_RANKING = 4; 145 static final int MESSAGE_RANKING_CONFIG_CHANGE = 5; 146 static final int MESSAGE_SEND_RANKING_UPDATE = 6; 147 static final int MESSAGE_LISTENER_HINTS_CHANGED = 7; 148 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8; 149 150 static final int LONG_DELAY = 3500; // 3.5 seconds 151 static final int SHORT_DELAY = 2000; // 2 seconds 152 153 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 154 155 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 156 157 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 158 static final boolean SCORE_ONGOING_HIGHER = false; 159 160 static final int JUNK_SCORE = -1000; 161 static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; 162 static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER; 163 164 // Notifications with scores below this will not interrupt the user, either via LED or 165 // sound or vibration 166 static final int SCORE_INTERRUPTION_THRESHOLD = 167 Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; 168 169 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; 170 static final boolean ENABLE_BLOCKED_TOASTS = true; 171 172 // When #matchesCallFilter is called from the ringer, wait at most 173 // 3s to resolve the contacts. This timeout is required since 174 // ContactsProvider might take a long time to start up. 175 // 176 // Return STARRED_CONTACT when the timeout is hit in order to avoid 177 // missed calls in ZEN mode "Important". 178 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 179 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 180 ValidateNotificationPeople.STARRED_CONTACT; 181 182 /** notification_enqueue status value for a newly enqueued notification. */ 183 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 184 185 /** notification_enqueue status value for an existing notification. */ 186 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 187 188 /** notification_enqueue status value for an ignored notification. */ 189 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 190 191 private IActivityManager mAm; 192 AudioManager mAudioManager; 193 AudioManagerInternal mAudioManagerInternal; 194 StatusBarManagerInternal mStatusBar; 195 Vibrator mVibrator; 196 197 final IBinder mForegroundToken = new Binder(); 198 private WorkerHandler mHandler; 199 private final HandlerThread mRankingThread = new HandlerThread("ranker", 200 Process.THREAD_PRIORITY_BACKGROUND); 201 202 private Light mNotificationLight; 203 Light mAttentionLight; 204 private int mDefaultNotificationColor; 205 private int mDefaultNotificationLedOn; 206 207 private int mDefaultNotificationLedOff; 208 private long[] mDefaultVibrationPattern; 209 210 private long[] mFallbackVibrationPattern; 211 private boolean mUseAttentionLight; 212 boolean mSystemReady; 213 214 private boolean mDisableNotificationEffects; 215 private int mCallState; 216 private String mSoundNotificationKey; 217 private String mVibrateNotificationKey; 218 219 private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>(); 220 private ComponentName mEffectsSuppressor; 221 private int mListenerHints; // right now, all hints are global 222 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 223 224 // for enabling and disabling notification pulse behavior 225 private boolean mScreenOn = true; 226 private boolean mInCall = false; 227 private boolean mNotificationPulseEnabled; 228 229 // used as a mutex for access to all active notifications & listeners 230 final ArrayList<NotificationRecord> mNotificationList = 231 new ArrayList<NotificationRecord>(); 232 final ArrayMap<String, NotificationRecord> mNotificationsByKey = 233 new ArrayMap<String, NotificationRecord>(); 234 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); 235 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 236 private final ArrayMap<String, Boolean> mPolicyAccess = new ArrayMap<>(); 237 238 239 // The last key in this list owns the hardware. 240 ArrayList<String> mLights = new ArrayList<>(); 241 242 private AppOpsManager mAppOps; 243 private UsageStatsManagerInternal mAppUsageStats; 244 245 private Archive mArchive; 246 247 // Notification control database. For now just contains disabled packages. 248 private AtomicFile mPolicyFile; 249 private HashSet<String> mBlockedPackages = new HashSet<String>(); 250 251 private static final int DB_VERSION = 1; 252 253 private static final String TAG_BODY = "notification-policy"; 254 private static final String ATTR_VERSION = "version"; 255 256 private static final String TAG_BLOCKED_PKGS = "blocked-packages"; 257 private static final String TAG_PACKAGE = "package"; 258 private static final String ATTR_NAME = "name"; 259 260 private RankingHelper mRankingHelper; 261 262 private final UserProfiles mUserProfiles = new UserProfiles(); 263 private NotificationListeners mListeners; 264 private ConditionProviders mConditionProviders; 265 private NotificationUsageStats mUsageStats; 266 267 private static final int MY_UID = Process.myUid(); 268 private static final int MY_PID = Process.myPid(); 269 private static final int REASON_DELEGATE_CLICK = 1; 270 private static final int REASON_DELEGATE_CANCEL = 2; 271 private static final int REASON_DELEGATE_CANCEL_ALL = 3; 272 private static final int REASON_DELEGATE_ERROR = 4; 273 private static final int REASON_PACKAGE_CHANGED = 5; 274 private static final int REASON_USER_STOPPED = 6; 275 private static final int REASON_PACKAGE_BANNED = 7; 276 private static final int REASON_NOMAN_CANCEL = 8; 277 private static final int REASON_NOMAN_CANCEL_ALL = 9; 278 private static final int REASON_LISTENER_CANCEL = 10; 279 private static final int REASON_LISTENER_CANCEL_ALL = 11; 280 private static final int REASON_GROUP_SUMMARY_CANCELED = 12; 281 private static final int REASON_GROUP_OPTIMIZATION = 13; 282 283 private static class Archive { 284 final int mBufferSize; 285 final ArrayDeque<StatusBarNotification> mBuffer; 286 287 public Archive(int size) { 288 mBufferSize = size; 289 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize); 290 } 291 292 public String toString() { 293 final StringBuilder sb = new StringBuilder(); 294 final int N = mBuffer.size(); 295 sb.append("Archive ("); 296 sb.append(N); 297 sb.append(" notification"); 298 sb.append((N==1)?")":"s)"); 299 return sb.toString(); 300 } 301 302 public void record(StatusBarNotification nr) { 303 if (mBuffer.size() == mBufferSize) { 304 mBuffer.removeFirst(); 305 } 306 307 // We don't want to store the heavy bits of the notification in the archive, 308 // but other clients in the system process might be using the object, so we 309 // store a (lightened) copy. 310 mBuffer.addLast(nr.cloneLight()); 311 } 312 313 public void clear() { 314 mBuffer.clear(); 315 } 316 317 public Iterator<StatusBarNotification> descendingIterator() { 318 return mBuffer.descendingIterator(); 319 } 320 public Iterator<StatusBarNotification> ascendingIterator() { 321 return mBuffer.iterator(); 322 } 323 public Iterator<StatusBarNotification> filter( 324 final Iterator<StatusBarNotification> iter, final String pkg, final int userId) { 325 return new Iterator<StatusBarNotification>() { 326 StatusBarNotification mNext = findNext(); 327 328 private StatusBarNotification findNext() { 329 while (iter.hasNext()) { 330 StatusBarNotification nr = iter.next(); 331 if ((pkg == null || nr.getPackageName() == pkg) 332 && (userId == UserHandle.USER_ALL || nr.getUserId() == userId)) { 333 return nr; 334 } 335 } 336 return null; 337 } 338 339 @Override 340 public boolean hasNext() { 341 return mNext == null; 342 } 343 344 @Override 345 public StatusBarNotification next() { 346 StatusBarNotification next = mNext; 347 if (next == null) { 348 throw new NoSuchElementException(); 349 } 350 mNext = findNext(); 351 return next; 352 } 353 354 @Override 355 public void remove() { 356 iter.remove(); 357 } 358 }; 359 } 360 361 public StatusBarNotification[] getArray(int count) { 362 if (count == 0) count = mBufferSize; 363 final StatusBarNotification[] a 364 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 365 Iterator<StatusBarNotification> iter = descendingIterator(); 366 int i=0; 367 while (iter.hasNext() && i < count) { 368 a[i++] = iter.next(); 369 } 370 return a; 371 } 372 373 public StatusBarNotification[] getArray(int count, String pkg, int userId) { 374 if (count == 0) count = mBufferSize; 375 final StatusBarNotification[] a 376 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 377 Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId); 378 int i=0; 379 while (iter.hasNext() && i < count) { 380 a[i++] = iter.next(); 381 } 382 return a; 383 } 384 385 } 386 387 private void loadPolicyFile() { 388 synchronized(mPolicyFile) { 389 mBlockedPackages.clear(); 390 391 FileInputStream infile = null; 392 try { 393 infile = mPolicyFile.openRead(); 394 final XmlPullParser parser = Xml.newPullParser(); 395 parser.setInput(infile, StandardCharsets.UTF_8.name()); 396 397 int type; 398 String tag; 399 int version = DB_VERSION; 400 while ((type = parser.next()) != END_DOCUMENT) { 401 tag = parser.getName(); 402 if (type == START_TAG) { 403 if (TAG_BODY.equals(tag)) { 404 version = Integer.parseInt( 405 parser.getAttributeValue(null, ATTR_VERSION)); 406 } else if (TAG_BLOCKED_PKGS.equals(tag)) { 407 while ((type = parser.next()) != END_DOCUMENT) { 408 tag = parser.getName(); 409 if (TAG_PACKAGE.equals(tag)) { 410 mBlockedPackages.add( 411 parser.getAttributeValue(null, ATTR_NAME)); 412 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) { 413 break; 414 } 415 } 416 } 417 } 418 mZenModeHelper.readXml(parser); 419 mRankingHelper.readXml(parser); 420 } 421 } catch (FileNotFoundException e) { 422 // No data yet 423 } catch (IOException e) { 424 Log.wtf(TAG, "Unable to read notification policy", e); 425 } catch (NumberFormatException e) { 426 Log.wtf(TAG, "Unable to parse notification policy", e); 427 } catch (XmlPullParserException e) { 428 Log.wtf(TAG, "Unable to parse notification policy", e); 429 } finally { 430 IoUtils.closeQuietly(infile); 431 } 432 } 433 } 434 435 public void savePolicyFile() { 436 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE); 437 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE); 438 } 439 440 private void handleSavePolicyFile() { 441 Slog.d(TAG, "handleSavePolicyFile"); 442 synchronized (mPolicyFile) { 443 final FileOutputStream stream; 444 try { 445 stream = mPolicyFile.startWrite(); 446 } catch (IOException e) { 447 Slog.w(TAG, "Failed to save policy file", e); 448 return; 449 } 450 451 try { 452 final XmlSerializer out = new FastXmlSerializer(); 453 out.setOutput(stream, StandardCharsets.UTF_8.name()); 454 out.startDocument(null, true); 455 out.startTag(null, TAG_BODY); 456 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 457 mZenModeHelper.writeXml(out); 458 mRankingHelper.writeXml(out); 459 out.endTag(null, TAG_BODY); 460 out.endDocument(); 461 mPolicyFile.finishWrite(stream); 462 } catch (IOException e) { 463 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 464 mPolicyFile.failWrite(stream); 465 } 466 } 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 private static final class ToastRecord 483 { 484 final int pid; 485 final String pkg; 486 final ITransientNotification callback; 487 int duration; 488 489 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration) 490 { 491 this.pid = pid; 492 this.pkg = pkg; 493 this.callback = callback; 494 this.duration = duration; 495 } 496 497 void update(int duration) { 498 this.duration = duration; 499 } 500 501 void dump(PrintWriter pw, String prefix, DumpFilter filter) { 502 if (filter != null && !filter.matches(pkg)) return; 503 pw.println(prefix + this); 504 } 505 506 @Override 507 public final String toString() 508 { 509 return "ToastRecord{" 510 + Integer.toHexString(System.identityHashCode(this)) 511 + " pkg=" + pkg 512 + " callback=" + callback 513 + " duration=" + duration; 514 } 515 } 516 517 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 518 519 @Override 520 public void onSetDisabled(int status) { 521 synchronized (mNotificationList) { 522 mDisableNotificationEffects = 523 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 524 if (disableNotificationEffects(null) != null) { 525 // cancel whatever's going on 526 long identity = Binder.clearCallingIdentity(); 527 try { 528 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 529 if (player != null) { 530 player.stopAsync(); 531 } 532 } catch (RemoteException e) { 533 } finally { 534 Binder.restoreCallingIdentity(identity); 535 } 536 537 identity = Binder.clearCallingIdentity(); 538 try { 539 mVibrator.cancel(); 540 } finally { 541 Binder.restoreCallingIdentity(identity); 542 } 543 } 544 } 545 } 546 547 @Override 548 public void onClearAll(int callingUid, int callingPid, int userId) { 549 synchronized (mNotificationList) { 550 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null, 551 /*includeCurrentProfiles*/ true); 552 } 553 } 554 555 @Override 556 public void onNotificationClick(int callingUid, int callingPid, String key) { 557 synchronized (mNotificationList) { 558 NotificationRecord r = mNotificationsByKey.get(key); 559 if (r == null) { 560 Log.w(TAG, "No notification with key: " + key); 561 return; 562 } 563 final long now = System.currentTimeMillis(); 564 EventLogTags.writeNotificationClicked(key, 565 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 566 567 StatusBarNotification sbn = r.sbn; 568 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 569 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 570 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), 571 REASON_DELEGATE_CLICK, null); 572 } 573 } 574 575 @Override 576 public void onNotificationActionClick(int callingUid, int callingPid, String key, 577 int actionIndex) { 578 synchronized (mNotificationList) { 579 NotificationRecord r = mNotificationsByKey.get(key); 580 if (r == null) { 581 Log.w(TAG, "No notification with key: " + key); 582 return; 583 } 584 final long now = System.currentTimeMillis(); 585 EventLogTags.writeNotificationActionClicked(key, actionIndex, 586 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 587 // TODO: Log action click via UsageStats. 588 } 589 } 590 591 @Override 592 public void onNotificationClear(int callingUid, int callingPid, 593 String pkg, String tag, int id, int userId) { 594 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 595 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 596 true, userId, REASON_DELEGATE_CANCEL, null); 597 } 598 599 @Override 600 public void onPanelRevealed(boolean clearEffects) { 601 EventLogTags.writeNotificationPanelRevealed(); 602 if (clearEffects) { 603 clearEffects(); 604 } 605 } 606 607 @Override 608 public void onPanelHidden() { 609 EventLogTags.writeNotificationPanelHidden(); 610 } 611 612 @Override 613 public void clearEffects() { 614 synchronized (mNotificationList) { 615 if (DBG) Slog.d(TAG, "clearEffects"); 616 617 // sound 618 mSoundNotificationKey = null; 619 620 long identity = Binder.clearCallingIdentity(); 621 try { 622 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 623 if (player != null) { 624 player.stopAsync(); 625 } 626 } catch (RemoteException e) { 627 } finally { 628 Binder.restoreCallingIdentity(identity); 629 } 630 631 // vibrate 632 mVibrateNotificationKey = null; 633 identity = Binder.clearCallingIdentity(); 634 try { 635 mVibrator.cancel(); 636 } finally { 637 Binder.restoreCallingIdentity(identity); 638 } 639 640 // light 641 mLights.clear(); 642 updateLightsLocked(); 643 } 644 } 645 646 @Override 647 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 648 int uid, int initialPid, String message, int userId) { 649 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 650 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 651 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 652 REASON_DELEGATE_ERROR, null); 653 long ident = Binder.clearCallingIdentity(); 654 try { 655 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, 656 "Bad notification posted from package " + pkg 657 + ": " + message); 658 } catch (RemoteException e) { 659 } 660 Binder.restoreCallingIdentity(ident); 661 } 662 663 @Override 664 public void onNotificationVisibilityChanged( 665 String[] newlyVisibleKeys, String[] noLongerVisibleKeys) { 666 // Using ';' as separator since eventlogs uses ',' to separate 667 // args. 668 // TODO remove this: b/21248682 669 EventLogTags.writeNotificationVisibilityChanged( 670 TextUtils.join(";", newlyVisibleKeys), 671 TextUtils.join(";", noLongerVisibleKeys)); 672 synchronized (mNotificationList) { 673 for (String key : newlyVisibleKeys) { 674 NotificationRecord r = mNotificationsByKey.get(key); 675 if (r == null) continue; 676 r.setVisibility(true); 677 } 678 // Note that we might receive this event after notifications 679 // have already left the system, e.g. after dismissing from the 680 // shade. Hence not finding notifications in 681 // mNotificationsByKey is not an exceptional condition. 682 for (String key : noLongerVisibleKeys) { 683 NotificationRecord r = mNotificationsByKey.get(key); 684 if (r == null) continue; 685 r.setVisibility(false); 686 } 687 } 688 } 689 690 @Override 691 public void onNotificationExpansionChanged(String key, 692 boolean userAction, boolean expanded) { 693 synchronized (mNotificationList) { 694 NotificationRecord r = mNotificationsByKey.get(key); 695 if (r != null) { 696 r.stats.onExpansionChanged(userAction, expanded); 697 final long now = System.currentTimeMillis(); 698 EventLogTags.writeNotificationExpansion(key, 699 userAction ? 1 : 0, expanded ? 1 : 0, 700 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 701 } 702 } 703 } 704 }; 705 706 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 707 @Override 708 public void onReceive(Context context, Intent intent) { 709 String action = intent.getAction(); 710 if (action == null) { 711 return; 712 } 713 714 boolean queryRestart = false; 715 boolean queryRemove = false; 716 boolean packageChanged = false; 717 boolean cancelNotifications = true; 718 719 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 720 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 721 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 722 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 723 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 724 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 725 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 726 UserHandle.USER_ALL); 727 String pkgList[] = null; 728 boolean queryReplace = queryRemove && 729 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 730 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace); 731 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 732 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 733 } else if (queryRestart) { 734 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 735 } else { 736 Uri uri = intent.getData(); 737 if (uri == null) { 738 return; 739 } 740 String pkgName = uri.getSchemeSpecificPart(); 741 if (pkgName == null) { 742 return; 743 } 744 if (packageChanged) { 745 // We cancel notifications for packages which have just been disabled 746 try { 747 final IPackageManager pm = AppGlobals.getPackageManager(); 748 final int enabled = pm.getApplicationEnabledSetting(pkgName, 749 changeUserId != UserHandle.USER_ALL ? changeUserId : 750 UserHandle.USER_OWNER); 751 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 752 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 753 cancelNotifications = false; 754 } 755 } catch (IllegalArgumentException e) { 756 // Package doesn't exist; probably racing with uninstall. 757 // cancelNotifications is already true, so nothing to do here. 758 if (DBG) { 759 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 760 } 761 } catch (RemoteException e) { 762 // Failed to talk to PackageManagerService Should never happen! 763 } 764 } 765 pkgList = new String[]{pkgName}; 766 } 767 768 if (pkgList != null && (pkgList.length > 0)) { 769 for (String pkgName : pkgList) { 770 if (cancelNotifications) { 771 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, 772 changeUserId, REASON_PACKAGE_CHANGED, null); 773 } 774 } 775 } 776 mListeners.onPackagesChanged(queryReplace, pkgList); 777 mConditionProviders.onPackagesChanged(queryReplace, pkgList); 778 } 779 } 780 }; 781 782 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 783 @Override 784 public void onReceive(Context context, Intent intent) { 785 String action = intent.getAction(); 786 787 if (action.equals(Intent.ACTION_SCREEN_ON)) { 788 // Keep track of screen on/off state, but do not turn off the notification light 789 // until user passes through the lock screen or views the notification. 790 mScreenOn = true; 791 updateNotificationPulse(); 792 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 793 mScreenOn = false; 794 updateNotificationPulse(); 795 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 796 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 797 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 798 updateNotificationPulse(); 799 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 800 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 801 if (userHandle >= 0) { 802 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 803 REASON_USER_STOPPED, null); 804 } 805 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 806 // turn off LED when user passes through lock screen 807 mNotificationLight.turnOff(); 808 mStatusBar.notificationLightOff(); 809 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 810 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 811 // reload per-user settings 812 mSettingsObserver.update(null); 813 mUserProfiles.updateCache(context); 814 // Refresh managed services 815 mConditionProviders.onUserSwitched(user); 816 mListeners.onUserSwitched(user); 817 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 818 mUserProfiles.updateCache(context); 819 } 820 } 821 }; 822 823 class SettingsObserver extends ContentObserver { 824 private final Uri NOTIFICATION_LIGHT_PULSE_URI 825 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 826 827 SettingsObserver(Handler handler) { 828 super(handler); 829 } 830 831 void observe() { 832 ContentResolver resolver = getContext().getContentResolver(); 833 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 834 false, this, UserHandle.USER_ALL); 835 update(null); 836 } 837 838 @Override public void onChange(boolean selfChange, Uri uri) { 839 update(uri); 840 } 841 842 public void update(Uri uri) { 843 ContentResolver resolver = getContext().getContentResolver(); 844 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 845 boolean pulseEnabled = Settings.System.getInt(resolver, 846 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 847 if (mNotificationPulseEnabled != pulseEnabled) { 848 mNotificationPulseEnabled = pulseEnabled; 849 updateNotificationPulse(); 850 } 851 } 852 } 853 } 854 855 private SettingsObserver mSettingsObserver; 856 private ZenModeHelper mZenModeHelper; 857 858 private final Runnable mBuzzBeepBlinked = new Runnable() { 859 @Override 860 public void run() { 861 mStatusBar.buzzBeepBlinked(); 862 } 863 }; 864 865 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 866 int[] ar = r.getIntArray(resid); 867 if (ar == null) { 868 return def; 869 } 870 final int len = ar.length > maxlen ? maxlen : ar.length; 871 long[] out = new long[len]; 872 for (int i=0; i<len; i++) { 873 out[i] = ar[i]; 874 } 875 return out; 876 } 877 878 public NotificationManagerService(Context context) { 879 super(context); 880 } 881 882 @Override 883 public void onStart() { 884 Resources resources = getContext().getResources(); 885 886 mAm = ActivityManagerNative.getDefault(); 887 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 888 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 889 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); 890 891 mHandler = new WorkerHandler(); 892 mRankingThread.start(); 893 String[] extractorNames; 894 try { 895 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 896 } catch (Resources.NotFoundException e) { 897 extractorNames = new String[0]; 898 } 899 mRankingHelper = new RankingHelper(getContext(), 900 new RankingWorkerHandler(mRankingThread.getLooper()), 901 extractorNames); 902 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles); 903 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); 904 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 905 @Override 906 public void onConfigChanged() { 907 savePolicyFile(); 908 } 909 910 @Override 911 void onZenModeChanged() { 912 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 913 synchronized(mNotificationList) { 914 updateInterruptionFilterLocked(); 915 } 916 } 917 918 @Override 919 void onPolicyChanged() { 920 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 921 } 922 }); 923 final File systemDir = new File(Environment.getDataDirectory(), "system"); 924 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); 925 mUsageStats = new NotificationUsageStats(getContext()); 926 927 importOldBlockDb(); 928 929 mListeners = new NotificationListeners(); 930 mStatusBar = getLocalService(StatusBarManagerInternal.class); 931 mStatusBar.setNotificationDelegate(mNotificationDelegate); 932 933 final LightsManager lights = getLocalService(LightsManager.class); 934 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 935 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); 936 937 mDefaultNotificationColor = resources.getColor( 938 R.color.config_defaultNotificationColor); 939 mDefaultNotificationLedOn = resources.getInteger( 940 R.integer.config_defaultNotificationLedOn); 941 mDefaultNotificationLedOff = resources.getInteger( 942 R.integer.config_defaultNotificationLedOff); 943 944 mDefaultVibrationPattern = getLongArray(resources, 945 R.array.config_defaultNotificationVibePattern, 946 VIBRATE_PATTERN_MAXLEN, 947 DEFAULT_VIBRATE_PATTERN); 948 949 mFallbackVibrationPattern = getLongArray(resources, 950 R.array.config_notificationFallbackVibePattern, 951 VIBRATE_PATTERN_MAXLEN, 952 DEFAULT_VIBRATE_PATTERN); 953 954 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); 955 956 // Don't start allowing notifications until the setup wizard has run once. 957 // After that, including subsequent boots, init with notifications turned on. 958 // This works on the first boot because the setup wizard will toggle this 959 // flag at least once and we'll go back to 0 after that. 960 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 961 Settings.Global.DEVICE_PROVISIONED, 0)) { 962 mDisableNotificationEffects = true; 963 } 964 mZenModeHelper.initZenMode(); 965 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 966 967 mUserProfiles.updateCache(getContext()); 968 listenForCallState(); 969 970 // register for various Intents 971 IntentFilter filter = new IntentFilter(); 972 filter.addAction(Intent.ACTION_SCREEN_ON); 973 filter.addAction(Intent.ACTION_SCREEN_OFF); 974 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 975 filter.addAction(Intent.ACTION_USER_PRESENT); 976 filter.addAction(Intent.ACTION_USER_STOPPED); 977 filter.addAction(Intent.ACTION_USER_SWITCHED); 978 filter.addAction(Intent.ACTION_USER_ADDED); 979 getContext().registerReceiver(mIntentReceiver, filter); 980 981 IntentFilter pkgFilter = new IntentFilter(); 982 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 983 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 984 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 985 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 986 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 987 pkgFilter.addDataScheme("package"); 988 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 989 null); 990 991 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 992 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 993 null); 994 995 mSettingsObserver = new SettingsObserver(mHandler); 996 997 mArchive = new Archive(resources.getInteger( 998 R.integer.config_notificationServiceArchiveSize)); 999 1000 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 1001 publishLocalService(NotificationManagerInternal.class, mInternalService); 1002 } 1003 1004 private void sendRegisteredOnlyBroadcast(String action) { 1005 getContext().sendBroadcastAsUser(new Intent(action) 1006 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null); 1007 } 1008 1009 /** 1010 * Read the old XML-based app block database and import those blockages into the AppOps system. 1011 */ 1012 private void importOldBlockDb() { 1013 loadPolicyFile(); 1014 1015 PackageManager pm = getContext().getPackageManager(); 1016 for (String pkg : mBlockedPackages) { 1017 PackageInfo info = null; 1018 try { 1019 info = pm.getPackageInfo(pkg, 0); 1020 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); 1021 } catch (NameNotFoundException e) { 1022 // forget you 1023 } 1024 } 1025 mBlockedPackages.clear(); 1026 } 1027 1028 @Override 1029 public void onBootPhase(int phase) { 1030 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1031 // no beeping until we're basically done booting 1032 mSystemReady = true; 1033 1034 // Grab our optional AudioService 1035 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1036 mAudioManagerInternal = getLocalService(AudioManagerInternal.class); 1037 mZenModeHelper.onSystemReady(); 1038 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1039 // This observer will force an update when observe is called, causing us to 1040 // bind to listener services. 1041 mSettingsObserver.observe(); 1042 mListeners.onBootPhaseAppsCanStart(); 1043 mConditionProviders.onBootPhaseAppsCanStart(); 1044 } 1045 } 1046 1047 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { 1048 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); 1049 1050 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 1051 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 1052 1053 // Now, cancel any outstanding notifications that are part of a just-disabled app 1054 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 1055 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), 1056 REASON_PACKAGE_BANNED, null); 1057 } 1058 } 1059 1060 private void updateListenerHintsLocked() { 1061 final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS; 1062 if (hints == mListenerHints) return; 1063 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size()); 1064 mListenerHints = hints; 1065 scheduleListenerHintsChanged(hints); 1066 } 1067 1068 private void updateEffectsSuppressorLocked() { 1069 final ComponentName suppressor = !mListenersDisablingEffects.isEmpty() 1070 ? mListenersDisablingEffects.valueAt(0).component : null; 1071 if (Objects.equals(suppressor, mEffectsSuppressor)) return; 1072 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor); 1073 mEffectsSuppressor = suppressor; 1074 mZenModeHelper.setEffectsSuppressed(suppressor != null); 1075 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 1076 } 1077 1078 private void updateInterruptionFilterLocked() { 1079 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1080 if (interruptionFilter == mInterruptionFilter) return; 1081 mInterruptionFilter = interruptionFilter; 1082 scheduleInterruptionFilterChanged(interruptionFilter); 1083 } 1084 1085 private final IBinder mService = new INotificationManager.Stub() { 1086 // Toasts 1087 // ============================================================================ 1088 1089 @Override 1090 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 1091 { 1092 if (DBG) { 1093 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 1094 + " duration=" + duration); 1095 } 1096 1097 if (pkg == null || callback == null) { 1098 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 1099 return ; 1100 } 1101 1102 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); 1103 1104 if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { 1105 if (!isSystemToast) { 1106 Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); 1107 return; 1108 } 1109 } 1110 1111 synchronized (mToastQueue) { 1112 int callingPid = Binder.getCallingPid(); 1113 long callingId = Binder.clearCallingIdentity(); 1114 try { 1115 ToastRecord record; 1116 int index = indexOfToastLocked(pkg, callback); 1117 // If it's already in the queue, we update it in place, we don't 1118 // move it to the end of the queue. 1119 if (index >= 0) { 1120 record = mToastQueue.get(index); 1121 record.update(duration); 1122 } else { 1123 // Limit the number of toasts that any given package except the android 1124 // package can enqueue. Prevents DOS attacks and deals with leaks. 1125 if (!isSystemToast) { 1126 int count = 0; 1127 final int N = mToastQueue.size(); 1128 for (int i=0; i<N; i++) { 1129 final ToastRecord r = mToastQueue.get(i); 1130 if (r.pkg.equals(pkg)) { 1131 count++; 1132 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1133 Slog.e(TAG, "Package has already posted " + count 1134 + " toasts. Not showing more. Package=" + pkg); 1135 return; 1136 } 1137 } 1138 } 1139 } 1140 1141 record = new ToastRecord(callingPid, pkg, callback, duration); 1142 mToastQueue.add(record); 1143 index = mToastQueue.size() - 1; 1144 keepProcessAliveLocked(callingPid); 1145 } 1146 // If it's at index 0, it's the current toast. It doesn't matter if it's 1147 // new or just been updated. Call back and tell it to show itself. 1148 // If the callback fails, this will remove it from the list, so don't 1149 // assume that it's valid after this. 1150 if (index == 0) { 1151 showNextToastLocked(); 1152 } 1153 } finally { 1154 Binder.restoreCallingIdentity(callingId); 1155 } 1156 } 1157 } 1158 1159 @Override 1160 public void cancelToast(String pkg, ITransientNotification callback) { 1161 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 1162 1163 if (pkg == null || callback == null) { 1164 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 1165 return ; 1166 } 1167 1168 synchronized (mToastQueue) { 1169 long callingId = Binder.clearCallingIdentity(); 1170 try { 1171 int index = indexOfToastLocked(pkg, callback); 1172 if (index >= 0) { 1173 cancelToastLocked(index); 1174 } else { 1175 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 1176 + " callback=" + callback); 1177 } 1178 } finally { 1179 Binder.restoreCallingIdentity(callingId); 1180 } 1181 } 1182 } 1183 1184 @Override 1185 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 1186 Notification notification, int[] idOut, int userId) throws RemoteException { 1187 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 1188 Binder.getCallingPid(), tag, id, notification, idOut, userId); 1189 } 1190 1191 @Override 1192 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1193 checkCallerIsSystemOrSameApp(pkg); 1194 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1195 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1196 // Don't allow client applications to cancel foreground service notis. 1197 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1198 Binder.getCallingUid() == Process.SYSTEM_UID 1199 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL, 1200 null); 1201 } 1202 1203 @Override 1204 public void cancelAllNotifications(String pkg, int userId) { 1205 checkCallerIsSystemOrSameApp(pkg); 1206 1207 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1208 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1209 1210 // Calling from user space, don't allow the canceling of actively 1211 // running foreground services. 1212 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1213 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1214 REASON_NOMAN_CANCEL_ALL, null); 1215 } 1216 1217 @Override 1218 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1219 checkCallerIsSystem(); 1220 1221 setNotificationsEnabledForPackageImpl(pkg, uid, enabled); 1222 } 1223 1224 /** 1225 * Use this when you just want to know if notifications are OK for this package. 1226 */ 1227 @Override 1228 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1229 checkCallerIsSystem(); 1230 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 1231 == AppOpsManager.MODE_ALLOWED); 1232 } 1233 1234 @Override 1235 public void setPackagePriority(String pkg, int uid, int priority) { 1236 checkCallerIsSystem(); 1237 mRankingHelper.setPackagePriority(pkg, uid, priority); 1238 savePolicyFile(); 1239 } 1240 1241 @Override 1242 public int getPackagePriority(String pkg, int uid) { 1243 checkCallerIsSystem(); 1244 return mRankingHelper.getPackagePriority(pkg, uid); 1245 } 1246 1247 @Override 1248 public void setPackagePeekable(String pkg, int uid, boolean peekable) { 1249 checkCallerIsSystem(); 1250 1251 mRankingHelper.setPackagePeekable(pkg, uid, peekable); 1252 } 1253 1254 @Override 1255 public boolean getPackagePeekable(String pkg, int uid) { 1256 checkCallerIsSystem(); 1257 return mRankingHelper.getPackagePeekable(pkg, uid); 1258 } 1259 1260 @Override 1261 public void setPackageVisibilityOverride(String pkg, int uid, int visibility) { 1262 checkCallerIsSystem(); 1263 mRankingHelper.setPackageVisibilityOverride(pkg, uid, visibility); 1264 savePolicyFile(); 1265 } 1266 1267 @Override 1268 public int getPackageVisibilityOverride(String pkg, int uid) { 1269 checkCallerIsSystem(); 1270 return mRankingHelper.getPackageVisibilityOverride(pkg, uid); 1271 } 1272 1273 /** 1274 * System-only API for getting a list of current (i.e. not cleared) notifications. 1275 * 1276 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1277 * @returns A list of all the notifications, in natural order. 1278 */ 1279 @Override 1280 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1281 // enforce() will ensure the calling uid has the correct permission 1282 getContext().enforceCallingOrSelfPermission( 1283 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1284 "NotificationManagerService.getActiveNotifications"); 1285 1286 StatusBarNotification[] tmp = null; 1287 int uid = Binder.getCallingUid(); 1288 1289 // noteOp will check to make sure the callingPkg matches the uid 1290 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1291 == AppOpsManager.MODE_ALLOWED) { 1292 synchronized (mNotificationList) { 1293 tmp = new StatusBarNotification[mNotificationList.size()]; 1294 final int N = mNotificationList.size(); 1295 for (int i=0; i<N; i++) { 1296 tmp[i] = mNotificationList.get(i).sbn; 1297 } 1298 } 1299 } 1300 return tmp; 1301 } 1302 1303 /** 1304 * Public API for getting a list of current notifications for the calling package/uid. 1305 * 1306 * @returns A list of all the package's notifications, in natural order. 1307 */ 1308 @Override 1309 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 1310 int incomingUserId) { 1311 checkCallerIsSystemOrSameApp(pkg); 1312 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1313 Binder.getCallingUid(), incomingUserId, true, false, 1314 "getAppActiveNotifications", pkg); 1315 1316 final int N = mNotificationList.size(); 1317 final ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>(N); 1318 1319 synchronized (mNotificationList) { 1320 for (int i = 0; i < N; i++) { 1321 final StatusBarNotification sbn = mNotificationList.get(i).sbn; 1322 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) { 1323 // We could pass back a cloneLight() but clients might get confused and 1324 // try to send this thing back to notify() again, which would not work 1325 // very well. 1326 final StatusBarNotification sbnOut = new StatusBarNotification( 1327 sbn.getPackageName(), 1328 sbn.getOpPkg(), 1329 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 1330 0, // hide score from apps 1331 sbn.getNotification().clone(), 1332 sbn.getUser(), sbn.getPostTime()); 1333 list.add(sbnOut); 1334 } 1335 } 1336 } 1337 1338 return new ParceledListSlice<StatusBarNotification>(list); 1339 } 1340 1341 /** 1342 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1343 * 1344 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1345 */ 1346 @Override 1347 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1348 // enforce() will ensure the calling uid has the correct permission 1349 getContext().enforceCallingOrSelfPermission( 1350 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1351 "NotificationManagerService.getHistoricalNotifications"); 1352 1353 StatusBarNotification[] tmp = null; 1354 int uid = Binder.getCallingUid(); 1355 1356 // noteOp will check to make sure the callingPkg matches the uid 1357 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1358 == AppOpsManager.MODE_ALLOWED) { 1359 synchronized (mArchive) { 1360 tmp = mArchive.getArray(count); 1361 } 1362 } 1363 return tmp; 1364 } 1365 1366 /** 1367 * Register a listener binder directly with the notification manager. 1368 * 1369 * Only works with system callers. Apps should extend 1370 * {@link android.service.notification.NotificationListenerService}. 1371 */ 1372 @Override 1373 public void registerListener(final INotificationListener listener, 1374 final ComponentName component, final int userid) { 1375 enforceSystemOrSystemUI("INotificationManager.registerListener"); 1376 mListeners.registerService(listener, component, userid); 1377 } 1378 1379 /** 1380 * Remove a listener binder directly 1381 */ 1382 @Override 1383 public void unregisterListener(INotificationListener listener, int userid) { 1384 mListeners.unregisterService(listener, userid); 1385 } 1386 1387 /** 1388 * Allow an INotificationListener to simulate a "clear all" operation. 1389 * 1390 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1391 * 1392 * @param token The binder for the listener, to check that the caller is allowed 1393 */ 1394 @Override 1395 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1396 final int callingUid = Binder.getCallingUid(); 1397 final int callingPid = Binder.getCallingPid(); 1398 long identity = Binder.clearCallingIdentity(); 1399 try { 1400 synchronized (mNotificationList) { 1401 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1402 if (keys != null) { 1403 final int N = keys.length; 1404 for (int i = 0; i < N; i++) { 1405 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1406 if (r == null) continue; 1407 final int userId = r.sbn.getUserId(); 1408 if (userId != info.userid && userId != UserHandle.USER_ALL && 1409 !mUserProfiles.isCurrentProfile(userId)) { 1410 throw new SecurityException("Disallowed call from listener: " 1411 + info.service); 1412 } 1413 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1414 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 1415 userId); 1416 } 1417 } else { 1418 cancelAllLocked(callingUid, callingPid, info.userid, 1419 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 1420 } 1421 } 1422 } finally { 1423 Binder.restoreCallingIdentity(identity); 1424 } 1425 } 1426 1427 @Override 1428 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 1429 final int callingUid = Binder.getCallingUid(); 1430 final int callingPid = Binder.getCallingPid(); 1431 long identity = Binder.clearCallingIdentity(); 1432 try { 1433 synchronized (mNotificationList) { 1434 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1435 if (keys != null) { 1436 final int N = keys.length; 1437 for (int i = 0; i < N; i++) { 1438 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1439 if (r == null) continue; 1440 final int userId = r.sbn.getUserId(); 1441 if (userId != info.userid && userId != UserHandle.USER_ALL && 1442 !mUserProfiles.isCurrentProfile(userId)) { 1443 throw new SecurityException("Disallowed call from listener: " 1444 + info.service); 1445 } 1446 if (!r.isSeen()) { 1447 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 1448 mAppUsageStats.reportEvent(r.sbn.getPackageName(), 1449 userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER 1450 : userId, 1451 UsageEvents.Event.INTERACTION); 1452 r.setSeen(); 1453 } 1454 } 1455 } 1456 } 1457 } finally { 1458 Binder.restoreCallingIdentity(identity); 1459 } 1460 } 1461 1462 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 1463 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 1464 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 1465 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 1466 true, 1467 userId, REASON_LISTENER_CANCEL, info); 1468 } 1469 1470 /** 1471 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 1472 * 1473 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 1474 * 1475 * @param token The binder for the listener, to check that the caller is allowed 1476 */ 1477 @Override 1478 public void cancelNotificationFromListener(INotificationListener token, String pkg, 1479 String tag, int id) { 1480 final int callingUid = Binder.getCallingUid(); 1481 final int callingPid = Binder.getCallingPid(); 1482 long identity = Binder.clearCallingIdentity(); 1483 try { 1484 synchronized (mNotificationList) { 1485 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1486 if (info.supportsProfiles()) { 1487 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 1488 + "from " + info.component 1489 + " use cancelNotification(key) instead."); 1490 } else { 1491 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1492 pkg, tag, id, info.userid); 1493 } 1494 } 1495 } finally { 1496 Binder.restoreCallingIdentity(identity); 1497 } 1498 } 1499 1500 /** 1501 * Allow an INotificationListener to request the list of outstanding notifications seen by 1502 * the current user. Useful when starting up, after which point the listener callbacks 1503 * should be used. 1504 * 1505 * @param token The binder for the listener, to check that the caller is allowed 1506 * @param keys An array of notification keys to fetch, or null to fetch everything 1507 * @returns The return value will contain the notifications specified in keys, in that 1508 * order, or if keys is null, all the notifications, in natural order. 1509 */ 1510 @Override 1511 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 1512 INotificationListener token, String[] keys, int trim) { 1513 synchronized (mNotificationList) { 1514 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1515 final boolean getKeys = keys != null; 1516 final int N = getKeys ? keys.length : mNotificationList.size(); 1517 final ArrayList<StatusBarNotification> list 1518 = new ArrayList<StatusBarNotification>(N); 1519 for (int i=0; i<N; i++) { 1520 final NotificationRecord r = getKeys 1521 ? mNotificationsByKey.get(keys[i]) 1522 : mNotificationList.get(i); 1523 if (r == null) continue; 1524 StatusBarNotification sbn = r.sbn; 1525 if (!isVisibleToListener(sbn, info)) continue; 1526 StatusBarNotification sbnToSend = 1527 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 1528 list.add(sbnToSend); 1529 } 1530 return new ParceledListSlice<StatusBarNotification>(list); 1531 } 1532 } 1533 1534 @Override 1535 public void requestHintsFromListener(INotificationListener token, int hints) { 1536 final long identity = Binder.clearCallingIdentity(); 1537 try { 1538 synchronized (mNotificationList) { 1539 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1540 final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0; 1541 if (disableEffects) { 1542 mListenersDisablingEffects.add(info); 1543 } else { 1544 mListenersDisablingEffects.remove(info); 1545 } 1546 updateListenerHintsLocked(); 1547 updateEffectsSuppressorLocked(); 1548 } 1549 } finally { 1550 Binder.restoreCallingIdentity(identity); 1551 } 1552 } 1553 1554 @Override 1555 public int getHintsFromListener(INotificationListener token) { 1556 synchronized (mNotificationList) { 1557 return mListenerHints; 1558 } 1559 } 1560 1561 @Override 1562 public void requestInterruptionFilterFromListener(INotificationListener token, 1563 int interruptionFilter) throws RemoteException { 1564 final long identity = Binder.clearCallingIdentity(); 1565 try { 1566 synchronized (mNotificationList) { 1567 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1568 mZenModeHelper.requestFromListener(info.component, interruptionFilter); 1569 updateInterruptionFilterLocked(); 1570 } 1571 } finally { 1572 Binder.restoreCallingIdentity(identity); 1573 } 1574 } 1575 1576 @Override 1577 public int getInterruptionFilterFromListener(INotificationListener token) 1578 throws RemoteException { 1579 synchronized (mNotificationLight) { 1580 return mInterruptionFilter; 1581 } 1582 } 1583 1584 @Override 1585 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 1586 throws RemoteException { 1587 synchronized (mNotificationList) { 1588 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1589 if (info == null) return; 1590 mListeners.setOnNotificationPostedTrimLocked(info, trim); 1591 } 1592 } 1593 1594 @Override 1595 public int getZenMode() { 1596 return mZenModeHelper.getZenMode(); 1597 } 1598 1599 @Override 1600 public ZenModeConfig getZenModeConfig() { 1601 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig"); 1602 return mZenModeHelper.getConfig(); 1603 } 1604 1605 @Override 1606 public boolean setZenModeConfig(ZenModeConfig config, String reason) { 1607 checkCallerIsSystem(); 1608 return mZenModeHelper.setConfig(config, reason); 1609 } 1610 1611 @Override 1612 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { 1613 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode"); 1614 final long identity = Binder.clearCallingIdentity(); 1615 try { 1616 mZenModeHelper.setManualZenMode(mode, conditionId, reason); 1617 } finally { 1618 Binder.restoreCallingIdentity(identity); 1619 } 1620 } 1621 1622 @Override 1623 public void setInterruptionFilter(String pkg, int filter) throws RemoteException { 1624 enforcePolicyAccess(pkg, "setInterruptionFilter"); 1625 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 1626 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 1627 final long identity = Binder.clearCallingIdentity(); 1628 try { 1629 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter"); 1630 } finally { 1631 Binder.restoreCallingIdentity(identity); 1632 } 1633 } 1634 1635 @Override 1636 public void notifyConditions(final String pkg, IConditionProvider provider, 1637 final Condition[] conditions) { 1638 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 1639 checkCallerIsSystemOrSameApp(pkg); 1640 mHandler.post(new Runnable() { 1641 @Override 1642 public void run() { 1643 mConditionProviders.notifyConditions(pkg, info, conditions); 1644 } 1645 }); 1646 } 1647 1648 @Override 1649 public void requestZenModeConditions(IConditionListener callback, int relevance) { 1650 enforceSystemOrSystemUIOrVolume("INotificationManager.requestZenModeConditions"); 1651 mZenModeHelper.requestZenModeConditions(callback, relevance); 1652 } 1653 1654 private void enforceSystemOrSystemUIOrVolume(String message) { 1655 if (mAudioManagerInternal != null) { 1656 final int vcuid = mAudioManagerInternal.getVolumeControllerUid(); 1657 if (vcuid > 0 && Binder.getCallingUid() == vcuid) { 1658 return; 1659 } 1660 } 1661 enforceSystemOrSystemUI(message); 1662 } 1663 1664 private void enforceSystemOrSystemUI(String message) { 1665 if (isCallerSystem()) return; 1666 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 1667 message); 1668 } 1669 1670 private void enforcePolicyAccess(String pkg, String method) { 1671 if (!checkPolicyAccess(pkg)) { 1672 Slog.w(TAG, "Notification policy access denied calling " + method); 1673 throw new SecurityException("Notification policy access denied"); 1674 } 1675 } 1676 1677 private boolean checkPackagePolicyAccess(String pkg) { 1678 return Boolean.TRUE.equals(mPolicyAccess.get(pkg)); 1679 } 1680 1681 private boolean checkPolicyAccess(String pkg) { 1682 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg); 1683 } 1684 1685 @Override 1686 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1687 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1688 != PackageManager.PERMISSION_GRANTED) { 1689 pw.println("Permission Denial: can't dump NotificationManager from pid=" 1690 + Binder.getCallingPid() 1691 + ", uid=" + Binder.getCallingUid()); 1692 return; 1693 } 1694 1695 dumpImpl(pw, DumpFilter.parseFromArguments(args)); 1696 } 1697 1698 @Override 1699 public ComponentName getEffectsSuppressor() { 1700 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor"); 1701 return mEffectsSuppressor; 1702 } 1703 1704 @Override 1705 public boolean matchesCallFilter(Bundle extras) { 1706 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 1707 return mZenModeHelper.matchesCallFilter( 1708 UserHandle.getCallingUserHandle(), 1709 extras, 1710 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 1711 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 1712 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); 1713 } 1714 1715 @Override 1716 public boolean isSystemConditionProviderEnabled(String path) { 1717 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled"); 1718 return mConditionProviders.isSystemProviderEnabled(path); 1719 } 1720 1721 // Backup/restore interface 1722 @Override 1723 public byte[] getBackupPayload(int user) { 1724 // TODO: build a payload of whatever is appropriate 1725 return null; 1726 } 1727 1728 @Override 1729 public void applyRestore(byte[] payload, int user) { 1730 // TODO: apply the restored payload as new current state 1731 } 1732 1733 @Override 1734 public void requestNotificationPolicyAccess(String pkg, 1735 INotificationManagerCallback callback) throws RemoteException { 1736 if (callback == null) { 1737 Slog.w(TAG, "requestNotificationPolicyAccess: no callback specified"); 1738 return; 1739 } 1740 if (pkg == null) { 1741 Slog.w(TAG, "requestNotificationPolicyAccess denied: no package specified"); 1742 callback.onPolicyRequestResult(false); 1743 return; 1744 } 1745 final long identity = Binder.clearCallingIdentity(); 1746 try { 1747 synchronized (mNotificationList) { 1748 // immediately grant for now 1749 mPolicyAccess.put(pkg, true); 1750 if (DBG) Slog.w(TAG, "requestNotificationPolicyAccess granted for " + pkg); 1751 } 1752 } finally { 1753 Binder.restoreCallingIdentity(identity); 1754 } 1755 callback.onPolicyRequestResult(true); 1756 } 1757 1758 @Override 1759 public boolean isNotificationPolicyAccessGranted(String pkg) { 1760 return checkPolicyAccess(pkg); 1761 } 1762 1763 @Override 1764 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { 1765 enforceSystemOrSystemUI("request policy access status for another package"); 1766 return checkPackagePolicyAccess(pkg); 1767 } 1768 1769 @Override 1770 public String[] getPackagesRequestingNotificationPolicyAccess() 1771 throws RemoteException { 1772 enforceSystemOrSystemUI("request policy access packages"); 1773 final long identity = Binder.clearCallingIdentity(); 1774 try { 1775 synchronized (mNotificationList) { 1776 final String[] rt = new String[mPolicyAccess.size()]; 1777 for (int i = 0; i < mPolicyAccess.size(); i++) { 1778 rt[i] = mPolicyAccess.keyAt(i); 1779 } 1780 return rt; 1781 } 1782 } finally { 1783 Binder.restoreCallingIdentity(identity); 1784 } 1785 } 1786 1787 @Override 1788 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 1789 throws RemoteException { 1790 enforceSystemOrSystemUI("grant notification policy access"); 1791 final long identity = Binder.clearCallingIdentity(); 1792 try { 1793 synchronized (mNotificationList) { 1794 mPolicyAccess.put(pkg, granted); 1795 } 1796 } finally { 1797 Binder.restoreCallingIdentity(identity); 1798 } 1799 } 1800 1801 @Override 1802 public Policy getNotificationPolicy(String pkg) { 1803 enforcePolicyAccess(pkg, "getNotificationPolicy"); 1804 final long identity = Binder.clearCallingIdentity(); 1805 try { 1806 return mZenModeHelper.getNotificationPolicy(); 1807 } finally { 1808 Binder.restoreCallingIdentity(identity); 1809 } 1810 } 1811 1812 @Override 1813 public void setNotificationPolicy(String pkg, Policy policy) { 1814 enforcePolicyAccess(pkg, "setNotificationPolicy"); 1815 final long identity = Binder.clearCallingIdentity(); 1816 try { 1817 mZenModeHelper.setNotificationPolicy(policy); 1818 } finally { 1819 Binder.restoreCallingIdentity(identity); 1820 } 1821 } 1822 }; 1823 1824 private String disableNotificationEffects(NotificationRecord record) { 1825 if (mDisableNotificationEffects) { 1826 return "booleanState"; 1827 } 1828 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 1829 return "listenerHints"; 1830 } 1831 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 1832 return "callState"; 1833 } 1834 return null; 1835 } 1836 1837 void dumpImpl(PrintWriter pw, DumpFilter filter) { 1838 pw.print("Current Notification Manager state"); 1839 if (filter != null) { 1840 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 1841 } 1842 pw.println(':'); 1843 int N; 1844 final boolean zenOnly = filter != null && filter.zen; 1845 1846 if (!zenOnly) { 1847 synchronized (mToastQueue) { 1848 N = mToastQueue.size(); 1849 if (N > 0) { 1850 pw.println(" Toast Queue:"); 1851 for (int i=0; i<N; i++) { 1852 mToastQueue.get(i).dump(pw, " ", filter); 1853 } 1854 pw.println(" "); 1855 } 1856 } 1857 } 1858 1859 synchronized (mNotificationList) { 1860 if (!zenOnly) { 1861 N = mNotificationList.size(); 1862 if (N > 0) { 1863 pw.println(" Notification List:"); 1864 for (int i=0; i<N; i++) { 1865 final NotificationRecord nr = mNotificationList.get(i); 1866 if (filter != null && !filter.matches(nr.sbn)) continue; 1867 nr.dump(pw, " ", getContext()); 1868 } 1869 pw.println(" "); 1870 } 1871 1872 if (filter == null) { 1873 N = mLights.size(); 1874 if (N > 0) { 1875 pw.println(" Lights List:"); 1876 for (int i=0; i<N; i++) { 1877 if (i == N - 1) { 1878 pw.print(" > "); 1879 } else { 1880 pw.print(" "); 1881 } 1882 pw.println(mLights.get(i)); 1883 } 1884 pw.println(" "); 1885 } 1886 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 1887 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 1888 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 1889 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 1890 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 1891 pw.println(" mCallState=" + callStateToString(mCallState)); 1892 pw.println(" mSystemReady=" + mSystemReady); 1893 } 1894 pw.println(" mArchive=" + mArchive.toString()); 1895 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 1896 int i=0; 1897 while (iter.hasNext()) { 1898 final StatusBarNotification sbn = iter.next(); 1899 if (filter != null && !filter.matches(sbn)) continue; 1900 pw.println(" " + sbn); 1901 if (++i >= 5) { 1902 if (iter.hasNext()) pw.println(" ..."); 1903 break; 1904 } 1905 } 1906 } 1907 1908 if (!zenOnly) { 1909 pw.println("\n Usage Stats:"); 1910 mUsageStats.dump(pw, " ", filter); 1911 } 1912 1913 if (filter == null || zenOnly) { 1914 pw.println("\n Zen Mode:"); 1915 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 1916 mZenModeHelper.dump(pw, " "); 1917 1918 pw.println("\n Zen Log:"); 1919 ZenLog.dump(pw, " "); 1920 } 1921 1922 if (!zenOnly) { 1923 pw.println("\n Ranking Config:"); 1924 mRankingHelper.dump(pw, " ", filter); 1925 1926 pw.println("\n Notification listeners:"); 1927 mListeners.dump(pw, filter); 1928 pw.print(" mListenerHints: "); pw.println(mListenerHints); 1929 pw.print(" mListenersDisablingEffects: ("); 1930 N = mListenersDisablingEffects.size(); 1931 for (int i = 0; i < N; i++) { 1932 final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i); 1933 if (i > 0) pw.print(','); 1934 pw.print(listener.component); 1935 } 1936 pw.println(')'); 1937 } 1938 pw.println("\n Policy access:"); 1939 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); 1940 1941 pw.println("\n Condition providers:"); 1942 mConditionProviders.dump(pw, filter); 1943 1944 pw.println("\n Group summaries:"); 1945 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 1946 NotificationRecord r = entry.getValue(); 1947 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 1948 if (mNotificationsByKey.get(r.getKey()) != r) { 1949 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 1950 r.dump(pw, " ", getContext()); 1951 } 1952 } 1953 } 1954 } 1955 1956 /** 1957 * The private API only accessible to the system process. 1958 */ 1959 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 1960 @Override 1961 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 1962 String tag, int id, Notification notification, int[] idReceived, int userId) { 1963 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 1964 idReceived, userId); 1965 } 1966 1967 @Override 1968 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 1969 int userId) { 1970 checkCallerIsSystem(); 1971 synchronized (mNotificationList) { 1972 int i = indexOfNotificationLocked(pkg, null, notificationId, userId); 1973 if (i < 0) { 1974 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with " 1975 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId); 1976 return; 1977 } 1978 NotificationRecord r = mNotificationList.get(i); 1979 StatusBarNotification sbn = r.sbn; 1980 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 1981 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE, 1982 // we have to revert to the flags we received initially *and* force remove 1983 // FLAG_FOREGROUND_SERVICE. 1984 sbn.getNotification().flags = 1985 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE); 1986 mRankingHelper.sort(mNotificationList); 1987 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */); 1988 } 1989 } 1990 }; 1991 1992 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 1993 final int callingPid, final String tag, final int id, final Notification notification, 1994 int[] idOut, int incomingUserId) { 1995 if (DBG) { 1996 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 1997 + " notification=" + notification); 1998 } 1999 checkCallerIsSystemOrSameApp(pkg); 2000 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 2001 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 2002 2003 final int userId = ActivityManager.handleIncomingUser(callingPid, 2004 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 2005 final UserHandle user = new UserHandle(userId); 2006 2007 // Limit the number of notifications that any given package except the android 2008 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 2009 if (!isSystemNotification && !isNotificationFromListener) { 2010 synchronized (mNotificationList) { 2011 int count = 0; 2012 final int N = mNotificationList.size(); 2013 for (int i=0; i<N; i++) { 2014 final NotificationRecord r = mNotificationList.get(i); 2015 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 2016 count++; 2017 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2018 Slog.e(TAG, "Package has already posted " + count 2019 + " notifications. Not showing more. package=" + pkg); 2020 return; 2021 } 2022 } 2023 } 2024 } 2025 } 2026 2027 if (pkg == null || notification == null) { 2028 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 2029 + " id=" + id + " notification=" + notification); 2030 } 2031 2032 if (notification.getSmallIcon() != null) { 2033 if (!notification.isValid()) { 2034 throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg 2035 + " id=" + id + " notification=" + notification); 2036 } 2037 } 2038 2039 mHandler.post(new Runnable() { 2040 @Override 2041 public void run() { 2042 2043 synchronized (mNotificationList) { 2044 2045 // === Scoring === 2046 2047 // 0. Sanitize inputs 2048 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 2049 Notification.PRIORITY_MAX); 2050 // Migrate notification flags to scores 2051 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { 2052 if (notification.priority < Notification.PRIORITY_MAX) { 2053 notification.priority = Notification.PRIORITY_MAX; 2054 } 2055 } else if (SCORE_ONGOING_HIGHER && 2056 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { 2057 if (notification.priority < Notification.PRIORITY_HIGH) { 2058 notification.priority = Notification.PRIORITY_HIGH; 2059 } 2060 } 2061 // force no heads up per package config 2062 if (!mRankingHelper.getPackagePeekable(pkg, callingUid)) { 2063 if (notification.extras == null) { 2064 notification.extras = new Bundle(); 2065 } 2066 notification.extras.putInt(Notification.EXTRA_AS_HEADS_UP, 2067 Notification.HEADS_UP_NEVER); 2068 } 2069 2070 // 1. initial score: buckets of 10, around the app [-20..20] 2071 final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; 2072 2073 // 2. extract ranking signals from the notification data 2074 final StatusBarNotification n = new StatusBarNotification( 2075 pkg, opPkg, id, tag, callingUid, callingPid, score, notification, 2076 user); 2077 NotificationRecord r = new NotificationRecord(n, score); 2078 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 2079 if (old != null) { 2080 // Retain ranking information from previous record 2081 r.copyRankingInformation(old); 2082 } 2083 2084 // Handle grouped notifications and bail out early if we 2085 // can to avoid extracting signals. 2086 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 2087 boolean ignoreNotification = 2088 removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid); 2089 2090 // This conditional is a dirty hack to limit the logging done on 2091 // behalf of the download manager without affecting other apps. 2092 if (!pkg.equals("com.android.providers.downloads") 2093 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 2094 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 2095 if (ignoreNotification) { 2096 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; 2097 } else if (old != null) { 2098 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 2099 } 2100 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 2101 pkg, id, tag, userId, notification.toString(), 2102 enqueueStatus); 2103 } 2104 2105 if (ignoreNotification) { 2106 return; 2107 } 2108 2109 mRankingHelper.extractSignals(r); 2110 2111 // 3. Apply local rules 2112 2113 // blocked apps 2114 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { 2115 if (!isSystemNotification) { 2116 r.score = JUNK_SCORE; 2117 Slog.e(TAG, "Suppressing notification from package " + pkg 2118 + " by user request."); 2119 } 2120 } 2121 2122 if (r.score < SCORE_DISPLAY_THRESHOLD) { 2123 // Notification will be blocked because the score is too low. 2124 return; 2125 } 2126 2127 int index = indexOfNotificationLocked(n.getKey()); 2128 if (index < 0) { 2129 mNotificationList.add(r); 2130 mUsageStats.registerPostedByApp(r); 2131 } else { 2132 old = mNotificationList.get(index); 2133 mNotificationList.set(index, r); 2134 mUsageStats.registerUpdatedByApp(r, old); 2135 // Make sure we don't lose the foreground service state. 2136 notification.flags |= 2137 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 2138 r.isUpdate = true; 2139 } 2140 2141 mNotificationsByKey.put(n.getKey(), r); 2142 2143 // Ensure if this is a foreground service that the proper additional 2144 // flags are set. 2145 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 2146 notification.flags |= Notification.FLAG_ONGOING_EVENT 2147 | Notification.FLAG_NO_CLEAR; 2148 } 2149 2150 applyZenModeLocked(r); 2151 mRankingHelper.sort(mNotificationList); 2152 2153 if (notification.getSmallIcon() != null) { 2154 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 2155 mListeners.notifyPostedLocked(n, oldSbn); 2156 } else { 2157 Slog.e(TAG, "Not posting notification without small icon: " + notification); 2158 if (old != null && !old.isCanceled) { 2159 mListeners.notifyRemovedLocked(n); 2160 } 2161 // ATTENTION: in a future release we will bail out here 2162 // so that we do not play sounds, show lights, etc. for invalid 2163 // notifications 2164 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 2165 + n.getPackageName()); 2166 } 2167 2168 buzzBeepBlinkLocked(r); 2169 } 2170 } 2171 }); 2172 2173 idOut[0] = id; 2174 } 2175 2176 /** 2177 * Ensures that grouped notification receive their special treatment. 2178 * 2179 * <p>Cancels group children if the new notification causes a group to lose 2180 * its summary.</p> 2181 * 2182 * <p>Updates mSummaryByGroupKey.</p> 2183 */ 2184 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 2185 int callingUid, int callingPid) { 2186 StatusBarNotification sbn = r.sbn; 2187 Notification n = sbn.getNotification(); 2188 String group = sbn.getGroupKey(); 2189 boolean isSummary = n.isGroupSummary(); 2190 2191 Notification oldN = old != null ? old.sbn.getNotification() : null; 2192 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 2193 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 2194 2195 if (oldIsSummary) { 2196 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 2197 if (removedSummary != old) { 2198 String removedKey = 2199 removedSummary != null ? removedSummary.getKey() : "<null>"; 2200 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 2201 ", removed=" + removedKey); 2202 } 2203 } 2204 if (isSummary) { 2205 mSummaryByGroupKey.put(group, r); 2206 } 2207 2208 // Clear out group children of the old notification if the update 2209 // causes the group summary to go away. This happens when the old 2210 // notification was a summary and the new one isn't, or when the old 2211 // notification was a summary and its group key changed. 2212 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 2213 cancelGroupChildrenLocked(old, callingUid, callingPid, null, 2214 REASON_GROUP_SUMMARY_CANCELED); 2215 } 2216 } 2217 2218 /** 2219 * Performs group notification optimizations if SysUI is the only active 2220 * notification listener and returns whether the given notification should 2221 * be ignored. 2222 * 2223 * <p>Returns true if the given notification is a child of a group with a 2224 * summary, which means that SysUI will never show it, and hence the new 2225 * notification can be safely ignored. Also cancels any previous instance 2226 * of the ignored notification.</p> 2227 * 2228 * <p>For summaries, cancels all children of that group, as SysUI will 2229 * never show them anymore.</p> 2230 * 2231 * @return true if the given notification can be ignored as an optimization 2232 */ 2233 private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r, 2234 NotificationRecord old, int callingUid, int callingPid) { 2235 if (!ENABLE_CHILD_NOTIFICATIONS) { 2236 // No optimizations are possible if listeners want groups. 2237 if (mListeners.notificationGroupsDesired()) { 2238 return false; 2239 } 2240 2241 StatusBarNotification sbn = r.sbn; 2242 String group = sbn.getGroupKey(); 2243 boolean isSummary = sbn.getNotification().isGroupSummary(); 2244 boolean isChild = sbn.getNotification().isGroupChild(); 2245 2246 NotificationRecord summary = mSummaryByGroupKey.get(group); 2247 if (isChild && summary != null) { 2248 // Child with an active summary -> ignore 2249 if (DBG) { 2250 Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary " 2251 + summary.getKey()); 2252 } 2253 // Make sure we don't leave an old version of the notification around. 2254 if (old != null) { 2255 if (DBG) { 2256 Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey()); 2257 } 2258 cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION); 2259 } 2260 return true; 2261 } else if (isSummary) { 2262 // Summary -> cancel children 2263 cancelGroupChildrenLocked(r, callingUid, callingPid, null, 2264 REASON_GROUP_OPTIMIZATION); 2265 } 2266 } 2267 return false; 2268 } 2269 2270 private void buzzBeepBlinkLocked(NotificationRecord record) { 2271 boolean buzzBeepBlinked = false; 2272 final Notification notification = record.sbn.getNotification(); 2273 2274 // Should this notification make noise, vibe, or use the LED? 2275 final boolean aboveThreshold = record.score >= SCORE_INTERRUPTION_THRESHOLD; 2276 final boolean canInterrupt = aboveThreshold && !record.isIntercepted(); 2277 if (DBG || record.isIntercepted()) 2278 Slog.v(TAG, 2279 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt + 2280 " intercept=" + record.isIntercepted() 2281 ); 2282 2283 final int currentUser; 2284 final long token = Binder.clearCallingIdentity(); 2285 try { 2286 currentUser = ActivityManager.getCurrentUser(); 2287 } finally { 2288 Binder.restoreCallingIdentity(token); 2289 } 2290 2291 // If we're not supposed to beep, vibrate, etc. then don't. 2292 final String disableEffects = disableNotificationEffects(record); 2293 if (disableEffects != null) { 2294 ZenLog.traceDisableEffects(record, disableEffects); 2295 } 2296 if (disableEffects == null 2297 && (!(record.isUpdate 2298 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) 2299 && (record.getUserId() == UserHandle.USER_ALL || 2300 record.getUserId() == currentUser || 2301 mUserProfiles.isCurrentProfile(record.getUserId())) 2302 && canInterrupt 2303 && mSystemReady 2304 && mAudioManager != null) { 2305 if (DBG) Slog.v(TAG, "Interrupting!"); 2306 2307 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 2308 2309 // sound 2310 2311 // should we use the default notification sound? (indicated either by 2312 // DEFAULT_SOUND or because notification.sound is pointing at 2313 // Settings.System.NOTIFICATION_SOUND) 2314 final boolean useDefaultSound = 2315 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2316 Settings.System.DEFAULT_NOTIFICATION_URI 2317 .equals(notification.sound); 2318 2319 Uri soundUri = null; 2320 boolean hasValidSound = false; 2321 2322 if (useDefaultSound) { 2323 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2324 2325 // check to see if the default notification sound is silent 2326 ContentResolver resolver = getContext().getContentResolver(); 2327 hasValidSound = Settings.System.getString(resolver, 2328 Settings.System.NOTIFICATION_SOUND) != null; 2329 } else if (notification.sound != null) { 2330 soundUri = notification.sound; 2331 hasValidSound = (soundUri != null); 2332 } 2333 2334 if (hasValidSound) { 2335 boolean looping = 2336 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2337 AudioAttributes audioAttributes = audioAttributesForNotification(notification); 2338 mSoundNotificationKey = record.getKey(); 2339 // do not play notifications if stream volume is 0 (typically because 2340 // ringer mode is silent) or if there is a user of exclusive audio focus 2341 if ((mAudioManager.getStreamVolume( 2342 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0) 2343 && !mAudioManager.isAudioFocusExclusive()) { 2344 final long identity = Binder.clearCallingIdentity(); 2345 try { 2346 final IRingtonePlayer player = 2347 mAudioManager.getRingtonePlayer(); 2348 if (player != null) { 2349 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2350 + " with attributes " + audioAttributes); 2351 player.playAsync(soundUri, record.sbn.getUser(), looping, 2352 audioAttributes); 2353 buzzBeepBlinked = true; 2354 } 2355 } catch (RemoteException e) { 2356 } finally { 2357 Binder.restoreCallingIdentity(identity); 2358 } 2359 } 2360 } 2361 2362 // vibrate 2363 // Does the notification want to specify its own vibration? 2364 final boolean hasCustomVibrate = notification.vibrate != null; 2365 2366 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2367 // mode, and no other vibration is specified, we fall back to vibration 2368 final boolean convertSoundToVibration = 2369 !hasCustomVibrate 2370 && hasValidSound 2371 && (mAudioManager.getRingerModeInternal() 2372 == AudioManager.RINGER_MODE_VIBRATE); 2373 2374 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2375 final boolean useDefaultVibrate = 2376 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2377 2378 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) 2379 && !(mAudioManager.getRingerModeInternal() 2380 == AudioManager.RINGER_MODE_SILENT)) { 2381 mVibrateNotificationKey = record.getKey(); 2382 2383 if (useDefaultVibrate || convertSoundToVibration) { 2384 // Escalate privileges so we can use the vibrator even if the 2385 // notifying app does not have the VIBRATE permission. 2386 long identity = Binder.clearCallingIdentity(); 2387 try { 2388 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2389 useDefaultVibrate ? mDefaultVibrationPattern 2390 : mFallbackVibrationPattern, 2391 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2392 ? 0: -1, audioAttributesForNotification(notification)); 2393 buzzBeepBlinked = true; 2394 } finally { 2395 Binder.restoreCallingIdentity(identity); 2396 } 2397 } else if (notification.vibrate.length > 1) { 2398 // If you want your own vibration pattern, you need the VIBRATE 2399 // permission 2400 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2401 notification.vibrate, 2402 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2403 ? 0: -1, audioAttributesForNotification(notification)); 2404 buzzBeepBlinked = true; 2405 } 2406 } 2407 } 2408 2409 // light 2410 // release the light 2411 boolean wasShowLights = mLights.remove(record.getKey()); 2412 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) { 2413 mLights.add(record.getKey()); 2414 updateLightsLocked(); 2415 if (mUseAttentionLight) { 2416 mAttentionLight.pulse(); 2417 } 2418 buzzBeepBlinked = true; 2419 } else if (wasShowLights) { 2420 updateLightsLocked(); 2421 } 2422 if (buzzBeepBlinked) { 2423 mHandler.post(mBuzzBeepBlinked); 2424 } 2425 } 2426 2427 private static AudioAttributes audioAttributesForNotification(Notification n) { 2428 if (n.audioAttributes != null 2429 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) { 2430 // the audio attributes are set and different from the default, use them 2431 return n.audioAttributes; 2432 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { 2433 // the stream type is valid, use it 2434 return new AudioAttributes.Builder() 2435 .setInternalLegacyStreamType(n.audioStreamType) 2436 .build(); 2437 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) { 2438 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2439 } else { 2440 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); 2441 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2442 } 2443 } 2444 2445 void showNextToastLocked() { 2446 ToastRecord record = mToastQueue.get(0); 2447 while (record != null) { 2448 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 2449 try { 2450 record.callback.show(); 2451 scheduleTimeoutLocked(record); 2452 return; 2453 } catch (RemoteException e) { 2454 Slog.w(TAG, "Object died trying to show notification " + record.callback 2455 + " in package " + record.pkg); 2456 // remove it from the list and let the process die 2457 int index = mToastQueue.indexOf(record); 2458 if (index >= 0) { 2459 mToastQueue.remove(index); 2460 } 2461 keepProcessAliveLocked(record.pid); 2462 if (mToastQueue.size() > 0) { 2463 record = mToastQueue.get(0); 2464 } else { 2465 record = null; 2466 } 2467 } 2468 } 2469 } 2470 2471 void cancelToastLocked(int index) { 2472 ToastRecord record = mToastQueue.get(index); 2473 try { 2474 record.callback.hide(); 2475 } catch (RemoteException e) { 2476 Slog.w(TAG, "Object died trying to hide notification " + record.callback 2477 + " in package " + record.pkg); 2478 // don't worry about this, we're about to remove it from 2479 // the list anyway 2480 } 2481 mToastQueue.remove(index); 2482 keepProcessAliveLocked(record.pid); 2483 if (mToastQueue.size() > 0) { 2484 // Show the next one. If the callback fails, this will remove 2485 // it from the list, so don't assume that the list hasn't changed 2486 // after this point. 2487 showNextToastLocked(); 2488 } 2489 } 2490 2491 private void scheduleTimeoutLocked(ToastRecord r) 2492 { 2493 mHandler.removeCallbacksAndMessages(r); 2494 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 2495 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 2496 mHandler.sendMessageDelayed(m, delay); 2497 } 2498 2499 private void handleTimeout(ToastRecord record) 2500 { 2501 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 2502 synchronized (mToastQueue) { 2503 int index = indexOfToastLocked(record.pkg, record.callback); 2504 if (index >= 0) { 2505 cancelToastLocked(index); 2506 } 2507 } 2508 } 2509 2510 // lock on mToastQueue 2511 int indexOfToastLocked(String pkg, ITransientNotification callback) 2512 { 2513 IBinder cbak = callback.asBinder(); 2514 ArrayList<ToastRecord> list = mToastQueue; 2515 int len = list.size(); 2516 for (int i=0; i<len; i++) { 2517 ToastRecord r = list.get(i); 2518 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 2519 return i; 2520 } 2521 } 2522 return -1; 2523 } 2524 2525 // lock on mToastQueue 2526 void keepProcessAliveLocked(int pid) 2527 { 2528 int toastCount = 0; // toasts from this pid 2529 ArrayList<ToastRecord> list = mToastQueue; 2530 int N = list.size(); 2531 for (int i=0; i<N; i++) { 2532 ToastRecord r = list.get(i); 2533 if (r.pid == pid) { 2534 toastCount++; 2535 } 2536 } 2537 try { 2538 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 2539 } catch (RemoteException e) { 2540 // Shouldn't happen. 2541 } 2542 } 2543 2544 private void handleRankingReconsideration(Message message) { 2545 if (!(message.obj instanceof RankingReconsideration)) return; 2546 RankingReconsideration recon = (RankingReconsideration) message.obj; 2547 recon.run(); 2548 boolean changed; 2549 synchronized (mNotificationList) { 2550 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 2551 if (record == null) { 2552 return; 2553 } 2554 int indexBefore = findNotificationRecordIndexLocked(record); 2555 boolean interceptBefore = record.isIntercepted(); 2556 int visibilityBefore = record.getPackageVisibilityOverride(); 2557 recon.applyChangesLocked(record); 2558 applyZenModeLocked(record); 2559 mRankingHelper.sort(mNotificationList); 2560 int indexAfter = findNotificationRecordIndexLocked(record); 2561 boolean interceptAfter = record.isIntercepted(); 2562 int visibilityAfter = record.getPackageVisibilityOverride(); 2563 changed = indexBefore != indexAfter || interceptBefore != interceptAfter 2564 || visibilityBefore != visibilityAfter; 2565 if (interceptBefore && !interceptAfter) { 2566 buzzBeepBlinkLocked(record); 2567 } 2568 } 2569 if (changed) { 2570 scheduleSendRankingUpdate(); 2571 } 2572 } 2573 2574 private void handleRankingConfigChange() { 2575 synchronized (mNotificationList) { 2576 final int N = mNotificationList.size(); 2577 ArrayList<String> orderBefore = new ArrayList<String>(N); 2578 int[] visibilities = new int[N]; 2579 for (int i = 0; i < N; i++) { 2580 final NotificationRecord r = mNotificationList.get(i); 2581 orderBefore.add(r.getKey()); 2582 visibilities[i] = r.getPackageVisibilityOverride(); 2583 mRankingHelper.extractSignals(r); 2584 } 2585 for (int i = 0; i < N; i++) { 2586 mRankingHelper.sort(mNotificationList); 2587 final NotificationRecord r = mNotificationList.get(i); 2588 if (!orderBefore.get(i).equals(r.getKey()) 2589 || visibilities[i] != r.getPackageVisibilityOverride()) { 2590 scheduleSendRankingUpdate(); 2591 return; 2592 } 2593 } 2594 } 2595 } 2596 2597 // let zen mode evaluate this record 2598 private void applyZenModeLocked(NotificationRecord record) { 2599 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 2600 } 2601 2602 // lock on mNotificationList 2603 private int findNotificationRecordIndexLocked(NotificationRecord target) { 2604 return mRankingHelper.indexOf(mNotificationList, target); 2605 } 2606 2607 private void scheduleSendRankingUpdate() { 2608 mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE); 2609 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 2610 mHandler.sendMessage(m); 2611 } 2612 2613 private void handleSendRankingUpdate() { 2614 synchronized (mNotificationList) { 2615 mListeners.notifyRankingUpdateLocked(); 2616 } 2617 } 2618 2619 private void scheduleListenerHintsChanged(int state) { 2620 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 2621 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 2622 } 2623 2624 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 2625 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 2626 mHandler.obtainMessage( 2627 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 2628 listenerInterruptionFilter, 2629 0).sendToTarget(); 2630 } 2631 2632 private void handleListenerHintsChanged(int hints) { 2633 synchronized (mNotificationList) { 2634 mListeners.notifyListenerHintsChangedLocked(hints); 2635 } 2636 } 2637 2638 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 2639 synchronized (mNotificationList) { 2640 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 2641 } 2642 } 2643 2644 private final class WorkerHandler extends Handler 2645 { 2646 @Override 2647 public void handleMessage(Message msg) 2648 { 2649 switch (msg.what) 2650 { 2651 case MESSAGE_TIMEOUT: 2652 handleTimeout((ToastRecord)msg.obj); 2653 break; 2654 case MESSAGE_SAVE_POLICY_FILE: 2655 handleSavePolicyFile(); 2656 break; 2657 case MESSAGE_SEND_RANKING_UPDATE: 2658 handleSendRankingUpdate(); 2659 break; 2660 case MESSAGE_LISTENER_HINTS_CHANGED: 2661 handleListenerHintsChanged(msg.arg1); 2662 break; 2663 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 2664 handleListenerInterruptionFilterChanged(msg.arg1); 2665 break; 2666 } 2667 } 2668 2669 } 2670 2671 private final class RankingWorkerHandler extends Handler 2672 { 2673 public RankingWorkerHandler(Looper looper) { 2674 super(looper); 2675 } 2676 2677 @Override 2678 public void handleMessage(Message msg) { 2679 switch (msg.what) { 2680 case MESSAGE_RECONSIDER_RANKING: 2681 handleRankingReconsideration(msg); 2682 break; 2683 case MESSAGE_RANKING_CONFIG_CHANGE: 2684 handleRankingConfigChange(); 2685 break; 2686 } 2687 } 2688 } 2689 2690 // Notifications 2691 // ============================================================================ 2692 static int clamp(int x, int low, int high) { 2693 return (x < low) ? low : ((x > high) ? high : x); 2694 } 2695 2696 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 2697 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 2698 if (!manager.isEnabled()) { 2699 return; 2700 } 2701 2702 AccessibilityEvent event = 2703 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 2704 event.setPackageName(packageName); 2705 event.setClassName(Notification.class.getName()); 2706 event.setParcelableData(notification); 2707 CharSequence tickerText = notification.tickerText; 2708 if (!TextUtils.isEmpty(tickerText)) { 2709 event.getText().add(tickerText); 2710 } 2711 2712 manager.sendAccessibilityEvent(event); 2713 } 2714 2715 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 2716 // tell the app 2717 if (sendDelete) { 2718 if (r.getNotification().deleteIntent != null) { 2719 try { 2720 r.getNotification().deleteIntent.send(); 2721 } catch (PendingIntent.CanceledException ex) { 2722 // do nothing - there's no relevant way to recover, and 2723 // no reason to let this propagate 2724 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 2725 } 2726 } 2727 } 2728 2729 // status bar 2730 if (r.getNotification().getSmallIcon() != null) { 2731 r.isCanceled = true; 2732 mListeners.notifyRemovedLocked(r.sbn); 2733 } 2734 2735 final String canceledKey = r.getKey(); 2736 2737 // sound 2738 if (canceledKey.equals(mSoundNotificationKey)) { 2739 mSoundNotificationKey = null; 2740 final long identity = Binder.clearCallingIdentity(); 2741 try { 2742 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 2743 if (player != null) { 2744 player.stopAsync(); 2745 } 2746 } catch (RemoteException e) { 2747 } finally { 2748 Binder.restoreCallingIdentity(identity); 2749 } 2750 } 2751 2752 // vibrate 2753 if (canceledKey.equals(mVibrateNotificationKey)) { 2754 mVibrateNotificationKey = null; 2755 long identity = Binder.clearCallingIdentity(); 2756 try { 2757 mVibrator.cancel(); 2758 } 2759 finally { 2760 Binder.restoreCallingIdentity(identity); 2761 } 2762 } 2763 2764 // light 2765 mLights.remove(canceledKey); 2766 2767 // Record usage stats 2768 switch (reason) { 2769 case REASON_DELEGATE_CANCEL: 2770 case REASON_DELEGATE_CANCEL_ALL: 2771 case REASON_LISTENER_CANCEL: 2772 case REASON_LISTENER_CANCEL_ALL: 2773 mUsageStats.registerDismissedByUser(r); 2774 break; 2775 case REASON_NOMAN_CANCEL: 2776 case REASON_NOMAN_CANCEL_ALL: 2777 mUsageStats.registerRemovedByApp(r); 2778 break; 2779 case REASON_DELEGATE_CLICK: 2780 mUsageStats.registerCancelDueToClick(r); 2781 break; 2782 default: 2783 mUsageStats.registerCancelUnknown(r); 2784 break; 2785 } 2786 2787 mNotificationsByKey.remove(r.sbn.getKey()); 2788 String groupKey = r.getGroupKey(); 2789 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 2790 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { 2791 mSummaryByGroupKey.remove(groupKey); 2792 } 2793 2794 // Save it for users of getHistoricalNotifications() 2795 mArchive.record(r.sbn); 2796 2797 final long now = System.currentTimeMillis(); 2798 EventLogTags.writeNotificationCanceled(canceledKey, reason, 2799 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 2800 } 2801 2802 /** 2803 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 2804 * and none of the {@code mustNotHaveFlags}. 2805 */ 2806 void cancelNotification(final int callingUid, final int callingPid, 2807 final String pkg, final String tag, final int id, 2808 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 2809 final int userId, final int reason, final ManagedServiceInfo listener) { 2810 // In enqueueNotificationInternal notifications are added by scheduling the 2811 // work on the worker handler. Hence, we also schedule the cancel on this 2812 // handler to avoid a scenario where an add notification call followed by a 2813 // remove notification call ends up in not removing the notification. 2814 mHandler.post(new Runnable() { 2815 @Override 2816 public void run() { 2817 String listenerName = listener == null ? null : listener.component.toShortString(); 2818 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, 2819 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName); 2820 2821 synchronized (mNotificationList) { 2822 int index = indexOfNotificationLocked(pkg, tag, id, userId); 2823 if (index >= 0) { 2824 NotificationRecord r = mNotificationList.get(index); 2825 2826 // Ideally we'd do this in the caller of this method. However, that would 2827 // require the caller to also find the notification. 2828 if (reason == REASON_DELEGATE_CLICK) { 2829 mUsageStats.registerClickedByUser(r); 2830 } 2831 2832 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 2833 return; 2834 } 2835 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 2836 return; 2837 } 2838 2839 mNotificationList.remove(index); 2840 2841 cancelNotificationLocked(r, sendDelete, reason); 2842 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, 2843 REASON_GROUP_SUMMARY_CANCELED); 2844 updateLightsLocked(); 2845 } 2846 } 2847 } 2848 }); 2849 } 2850 2851 /** 2852 * Determine whether the userId applies to the notification in question, either because 2853 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 2854 */ 2855 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 2856 return 2857 // looking for USER_ALL notifications? match everything 2858 userId == UserHandle.USER_ALL 2859 // a notification sent to USER_ALL matches any query 2860 || r.getUserId() == UserHandle.USER_ALL 2861 // an exact user match 2862 || r.getUserId() == userId; 2863 } 2864 2865 /** 2866 * Determine whether the userId applies to the notification in question, either because 2867 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 2868 * because it matches one of the users profiles. 2869 */ 2870 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 2871 return notificationMatchesUserId(r, userId) 2872 || mUserProfiles.isCurrentProfile(r.getUserId()); 2873 } 2874 2875 /** 2876 * Cancels all notifications from a given package that have all of the 2877 * {@code mustHaveFlags}. 2878 */ 2879 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 2880 int mustNotHaveFlags, boolean doit, int userId, int reason, 2881 ManagedServiceInfo listener) { 2882 String listenerName = listener == null ? null : listener.component.toShortString(); 2883 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2884 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 2885 listenerName); 2886 2887 synchronized (mNotificationList) { 2888 final int N = mNotificationList.size(); 2889 ArrayList<NotificationRecord> canceledNotifications = null; 2890 for (int i = N-1; i >= 0; --i) { 2891 NotificationRecord r = mNotificationList.get(i); 2892 if (!notificationMatchesUserId(r, userId)) { 2893 continue; 2894 } 2895 // Don't remove notifications to all, if there's no package name specified 2896 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 2897 continue; 2898 } 2899 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 2900 continue; 2901 } 2902 if ((r.getFlags() & mustNotHaveFlags) != 0) { 2903 continue; 2904 } 2905 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 2906 continue; 2907 } 2908 if (canceledNotifications == null) { 2909 canceledNotifications = new ArrayList<>(); 2910 } 2911 canceledNotifications.add(r); 2912 if (!doit) { 2913 return true; 2914 } 2915 mNotificationList.remove(i); 2916 cancelNotificationLocked(r, false, reason); 2917 } 2918 if (doit && canceledNotifications != null) { 2919 final int M = canceledNotifications.size(); 2920 for (int i = 0; i < M; i++) { 2921 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 2922 listenerName, REASON_GROUP_SUMMARY_CANCELED); 2923 } 2924 } 2925 if (canceledNotifications != null) { 2926 updateLightsLocked(); 2927 } 2928 return canceledNotifications != null; 2929 } 2930 } 2931 2932 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 2933 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 2934 String listenerName = listener == null ? null : listener.component.toShortString(); 2935 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2936 null, userId, 0, 0, reason, listenerName); 2937 2938 ArrayList<NotificationRecord> canceledNotifications = null; 2939 final int N = mNotificationList.size(); 2940 for (int i=N-1; i>=0; i--) { 2941 NotificationRecord r = mNotificationList.get(i); 2942 if (includeCurrentProfiles) { 2943 if (!notificationMatchesCurrentProfiles(r, userId)) { 2944 continue; 2945 } 2946 } else { 2947 if (!notificationMatchesUserId(r, userId)) { 2948 continue; 2949 } 2950 } 2951 2952 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 2953 | Notification.FLAG_NO_CLEAR)) == 0) { 2954 mNotificationList.remove(i); 2955 cancelNotificationLocked(r, true, reason); 2956 // Make a note so we can cancel children later. 2957 if (canceledNotifications == null) { 2958 canceledNotifications = new ArrayList<>(); 2959 } 2960 canceledNotifications.add(r); 2961 } 2962 } 2963 int M = canceledNotifications != null ? canceledNotifications.size() : 0; 2964 for (int i = 0; i < M; i++) { 2965 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 2966 listenerName, REASON_GROUP_SUMMARY_CANCELED); 2967 } 2968 updateLightsLocked(); 2969 } 2970 2971 // Warning: The caller is responsible for invoking updateLightsLocked(). 2972 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 2973 String listenerName, int reason) { 2974 Notification n = r.getNotification(); 2975 if (!n.isGroupSummary()) { 2976 return; 2977 } 2978 2979 String pkg = r.sbn.getPackageName(); 2980 int userId = r.getUserId(); 2981 2982 if (pkg == null) { 2983 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey()); 2984 return; 2985 } 2986 2987 final int N = mNotificationList.size(); 2988 for (int i = N - 1; i >= 0; i--) { 2989 NotificationRecord childR = mNotificationList.get(i); 2990 StatusBarNotification childSbn = childR.sbn; 2991 if (childR.getNotification().isGroupChild() && 2992 childR.getGroupKey().equals(r.getGroupKey())) { 2993 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 2994 childSbn.getTag(), userId, 0, 0, reason, listenerName); 2995 mNotificationList.remove(i); 2996 cancelNotificationLocked(childR, false, reason); 2997 } 2998 } 2999 } 3000 3001 // lock on mNotificationList 3002 void updateLightsLocked() 3003 { 3004 // handle notification lights 3005 NotificationRecord ledNotification = null; 3006 while (ledNotification == null && !mLights.isEmpty()) { 3007 final String owner = mLights.get(mLights.size() - 1); 3008 ledNotification = mNotificationsByKey.get(owner); 3009 if (ledNotification == null) { 3010 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 3011 mLights.remove(owner); 3012 } 3013 } 3014 3015 // Don't flash while we are in a call or screen is on 3016 if (ledNotification == null || mInCall || mScreenOn) { 3017 mNotificationLight.turnOff(); 3018 mStatusBar.notificationLightOff(); 3019 } else { 3020 final Notification ledno = ledNotification.sbn.getNotification(); 3021 int ledARGB = ledno.ledARGB; 3022 int ledOnMS = ledno.ledOnMS; 3023 int ledOffMS = ledno.ledOffMS; 3024 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 3025 ledARGB = mDefaultNotificationColor; 3026 ledOnMS = mDefaultNotificationLedOn; 3027 ledOffMS = mDefaultNotificationLedOff; 3028 } 3029 if (mNotificationPulseEnabled) { 3030 // pulse repeatedly 3031 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 3032 ledOnMS, ledOffMS); 3033 } 3034 // let SystemUI make an independent decision 3035 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS); 3036 } 3037 } 3038 3039 // lock on mNotificationList 3040 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 3041 { 3042 ArrayList<NotificationRecord> list = mNotificationList; 3043 final int len = list.size(); 3044 for (int i=0; i<len; i++) { 3045 NotificationRecord r = list.get(i); 3046 if (!notificationMatchesUserId(r, userId) || r.sbn.getId() != id) { 3047 continue; 3048 } 3049 if (tag == null) { 3050 if (r.sbn.getTag() != null) { 3051 continue; 3052 } 3053 } else { 3054 if (!tag.equals(r.sbn.getTag())) { 3055 continue; 3056 } 3057 } 3058 if (r.sbn.getPackageName().equals(pkg)) { 3059 return i; 3060 } 3061 } 3062 return -1; 3063 } 3064 3065 // lock on mNotificationList 3066 int indexOfNotificationLocked(String key) { 3067 final int N = mNotificationList.size(); 3068 for (int i = 0; i < N; i++) { 3069 if (key.equals(mNotificationList.get(i).getKey())) { 3070 return i; 3071 } 3072 } 3073 return -1; 3074 } 3075 3076 private void updateNotificationPulse() { 3077 synchronized (mNotificationList) { 3078 updateLightsLocked(); 3079 } 3080 } 3081 3082 private static boolean isUidSystem(int uid) { 3083 final int appid = UserHandle.getAppId(uid); 3084 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 3085 } 3086 3087 private static boolean isCallerSystem() { 3088 return isUidSystem(Binder.getCallingUid()); 3089 } 3090 3091 private static void checkCallerIsSystem() { 3092 if (isCallerSystem()) { 3093 return; 3094 } 3095 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 3096 } 3097 3098 private static void checkCallerIsSystemOrSameApp(String pkg) { 3099 if (isCallerSystem()) { 3100 return; 3101 } 3102 final int uid = Binder.getCallingUid(); 3103 try { 3104 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 3105 pkg, 0, UserHandle.getCallingUserId()); 3106 if (ai == null) { 3107 throw new SecurityException("Unknown package " + pkg); 3108 } 3109 if (!UserHandle.isSameApp(ai.uid, uid)) { 3110 throw new SecurityException("Calling uid " + uid + " gave package" 3111 + pkg + " which is owned by uid " + ai.uid); 3112 } 3113 } catch (RemoteException re) { 3114 throw new SecurityException("Unknown package " + pkg + "\n" + re); 3115 } 3116 } 3117 3118 private static String callStateToString(int state) { 3119 switch (state) { 3120 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 3121 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 3122 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 3123 default: return "CALL_STATE_UNKNOWN_" + state; 3124 } 3125 } 3126 3127 private void listenForCallState() { 3128 TelephonyManager.from(getContext()).listen(new PhoneStateListener() { 3129 @Override 3130 public void onCallStateChanged(int state, String incomingNumber) { 3131 if (mCallState == state) return; 3132 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 3133 mCallState = state; 3134 } 3135 }, PhoneStateListener.LISTEN_CALL_STATE); 3136 } 3137 3138 /** 3139 * Generates a NotificationRankingUpdate from 'sbns', considering only 3140 * notifications visible to the given listener. 3141 * 3142 * <p>Caller must hold a lock on mNotificationList.</p> 3143 */ 3144 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 3145 int speedBumpIndex = -1; 3146 final int N = mNotificationList.size(); 3147 ArrayList<String> keys = new ArrayList<String>(N); 3148 ArrayList<String> interceptedKeys = new ArrayList<String>(N); 3149 Bundle visibilityOverrides = new Bundle(); 3150 for (int i = 0; i < N; i++) { 3151 NotificationRecord record = mNotificationList.get(i); 3152 if (!isVisibleToListener(record.sbn, info)) { 3153 continue; 3154 } 3155 keys.add(record.sbn.getKey()); 3156 if (record.isIntercepted()) { 3157 interceptedKeys.add(record.sbn.getKey()); 3158 } 3159 if (record.getPackageVisibilityOverride() 3160 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { 3161 visibilityOverrides.putInt(record.sbn.getKey(), 3162 record.getPackageVisibilityOverride()); 3163 } 3164 // Find first min-prio notification for speedbump placement. 3165 if (speedBumpIndex == -1 && 3166 // Intrusiveness trumps priority, hence ignore intrusives. 3167 !record.isRecentlyIntrusive() && 3168 // Currently, package priority is either PRIORITY_DEFAULT or PRIORITY_MAX, so 3169 // scanning for PRIORITY_MIN within the package bucket PRIORITY_DEFAULT 3170 // (or lower as a safeguard) is sufficient to find the speedbump index. 3171 // We'll have to revisit this when more package priority buckets are introduced. 3172 record.getPackagePriority() <= Notification.PRIORITY_DEFAULT && 3173 record.sbn.getNotification().priority == Notification.PRIORITY_MIN) { 3174 speedBumpIndex = keys.size() - 1; 3175 } 3176 } 3177 String[] keysAr = keys.toArray(new String[keys.size()]); 3178 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); 3179 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, 3180 speedBumpIndex); 3181 } 3182 3183 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 3184 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 3185 return false; 3186 } 3187 // TODO: remove this for older listeners. 3188 return true; 3189 } 3190 3191 public class NotificationListeners extends ManagedServices { 3192 3193 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 3194 private boolean mNotificationGroupsDesired; 3195 3196 public NotificationListeners() { 3197 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3198 } 3199 3200 @Override 3201 protected Config getConfig() { 3202 Config c = new Config(); 3203 c.caption = "notification listener"; 3204 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 3205 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 3206 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 3207 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 3208 c.clientLabel = R.string.notification_listener_binding_label; 3209 return c; 3210 } 3211 3212 @Override 3213 protected IInterface asInterface(IBinder binder) { 3214 return INotificationListener.Stub.asInterface(binder); 3215 } 3216 3217 @Override 3218 public void onServiceAdded(ManagedServiceInfo info) { 3219 final INotificationListener listener = (INotificationListener) info.service; 3220 final NotificationRankingUpdate update; 3221 synchronized (mNotificationList) { 3222 updateNotificationGroupsDesiredLocked(); 3223 update = makeRankingUpdateLocked(info); 3224 } 3225 try { 3226 listener.onListenerConnected(update); 3227 } catch (RemoteException e) { 3228 // we tried 3229 } 3230 } 3231 3232 @Override 3233 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3234 if (mListenersDisablingEffects.remove(removed)) { 3235 updateListenerHintsLocked(); 3236 updateEffectsSuppressorLocked(); 3237 } 3238 mLightTrimListeners.remove(removed); 3239 updateNotificationGroupsDesiredLocked(); 3240 } 3241 3242 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 3243 if (trim == TRIM_LIGHT) { 3244 mLightTrimListeners.add(info); 3245 } else { 3246 mLightTrimListeners.remove(info); 3247 } 3248 } 3249 3250 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 3251 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 3252 3253 } 3254 3255 /** 3256 * asynchronously notify all listeners about a new notification 3257 * 3258 * <p> 3259 * Also takes care of removing a notification that has been visible to a listener before, 3260 * but isn't anymore. 3261 */ 3262 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { 3263 // Lazily initialized snapshots of the notification. 3264 StatusBarNotification sbnClone = null; 3265 StatusBarNotification sbnCloneLight = null; 3266 3267 for (final ManagedServiceInfo info : mServices) { 3268 boolean sbnVisible = isVisibleToListener(sbn, info); 3269 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 3270 // This notification hasn't been and still isn't visible -> ignore. 3271 if (!oldSbnVisible && !sbnVisible) { 3272 continue; 3273 } 3274 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3275 3276 // This notification became invisible -> remove the old one. 3277 if (oldSbnVisible && !sbnVisible) { 3278 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 3279 mHandler.post(new Runnable() { 3280 @Override 3281 public void run() { 3282 notifyRemoved(info, oldSbnLightClone, update); 3283 } 3284 }); 3285 continue; 3286 } 3287 3288 final int trim = mListeners.getOnNotificationPostedTrim(info); 3289 3290 if (trim == TRIM_LIGHT && sbnCloneLight == null) { 3291 sbnCloneLight = sbn.cloneLight(); 3292 } else if (trim == TRIM_FULL && sbnClone == null) { 3293 sbnClone = sbn.clone(); 3294 } 3295 final StatusBarNotification sbnToPost = 3296 (trim == TRIM_FULL) ? sbnClone : sbnCloneLight; 3297 3298 mHandler.post(new Runnable() { 3299 @Override 3300 public void run() { 3301 notifyPosted(info, sbnToPost, update); 3302 } 3303 }); 3304 } 3305 } 3306 3307 /** 3308 * asynchronously notify all listeners about a removed notification 3309 */ 3310 public void notifyRemovedLocked(StatusBarNotification sbn) { 3311 // make a copy in case changes are made to the underlying Notification object 3312 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 3313 // notification 3314 final StatusBarNotification sbnLight = sbn.cloneLight(); 3315 for (final ManagedServiceInfo info : mServices) { 3316 if (!isVisibleToListener(sbn, info)) { 3317 continue; 3318 } 3319 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3320 mHandler.post(new Runnable() { 3321 @Override 3322 public void run() { 3323 notifyRemoved(info, sbnLight, update); 3324 } 3325 }); 3326 } 3327 } 3328 3329 /** 3330 * asynchronously notify all listeners about a reordering of notifications 3331 */ 3332 public void notifyRankingUpdateLocked() { 3333 for (final ManagedServiceInfo serviceInfo : mServices) { 3334 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3335 continue; 3336 } 3337 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); 3338 mHandler.post(new Runnable() { 3339 @Override 3340 public void run() { 3341 notifyRankingUpdate(serviceInfo, update); 3342 } 3343 }); 3344 } 3345 } 3346 3347 public void notifyListenerHintsChangedLocked(final int hints) { 3348 for (final ManagedServiceInfo serviceInfo : mServices) { 3349 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3350 continue; 3351 } 3352 mHandler.post(new Runnable() { 3353 @Override 3354 public void run() { 3355 notifyListenerHintsChanged(serviceInfo, hints); 3356 } 3357 }); 3358 } 3359 } 3360 3361 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 3362 for (final ManagedServiceInfo serviceInfo : mServices) { 3363 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3364 continue; 3365 } 3366 mHandler.post(new Runnable() { 3367 @Override 3368 public void run() { 3369 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 3370 } 3371 }); 3372 } 3373 } 3374 3375 private void notifyPosted(final ManagedServiceInfo info, 3376 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 3377 final INotificationListener listener = (INotificationListener)info.service; 3378 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3379 try { 3380 listener.onNotificationPosted(sbnHolder, rankingUpdate); 3381 } catch (RemoteException ex) { 3382 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 3383 } 3384 } 3385 3386 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 3387 NotificationRankingUpdate rankingUpdate) { 3388 if (!info.enabledAndUserMatches(sbn.getUserId())) { 3389 return; 3390 } 3391 final INotificationListener listener = (INotificationListener) info.service; 3392 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3393 try { 3394 listener.onNotificationRemoved(sbnHolder, rankingUpdate); 3395 } catch (RemoteException ex) { 3396 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 3397 } 3398 } 3399 3400 private void notifyRankingUpdate(ManagedServiceInfo info, 3401 NotificationRankingUpdate rankingUpdate) { 3402 final INotificationListener listener = (INotificationListener) info.service; 3403 try { 3404 listener.onNotificationRankingUpdate(rankingUpdate); 3405 } catch (RemoteException ex) { 3406 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 3407 } 3408 } 3409 3410 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 3411 final INotificationListener listener = (INotificationListener) info.service; 3412 try { 3413 listener.onListenerHintsChanged(hints); 3414 } catch (RemoteException ex) { 3415 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 3416 } 3417 } 3418 3419 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 3420 int interruptionFilter) { 3421 final INotificationListener listener = (INotificationListener) info.service; 3422 try { 3423 listener.onInterruptionFilterChanged(interruptionFilter); 3424 } catch (RemoteException ex) { 3425 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 3426 } 3427 } 3428 3429 private boolean isListenerPackage(String packageName) { 3430 if (packageName == null) { 3431 return false; 3432 } 3433 // TODO: clean up locking object later 3434 synchronized (mNotificationList) { 3435 for (final ManagedServiceInfo serviceInfo : mServices) { 3436 if (packageName.equals(serviceInfo.component.getPackageName())) { 3437 return true; 3438 } 3439 } 3440 } 3441 return false; 3442 } 3443 3444 /** 3445 * Returns whether any of the currently registered listeners wants to receive notification 3446 * groups. 3447 * 3448 * <p>Currently we assume groups are desired by non-SystemUI listeners.</p> 3449 */ 3450 public boolean notificationGroupsDesired() { 3451 return mNotificationGroupsDesired; 3452 } 3453 3454 private void updateNotificationGroupsDesiredLocked() { 3455 mNotificationGroupsDesired = true; 3456 // No listeners, no groups. 3457 if (mServices.isEmpty()) { 3458 mNotificationGroupsDesired = false; 3459 return; 3460 } 3461 // One listener: Check whether it's SysUI. 3462 if (mServices.size() == 1 && 3463 mServices.get(0).component.getPackageName().equals("com.android.systemui")) { 3464 mNotificationGroupsDesired = false; 3465 return; 3466 } 3467 } 3468 } 3469 3470 public static final class DumpFilter { 3471 public String pkgFilter; 3472 public boolean zen; 3473 3474 public static DumpFilter parseFromArguments(String[] args) { 3475 if (args != null && args.length == 2 && "p".equals(args[0]) 3476 && args[1] != null && !args[1].trim().isEmpty()) { 3477 final DumpFilter filter = new DumpFilter(); 3478 filter.pkgFilter = args[1].trim().toLowerCase(); 3479 return filter; 3480 } 3481 if (args != null && args.length == 1 && "zen".equals(args[0])) { 3482 final DumpFilter filter = new DumpFilter(); 3483 filter.zen = true; 3484 return filter; 3485 } 3486 return null; 3487 } 3488 3489 public boolean matches(StatusBarNotification sbn) { 3490 return zen ? true : sbn != null 3491 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 3492 } 3493 3494 public boolean matches(ComponentName component) { 3495 return zen ? true : component != null && matches(component.getPackageName()); 3496 } 3497 3498 public boolean matches(String pkg) { 3499 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 3500 } 3501 3502 @Override 3503 public String toString() { 3504 return zen ? "zen" : ('\'' + pkgFilter + '\''); 3505 } 3506 } 3507 3508 /** 3509 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 3510 * binder without sending large amounts of data over a oneway transaction. 3511 */ 3512 private static final class StatusBarNotificationHolder 3513 extends IStatusBarNotificationHolder.Stub { 3514 private StatusBarNotification mValue; 3515 3516 public StatusBarNotificationHolder(StatusBarNotification value) { 3517 mValue = value; 3518 } 3519 3520 /** Get the held value and clear it. This function should only be called once per holder */ 3521 @Override 3522 public StatusBarNotification get() { 3523 StatusBarNotification value = mValue; 3524 mValue = null; 3525 return value; 3526 } 3527 } 3528} 3529