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