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