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