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