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