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