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