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