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