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