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