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