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