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