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