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