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