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