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