NotificationManagerService.java revision 8bc45cb78fafcd6165004addf9d8c538ee91b936
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.notification; 18 19import static android.app.NotificationManager.IMPORTANCE_MIN; 20import static android.app.NotificationManager.IMPORTANCE_NONE; 21import static android.content.pm.PackageManager.FEATURE_LEANBACK; 22import static android.content.pm.PackageManager.FEATURE_TELEVISION; 23import static android.service.notification.NotificationListenerService 24 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED; 25import static android.service.notification.NotificationListenerService 26 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED; 27import static android.service.notification.NotificationListenerService 28 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; 29import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 30import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; 31import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; 32import static android.service.notification.NotificationListenerService.REASON_CANCEL; 33import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; 34import static android.service.notification.NotificationListenerService.REASON_CLICK; 35import static android.service.notification.NotificationListenerService.REASON_ERROR; 36import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; 37import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; 38import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; 39import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; 40import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; 41import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; 42import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF; 43import static android.service.notification.NotificationListenerService.REASON_SNOOZED; 44import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; 45import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; 46import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; 47import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 48import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 49import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 50import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF; 51import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON; 52import static android.service.notification.NotificationListenerService.TRIM_FULL; 53import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 54 55import static android.view.Display.DEFAULT_DISPLAY; 56import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 57import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 58 59import android.Manifest; 60import android.annotation.NonNull; 61import android.annotation.Nullable; 62import android.app.ActivityManager; 63import android.app.ActivityManagerInternal; 64import android.app.AlarmManager; 65import android.app.AppGlobals; 66import android.app.AppOpsManager; 67import android.app.AutomaticZenRule; 68import android.app.NotificationChannelGroup; 69import android.app.backup.BackupManager; 70import android.app.IActivityManager; 71import android.app.INotificationManager; 72import android.app.ITransientNotification; 73import android.app.Notification; 74import android.app.NotificationChannel; 75import android.app.NotificationManager.Policy; 76import android.app.NotificationManager; 77import android.app.PendingIntent; 78import android.app.StatusBarManager; 79import android.app.usage.UsageEvents; 80import android.app.usage.UsageStatsManagerInternal; 81import android.companion.ICompanionDeviceManager; 82import android.content.BroadcastReceiver; 83import android.content.ComponentName; 84import android.content.ContentResolver; 85import android.content.Context; 86import android.content.Intent; 87import android.content.IntentFilter; 88import android.content.pm.ApplicationInfo; 89import android.content.pm.IPackageManager; 90import android.content.pm.PackageInfo; 91import android.content.pm.PackageManager; 92import android.content.pm.PackageManager.NameNotFoundException; 93import android.content.pm.ParceledListSlice; 94import android.content.res.Resources; 95import android.database.ContentObserver; 96import android.media.AudioManager; 97import android.media.AudioManagerInternal; 98import android.media.IRingtonePlayer; 99import android.media.ToneGenerator; 100import android.net.Uri; 101import android.os.Binder; 102import android.os.Build; 103import android.os.Bundle; 104import android.os.Environment; 105import android.os.Handler; 106import android.os.HandlerThread; 107import android.os.IBinder; 108import android.os.IInterface; 109import android.os.Looper; 110import android.os.Message; 111import android.os.Process; 112import android.os.RemoteException; 113import android.os.ServiceManager; 114import android.os.SystemClock; 115import android.os.SystemProperties; 116import android.os.UserHandle; 117import android.os.Vibrator; 118import android.os.VibrationEffect; 119import android.provider.Settings; 120import android.service.notification.Adjustment; 121import android.service.notification.Condition; 122import android.service.notification.IConditionProvider; 123import android.service.notification.INotificationListener; 124import android.service.notification.IStatusBarNotificationHolder; 125import android.service.notification.NotificationAssistantService; 126import android.service.notification.NotificationListenerService; 127import android.service.notification.NotificationRankingUpdate; 128import android.service.notification.NotificationRecordProto; 129import android.service.notification.NotificationServiceDumpProto; 130import android.service.notification.NotificationServiceProto; 131import android.service.notification.SnoozeCriterion; 132import android.service.notification.StatusBarNotification; 133import android.service.notification.ZenModeConfig; 134import android.service.notification.ZenModeProto; 135import android.telephony.PhoneStateListener; 136import android.telephony.TelephonyManager; 137import android.text.TextUtils; 138import android.util.ArrayMap; 139import android.util.ArraySet; 140import android.util.AtomicFile; 141import android.util.Log; 142import android.util.Slog; 143import android.util.SparseArray; 144import android.util.Xml; 145import android.util.proto.ProtoOutputStream; 146import android.view.WindowManagerInternal; 147import android.view.accessibility.AccessibilityEvent; 148import android.view.accessibility.AccessibilityManager; 149import android.widget.Toast; 150 151import com.android.internal.R; 152import com.android.internal.annotations.VisibleForTesting; 153import com.android.internal.logging.MetricsLogger; 154import com.android.internal.logging.nano.MetricsProto; 155import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 156import com.android.internal.statusbar.NotificationVisibility; 157import com.android.internal.util.ArrayUtils; 158import com.android.internal.util.DumpUtils; 159import com.android.internal.util.FastXmlSerializer; 160import com.android.internal.util.Preconditions; 161import com.android.server.DeviceIdleController; 162import com.android.server.EventLogTags; 163import com.android.server.LocalServices; 164import com.android.server.SystemService; 165import com.android.server.lights.Light; 166import com.android.server.lights.LightsManager; 167import com.android.server.notification.ManagedServices.ManagedServiceInfo; 168import com.android.server.policy.PhoneWindowManager; 169import com.android.server.statusbar.StatusBarManagerInternal; 170import com.android.server.notification.ManagedServices.UserProfiles; 171 172import libcore.io.IoUtils; 173 174import org.json.JSONException; 175import org.json.JSONObject; 176import org.xmlpull.v1.XmlPullParser; 177import org.xmlpull.v1.XmlPullParserException; 178import org.xmlpull.v1.XmlSerializer; 179 180import java.io.ByteArrayInputStream; 181import java.io.ByteArrayOutputStream; 182import java.io.File; 183import java.io.FileDescriptor; 184import java.io.FileInputStream; 185import java.io.FileNotFoundException; 186import java.io.FileOutputStream; 187import java.io.IOException; 188import java.io.InputStream; 189import java.io.OutputStream; 190import java.io.PrintWriter; 191import java.nio.charset.StandardCharsets; 192import java.util.ArrayDeque; 193import java.util.ArrayList; 194import java.util.Arrays; 195import java.util.Iterator; 196import java.util.List; 197import java.util.Map; 198import java.util.Map.Entry; 199import java.util.Objects; 200import java.util.concurrent.TimeUnit; 201 202/** {@hide} */ 203public class NotificationManagerService extends SystemService { 204 static final String TAG = "NotificationService"; 205 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 206 public static final boolean ENABLE_CHILD_NOTIFICATIONS 207 = SystemProperties.getBoolean("debug.child_notifs", true); 208 209 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 210 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f; 211 212 // message codes 213 static final int MESSAGE_TIMEOUT = 2; 214 static final int MESSAGE_SAVE_POLICY_FILE = 3; 215 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 216 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 217 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 218 219 // ranking thread messages 220 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 221 private static final int MESSAGE_RANKING_SORT = 1001; 222 223 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 224 static final int SHORT_DELAY = 2000; // 2 seconds 225 226 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 227 228 static final long SNOOZE_UNTIL_UNSPECIFIED = -1; 229 230 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 231 232 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 233 234 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; 235 static final boolean ENABLE_BLOCKED_TOASTS = true; 236 237 // When #matchesCallFilter is called from the ringer, wait at most 238 // 3s to resolve the contacts. This timeout is required since 239 // ContactsProvider might take a long time to start up. 240 // 241 // Return STARRED_CONTACT when the timeout is hit in order to avoid 242 // missed calls in ZEN mode "Important". 243 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 244 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 245 ValidateNotificationPeople.STARRED_CONTACT; 246 247 /** notification_enqueue status value for a newly enqueued notification. */ 248 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 249 250 /** notification_enqueue status value for an existing notification. */ 251 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 252 253 /** notification_enqueue status value for an ignored notification. */ 254 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 255 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds 256 257 private static final long DELAY_FOR_ASSISTANT_TIME = 100; 258 259 private static final String ACTION_NOTIFICATION_TIMEOUT = 260 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 261 private static final int REQUEST_CODE_TIMEOUT = 1; 262 private static final String SCHEME_TIMEOUT = "timeout"; 263 private static final String EXTRA_KEY = "key"; 264 265 private IActivityManager mAm; 266 private IPackageManager mPackageManager; 267 private PackageManager mPackageManagerClient; 268 AudioManager mAudioManager; 269 AudioManagerInternal mAudioManagerInternal; 270 @Nullable StatusBarManagerInternal mStatusBar; 271 Vibrator mVibrator; 272 private WindowManagerInternal mWindowManagerInternal; 273 private AlarmManager mAlarmManager; 274 private ICompanionDeviceManager mCompanionManager; 275 276 final IBinder mForegroundToken = new Binder(); 277 private Handler mHandler; 278 private final HandlerThread mRankingThread = new HandlerThread("ranker", 279 Process.THREAD_PRIORITY_BACKGROUND); 280 281 private Light mNotificationLight; 282 Light mAttentionLight; 283 284 private long[] mFallbackVibrationPattern; 285 private boolean mUseAttentionLight; 286 boolean mSystemReady; 287 288 private boolean mDisableNotificationEffects; 289 private int mCallState; 290 private String mSoundNotificationKey; 291 private String mVibrateNotificationKey; 292 293 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects = 294 new SparseArray<ArraySet<ManagedServiceInfo>>(); 295 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>(); 296 private int mListenerHints; // right now, all hints are global 297 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 298 299 // for enabling and disabling notification pulse behavior 300 private boolean mScreenOn = true; 301 private boolean mInCall = false; 302 private boolean mNotificationPulseEnabled; 303 304 // for generating notification tones in-call 305 private ToneGenerator mInCallToneGenerator; 306 private final Object mInCallToneGeneratorLock = new Object(); 307 308 // used as a mutex for access to all active notifications & listeners 309 final Object mNotificationLock = new Object(); 310 final ArrayList<NotificationRecord> mNotificationList = 311 new ArrayList<NotificationRecord>(); 312 final ArrayMap<String, NotificationRecord> mNotificationsByKey = 313 new ArrayMap<String, NotificationRecord>(); 314 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>(); 315 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); 316 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); 317 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 318 final PolicyAccess mPolicyAccess = new PolicyAccess(); 319 320 // The last key in this list owns the hardware. 321 ArrayList<String> mLights = new ArrayList<>(); 322 323 private AppOpsManager mAppOps; 324 private UsageStatsManagerInternal mAppUsageStats; 325 326 private Archive mArchive; 327 328 // Persistent storage for notification policy 329 private AtomicFile mPolicyFile; 330 331 private static final int DB_VERSION = 1; 332 333 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 334 private static final String ATTR_VERSION = "version"; 335 336 private RankingHelper mRankingHelper; 337 338 private final UserProfiles mUserProfiles = new UserProfiles(); 339 private NotificationListeners mListeners; 340 private NotificationAssistants mNotificationAssistants; 341 private ConditionProviders mConditionProviders; 342 private NotificationUsageStats mUsageStats; 343 344 private static final int MY_UID = Process.myUid(); 345 private static final int MY_PID = Process.myPid(); 346 private static final IBinder WHITELIST_TOKEN = new Binder(); 347 private RankingHandler mRankingHandler; 348 private long mLastOverRateLogTime; 349 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 350 351 private SnoozeHelper mSnoozeHelper; 352 private GroupHelper mGroupHelper; 353 private boolean mIsTelevision; 354 355 private static class Archive { 356 final int mBufferSize; 357 final ArrayDeque<StatusBarNotification> mBuffer; 358 359 public Archive(int size) { 360 mBufferSize = size; 361 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize); 362 } 363 364 public String toString() { 365 final StringBuilder sb = new StringBuilder(); 366 final int N = mBuffer.size(); 367 sb.append("Archive ("); 368 sb.append(N); 369 sb.append(" notification"); 370 sb.append((N==1)?")":"s)"); 371 return sb.toString(); 372 } 373 374 public void record(StatusBarNotification nr) { 375 if (mBuffer.size() == mBufferSize) { 376 mBuffer.removeFirst(); 377 } 378 379 // We don't want to store the heavy bits of the notification in the archive, 380 // but other clients in the system process might be using the object, so we 381 // store a (lightened) copy. 382 mBuffer.addLast(nr.cloneLight()); 383 } 384 385 public Iterator<StatusBarNotification> descendingIterator() { 386 return mBuffer.descendingIterator(); 387 } 388 389 public StatusBarNotification[] getArray(int count) { 390 if (count == 0) count = mBufferSize; 391 final StatusBarNotification[] a 392 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 393 Iterator<StatusBarNotification> iter = descendingIterator(); 394 int i=0; 395 while (iter.hasNext() && i < count) { 396 a[i++] = iter.next(); 397 } 398 return a; 399 } 400 401 } 402 403 private void readPolicyXml(InputStream stream, boolean forRestore) 404 throws XmlPullParserException, NumberFormatException, IOException { 405 final XmlPullParser parser = Xml.newPullParser(); 406 parser.setInput(stream, StandardCharsets.UTF_8.name()); 407 408 while (parser.next() != END_DOCUMENT) { 409 mZenModeHelper.readXml(parser, forRestore); 410 mRankingHelper.readXml(parser, forRestore); 411 } 412 } 413 414 private void loadPolicyFile() { 415 if (DBG) Slog.d(TAG, "loadPolicyFile"); 416 synchronized (mPolicyFile) { 417 418 FileInputStream infile = null; 419 try { 420 infile = mPolicyFile.openRead(); 421 readPolicyXml(infile, false /*forRestore*/); 422 } catch (FileNotFoundException e) { 423 // No data yet 424 } catch (IOException e) { 425 Log.wtf(TAG, "Unable to read notification policy", e); 426 } catch (NumberFormatException e) { 427 Log.wtf(TAG, "Unable to parse notification policy", e); 428 } catch (XmlPullParserException e) { 429 Log.wtf(TAG, "Unable to parse notification policy", e); 430 } finally { 431 IoUtils.closeQuietly(infile); 432 } 433 } 434 } 435 436 public void savePolicyFile() { 437 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE); 438 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE); 439 } 440 441 private void handleSavePolicyFile() { 442 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 443 synchronized (mPolicyFile) { 444 final FileOutputStream stream; 445 try { 446 stream = mPolicyFile.startWrite(); 447 } catch (IOException e) { 448 Slog.w(TAG, "Failed to save policy file", e); 449 return; 450 } 451 452 try { 453 writePolicyXml(stream, false /*forBackup*/); 454 mPolicyFile.finishWrite(stream); 455 } catch (IOException e) { 456 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 457 mPolicyFile.failWrite(stream); 458 } 459 } 460 BackupManager.dataChanged(getContext().getPackageName()); 461 } 462 463 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException { 464 final XmlSerializer out = new FastXmlSerializer(); 465 out.setOutput(stream, StandardCharsets.UTF_8.name()); 466 out.startDocument(null, true); 467 out.startTag(null, TAG_NOTIFICATION_POLICY); 468 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 469 mZenModeHelper.writeXml(out, forBackup); 470 mRankingHelper.writeXml(out, forBackup); 471 out.endTag(null, TAG_NOTIFICATION_POLICY); 472 out.endDocument(); 473 } 474 475 /** Use this to check if a package can post a notification or toast. */ 476 private boolean checkNotificationOp(String pkg, int uid) { 477 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 478 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid); 479 } 480 481 private static final class ToastRecord 482 { 483 final int pid; 484 final String pkg; 485 final ITransientNotification callback; 486 int duration; 487 Binder token; 488 489 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration, 490 Binder token) { 491 this.pid = pid; 492 this.pkg = pkg; 493 this.callback = callback; 494 this.duration = duration; 495 this.token = token; 496 } 497 498 void update(int duration) { 499 this.duration = duration; 500 } 501 502 void dump(PrintWriter pw, String prefix, DumpFilter filter) { 503 if (filter != null && !filter.matches(pkg)) return; 504 pw.println(prefix + this); 505 } 506 507 @Override 508 public final String toString() 509 { 510 return "ToastRecord{" 511 + Integer.toHexString(System.identityHashCode(this)) 512 + " pkg=" + pkg 513 + " callback=" + callback 514 + " duration=" + duration; 515 } 516 } 517 518 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 519 520 @Override 521 public void onSetDisabled(int status) { 522 synchronized (mNotificationLock) { 523 mDisableNotificationEffects = 524 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 525 if (disableNotificationEffects(null) != null) { 526 // cancel whatever's going on 527 long identity = Binder.clearCallingIdentity(); 528 try { 529 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 530 if (player != null) { 531 player.stopAsync(); 532 } 533 } catch (RemoteException e) { 534 } finally { 535 Binder.restoreCallingIdentity(identity); 536 } 537 538 identity = Binder.clearCallingIdentity(); 539 try { 540 mVibrator.cancel(); 541 } finally { 542 Binder.restoreCallingIdentity(identity); 543 } 544 } 545 } 546 } 547 548 @Override 549 public void onClearAll(int callingUid, int callingPid, int userId) { 550 synchronized (mNotificationLock) { 551 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null, 552 /*includeCurrentProfiles*/ true); 553 } 554 } 555 556 @Override 557 public void onNotificationClick(int callingUid, int callingPid, String key) { 558 synchronized (mNotificationLock) { 559 NotificationRecord r = mNotificationsByKey.get(key); 560 if (r == null) { 561 Log.w(TAG, "No notification with key: " + key); 562 return; 563 } 564 final long now = System.currentTimeMillis(); 565 MetricsLogger.action(r.getLogMaker(now) 566 .setCategory(MetricsEvent.NOTIFICATION_ITEM) 567 .setType(MetricsEvent.TYPE_ACTION)); 568 EventLogTags.writeNotificationClicked(key, 569 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 570 571 StatusBarNotification sbn = r.sbn; 572 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 573 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 574 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), 575 REASON_CLICK, null); 576 } 577 } 578 579 @Override 580 public void onNotificationActionClick(int callingUid, int callingPid, String key, 581 int actionIndex) { 582 synchronized (mNotificationLock) { 583 NotificationRecord r = mNotificationsByKey.get(key); 584 if (r == null) { 585 Log.w(TAG, "No notification with key: " + key); 586 return; 587 } 588 final long now = System.currentTimeMillis(); 589 MetricsLogger.action(r.getLogMaker(now) 590 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) 591 .setType(MetricsEvent.TYPE_ACTION) 592 .setSubtype(actionIndex)); 593 EventLogTags.writeNotificationActionClicked(key, actionIndex, 594 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 595 // TODO: Log action click via UsageStats. 596 } 597 } 598 599 @Override 600 public void onNotificationClear(int callingUid, int callingPid, 601 String pkg, String tag, int id, int userId) { 602 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 603 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 604 true, userId, REASON_CANCEL, null); 605 } 606 607 @Override 608 public void onPanelRevealed(boolean clearEffects, int items) { 609 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL); 610 MetricsLogger.histogram(getContext(), "notification_load", items); 611 EventLogTags.writeNotificationPanelRevealed(items); 612 if (clearEffects) { 613 clearEffects(); 614 } 615 } 616 617 @Override 618 public void onPanelHidden() { 619 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL); 620 EventLogTags.writeNotificationPanelHidden(); 621 } 622 623 @Override 624 public void clearEffects() { 625 synchronized (mNotificationLock) { 626 if (DBG) Slog.d(TAG, "clearEffects"); 627 clearSoundLocked(); 628 clearVibrateLocked(); 629 clearLightsLocked(); 630 } 631 } 632 633 @Override 634 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 635 int uid, int initialPid, String message, int userId) { 636 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 637 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 638 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 639 REASON_ERROR, null); 640 long ident = Binder.clearCallingIdentity(); 641 try { 642 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1, 643 "Bad notification posted from package " + pkg 644 + ": " + message); 645 } catch (RemoteException e) { 646 } 647 Binder.restoreCallingIdentity(ident); 648 } 649 650 @Override 651 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 652 NotificationVisibility[] noLongerVisibleKeys) { 653 synchronized (mNotificationLock) { 654 for (NotificationVisibility nv : newlyVisibleKeys) { 655 NotificationRecord r = mNotificationsByKey.get(nv.key); 656 if (r == null) continue; 657 r.setVisibility(true, nv.rank); 658 nv.recycle(); 659 } 660 // Note that we might receive this event after notifications 661 // have already left the system, e.g. after dismissing from the 662 // shade. Hence not finding notifications in 663 // mNotificationsByKey is not an exceptional condition. 664 for (NotificationVisibility nv : noLongerVisibleKeys) { 665 NotificationRecord r = mNotificationsByKey.get(nv.key); 666 if (r == null) continue; 667 r.setVisibility(false, nv.rank); 668 nv.recycle(); 669 } 670 } 671 } 672 673 @Override 674 public void onNotificationExpansionChanged(String key, 675 boolean userAction, boolean expanded) { 676 synchronized (mNotificationLock) { 677 NotificationRecord r = mNotificationsByKey.get(key); 678 if (r != null) { 679 r.stats.onExpansionChanged(userAction, expanded); 680 final long now = System.currentTimeMillis(); 681 MetricsLogger.action(r.getLogMaker(now) 682 .setCategory(MetricsEvent.NOTIFICATION_ITEM) 683 .setType(MetricsEvent.TYPE_DETAIL)); 684 EventLogTags.writeNotificationExpansion(key, 685 userAction ? 1 : 0, expanded ? 1 : 0, 686 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 687 } 688 } 689 } 690 }; 691 692 private void clearSoundLocked() { 693 mSoundNotificationKey = null; 694 long identity = Binder.clearCallingIdentity(); 695 try { 696 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 697 if (player != null) { 698 player.stopAsync(); 699 } 700 } catch (RemoteException e) { 701 } finally { 702 Binder.restoreCallingIdentity(identity); 703 } 704 } 705 706 private void clearVibrateLocked() { 707 mVibrateNotificationKey = null; 708 long identity = Binder.clearCallingIdentity(); 709 try { 710 mVibrator.cancel(); 711 } finally { 712 Binder.restoreCallingIdentity(identity); 713 } 714 } 715 716 private void clearLightsLocked() { 717 // light 718 mLights.clear(); 719 updateLightsLocked(); 720 } 721 722 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() { 723 @Override 724 public void onReceive(Context context, Intent intent) { 725 String action = intent.getAction(); 726 if (action == null) { 727 return; 728 } 729 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) { 730 final NotificationRecord record; 731 synchronized (mNotificationLock) { 732 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY)); 733 } 734 if (record != null) { 735 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(), 736 record.sbn.getPackageName(), record.sbn.getTag(), 737 record.sbn.getId(), 0, 738 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(), 739 REASON_TIMEOUT, null); 740 } 741 } 742 } 743 }; 744 745 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 746 @Override 747 public void onReceive(Context context, Intent intent) { 748 String action = intent.getAction(); 749 if (action == null) { 750 return; 751 } 752 753 boolean queryRestart = false; 754 boolean queryRemove = false; 755 boolean packageChanged = false; 756 boolean cancelNotifications = true; 757 int reason = REASON_PACKAGE_CHANGED; 758 759 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 760 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 761 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 762 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 763 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 764 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) 765 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 766 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 767 UserHandle.USER_ALL); 768 String pkgList[] = null; 769 int uidList[] = null; 770 boolean removingPackage = queryRemove && 771 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 772 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage); 773 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 774 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 775 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 776 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 777 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 778 reason = REASON_PACKAGE_SUSPENDED; 779 } else if (queryRestart) { 780 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 781 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 782 } else { 783 Uri uri = intent.getData(); 784 if (uri == null) { 785 return; 786 } 787 String pkgName = uri.getSchemeSpecificPart(); 788 if (pkgName == null) { 789 return; 790 } 791 if (packageChanged) { 792 // We cancel notifications for packages which have just been disabled 793 try { 794 final int enabled = mPackageManager.getApplicationEnabledSetting( 795 pkgName, 796 changeUserId != UserHandle.USER_ALL ? changeUserId : 797 UserHandle.USER_SYSTEM); 798 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 799 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 800 cancelNotifications = false; 801 } 802 } catch (IllegalArgumentException e) { 803 // Package doesn't exist; probably racing with uninstall. 804 // cancelNotifications is already true, so nothing to do here. 805 if (DBG) { 806 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 807 } 808 } catch (RemoteException e) { 809 // Failed to talk to PackageManagerService Should never happen! 810 } 811 } 812 pkgList = new String[]{pkgName}; 813 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; 814 } 815 if (pkgList != null && (pkgList.length > 0)) { 816 for (String pkgName : pkgList) { 817 if (cancelNotifications) { 818 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, 819 !queryRestart, changeUserId, reason, null); 820 } 821 } 822 } 823 mListeners.onPackagesChanged(removingPackage, pkgList); 824 mNotificationAssistants.onPackagesChanged(removingPackage, pkgList); 825 mConditionProviders.onPackagesChanged(removingPackage, pkgList); 826 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList); 827 savePolicyFile(); 828 } 829 } 830 }; 831 832 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 833 @Override 834 public void onReceive(Context context, Intent intent) { 835 String action = intent.getAction(); 836 837 if (action.equals(Intent.ACTION_SCREEN_ON)) { 838 // Keep track of screen on/off state, but do not turn off the notification light 839 // until user passes through the lock screen or views the notification. 840 mScreenOn = true; 841 updateNotificationPulse(); 842 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 843 mScreenOn = false; 844 updateNotificationPulse(); 845 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 846 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 847 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 848 updateNotificationPulse(); 849 synchronized (mInCallToneGeneratorLock) { 850 if (mInCall) { 851 if (mInCallToneGenerator == null) { 852 int relativeToneVolume = getContext().getResources().getInteger( 853 R.integer.config_inCallNotificationVolumeRelative); 854 if (relativeToneVolume < ToneGenerator.MIN_VOLUME 855 || relativeToneVolume > ToneGenerator.MAX_VOLUME) { 856 relativeToneVolume = ToneGenerator.MAX_VOLUME; 857 } 858 try { 859 mInCallToneGenerator = new ToneGenerator( 860 AudioManager.STREAM_VOICE_CALL, relativeToneVolume); 861 } catch (RuntimeException e) { 862 Log.e(TAG, "Error creating local tone generator: " + e); 863 mInCallToneGenerator = null; 864 } 865 } 866 } else { 867 if (mInCallToneGenerator != null) { 868 mInCallToneGenerator.release(); 869 mInCallToneGenerator = null; 870 } 871 } 872 } 873 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 874 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 875 if (userHandle >= 0) { 876 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle, 877 REASON_USER_STOPPED, null); 878 } 879 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 880 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 881 if (userHandle >= 0) { 882 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle, 883 REASON_PROFILE_TURNED_OFF, null); 884 } 885 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 886 // turn off LED when user passes through lock screen 887 mNotificationLight.turnOff(); 888 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 889 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 890 // reload per-user settings 891 mSettingsObserver.update(null); 892 mUserProfiles.updateCache(context); 893 // Refresh managed services 894 mConditionProviders.onUserSwitched(user); 895 mListeners.onUserSwitched(user); 896 mNotificationAssistants.onUserSwitched(user); 897 mZenModeHelper.onUserSwitched(user); 898 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 899 mUserProfiles.updateCache(context); 900 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 901 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 902 mZenModeHelper.onUserRemoved(user); 903 mRankingHelper.onUserRemoved(user); 904 savePolicyFile(); 905 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { 906 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 907 mConditionProviders.onUserUnlocked(user); 908 mListeners.onUserUnlocked(user); 909 mNotificationAssistants.onUserUnlocked(user); 910 mZenModeHelper.onUserUnlocked(user); 911 } 912 } 913 }; 914 915 private final class SettingsObserver extends ContentObserver { 916 private final Uri NOTIFICATION_BADGING_URI 917 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING); 918 private final Uri NOTIFICATION_LIGHT_PULSE_URI 919 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 920 private final Uri NOTIFICATION_RATE_LIMIT_URI 921 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); 922 923 SettingsObserver(Handler handler) { 924 super(handler); 925 } 926 927 void observe() { 928 ContentResolver resolver = getContext().getContentResolver(); 929 resolver.registerContentObserver(NOTIFICATION_BADGING_URI, 930 false, this, UserHandle.USER_ALL); 931 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 932 false, this, UserHandle.USER_ALL); 933 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, 934 false, this, UserHandle.USER_ALL); 935 update(null); 936 } 937 938 @Override public void onChange(boolean selfChange, Uri uri) { 939 update(uri); 940 } 941 942 public void update(Uri uri) { 943 ContentResolver resolver = getContext().getContentResolver(); 944 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 945 boolean pulseEnabled = Settings.System.getInt(resolver, 946 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 947 if (mNotificationPulseEnabled != pulseEnabled) { 948 mNotificationPulseEnabled = pulseEnabled; 949 updateNotificationPulse(); 950 } 951 } 952 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) { 953 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver, 954 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate); 955 } 956 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { 957 mRankingHelper.updateBadgingEnabled(); 958 } 959 } 960 } 961 962 private SettingsObserver mSettingsObserver; 963 private ZenModeHelper mZenModeHelper; 964 965 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 966 int[] ar = r.getIntArray(resid); 967 if (ar == null) { 968 return def; 969 } 970 final int len = ar.length > maxlen ? maxlen : ar.length; 971 long[] out = new long[len]; 972 for (int i=0; i<len; i++) { 973 out[i] = ar[i]; 974 } 975 return out; 976 } 977 978 public NotificationManagerService(Context context) { 979 super(context); 980 Notification.processWhitelistToken = WHITELIST_TOKEN; 981 } 982 983 // TODO - replace these methods with a single VisibleForTesting constructor 984 @VisibleForTesting 985 void setAudioManager(AudioManager audioMananger) { 986 mAudioManager = audioMananger; 987 } 988 989 @VisibleForTesting 990 void setVibrator(Vibrator vibrator) { 991 mVibrator = vibrator; 992 } 993 994 @VisibleForTesting 995 void setLights(Light light) { 996 mNotificationLight = light; 997 mAttentionLight = light; 998 mNotificationPulseEnabled = true; 999 } 1000 1001 @VisibleForTesting 1002 void setScreenOn(boolean on) { 1003 mScreenOn = on; 1004 } 1005 1006 @VisibleForTesting 1007 void addNotification(NotificationRecord r) { 1008 mNotificationList.add(r); 1009 mNotificationsByKey.put(r.sbn.getKey(), r); 1010 if (r.sbn.isGroup()) { 1011 mSummaryByGroupKey.put(r.getGroupKey(), r); 1012 } 1013 } 1014 1015 @VisibleForTesting 1016 void addEnqueuedNotification(NotificationRecord r) { 1017 mEnqueuedNotifications.add(r); 1018 } 1019 1020 @VisibleForTesting 1021 void setSystemReady(boolean systemReady) { 1022 mSystemReady = systemReady; 1023 } 1024 1025 @VisibleForTesting 1026 void setHandler(Handler handler) { 1027 mHandler = handler; 1028 } 1029 1030 @VisibleForTesting 1031 void setFallbackVibrationPattern(long[] vibrationPattern) { 1032 mFallbackVibrationPattern = vibrationPattern; 1033 } 1034 1035 @VisibleForTesting 1036 void setPackageManager(IPackageManager packageManager) { 1037 mPackageManager = packageManager; 1038 } 1039 1040 @VisibleForTesting 1041 void setRankingHelper(RankingHelper rankingHelper) { 1042 mRankingHelper = rankingHelper; 1043 } 1044 1045 @VisibleForTesting 1046 void setIsTelevision(boolean isTelevision) { 1047 mIsTelevision = isTelevision; 1048 } 1049 1050 // TODO: Tests should call onStart instead once the methods above are removed. 1051 @VisibleForTesting 1052 void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient, 1053 LightsManager lightsManager, NotificationListeners notificationListeners, 1054 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper) { 1055 Resources resources = getContext().getResources(); 1056 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), 1057 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, 1058 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); 1059 1060 mAm = ActivityManager.getService(); 1061 mPackageManager = packageManager; 1062 mPackageManagerClient = packageManagerClient; 1063 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 1064 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 1065 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); 1066 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 1067 mCompanionManager = companionManager; 1068 1069 mHandler = new WorkerHandler(looper); 1070 mRankingThread.start(); 1071 String[] extractorNames; 1072 try { 1073 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 1074 } catch (Resources.NotFoundException e) { 1075 extractorNames = new String[0]; 1076 } 1077 mUsageStats = new NotificationUsageStats(getContext()); 1078 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper()); 1079 mRankingHelper = new RankingHelper(getContext(), 1080 getContext().getPackageManager(), 1081 mRankingHandler, 1082 mUsageStats, 1083 extractorNames); 1084 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles); 1085 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); 1086 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 1087 @Override 1088 public void onConfigChanged() { 1089 savePolicyFile(); 1090 } 1091 1092 @Override 1093 void onZenModeChanged() { 1094 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 1095 getContext().sendBroadcastAsUser( 1096 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 1097 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 1098 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); 1099 synchronized (mNotificationLock) { 1100 updateInterruptionFilterLocked(); 1101 } 1102 } 1103 1104 @Override 1105 void onPolicyChanged() { 1106 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 1107 } 1108 }); 1109 mSnoozeHelper = snoozeHelper; 1110 mGroupHelper = new GroupHelper(new GroupHelper.Callback() { 1111 @Override 1112 public void addAutoGroup(String key) { 1113 synchronized (mNotificationLock) { 1114 addAutogroupKeyLocked(key); 1115 } 1116 mRankingHandler.requestSort(false); 1117 } 1118 1119 @Override 1120 public void removeAutoGroup(String key) { 1121 synchronized (mNotificationLock) { 1122 removeAutogroupKeyLocked(key); 1123 } 1124 mRankingHandler.requestSort(false); 1125 } 1126 1127 @Override 1128 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) { 1129 createAutoGroupSummary(userId, pkg, triggeringKey); 1130 } 1131 1132 @Override 1133 public void removeAutoGroupSummary(int userId, String pkg) { 1134 synchronized (mNotificationLock) { 1135 clearAutogroupSummaryLocked(userId, pkg); 1136 } 1137 } 1138 }); 1139 1140 final File systemDir = new File(Environment.getDataDirectory(), "system"); 1141 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); 1142 1143 loadPolicyFile(); 1144 1145 // This is a ManagedServices object that keeps track of the listeners. 1146 mListeners = notificationListeners; 1147 1148 // This is a MangedServices object that keeps track of the assistant. 1149 mNotificationAssistants = new NotificationAssistants(); 1150 1151 mStatusBar = getLocalService(StatusBarManagerInternal.class); 1152 if (mStatusBar != null) { 1153 mStatusBar.setNotificationDelegate(mNotificationDelegate); 1154 } 1155 1156 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 1157 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION); 1158 1159 mFallbackVibrationPattern = getLongArray(resources, 1160 R.array.config_notificationFallbackVibePattern, 1161 VIBRATE_PATTERN_MAXLEN, 1162 DEFAULT_VIBRATE_PATTERN); 1163 1164 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); 1165 1166 // Don't start allowing notifications until the setup wizard has run once. 1167 // After that, including subsequent boots, init with notifications turned on. 1168 // This works on the first boot because the setup wizard will toggle this 1169 // flag at least once and we'll go back to 0 after that. 1170 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 1171 Settings.Global.DEVICE_PROVISIONED, 0)) { 1172 mDisableNotificationEffects = true; 1173 } 1174 mZenModeHelper.initZenMode(); 1175 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1176 1177 mUserProfiles.updateCache(getContext()); 1178 listenForCallState(); 1179 1180 // register for various Intents 1181 IntentFilter filter = new IntentFilter(); 1182 filter.addAction(Intent.ACTION_SCREEN_ON); 1183 filter.addAction(Intent.ACTION_SCREEN_OFF); 1184 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 1185 filter.addAction(Intent.ACTION_USER_PRESENT); 1186 filter.addAction(Intent.ACTION_USER_STOPPED); 1187 filter.addAction(Intent.ACTION_USER_SWITCHED); 1188 filter.addAction(Intent.ACTION_USER_ADDED); 1189 filter.addAction(Intent.ACTION_USER_REMOVED); 1190 filter.addAction(Intent.ACTION_USER_UNLOCKED); 1191 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 1192 getContext().registerReceiver(mIntentReceiver, filter); 1193 1194 IntentFilter pkgFilter = new IntentFilter(); 1195 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1196 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1197 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1198 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1199 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1200 pkgFilter.addDataScheme("package"); 1201 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 1202 null); 1203 1204 IntentFilter suspendedPkgFilter = new IntentFilter(); 1205 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 1206 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, 1207 suspendedPkgFilter, null, null); 1208 1209 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1210 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 1211 null); 1212 1213 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT); 1214 timeoutFilter.addDataScheme(SCHEME_TIMEOUT); 1215 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter); 1216 1217 mSettingsObserver = new SettingsObserver(mHandler); 1218 1219 mArchive = new Archive(resources.getInteger( 1220 R.integer.config_notificationServiceArchiveSize)); 1221 1222 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK) 1223 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION); 1224 } 1225 1226 @Override 1227 public void onStart() { 1228 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() { 1229 @Override 1230 public void repost(int userId, NotificationRecord r) { 1231 try { 1232 if (DBG) { 1233 Slog.d(TAG, "Reposting " + r.getKey()); 1234 } 1235 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(), 1236 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(), 1237 r.sbn.getNotification(), userId); 1238 } catch (Exception e) { 1239 Slog.e(TAG, "Cannot un-snooze notification", e); 1240 } 1241 } 1242 }, mUserProfiles); 1243 1244 init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(), 1245 getLocalService(LightsManager.class), new NotificationListeners(), 1246 null, snoozeHelper); 1247 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 1248 publishLocalService(NotificationManagerInternal.class, mInternalService); 1249 } 1250 1251 private void sendRegisteredOnlyBroadcast(String action) { 1252 getContext().sendBroadcastAsUser(new Intent(action) 1253 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null); 1254 } 1255 1256 @Override 1257 public void onBootPhase(int phase) { 1258 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1259 // no beeping until we're basically done booting 1260 mSystemReady = true; 1261 1262 // Grab our optional AudioService 1263 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1264 mAudioManagerInternal = getLocalService(AudioManagerInternal.class); 1265 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 1266 mZenModeHelper.onSystemReady(); 1267 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1268 // This observer will force an update when observe is called, causing us to 1269 // bind to listener services. 1270 mSettingsObserver.observe(); 1271 mListeners.onBootPhaseAppsCanStart(); 1272 mNotificationAssistants.onBootPhaseAppsCanStart(); 1273 mConditionProviders.onBootPhaseAppsCanStart(); 1274 } 1275 } 1276 1277 private void updateListenerHintsLocked() { 1278 final int hints = calculateHints(); 1279 if (hints == mListenerHints) return; 1280 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size()); 1281 mListenerHints = hints; 1282 scheduleListenerHintsChanged(hints); 1283 } 1284 1285 private void updateEffectsSuppressorLocked() { 1286 final long updatedSuppressedEffects = calculateSuppressedEffects(); 1287 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; 1288 final List<ComponentName> suppressors = getSuppressors(); 1289 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects); 1290 mEffectsSuppressors = suppressors; 1291 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); 1292 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 1293 } 1294 1295 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel, 1296 boolean fromListener) { 1297 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) { 1298 // cancel 1299 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, 1300 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, 1301 null); 1302 } 1303 mRankingHelper.updateNotificationChannel(pkg, uid, channel); 1304 1305 final NotificationChannel modifiedChannel = 1306 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false); 1307 1308 if (!fromListener) { 1309 mListeners.notifyNotificationChannelChanged( 1310 pkg, UserHandle.getUserHandleForUid(uid), 1311 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); 1312 } 1313 1314 synchronized (mNotificationLock) { 1315 final int N = mNotificationList.size(); 1316 for (int i = N - 1; i >= 0; --i) { 1317 NotificationRecord r = mNotificationList.get(i); 1318 if (r.sbn.getPackageName().equals(pkg) 1319 && r.sbn.getUid() == uid 1320 && channel.getId() != null 1321 && channel.getId().equals(r.getChannel().getId())) { 1322 r.updateNotificationChannel(modifiedChannel); 1323 } 1324 } 1325 } 1326 mRankingHandler.requestSort(true); 1327 savePolicyFile(); 1328 } 1329 1330 private ArrayList<ComponentName> getSuppressors() { 1331 ArrayList<ComponentName> names = new ArrayList<ComponentName>(); 1332 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 1333 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i); 1334 1335 for (ManagedServiceInfo info : serviceInfoList) { 1336 names.add(info.component); 1337 } 1338 } 1339 1340 return names; 1341 } 1342 1343 private boolean removeDisabledHints(ManagedServiceInfo info) { 1344 return removeDisabledHints(info, 0); 1345 } 1346 1347 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) { 1348 boolean removed = false; 1349 1350 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 1351 final int hint = mListenersDisablingEffects.keyAt(i); 1352 final ArraySet<ManagedServiceInfo> listeners = 1353 mListenersDisablingEffects.valueAt(i); 1354 1355 if (hints == 0 || (hint & hints) == hint) { 1356 removed = removed || listeners.remove(info); 1357 } 1358 } 1359 1360 return removed; 1361 } 1362 1363 private void addDisabledHints(ManagedServiceInfo info, int hints) { 1364 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 1365 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS); 1366 } 1367 1368 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 1369 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 1370 } 1371 1372 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 1373 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS); 1374 } 1375 } 1376 1377 private void addDisabledHint(ManagedServiceInfo info, int hint) { 1378 if (mListenersDisablingEffects.indexOfKey(hint) < 0) { 1379 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>()); 1380 } 1381 1382 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint); 1383 hintListeners.add(info); 1384 } 1385 1386 private int calculateHints() { 1387 int hints = 0; 1388 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 1389 int hint = mListenersDisablingEffects.keyAt(i); 1390 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i); 1391 1392 if (!serviceInfoList.isEmpty()) { 1393 hints |= hint; 1394 } 1395 } 1396 1397 return hints; 1398 } 1399 1400 private long calculateSuppressedEffects() { 1401 int hints = calculateHints(); 1402 long suppressedEffects = 0; 1403 1404 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 1405 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL; 1406 } 1407 1408 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 1409 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS; 1410 } 1411 1412 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 1413 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS; 1414 } 1415 1416 return suppressedEffects; 1417 } 1418 1419 private void updateInterruptionFilterLocked() { 1420 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1421 if (interruptionFilter == mInterruptionFilter) return; 1422 mInterruptionFilter = interruptionFilter; 1423 scheduleInterruptionFilterChanged(interruptionFilter); 1424 } 1425 1426 @VisibleForTesting 1427 INotificationManager getBinderService() { 1428 return INotificationManager.Stub.asInterface(mService); 1429 } 1430 1431 @VisibleForTesting 1432 NotificationManagerInternal getInternalService() { 1433 return mInternalService; 1434 } 1435 1436 private final IBinder mService = new INotificationManager.Stub() { 1437 // Toasts 1438 // ============================================================================ 1439 1440 @Override 1441 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 1442 { 1443 if (DBG) { 1444 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 1445 + " duration=" + duration); 1446 } 1447 1448 if (pkg == null || callback == null) { 1449 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 1450 return ; 1451 } 1452 1453 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg)); 1454 final boolean isPackageSuspended = 1455 isPackageSuspendedForUser(pkg, Binder.getCallingUid()); 1456 1457 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && 1458 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()) 1459 || isPackageSuspended)) { 1460 Slog.e(TAG, "Suppressing toast from package " + pkg 1461 + (isPackageSuspended 1462 ? " due to package suspended by administrator." 1463 : " by user request.")); 1464 return; 1465 } 1466 1467 synchronized (mToastQueue) { 1468 int callingPid = Binder.getCallingPid(); 1469 long callingId = Binder.clearCallingIdentity(); 1470 try { 1471 ToastRecord record; 1472 int index = indexOfToastLocked(pkg, callback); 1473 // If it's already in the queue, we update it in place, we don't 1474 // move it to the end of the queue. 1475 if (index >= 0) { 1476 record = mToastQueue.get(index); 1477 record.update(duration); 1478 } else { 1479 // Limit the number of toasts that any given package except the android 1480 // package can enqueue. Prevents DOS attacks and deals with leaks. 1481 if (!isSystemToast) { 1482 int count = 0; 1483 final int N = mToastQueue.size(); 1484 for (int i=0; i<N; i++) { 1485 final ToastRecord r = mToastQueue.get(i); 1486 if (r.pkg.equals(pkg)) { 1487 count++; 1488 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1489 Slog.e(TAG, "Package has already posted " + count 1490 + " toasts. Not showing more. Package=" + pkg); 1491 return; 1492 } 1493 } 1494 } 1495 } 1496 1497 Binder token = new Binder(); 1498 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY); 1499 record = new ToastRecord(callingPid, pkg, callback, duration, token); 1500 mToastQueue.add(record); 1501 index = mToastQueue.size() - 1; 1502 keepProcessAliveIfNeededLocked(callingPid); 1503 } 1504 // If it's at index 0, it's the current toast. It doesn't matter if it's 1505 // new or just been updated. Call back and tell it to show itself. 1506 // If the callback fails, this will remove it from the list, so don't 1507 // assume that it's valid after this. 1508 if (index == 0) { 1509 showNextToastLocked(); 1510 } 1511 } finally { 1512 Binder.restoreCallingIdentity(callingId); 1513 } 1514 } 1515 } 1516 1517 @Override 1518 public void cancelToast(String pkg, ITransientNotification callback) { 1519 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 1520 1521 if (pkg == null || callback == null) { 1522 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 1523 return ; 1524 } 1525 1526 synchronized (mToastQueue) { 1527 long callingId = Binder.clearCallingIdentity(); 1528 try { 1529 int index = indexOfToastLocked(pkg, callback); 1530 if (index >= 0) { 1531 cancelToastLocked(index); 1532 } else { 1533 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 1534 + " callback=" + callback); 1535 } 1536 } finally { 1537 Binder.restoreCallingIdentity(callingId); 1538 } 1539 } 1540 } 1541 1542 @Override 1543 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 1544 Notification notification, int userId) throws RemoteException { 1545 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 1546 Binder.getCallingPid(), tag, id, notification, userId); 1547 } 1548 1549 @Override 1550 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1551 checkCallerIsSystemOrSameApp(pkg); 1552 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1553 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1554 // Don't allow client applications to cancel foreground service notis or autobundled 1555 // summaries. 1556 final int mustNotHaveFlags = isCallingUidSystem() ? 0 : 1557 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY); 1558 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1559 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); 1560 } 1561 1562 @Override 1563 public void cancelAllNotifications(String pkg, int userId) { 1564 checkCallerIsSystemOrSameApp(pkg); 1565 1566 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1567 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1568 1569 // Calling from user space, don't allow the canceling of actively 1570 // running foreground services. 1571 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1572 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1573 REASON_APP_CANCEL_ALL, null); 1574 } 1575 1576 @Override 1577 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1578 checkCallerIsSystem(); 1579 1580 mRankingHelper.setEnabled(pkg, uid, enabled); 1581 // Now, cancel any outstanding notifications that are part of a just-disabled app 1582 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 1583 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true, 1584 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null); 1585 } 1586 savePolicyFile(); 1587 } 1588 1589 /** 1590 * Use this when you just want to know if notifications are OK for this package. 1591 */ 1592 @Override 1593 public boolean areNotificationsEnabled(String pkg) { 1594 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()); 1595 } 1596 1597 /** 1598 * Use this when you just want to know if notifications are OK for this package. 1599 */ 1600 @Override 1601 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1602 checkCallerIsSystemOrSameApp(pkg); 1603 1604 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; 1605 } 1606 1607 @Override 1608 public int getPackageImportance(String pkg) { 1609 checkCallerIsSystemOrSameApp(pkg); 1610 return mRankingHelper.getImportance(pkg, Binder.getCallingUid()); 1611 } 1612 1613 @Override 1614 public boolean canShowBadge(String pkg, int uid) { 1615 checkCallerIsSystem(); 1616 return mRankingHelper.canShowBadge(pkg, uid); 1617 } 1618 1619 @Override 1620 public void setShowBadge(String pkg, int uid, boolean showBadge) { 1621 checkCallerIsSystem(); 1622 mRankingHelper.setShowBadge(pkg, uid, showBadge); 1623 savePolicyFile(); 1624 } 1625 1626 @Override 1627 public void createNotificationChannelGroups(String pkg, 1628 ParceledListSlice channelGroupList) throws RemoteException { 1629 checkCallerIsSystemOrSameApp(pkg); 1630 List<NotificationChannelGroup> groups = channelGroupList.getList(); 1631 final int groupSize = groups.size(); 1632 for (int i = 0; i < groupSize; i++) { 1633 final NotificationChannelGroup group = groups.get(i); 1634 Preconditions.checkNotNull(group, "group in list is null"); 1635 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, 1636 true /* fromTargetApp */); 1637 mListeners.notifyNotificationChannelGroupChanged(pkg, 1638 UserHandle.of(UserHandle.getCallingUserId()), group, 1639 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 1640 } 1641 savePolicyFile(); 1642 } 1643 1644 private void createNotificationChannelsImpl(String pkg, int uid, 1645 ParceledListSlice channelsList) { 1646 List<NotificationChannel> channels = channelsList.getList(); 1647 final int channelsSize = channels.size(); 1648 for (int i = 0; i < channelsSize; i++) { 1649 final NotificationChannel channel = channels.get(i); 1650 Preconditions.checkNotNull(channel, "channel in list is null"); 1651 mRankingHelper.createNotificationChannel(pkg, uid, channel, 1652 true /* fromTargetApp */); 1653 mListeners.notifyNotificationChannelChanged(pkg, 1654 UserHandle.getUserHandleForUid(uid), 1655 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false), 1656 NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 1657 } 1658 savePolicyFile(); 1659 } 1660 1661 @Override 1662 public void createNotificationChannels(String pkg, 1663 ParceledListSlice channelsList) throws RemoteException { 1664 checkCallerIsSystemOrSameApp(pkg); 1665 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList); 1666 } 1667 1668 @Override 1669 public void createNotificationChannelsForPackage(String pkg, int uid, 1670 ParceledListSlice channelsList) throws RemoteException { 1671 checkCallerIsSystem(); 1672 createNotificationChannelsImpl(pkg, uid, channelsList); 1673 } 1674 1675 @Override 1676 public NotificationChannel getNotificationChannel(String pkg, String channelId) { 1677 checkCallerIsSystemOrSameApp(pkg); 1678 return mRankingHelper.getNotificationChannel( 1679 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */); 1680 } 1681 1682 @Override 1683 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, 1684 String channelId, boolean includeDeleted) { 1685 checkCallerIsSystem(); 1686 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted); 1687 } 1688 1689 @Override 1690 public void deleteNotificationChannel(String pkg, String channelId) { 1691 checkCallerIsSystemOrSameApp(pkg); 1692 final int callingUid = Binder.getCallingUid(); 1693 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { 1694 throw new IllegalArgumentException("Cannot delete default channel"); 1695 } 1696 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, 1697 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); 1698 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId); 1699 mListeners.notifyNotificationChannelChanged(pkg, 1700 UserHandle.getUserHandleForUid(callingUid), 1701 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true), 1702 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 1703 savePolicyFile(); 1704 } 1705 1706 @Override 1707 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups( 1708 String pkg) { 1709 checkCallerIsSystemOrSameApp(pkg); 1710 return new ParceledListSlice<>(new ArrayList( 1711 mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid()))); 1712 } 1713 1714 @Override 1715 public void deleteNotificationChannelGroup(String pkg, String groupId) { 1716 checkCallerIsSystemOrSameApp(pkg); 1717 1718 final int callingUid = Binder.getCallingUid(); 1719 NotificationChannelGroup groupToDelete = 1720 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid); 1721 if (groupToDelete != null) { 1722 List<NotificationChannel> deletedChannels = 1723 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); 1724 for (int i = 0; i < deletedChannels.size(); i++) { 1725 final NotificationChannel deletedChannel = deletedChannels.get(i); 1726 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, 1727 true, 1728 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, 1729 null); 1730 mListeners.notifyNotificationChannelChanged(pkg, 1731 UserHandle.getUserHandleForUid(callingUid), 1732 deletedChannel, 1733 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 1734 } 1735 mListeners.notifyNotificationChannelGroupChanged( 1736 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, 1737 NOTIFICATION_CHANNEL_OR_GROUP_DELETED); 1738 savePolicyFile(); 1739 } 1740 } 1741 1742 @Override 1743 public void updateNotificationChannelForPackage(String pkg, int uid, 1744 NotificationChannel channel) { 1745 enforceSystemOrSystemUI("Caller not system or systemui"); 1746 Preconditions.checkNotNull(channel); 1747 updateNotificationChannelInt(pkg, uid, channel, false); 1748 } 1749 1750 @Override 1751 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg, 1752 int uid, boolean includeDeleted) { 1753 enforceSystemOrSystemUI("getNotificationChannelsForPackage"); 1754 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted); 1755 } 1756 1757 @Override 1758 public int getNumNotificationChannelsForPackage(String pkg, int uid, 1759 boolean includeDeleted) { 1760 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage"); 1761 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted) 1762 .getList().size(); 1763 } 1764 1765 @Override 1766 public boolean onlyHasDefaultChannel(String pkg, int uid) { 1767 enforceSystemOrSystemUI("onlyHasDefaultChannel"); 1768 return mRankingHelper.onlyHasDefaultChannel(pkg, uid); 1769 } 1770 1771 @Override 1772 public int getDeletedChannelCount(String pkg, int uid) { 1773 enforceSystemOrSystemUI("getDeletedChannelCount"); 1774 return mRankingHelper.getDeletedChannelCount(pkg, uid); 1775 } 1776 1777 @Override 1778 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage( 1779 String pkg, int uid, boolean includeDeleted) { 1780 checkCallerIsSystem(); 1781 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted); 1782 } 1783 1784 @Override 1785 public NotificationChannelGroup getNotificationChannelGroupForPackage( 1786 String groupId, String pkg, int uid) { 1787 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage"); 1788 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid); 1789 } 1790 1791 @Override 1792 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) { 1793 checkCallerIsSystemOrSameApp(pkg); 1794 return mRankingHelper.getNotificationChannels( 1795 pkg, Binder.getCallingUid(), false /* includeDeleted */); 1796 } 1797 1798 @Override 1799 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException { 1800 checkCallerIsSystem(); 1801 1802 // Cancel posted notifications 1803 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true, 1804 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); 1805 1806 // Listener & assistant 1807 mListeners.onPackagesChanged(true, new String[] {packageName}); 1808 mNotificationAssistants.onPackagesChanged(true, new String[] {packageName}); 1809 1810 // Zen 1811 mConditionProviders.onPackagesChanged(true, new String[] {packageName}); 1812 1813 // Reset notification preferences 1814 if (!fromApp) { 1815 mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(), 1816 new String[]{packageName}, new int[]{uid}); 1817 } 1818 1819 savePolicyFile(); 1820 } 1821 1822 1823 /** 1824 * System-only API for getting a list of current (i.e. not cleared) notifications. 1825 * 1826 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1827 * @returns A list of all the notifications, in natural order. 1828 */ 1829 @Override 1830 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1831 // enforce() will ensure the calling uid has the correct permission 1832 getContext().enforceCallingOrSelfPermission( 1833 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1834 "NotificationManagerService.getActiveNotifications"); 1835 1836 StatusBarNotification[] tmp = null; 1837 int uid = Binder.getCallingUid(); 1838 1839 // noteOp will check to make sure the callingPkg matches the uid 1840 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1841 == AppOpsManager.MODE_ALLOWED) { 1842 synchronized (mNotificationLock) { 1843 tmp = new StatusBarNotification[mNotificationList.size()]; 1844 final int N = mNotificationList.size(); 1845 for (int i=0; i<N; i++) { 1846 tmp[i] = mNotificationList.get(i).sbn; 1847 } 1848 } 1849 } 1850 return tmp; 1851 } 1852 1853 /** 1854 * Public API for getting a list of current notifications for the calling package/uid. 1855 * 1856 * Note that since notification posting is done asynchronously, this will not return 1857 * notifications that are in the process of being posted. 1858 * 1859 * @returns A list of all the package's notifications, in natural order. 1860 */ 1861 @Override 1862 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 1863 int incomingUserId) { 1864 checkCallerIsSystemOrSameApp(pkg); 1865 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1866 Binder.getCallingUid(), incomingUserId, true, false, 1867 "getAppActiveNotifications", pkg); 1868 synchronized (mNotificationLock) { 1869 final ArrayMap<String, StatusBarNotification> map 1870 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); 1871 final int N = mNotificationList.size(); 1872 for (int i = 0; i < N; i++) { 1873 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 1874 mNotificationList.get(i).sbn); 1875 if (sbn != null) { 1876 map.put(sbn.getKey(), sbn); 1877 } 1878 } 1879 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) { 1880 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn); 1881 if (sbn != null) { 1882 map.put(sbn.getKey(), sbn); 1883 } 1884 } 1885 final int M = mEnqueuedNotifications.size(); 1886 for (int i = 0; i < M; i++) { 1887 StatusBarNotification sbn = sanitizeSbn(pkg, userId, 1888 mEnqueuedNotifications.get(i).sbn); 1889 if (sbn != null) { 1890 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here 1891 } 1892 } 1893 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); 1894 list.addAll(map.values()); 1895 return new ParceledListSlice<StatusBarNotification>(list); 1896 } 1897 } 1898 1899 private StatusBarNotification sanitizeSbn(String pkg, int userId, 1900 StatusBarNotification sbn) { 1901 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId 1902 && (sbn.getNotification().flags 1903 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) { 1904 // We could pass back a cloneLight() but clients might get confused and 1905 // try to send this thing back to notify() again, which would not work 1906 // very well. 1907 return new StatusBarNotification( 1908 sbn.getPackageName(), 1909 sbn.getOpPkg(), 1910 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 1911 sbn.getNotification().clone(), 1912 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); 1913 } 1914 return null; 1915 } 1916 1917 /** 1918 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1919 * 1920 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1921 */ 1922 @Override 1923 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1924 // enforce() will ensure the calling uid has the correct permission 1925 getContext().enforceCallingOrSelfPermission( 1926 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1927 "NotificationManagerService.getHistoricalNotifications"); 1928 1929 StatusBarNotification[] tmp = null; 1930 int uid = Binder.getCallingUid(); 1931 1932 // noteOp will check to make sure the callingPkg matches the uid 1933 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1934 == AppOpsManager.MODE_ALLOWED) { 1935 synchronized (mArchive) { 1936 tmp = mArchive.getArray(count); 1937 } 1938 } 1939 return tmp; 1940 } 1941 1942 /** 1943 * Register a listener binder directly with the notification manager. 1944 * 1945 * Only works with system callers. Apps should extend 1946 * {@link android.service.notification.NotificationListenerService}. 1947 */ 1948 @Override 1949 public void registerListener(final INotificationListener listener, 1950 final ComponentName component, final int userid) { 1951 enforceSystemOrSystemUI("INotificationManager.registerListener"); 1952 mListeners.registerService(listener, component, userid); 1953 } 1954 1955 /** 1956 * Remove a listener binder directly 1957 */ 1958 @Override 1959 public void unregisterListener(INotificationListener token, int userid) { 1960 mListeners.unregisterService(token, userid); 1961 } 1962 1963 /** 1964 * Allow an INotificationListener to simulate a "clear all" operation. 1965 * 1966 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1967 * 1968 * @param token The binder for the listener, to check that the caller is allowed 1969 */ 1970 @Override 1971 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1972 final int callingUid = Binder.getCallingUid(); 1973 final int callingPid = Binder.getCallingPid(); 1974 long identity = Binder.clearCallingIdentity(); 1975 try { 1976 synchronized (mNotificationLock) { 1977 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1978 if (keys != null) { 1979 final int N = keys.length; 1980 for (int i = 0; i < N; i++) { 1981 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1982 if (r == null) continue; 1983 final int userId = r.sbn.getUserId(); 1984 if (userId != info.userid && userId != UserHandle.USER_ALL && 1985 !mUserProfiles.isCurrentProfile(userId)) { 1986 throw new SecurityException("Disallowed call from listener: " 1987 + info.service); 1988 } 1989 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1990 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 1991 userId); 1992 } 1993 } else { 1994 cancelAllLocked(callingUid, callingPid, info.userid, 1995 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 1996 } 1997 } 1998 } finally { 1999 Binder.restoreCallingIdentity(identity); 2000 } 2001 } 2002 2003 /** 2004 * Handle request from an approved listener to re-enable itself. 2005 * 2006 * @param component The componenet to be re-enabled, caller must match package. 2007 */ 2008 @Override 2009 public void requestBindListener(ComponentName component) { 2010 checkCallerIsSystemOrSameApp(component.getPackageName()); 2011 long identity = Binder.clearCallingIdentity(); 2012 try { 2013 ManagedServices manager = 2014 mNotificationAssistants.isComponentEnabledForCurrentProfiles(component) 2015 ? mNotificationAssistants 2016 : mListeners; 2017 manager.setComponentState(component, true); 2018 } finally { 2019 Binder.restoreCallingIdentity(identity); 2020 } 2021 } 2022 2023 @Override 2024 public void requestUnbindListener(INotificationListener token) { 2025 long identity = Binder.clearCallingIdentity(); 2026 try { 2027 // allow bound services to disable themselves 2028 synchronized (mNotificationLock) { 2029 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2030 info.getOwner().setComponentState(info.component, false); 2031 } 2032 } finally { 2033 Binder.restoreCallingIdentity(identity); 2034 } 2035 } 2036 2037 @Override 2038 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 2039 long identity = Binder.clearCallingIdentity(); 2040 try { 2041 synchronized (mNotificationLock) { 2042 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2043 if (keys != null) { 2044 final int N = keys.length; 2045 for (int i = 0; i < N; i++) { 2046 NotificationRecord r = mNotificationsByKey.get(keys[i]); 2047 if (r == null) continue; 2048 final int userId = r.sbn.getUserId(); 2049 if (userId != info.userid && userId != UserHandle.USER_ALL && 2050 !mUserProfiles.isCurrentProfile(userId)) { 2051 throw new SecurityException("Disallowed call from listener: " 2052 + info.service); 2053 } 2054 if (!r.isSeen()) { 2055 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 2056 mAppUsageStats.reportEvent(r.sbn.getPackageName(), 2057 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM 2058 : userId, 2059 UsageEvents.Event.USER_INTERACTION); 2060 r.setSeen(); 2061 } 2062 } 2063 } 2064 } 2065 } finally { 2066 Binder.restoreCallingIdentity(identity); 2067 } 2068 } 2069 2070 /** 2071 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 2072 * 2073 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 2074 * 2075 * @param info The binder for the listener, to check that the caller is allowed 2076 */ 2077 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 2078 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 2079 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 2080 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 2081 true, 2082 userId, REASON_LISTENER_CANCEL, info); 2083 } 2084 2085 /** 2086 * Allow an INotificationListener to snooze a single notification until a context. 2087 * 2088 * @param token The binder for the listener, to check that the caller is allowed 2089 */ 2090 @Override 2091 public void snoozeNotificationUntilContextFromListener(INotificationListener token, 2092 String key, String snoozeCriterionId) { 2093 long identity = Binder.clearCallingIdentity(); 2094 try { 2095 synchronized (mNotificationLock) { 2096 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2097 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); 2098 } 2099 } finally { 2100 Binder.restoreCallingIdentity(identity); 2101 } 2102 } 2103 2104 /** 2105 * Allow an INotificationListener to snooze a single notification until a time. 2106 * 2107 * @param token The binder for the listener, to check that the caller is allowed 2108 */ 2109 @Override 2110 public void snoozeNotificationUntilFromListener(INotificationListener token, String key, 2111 long duration) { 2112 long identity = Binder.clearCallingIdentity(); 2113 try { 2114 synchronized (mNotificationLock) { 2115 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2116 snoozeNotificationInt(key, duration, null, info); 2117 } 2118 } finally { 2119 Binder.restoreCallingIdentity(identity); 2120 } 2121 } 2122 2123 /** 2124 * Allows the notification assistant to un-snooze a single notification. 2125 * 2126 * @param token The binder for the assistant, to check that the caller is allowed 2127 */ 2128 @Override 2129 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { 2130 long identity = Binder.clearCallingIdentity(); 2131 try { 2132 synchronized (mNotificationLock) { 2133 final ManagedServiceInfo info = 2134 mNotificationAssistants.checkServiceTokenLocked(token); 2135 unsnoozeNotificationInt(key, info); 2136 } 2137 } finally { 2138 Binder.restoreCallingIdentity(identity); 2139 } 2140 } 2141 2142 /** 2143 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 2144 * 2145 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 2146 * 2147 * @param token The binder for the listener, to check that the caller is allowed 2148 */ 2149 @Override 2150 public void cancelNotificationFromListener(INotificationListener token, String pkg, 2151 String tag, int id) { 2152 final int callingUid = Binder.getCallingUid(); 2153 final int callingPid = Binder.getCallingPid(); 2154 long identity = Binder.clearCallingIdentity(); 2155 try { 2156 synchronized (mNotificationLock) { 2157 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2158 if (info.supportsProfiles()) { 2159 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 2160 + "from " + info.component 2161 + " use cancelNotification(key) instead."); 2162 } else { 2163 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 2164 pkg, tag, id, info.userid); 2165 } 2166 } 2167 } finally { 2168 Binder.restoreCallingIdentity(identity); 2169 } 2170 } 2171 2172 /** 2173 * Allow an INotificationListener to request the list of outstanding notifications seen by 2174 * the current user. Useful when starting up, after which point the listener callbacks 2175 * should be used. 2176 * 2177 * @param token The binder for the listener, to check that the caller is allowed 2178 * @param keys An array of notification keys to fetch, or null to fetch everything 2179 * @returns The return value will contain the notifications specified in keys, in that 2180 * order, or if keys is null, all the notifications, in natural order. 2181 */ 2182 @Override 2183 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 2184 INotificationListener token, String[] keys, int trim) { 2185 synchronized (mNotificationLock) { 2186 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2187 final boolean getKeys = keys != null; 2188 final int N = getKeys ? keys.length : mNotificationList.size(); 2189 final ArrayList<StatusBarNotification> list 2190 = new ArrayList<StatusBarNotification>(N); 2191 for (int i=0; i<N; i++) { 2192 final NotificationRecord r = getKeys 2193 ? mNotificationsByKey.get(keys[i]) 2194 : mNotificationList.get(i); 2195 if (r == null) continue; 2196 StatusBarNotification sbn = r.sbn; 2197 if (!isVisibleToListener(sbn, info)) continue; 2198 StatusBarNotification sbnToSend = 2199 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 2200 list.add(sbnToSend); 2201 } 2202 return new ParceledListSlice<StatusBarNotification>(list); 2203 } 2204 } 2205 2206 /** 2207 * Allow an INotificationListener to request the list of outstanding snoozed notifications 2208 * seen by the current user. Useful when starting up, after which point the listener 2209 * callbacks should be used. 2210 * 2211 * @param token The binder for the listener, to check that the caller is allowed 2212 * @returns The return value will contain the notifications specified in keys, in that 2213 * order, or if keys is null, all the notifications, in natural order. 2214 */ 2215 @Override 2216 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener( 2217 INotificationListener token, int trim) { 2218 synchronized (mNotificationLock) { 2219 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2220 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed(); 2221 final int N = snoozedRecords.size(); 2222 final ArrayList<StatusBarNotification> list = new ArrayList<>(N); 2223 for (int i=0; i < N; i++) { 2224 final NotificationRecord r = snoozedRecords.get(i); 2225 if (r == null) continue; 2226 StatusBarNotification sbn = r.sbn; 2227 if (!isVisibleToListener(sbn, info)) continue; 2228 StatusBarNotification sbnToSend = 2229 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 2230 list.add(sbnToSend); 2231 } 2232 return new ParceledListSlice<>(list); 2233 } 2234 } 2235 2236 @Override 2237 public void requestHintsFromListener(INotificationListener token, int hints) { 2238 final long identity = Binder.clearCallingIdentity(); 2239 try { 2240 synchronized (mNotificationLock) { 2241 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2242 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS 2243 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS 2244 | HINT_HOST_DISABLE_CALL_EFFECTS; 2245 final boolean disableEffects = (hints & disableEffectsMask) != 0; 2246 if (disableEffects) { 2247 addDisabledHints(info, hints); 2248 } else { 2249 removeDisabledHints(info, hints); 2250 } 2251 updateListenerHintsLocked(); 2252 updateEffectsSuppressorLocked(); 2253 } 2254 } finally { 2255 Binder.restoreCallingIdentity(identity); 2256 } 2257 } 2258 2259 @Override 2260 public int getHintsFromListener(INotificationListener token) { 2261 synchronized (mNotificationLock) { 2262 return mListenerHints; 2263 } 2264 } 2265 2266 @Override 2267 public void requestInterruptionFilterFromListener(INotificationListener token, 2268 int interruptionFilter) throws RemoteException { 2269 final long identity = Binder.clearCallingIdentity(); 2270 try { 2271 synchronized (mNotificationLock) { 2272 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2273 mZenModeHelper.requestFromListener(info.component, interruptionFilter); 2274 updateInterruptionFilterLocked(); 2275 } 2276 } finally { 2277 Binder.restoreCallingIdentity(identity); 2278 } 2279 } 2280 2281 @Override 2282 public int getInterruptionFilterFromListener(INotificationListener token) 2283 throws RemoteException { 2284 synchronized (mNotificationLight) { 2285 return mInterruptionFilter; 2286 } 2287 } 2288 2289 @Override 2290 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 2291 throws RemoteException { 2292 synchronized (mNotificationLock) { 2293 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 2294 if (info == null) return; 2295 mListeners.setOnNotificationPostedTrimLocked(info, trim); 2296 } 2297 } 2298 2299 @Override 2300 public int getZenMode() { 2301 return mZenModeHelper.getZenMode(); 2302 } 2303 2304 @Override 2305 public ZenModeConfig getZenModeConfig() { 2306 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig"); 2307 return mZenModeHelper.getConfig(); 2308 } 2309 2310 @Override 2311 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { 2312 enforceSystemOrSystemUI("INotificationManager.setZenMode"); 2313 final long identity = Binder.clearCallingIdentity(); 2314 try { 2315 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason); 2316 } finally { 2317 Binder.restoreCallingIdentity(identity); 2318 } 2319 } 2320 2321 @Override 2322 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException { 2323 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); 2324 return mZenModeHelper.getZenRules(); 2325 } 2326 2327 @Override 2328 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 2329 Preconditions.checkNotNull(id, "Id is null"); 2330 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); 2331 return mZenModeHelper.getAutomaticZenRule(id); 2332 } 2333 2334 @Override 2335 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) 2336 throws RemoteException { 2337 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 2338 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 2339 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); 2340 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 2341 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 2342 2343 return mZenModeHelper.addAutomaticZenRule(automaticZenRule, 2344 "addAutomaticZenRule"); 2345 } 2346 2347 @Override 2348 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) 2349 throws RemoteException { 2350 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 2351 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 2352 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); 2353 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 2354 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 2355 2356 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule, 2357 "updateAutomaticZenRule"); 2358 } 2359 2360 @Override 2361 public boolean removeAutomaticZenRule(String id) throws RemoteException { 2362 Preconditions.checkNotNull(id, "Id is null"); 2363 // Verify that they can modify zen rules. 2364 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 2365 2366 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule"); 2367 } 2368 2369 @Override 2370 public boolean removeAutomaticZenRules(String packageName) throws RemoteException { 2371 Preconditions.checkNotNull(packageName, "Package name is null"); 2372 enforceSystemOrSystemUI("removeAutomaticZenRules"); 2373 2374 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules"); 2375 } 2376 2377 @Override 2378 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 2379 Preconditions.checkNotNull(owner, "Owner is null"); 2380 enforceSystemOrSystemUI("getRuleInstanceCount"); 2381 2382 return mZenModeHelper.getCurrentInstanceCount(owner); 2383 } 2384 2385 @Override 2386 public void setInterruptionFilter(String pkg, int filter) throws RemoteException { 2387 enforcePolicyAccess(pkg, "setInterruptionFilter"); 2388 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 2389 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 2390 final long identity = Binder.clearCallingIdentity(); 2391 try { 2392 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter"); 2393 } finally { 2394 Binder.restoreCallingIdentity(identity); 2395 } 2396 } 2397 2398 @Override 2399 public void notifyConditions(final String pkg, IConditionProvider provider, 2400 final Condition[] conditions) { 2401 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 2402 checkCallerIsSystemOrSameApp(pkg); 2403 mHandler.post(new Runnable() { 2404 @Override 2405 public void run() { 2406 mConditionProviders.notifyConditions(pkg, info, conditions); 2407 } 2408 }); 2409 } 2410 2411 @Override 2412 public void requestUnbindProvider(IConditionProvider provider) { 2413 long identity = Binder.clearCallingIdentity(); 2414 try { 2415 // allow bound services to disable themselves 2416 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 2417 info.getOwner().setComponentState(info.component, false); 2418 } finally { 2419 Binder.restoreCallingIdentity(identity); 2420 } 2421 } 2422 2423 @Override 2424 public void requestBindProvider(ComponentName component) { 2425 checkCallerIsSystemOrSameApp(component.getPackageName()); 2426 long identity = Binder.clearCallingIdentity(); 2427 try { 2428 mConditionProviders.setComponentState(component, true); 2429 } finally { 2430 Binder.restoreCallingIdentity(identity); 2431 } 2432 } 2433 2434 private void enforceSystemOrSystemUI(String message) { 2435 if (isCallerSystemOrPhone()) return; 2436 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 2437 message); 2438 } 2439 2440 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) { 2441 try { 2442 checkCallerIsSystemOrSameApp(pkg); 2443 } catch (SecurityException e) { 2444 getContext().enforceCallingPermission( 2445 android.Manifest.permission.STATUS_BAR_SERVICE, 2446 message); 2447 } 2448 } 2449 2450 private void enforcePolicyAccess(int uid, String method) { 2451 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 2452 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 2453 return; 2454 } 2455 boolean accessAllowed = false; 2456 String[] packages = getContext().getPackageManager().getPackagesForUid(uid); 2457 final int packageCount = packages.length; 2458 for (int i = 0; i < packageCount; i++) { 2459 if (checkPolicyAccess(packages[i])) { 2460 accessAllowed = true; 2461 } 2462 } 2463 if (!accessAllowed) { 2464 Slog.w(TAG, "Notification policy access denied calling " + method); 2465 throw new SecurityException("Notification policy access denied"); 2466 } 2467 } 2468 2469 private void enforcePolicyAccess(String pkg, String method) { 2470 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 2471 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 2472 return; 2473 } 2474 checkCallerIsSameApp(pkg); 2475 if (!checkPolicyAccess(pkg)) { 2476 Slog.w(TAG, "Notification policy access denied calling " + method); 2477 throw new SecurityException("Notification policy access denied"); 2478 } 2479 } 2480 2481 private boolean checkPackagePolicyAccess(String pkg) { 2482 return mPolicyAccess.isPackageGranted(pkg); 2483 } 2484 2485 private boolean checkPolicyAccess(String pkg) { 2486 try { 2487 int uid = getContext().getPackageManager().getPackageUidAsUser( 2488 pkg, UserHandle.getCallingUserId()); 2489 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission( 2490 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, 2491 -1, true)) { 2492 return true; 2493 } 2494 } catch (NameNotFoundException e) { 2495 return false; 2496 } 2497 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg); 2498 } 2499 2500 @Override 2501 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2502 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; 2503 final DumpFilter filter = DumpFilter.parseFromArguments(args); 2504 if (filter != null && filter.stats) { 2505 dumpJson(pw, filter); 2506 } else if (filter != null && filter.proto) { 2507 dumpProto(fd, filter); 2508 } else { 2509 dumpImpl(pw, filter); 2510 } 2511 } 2512 2513 @Override 2514 public ComponentName getEffectsSuppressor() { 2515 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null; 2516 } 2517 2518 @Override 2519 public boolean matchesCallFilter(Bundle extras) { 2520 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 2521 return mZenModeHelper.matchesCallFilter( 2522 Binder.getCallingUserHandle(), 2523 extras, 2524 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 2525 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 2526 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); 2527 } 2528 2529 @Override 2530 public boolean isSystemConditionProviderEnabled(String path) { 2531 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled"); 2532 return mConditionProviders.isSystemProviderEnabled(path); 2533 } 2534 2535 // Backup/restore interface 2536 @Override 2537 public byte[] getBackupPayload(int user) { 2538 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 2539 //TODO: http://b/22388012 2540 if (user != UserHandle.USER_SYSTEM) { 2541 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user); 2542 return null; 2543 } 2544 synchronized(mPolicyFile) { 2545 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 2546 try { 2547 writePolicyXml(baos, true /*forBackup*/); 2548 return baos.toByteArray(); 2549 } catch (IOException e) { 2550 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 2551 } 2552 } 2553 return null; 2554 } 2555 2556 @Override 2557 public void applyRestore(byte[] payload, int user) { 2558 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 2559 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 2560 if (payload == null) { 2561 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 2562 return; 2563 } 2564 //TODO: http://b/22388012 2565 if (user != UserHandle.USER_SYSTEM) { 2566 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user); 2567 return; 2568 } 2569 synchronized(mPolicyFile) { 2570 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 2571 try { 2572 readPolicyXml(bais, true /*forRestore*/); 2573 savePolicyFile(); 2574 } catch (NumberFormatException | XmlPullParserException | IOException e) { 2575 Slog.w(TAG, "applyRestore: error reading payload", e); 2576 } 2577 } 2578 } 2579 2580 @Override 2581 public boolean isNotificationPolicyAccessGranted(String pkg) { 2582 return checkPolicyAccess(pkg); 2583 } 2584 2585 @Override 2586 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {; 2587 enforceSystemOrSystemUIOrSamePackage(pkg, 2588 "request policy access status for another package"); 2589 return checkPolicyAccess(pkg); 2590 } 2591 2592 @Override 2593 public String[] getPackagesRequestingNotificationPolicyAccess() 2594 throws RemoteException { 2595 enforceSystemOrSystemUI("request policy access packages"); 2596 final long identity = Binder.clearCallingIdentity(); 2597 try { 2598 return mPolicyAccess.getRequestingPackages(); 2599 } finally { 2600 Binder.restoreCallingIdentity(identity); 2601 } 2602 } 2603 2604 @Override 2605 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 2606 throws RemoteException { 2607 enforceSystemOrSystemUI("grant notification policy access"); 2608 final long identity = Binder.clearCallingIdentity(); 2609 try { 2610 synchronized (mNotificationLock) { 2611 mPolicyAccess.put(pkg, granted); 2612 } 2613 } finally { 2614 Binder.restoreCallingIdentity(identity); 2615 } 2616 } 2617 2618 @Override 2619 public Policy getNotificationPolicy(String pkg) { 2620 enforcePolicyAccess(pkg, "getNotificationPolicy"); 2621 final long identity = Binder.clearCallingIdentity(); 2622 try { 2623 return mZenModeHelper.getNotificationPolicy(); 2624 } finally { 2625 Binder.restoreCallingIdentity(identity); 2626 } 2627 } 2628 2629 @Override 2630 public void setNotificationPolicy(String pkg, Policy policy) { 2631 enforcePolicyAccess(pkg, "setNotificationPolicy"); 2632 final long identity = Binder.clearCallingIdentity(); 2633 try { 2634 mZenModeHelper.setNotificationPolicy(policy); 2635 } finally { 2636 Binder.restoreCallingIdentity(identity); 2637 } 2638 } 2639 2640 @Override 2641 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token, 2642 Adjustment adjustment) throws RemoteException { 2643 final long identity = Binder.clearCallingIdentity(); 2644 try { 2645 synchronized (mNotificationLock) { 2646 mNotificationAssistants.checkServiceTokenLocked(token); 2647 int N = mEnqueuedNotifications.size(); 2648 for (int i = 0; i < N; i++) { 2649 final NotificationRecord n = mEnqueuedNotifications.get(i); 2650 if (Objects.equals(adjustment.getKey(), n.getKey()) 2651 && Objects.equals(adjustment.getUser(), n.getUserId())) { 2652 applyAdjustment(n, adjustment); 2653 break; 2654 } 2655 } 2656 } 2657 } finally { 2658 Binder.restoreCallingIdentity(identity); 2659 } 2660 } 2661 2662 @Override 2663 public void applyAdjustmentFromAssistant(INotificationListener token, 2664 Adjustment adjustment) throws RemoteException { 2665 final long identity = Binder.clearCallingIdentity(); 2666 try { 2667 synchronized (mNotificationLock) { 2668 mNotificationAssistants.checkServiceTokenLocked(token); 2669 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); 2670 applyAdjustment(n, adjustment); 2671 } 2672 mRankingHandler.requestSort(true); 2673 } finally { 2674 Binder.restoreCallingIdentity(identity); 2675 } 2676 } 2677 2678 @Override 2679 public void applyAdjustmentsFromAssistant(INotificationListener token, 2680 List<Adjustment> adjustments) throws RemoteException { 2681 2682 final long identity = Binder.clearCallingIdentity(); 2683 try { 2684 synchronized (mNotificationLock) { 2685 mNotificationAssistants.checkServiceTokenLocked(token); 2686 for (Adjustment adjustment : adjustments) { 2687 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); 2688 applyAdjustment(n, adjustment); 2689 } 2690 } 2691 mRankingHandler.requestSort(true); 2692 } finally { 2693 Binder.restoreCallingIdentity(identity); 2694 } 2695 } 2696 2697 @Override 2698 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, 2699 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { 2700 Preconditions.checkNotNull(channel); 2701 Preconditions.checkNotNull(pkg); 2702 Preconditions.checkNotNull(user); 2703 2704 verifyPrivilegedListener(token, user); 2705 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); 2706 } 2707 2708 @Override 2709 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( 2710 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 2711 Preconditions.checkNotNull(pkg); 2712 Preconditions.checkNotNull(user); 2713 verifyPrivilegedListener(token, user); 2714 2715 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), 2716 false /* includeDeleted */); 2717 } 2718 2719 @Override 2720 public ParceledListSlice<NotificationChannelGroup> 2721 getNotificationChannelGroupsFromPrivilegedListener( 2722 INotificationListener token, String pkg, UserHandle user) throws RemoteException { 2723 Preconditions.checkNotNull(pkg); 2724 Preconditions.checkNotNull(user); 2725 verifyPrivilegedListener(token, user); 2726 2727 List<NotificationChannelGroup> groups = new ArrayList<>(); 2728 groups.addAll(mRankingHelper.getNotificationChannelGroups( 2729 pkg, getUidForPackageAndUser(pkg, user))); 2730 return new ParceledListSlice<>(groups); 2731 } 2732 2733 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { 2734 ManagedServiceInfo info; 2735 synchronized (mNotificationLock) { 2736 info = mListeners.checkServiceTokenLocked(token); 2737 } 2738 if (!hasCompanionDevice(info)) { 2739 throw new SecurityException(info + " does not have access"); 2740 } 2741 if (!info.enabledAndUserMatches(user.getIdentifier())) { 2742 throw new SecurityException(info + " does not have access"); 2743 } 2744 } 2745 2746 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { 2747 int uid = 0; 2748 long identity = Binder.clearCallingIdentity(); 2749 try { 2750 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); 2751 } finally { 2752 Binder.restoreCallingIdentity(identity); 2753 } 2754 return uid; 2755 } 2756 }; 2757 2758 private void applyAdjustment(NotificationRecord n, Adjustment adjustment) { 2759 if (n == null) { 2760 return; 2761 } 2762 if (adjustment.getSignals() != null) { 2763 Bundle.setDefusable(adjustment.getSignals(), true); 2764 final ArrayList<String> people = 2765 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE); 2766 final ArrayList<SnoozeCriterion> snoozeCriterionList = 2767 adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA); 2768 n.setPeopleOverride(people); 2769 n.setSnoozeCriteria(snoozeCriterionList); 2770 } 2771 } 2772 2773 private void addAutogroupKeyLocked(String key) { 2774 NotificationRecord n = mNotificationsByKey.get(key); 2775 if (n == null) { 2776 return; 2777 } 2778 n.sbn.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY); 2779 EventLogTags.writeNotificationAutogrouped(key); 2780 } 2781 2782 private void removeAutogroupKeyLocked(String key) { 2783 NotificationRecord n = mNotificationsByKey.get(key); 2784 if (n == null) { 2785 return; 2786 } 2787 n.sbn.setOverrideGroupKey(null); 2788 EventLogTags.writeNotificationUnautogrouped(key); 2789 } 2790 2791 // Clears the 'fake' auto-group summary. 2792 private void clearAutogroupSummaryLocked(int userId, String pkg) { 2793 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 2794 if (summaries != null && summaries.containsKey(pkg)) { 2795 // Clear summary. 2796 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg)); 2797 if (removed != null) { 2798 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED); 2799 } 2800 } 2801 } 2802 2803 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit. 2804 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) { 2805 NotificationRecord summaryRecord = null; 2806 synchronized (mNotificationLock) { 2807 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey); 2808 if (notificationRecord == null) { 2809 // The notification could have been cancelled again already. A successive 2810 // adjustment will post a summary if needed. 2811 return; 2812 } 2813 final StatusBarNotification adjustedSbn = notificationRecord.sbn; 2814 userId = adjustedSbn.getUser().getIdentifier(); 2815 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 2816 if (summaries == null) { 2817 summaries = new ArrayMap<>(); 2818 } 2819 mAutobundledSummaries.put(userId, summaries); 2820 if (!summaries.containsKey(pkg)) { 2821 // Add summary 2822 final ApplicationInfo appInfo = 2823 adjustedSbn.getNotification().extras.getParcelable( 2824 Notification.EXTRA_BUILDER_APPLICATION_INFO); 2825 final Bundle extras = new Bundle(); 2826 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo); 2827 final String channelId = notificationRecord.getChannel().getId(); 2828 final Notification summaryNotification = 2829 new Notification.Builder(getContext(), channelId) 2830 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon()) 2831 .setGroupSummary(true) 2832 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) 2833 .setGroup(GroupHelper.AUTOGROUP_KEY) 2834 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true) 2835 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 2836 .setColor(adjustedSbn.getNotification().color) 2837 .setLocalOnly(true) 2838 .build(); 2839 summaryNotification.extras.putAll(extras); 2840 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); 2841 if (appIntent != null) { 2842 summaryNotification.contentIntent = PendingIntent.getActivityAsUser( 2843 getContext(), 0, appIntent, 0, null, UserHandle.of(userId)); 2844 } 2845 final StatusBarNotification summarySbn = 2846 new StatusBarNotification(adjustedSbn.getPackageName(), 2847 adjustedSbn.getOpPkg(), 2848 Integer.MAX_VALUE, 2849 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(), 2850 adjustedSbn.getInitialPid(), summaryNotification, 2851 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY, 2852 System.currentTimeMillis()); 2853 summaryRecord = new NotificationRecord(getContext(), summarySbn, 2854 notificationRecord.getChannel()); 2855 summaries.put(pkg, summarySbn.getKey()); 2856 } 2857 } 2858 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID, 2859 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) { 2860 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord)); 2861 } 2862 } 2863 2864 private String disableNotificationEffects(NotificationRecord record) { 2865 if (mDisableNotificationEffects) { 2866 return "booleanState"; 2867 } 2868 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2869 return "listenerHints"; 2870 } 2871 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 2872 return "callState"; 2873 } 2874 return null; 2875 }; 2876 2877 private void dumpJson(PrintWriter pw, DumpFilter filter) { 2878 JSONObject dump = new JSONObject(); 2879 try { 2880 dump.put("service", "Notification Manager"); 2881 dump.put("bans", mRankingHelper.dumpBansJson(filter)); 2882 dump.put("ranking", mRankingHelper.dumpJson(filter)); 2883 dump.put("stats", mUsageStats.dumpJson(filter)); 2884 dump.put("channels", mRankingHelper.dumpChannelsJson(filter)); 2885 } catch (JSONException e) { 2886 e.printStackTrace(); 2887 } 2888 pw.println(dump); 2889 } 2890 2891 private void dumpProto(FileDescriptor fd, DumpFilter filter) { 2892 final ProtoOutputStream proto = new ProtoOutputStream(fd); 2893 synchronized (mNotificationLock) { 2894 long records = proto.start(NotificationServiceDumpProto.RECORDS); 2895 int N = mNotificationList.size(); 2896 if (N > 0) { 2897 for (int i = 0; i < N; i++) { 2898 final NotificationRecord nr = mNotificationList.get(i); 2899 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2900 nr.dump(proto, filter.redact); 2901 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED); 2902 } 2903 } 2904 N = mEnqueuedNotifications.size(); 2905 if (N > 0) { 2906 for (int i = 0; i < N; i++) { 2907 final NotificationRecord nr = mEnqueuedNotifications.get(i); 2908 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2909 nr.dump(proto, filter.redact); 2910 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED); 2911 } 2912 } 2913 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed(); 2914 N = snoozed.size(); 2915 if (N > 0) { 2916 for (int i = 0; i < N; i++) { 2917 final NotificationRecord nr = snoozed.get(i); 2918 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2919 nr.dump(proto, filter.redact); 2920 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED); 2921 } 2922 } 2923 proto.end(records); 2924 } 2925 2926 long zenLog = proto.start(NotificationServiceDumpProto.ZEN); 2927 mZenModeHelper.dump(proto); 2928 for (ComponentName suppressor : mEffectsSuppressors) { 2929 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString()); 2930 } 2931 proto.end(zenLog); 2932 2933 proto.flush(); 2934 } 2935 2936 void dumpImpl(PrintWriter pw, DumpFilter filter) { 2937 pw.print("Current Notification Manager state"); 2938 if (filter.filtered) { 2939 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 2940 } 2941 pw.println(':'); 2942 int N; 2943 final boolean zenOnly = filter.filtered && filter.zen; 2944 2945 if (!zenOnly) { 2946 synchronized (mToastQueue) { 2947 N = mToastQueue.size(); 2948 if (N > 0) { 2949 pw.println(" Toast Queue:"); 2950 for (int i=0; i<N; i++) { 2951 mToastQueue.get(i).dump(pw, " ", filter); 2952 } 2953 pw.println(" "); 2954 } 2955 } 2956 } 2957 2958 synchronized (mNotificationLock) { 2959 if (!zenOnly) { 2960 N = mNotificationList.size(); 2961 if (N > 0) { 2962 pw.println(" Notification List:"); 2963 for (int i=0; i<N; i++) { 2964 final NotificationRecord nr = mNotificationList.get(i); 2965 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2966 nr.dump(pw, " ", getContext(), filter.redact); 2967 } 2968 pw.println(" "); 2969 } 2970 2971 if (!filter.filtered) { 2972 N = mLights.size(); 2973 if (N > 0) { 2974 pw.println(" Lights List:"); 2975 for (int i=0; i<N; i++) { 2976 if (i == N - 1) { 2977 pw.print(" > "); 2978 } else { 2979 pw.print(" "); 2980 } 2981 pw.println(mLights.get(i)); 2982 } 2983 pw.println(" "); 2984 } 2985 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 2986 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 2987 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 2988 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 2989 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 2990 pw.println(" mCallState=" + callStateToString(mCallState)); 2991 pw.println(" mSystemReady=" + mSystemReady); 2992 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate); 2993 } 2994 pw.println(" mArchive=" + mArchive.toString()); 2995 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 2996 int j=0; 2997 while (iter.hasNext()) { 2998 final StatusBarNotification sbn = iter.next(); 2999 if (filter != null && !filter.matches(sbn)) continue; 3000 pw.println(" " + sbn); 3001 if (++j >= 5) { 3002 if (iter.hasNext()) pw.println(" ..."); 3003 break; 3004 } 3005 } 3006 3007 if (!zenOnly) { 3008 N = mEnqueuedNotifications.size(); 3009 if (N > 0) { 3010 pw.println(" Enqueued Notification List:"); 3011 for (int i = 0; i < N; i++) { 3012 final NotificationRecord nr = mEnqueuedNotifications.get(i); 3013 if (filter.filtered && !filter.matches(nr.sbn)) continue; 3014 nr.dump(pw, " ", getContext(), filter.redact); 3015 } 3016 pw.println(" "); 3017 } 3018 3019 mSnoozeHelper.dump(pw, filter); 3020 } 3021 } 3022 3023 if (!zenOnly) { 3024 pw.println("\n Ranking Config:"); 3025 mRankingHelper.dump(pw, " ", filter); 3026 3027 pw.println("\n Notification listeners:"); 3028 mListeners.dump(pw, filter); 3029 pw.print(" mListenerHints: "); pw.println(mListenerHints); 3030 pw.print(" mListenersDisablingEffects: ("); 3031 N = mListenersDisablingEffects.size(); 3032 for (int i = 0; i < N; i++) { 3033 final int hint = mListenersDisablingEffects.keyAt(i); 3034 if (i > 0) pw.print(';'); 3035 pw.print("hint[" + hint + "]:"); 3036 3037 final ArraySet<ManagedServiceInfo> listeners = 3038 mListenersDisablingEffects.valueAt(i); 3039 final int listenerSize = listeners.size(); 3040 3041 for (int j = 0; j < listenerSize; j++) { 3042 if (i > 0) pw.print(','); 3043 final ManagedServiceInfo listener = listeners.valueAt(i); 3044 pw.print(listener.component); 3045 } 3046 } 3047 pw.println(')'); 3048 pw.println("\n Notification assistant services:"); 3049 mNotificationAssistants.dump(pw, filter); 3050 } 3051 3052 if (!filter.filtered || zenOnly) { 3053 pw.println("\n Zen Mode:"); 3054 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 3055 mZenModeHelper.dump(pw, " "); 3056 3057 pw.println("\n Zen Log:"); 3058 ZenLog.dump(pw, " "); 3059 } 3060 3061 pw.println("\n Policy access:"); 3062 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); 3063 3064 pw.println("\n Condition providers:"); 3065 mConditionProviders.dump(pw, filter); 3066 3067 pw.println("\n Group summaries:"); 3068 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 3069 NotificationRecord r = entry.getValue(); 3070 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 3071 if (mNotificationsByKey.get(r.getKey()) != r) { 3072 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 3073 r.dump(pw, " ", getContext(), filter.redact); 3074 } 3075 } 3076 3077 if (!zenOnly) { 3078 pw.println("\n Usage Stats:"); 3079 mUsageStats.dump(pw, " ", filter); 3080 } 3081 } 3082 } 3083 3084 /** 3085 * The private API only accessible to the system process. 3086 */ 3087 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 3088 @Override 3089 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 3090 String tag, int id, Notification notification, int userId) { 3091 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 3092 userId); 3093 } 3094 3095 @Override 3096 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 3097 int userId) { 3098 checkCallerIsSystem(); 3099 mHandler.post(new Runnable() { 3100 @Override 3101 public void run() { 3102 synchronized (mNotificationLock) { 3103 removeForegroundServiceFlagByListLocked( 3104 mEnqueuedNotifications, pkg, notificationId, userId); 3105 removeForegroundServiceFlagByListLocked( 3106 mNotificationList, pkg, notificationId, userId); 3107 } 3108 } 3109 }); 3110 } 3111 3112 private void removeForegroundServiceFlagByListLocked( 3113 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId, int userId) { 3114 NotificationRecord r = 3115 findNotificationByListLocked(notificationList, pkg, null, notificationId, userId); 3116 if (r == null) { 3117 return; 3118 } 3119 StatusBarNotification sbn = r.sbn; 3120 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 3121 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove 3122 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received 3123 // initially *and* force remove FLAG_FOREGROUND_SERVICE. 3124 sbn.getNotification().flags = 3125 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE); 3126 mRankingHelper.sort(mNotificationList); 3127 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */); 3128 mGroupHelper.onNotificationPosted(sbn); 3129 } 3130 }; 3131 3132 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 3133 final int callingPid, final String tag, final int id, final Notification notification, 3134 int incomingUserId) { 3135 if (DBG) { 3136 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 3137 + " notification=" + notification); 3138 } 3139 checkCallerIsSystemOrSameApp(pkg); 3140 3141 final int userId = ActivityManager.handleIncomingUser(callingPid, 3142 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 3143 final UserHandle user = new UserHandle(userId); 3144 3145 if (pkg == null || notification == null) { 3146 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 3147 + " id=" + id + " notification=" + notification); 3148 } 3149 3150 // The system can post notifications for any package, let us resolve that. 3151 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId); 3152 3153 // Fix the notification as best we can. 3154 try { 3155 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( 3156 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 3157 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); 3158 Notification.addFieldsFromContext(ai, notification); 3159 } catch (NameNotFoundException e) { 3160 Slog.e(TAG, "Cannot create a context for sending app", e); 3161 return; 3162 } 3163 3164 mUsageStats.registerEnqueuedByApp(pkg); 3165 3166 // setup local book-keeping 3167 String channelId = notification.getChannelId(); 3168 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) { 3169 channelId = (new Notification.TvExtender(notification)).getChannelId(); 3170 } 3171 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg, 3172 notificationUid, channelId, false /* includeDeleted */); 3173 if (channel == null) { 3174 final String noChannelStr = "No Channel found for " 3175 + "pkg=" + pkg 3176 + ", channelId=" + channelId 3177 + ", id=" + id 3178 + ", tag=" + tag 3179 + ", opPkg=" + opPkg 3180 + ", callingUid=" + callingUid 3181 + ", userId=" + userId 3182 + ", incomingUserId=" + incomingUserId 3183 + ", notificationUid=" + notificationUid 3184 + ", notification=" + notification; 3185 Log.e(TAG, noChannelStr); 3186 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" + 3187 "Failed to post notification on channel \"" + channelId + "\"\n" + 3188 "See log for more details"); 3189 return; 3190 } 3191 3192 final StatusBarNotification n = new StatusBarNotification( 3193 pkg, opPkg, id, tag, notificationUid, callingPid, notification, 3194 user, null, System.currentTimeMillis()); 3195 final NotificationRecord r = new NotificationRecord(getContext(), n, channel); 3196 3197 if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) { 3198 return; 3199 } 3200 3201 // Whitelist pending intents. 3202 if (notification.allPendingIntents != null) { 3203 final int intentCount = notification.allPendingIntents.size(); 3204 if (intentCount > 0) { 3205 final ActivityManagerInternal am = LocalServices 3206 .getService(ActivityManagerInternal.class); 3207 final long duration = LocalServices.getService( 3208 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration(); 3209 for (int i = 0; i < intentCount; i++) { 3210 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); 3211 if (pendingIntent != null) { 3212 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), 3213 WHITELIST_TOKEN, duration); 3214 } 3215 } 3216 } 3217 } 3218 3219 mHandler.post(new EnqueueNotificationRunnable(userId, r)); 3220 } 3221 3222 private void doChannelWarningToast(CharSequence toastText) { 3223 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0; 3224 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(), 3225 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0; 3226 if (warningEnabled) { 3227 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText, 3228 Toast.LENGTH_SHORT); 3229 toast.show(); 3230 } 3231 } 3232 3233 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) { 3234 // The system can post notifications on behalf of any package it wants 3235 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) { 3236 try { 3237 return getContext().getPackageManager() 3238 .getPackageUidAsUser(opPackageName, userId); 3239 } catch (NameNotFoundException e) { 3240 /* ignore */ 3241 } 3242 } 3243 return callingUid; 3244 } 3245 3246 /** 3247 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking. 3248 * 3249 * Has side effects. 3250 */ 3251 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag, 3252 NotificationRecord r) { 3253 final String pkg = r.sbn.getPackageName(); 3254 final boolean isSystemNotification = 3255 isUidSystemOrPhone(callingUid) || ("android".equals(pkg)); 3256 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 3257 3258 // Limit the number of notifications that any given package except the android 3259 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 3260 if (!isSystemNotification && !isNotificationFromListener) { 3261 synchronized (mNotificationLock) { 3262 if (mNotificationsByKey.get(r.sbn.getKey()) != null) { 3263 // this is an update, rate limit updates only 3264 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); 3265 if (appEnqueueRate > mMaxPackageEnqueueRate) { 3266 mUsageStats.registerOverRateQuota(pkg); 3267 final long now = SystemClock.elapsedRealtime(); 3268 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { 3269 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate 3270 + ". Shedding events. package=" + pkg); 3271 mLastOverRateLogTime = now; 3272 } 3273 return false; 3274 } 3275 } else if (isCallerInstantApp(pkg)) { 3276 // Ephemeral apps have some special constraints for notifications. 3277 // They are not allowed to create new notifications however they are allowed to 3278 // update notifications created by the system (e.g. a foreground service 3279 // notification). 3280 throw new SecurityException("Instant app " + pkg 3281 + " cannot create notifications"); 3282 } 3283 3284 int count = 0; 3285 final int N = mNotificationList.size(); 3286 for (int i=0; i<N; i++) { 3287 final NotificationRecord existing = mNotificationList.get(i); 3288 if (existing.sbn.getPackageName().equals(pkg) 3289 && existing.sbn.getUserId() == userId) { 3290 if (existing.sbn.getId() == id 3291 && TextUtils.equals(existing.sbn.getTag(), tag)) { 3292 break; // Allow updating existing notification 3293 } 3294 count++; 3295 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 3296 mUsageStats.registerOverCountQuota(pkg); 3297 Slog.e(TAG, "Package has already posted " + count 3298 + " notifications. Not showing more. package=" + pkg); 3299 return false; 3300 } 3301 } 3302 } 3303 } 3304 } 3305 3306 // snoozed apps 3307 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) { 3308 MetricsLogger.action(r.getLogMaker() 3309 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE) 3310 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)); 3311 if (DBG) { 3312 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey()); 3313 } 3314 mSnoozeHelper.update(userId, r); 3315 savePolicyFile(); 3316 return false; 3317 } 3318 3319 3320 // blocked apps 3321 if (isBlocked(r, mUsageStats)) { 3322 return false; 3323 } 3324 3325 return true; 3326 } 3327 3328 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) { 3329 final String pkg = r.sbn.getPackageName(); 3330 final int callingUid = r.sbn.getUid(); 3331 3332 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); 3333 if (isPackageSuspended) { 3334 Slog.e(TAG, "Suppressing notification from package due to package " 3335 + "suspended by administrator."); 3336 usageStats.registerSuspendedByAdmin(r); 3337 return isPackageSuspended; 3338 } 3339 3340 final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE 3341 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE; 3342 if (isBlocked) { 3343 Slog.e(TAG, "Suppressing notification from package by user request."); 3344 usageStats.registerBlocked(r); 3345 } 3346 return isBlocked; 3347 } 3348 3349 protected class SnoozeNotificationRunnable implements Runnable { 3350 private final String mKey; 3351 private final long mDuration; 3352 private final String mSnoozeCriterionId; 3353 3354 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) { 3355 mKey = key; 3356 mDuration = duration; 3357 mSnoozeCriterionId = snoozeCriterionId; 3358 } 3359 3360 @Override 3361 public void run() { 3362 synchronized (mNotificationLock) { 3363 final NotificationRecord r = findNotificationByKeyLocked(mKey); 3364 if (r != null) { 3365 snoozeLocked(r); 3366 } 3367 } 3368 } 3369 3370 void snoozeLocked(NotificationRecord r) { 3371 if (r.sbn.isGroup()) { 3372 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked( 3373 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId()); 3374 if (r.getNotification().isGroupSummary()) { 3375 // snooze summary and all children 3376 for (int i = 0; i < groupNotifications.size(); i++) { 3377 snoozeNotificationLocked(groupNotifications.get(i)); 3378 } 3379 } else { 3380 // if there is a valid summary for this group, and we are snoozing the only 3381 // child, also snooze the summary 3382 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) { 3383 if (groupNotifications.size() != 2) { 3384 snoozeNotificationLocked(r); 3385 } else { 3386 // snooze summary and the one child 3387 for (int i = 0; i < groupNotifications.size(); i++) { 3388 snoozeNotificationLocked(groupNotifications.get(i)); 3389 } 3390 } 3391 } else { 3392 snoozeNotificationLocked(r); 3393 } 3394 } 3395 } else { 3396 // just snooze the one notification 3397 snoozeNotificationLocked(r); 3398 } 3399 } 3400 3401 void snoozeNotificationLocked(NotificationRecord r) { 3402 MetricsLogger.action(r.getLogMaker() 3403 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED) 3404 .setType(MetricsEvent.TYPE_CLOSE) 3405 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA, 3406 mSnoozeCriterionId == null ? 0 : 1)); 3407 cancelNotificationLocked(r, false, REASON_SNOOZED); 3408 updateLightsLocked(); 3409 if (mSnoozeCriterionId != null) { 3410 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId); 3411 mSnoozeHelper.snooze(r); 3412 } else { 3413 mSnoozeHelper.snooze(r, mDuration); 3414 } 3415 savePolicyFile(); 3416 } 3417 } 3418 3419 protected class EnqueueNotificationRunnable implements Runnable { 3420 private final NotificationRecord r; 3421 private final int userId; 3422 3423 EnqueueNotificationRunnable(int userId, NotificationRecord r) { 3424 this.userId = userId; 3425 this.r = r; 3426 }; 3427 3428 @Override 3429 public void run() { 3430 synchronized (mNotificationLock) { 3431 mEnqueuedNotifications.add(r); 3432 scheduleTimeoutLocked(r); 3433 3434 final StatusBarNotification n = r.sbn; 3435 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 3436 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 3437 if (old != null) { 3438 // Retain ranking information from previous record 3439 r.copyRankingInformation(old); 3440 } 3441 3442 final int callingUid = n.getUid(); 3443 final int callingPid = n.getInitialPid(); 3444 final Notification notification = n.getNotification(); 3445 final String pkg = n.getPackageName(); 3446 final int id = n.getId(); 3447 final String tag = n.getTag(); 3448 3449 // Handle grouped notifications and bail out early if we 3450 // can to avoid extracting signals. 3451 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 3452 3453 // if this is a group child, unsnooze parent summary 3454 if (n.isGroup() && notification.isGroupChild()) { 3455 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey()); 3456 } 3457 3458 // This conditional is a dirty hack to limit the logging done on 3459 // behalf of the download manager without affecting other apps. 3460 if (!pkg.equals("com.android.providers.downloads") 3461 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 3462 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 3463 if (old != null) { 3464 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 3465 } 3466 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 3467 pkg, id, tag, userId, notification.toString(), 3468 enqueueStatus); 3469 } 3470 3471 mRankingHelper.extractSignals(r); 3472 3473 // tell the assistant service about the notification 3474 if (mNotificationAssistants.isEnabled()) { 3475 mNotificationAssistants.onNotificationEnqueued(r); 3476 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()), 3477 DELAY_FOR_ASSISTANT_TIME); 3478 } else { 3479 mHandler.post(new PostNotificationRunnable(r.getKey())); 3480 } 3481 } 3482 } 3483 } 3484 3485 protected class PostNotificationRunnable implements Runnable { 3486 private final String key; 3487 3488 PostNotificationRunnable(String key) { 3489 this.key = key; 3490 } 3491 3492 @Override 3493 public void run() { 3494 synchronized (mNotificationLock) { 3495 try { 3496 NotificationRecord r = null; 3497 int N = mEnqueuedNotifications.size(); 3498 for (int i = 0; i < N; i++) { 3499 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 3500 if (Objects.equals(key, enqueued.getKey())) { 3501 r = enqueued; 3502 break; 3503 } 3504 } 3505 if (r == null) { 3506 Slog.i(TAG, "Cannot find enqueued record for key: " + key); 3507 return; 3508 } 3509 NotificationRecord old = mNotificationsByKey.get(key); 3510 final StatusBarNotification n = r.sbn; 3511 final Notification notification = n.getNotification(); 3512 int index = indexOfNotificationLocked(n.getKey()); 3513 if (index < 0) { 3514 mNotificationList.add(r); 3515 mUsageStats.registerPostedByApp(r); 3516 } else { 3517 old = mNotificationList.get(index); 3518 mNotificationList.set(index, r); 3519 mUsageStats.registerUpdatedByApp(r, old); 3520 // Make sure we don't lose the foreground service state. 3521 notification.flags |= 3522 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 3523 r.isUpdate = true; 3524 } 3525 3526 mNotificationsByKey.put(n.getKey(), r); 3527 3528 // Ensure if this is a foreground service that the proper additional 3529 // flags are set. 3530 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 3531 notification.flags |= Notification.FLAG_ONGOING_EVENT 3532 | Notification.FLAG_NO_CLEAR; 3533 } 3534 3535 applyZenModeLocked(r); 3536 mRankingHelper.sort(mNotificationList); 3537 3538 if (notification.getSmallIcon() != null) { 3539 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 3540 mListeners.notifyPostedLocked(n, oldSbn); 3541 mHandler.post(new Runnable() { 3542 @Override 3543 public void run() { 3544 mGroupHelper.onNotificationPosted(n); 3545 } 3546 }); 3547 } else { 3548 Slog.e(TAG, "Not posting notification without small icon: " + notification); 3549 if (old != null && !old.isCanceled) { 3550 mListeners.notifyRemovedLocked(n, 3551 NotificationListenerService.REASON_ERROR); 3552 mHandler.post(new Runnable() { 3553 @Override 3554 public void run() { 3555 mGroupHelper.onNotificationRemoved(n); 3556 } 3557 }); 3558 } 3559 // ATTENTION: in a future release we will bail out here 3560 // so that we do not play sounds, show lights, etc. for invalid 3561 // notifications 3562 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 3563 + n.getPackageName()); 3564 } 3565 3566 buzzBeepBlinkLocked(r); 3567 } finally { 3568 int N = mEnqueuedNotifications.size(); 3569 for (int i = 0; i < N; i++) { 3570 final NotificationRecord enqueued = mEnqueuedNotifications.get(i); 3571 if (Objects.equals(key, enqueued.getKey())) { 3572 mEnqueuedNotifications.remove(i); 3573 break; 3574 } 3575 } 3576 } 3577 } 3578 } 3579 } 3580 3581 /** 3582 * Ensures that grouped notification receive their special treatment. 3583 * 3584 * <p>Cancels group children if the new notification causes a group to lose 3585 * its summary.</p> 3586 * 3587 * <p>Updates mSummaryByGroupKey.</p> 3588 */ 3589 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 3590 int callingUid, int callingPid) { 3591 StatusBarNotification sbn = r.sbn; 3592 Notification n = sbn.getNotification(); 3593 if (n.isGroupSummary() && !sbn.isAppGroup()) { 3594 // notifications without a group shouldn't be a summary, otherwise autobundling can 3595 // lead to bugs 3596 n.flags &= ~Notification.FLAG_GROUP_SUMMARY; 3597 } 3598 3599 String group = sbn.getGroupKey(); 3600 boolean isSummary = n.isGroupSummary(); 3601 3602 Notification oldN = old != null ? old.sbn.getNotification() : null; 3603 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 3604 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 3605 3606 if (oldIsSummary) { 3607 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 3608 if (removedSummary != old) { 3609 String removedKey = 3610 removedSummary != null ? removedSummary.getKey() : "<null>"; 3611 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 3612 ", removed=" + removedKey); 3613 } 3614 } 3615 if (isSummary) { 3616 mSummaryByGroupKey.put(group, r); 3617 } 3618 3619 // Clear out group children of the old notification if the update 3620 // causes the group summary to go away. This happens when the old 3621 // notification was a summary and the new one isn't, or when the old 3622 // notification was a summary and its group key changed. 3623 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 3624 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */); 3625 } 3626 } 3627 3628 @VisibleForTesting 3629 void scheduleTimeoutLocked(NotificationRecord record) { 3630 if (record.getNotification().getTimeoutAfter() > 0) { 3631 final PendingIntent pi = PendingIntent.getBroadcast(getContext(), 3632 REQUEST_CODE_TIMEOUT, 3633 new Intent(ACTION_NOTIFICATION_TIMEOUT) 3634 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT) 3635 .appendPath(record.getKey()).build()) 3636 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 3637 .putExtra(EXTRA_KEY, record.getKey()), 3638 PendingIntent.FLAG_UPDATE_CURRENT); 3639 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 3640 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi); 3641 } 3642 } 3643 3644 @VisibleForTesting 3645 void buzzBeepBlinkLocked(NotificationRecord record) { 3646 boolean buzz = false; 3647 boolean beep = false; 3648 boolean blink = false; 3649 3650 final Notification notification = record.sbn.getNotification(); 3651 final String key = record.getKey(); 3652 3653 // Should this notification make noise, vibe, or use the LED? 3654 final boolean aboveThreshold = 3655 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT; 3656 final boolean canInterrupt = aboveThreshold && !record.isIntercepted(); 3657 if (DBG) 3658 Slog.v(TAG, 3659 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt + 3660 " intercept=" + record.isIntercepted() 3661 ); 3662 3663 // If we're not supposed to beep, vibrate, etc. then don't. 3664 final String disableEffects = disableNotificationEffects(record); 3665 if (disableEffects != null) { 3666 ZenLog.traceDisableEffects(record, disableEffects); 3667 } 3668 3669 // Remember if this notification already owns the notification channels. 3670 boolean wasBeep = key != null && key.equals(mSoundNotificationKey); 3671 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey); 3672 // These are set inside the conditional if the notification is allowed to make noise. 3673 boolean hasValidVibrate = false; 3674 boolean hasValidSound = false; 3675 3676 if (isNotificationForCurrentUser(record)) { 3677 // If the notification will appear in the status bar, it should send an accessibility 3678 // event 3679 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { 3680 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 3681 } 3682 3683 if (disableEffects == null 3684 && canInterrupt 3685 && mSystemReady 3686 && mAudioManager != null) { 3687 if (DBG) Slog.v(TAG, "Interrupting!"); 3688 Uri soundUri = record.getSound(); 3689 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri); 3690 long[] vibration = record.getVibration(); 3691 // Demote sound to vibration if vibration missing & phone in vibration mode. 3692 if (vibration == null 3693 && hasValidSound 3694 && (mAudioManager.getRingerModeInternal() 3695 == AudioManager.RINGER_MODE_VIBRATE)) { 3696 vibration = mFallbackVibrationPattern; 3697 } 3698 hasValidVibrate = vibration != null; 3699 3700 if (!shouldMuteNotificationLocked(record)) { 3701 if (hasValidSound) { 3702 mSoundNotificationKey = key; 3703 if (mInCall) { 3704 playInCallNotification(); 3705 beep = true; 3706 } else { 3707 beep = playSound(record, soundUri); 3708 } 3709 } 3710 3711 final boolean ringerModeSilent = 3712 mAudioManager.getRingerModeInternal() 3713 == AudioManager.RINGER_MODE_SILENT; 3714 if (!mInCall && hasValidVibrate && !ringerModeSilent) { 3715 mVibrateNotificationKey = key; 3716 3717 buzz = playVibration(record, vibration); 3718 } 3719 } 3720 } 3721 } 3722 // If a notification is updated to remove the actively playing sound or vibrate, 3723 // cancel that feedback now 3724 if (wasBeep && !hasValidSound) { 3725 clearSoundLocked(); 3726 } 3727 if (wasBuzz && !hasValidVibrate) { 3728 clearVibrateLocked(); 3729 } 3730 3731 // light 3732 // release the light 3733 boolean wasShowLights = mLights.remove(key); 3734 if (record.getLight() != null && aboveThreshold 3735 && ((record.getSuppressedVisualEffects() 3736 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) { 3737 mLights.add(key); 3738 updateLightsLocked(); 3739 if (mUseAttentionLight) { 3740 mAttentionLight.pulse(); 3741 } 3742 blink = true; 3743 } else if (wasShowLights) { 3744 updateLightsLocked(); 3745 } 3746 if (buzz || beep || blink) { 3747 MetricsLogger.action(record.getLogMaker() 3748 .setCategory(MetricsEvent.NOTIFICATION_ALERT) 3749 .setType(MetricsEvent.TYPE_OPEN) 3750 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0))); 3751 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 3752 } 3753 } 3754 3755 boolean shouldMuteNotificationLocked(final NotificationRecord record) { 3756 final Notification notification = record.getNotification(); 3757 if(record.isUpdate 3758 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { 3759 return true; 3760 } 3761 if (record.sbn.isGroup()) { 3762 return notification.suppressAlertingDueToGrouping(); 3763 } 3764 return false; 3765 } 3766 3767 private boolean playSound(final NotificationRecord record, Uri soundUri) { 3768 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; 3769 // do not play notifications if there is a user of exclusive audio focus 3770 // or the device is in vibrate mode 3771 if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal() 3772 != AudioManager.RINGER_MODE_VIBRATE) { 3773 final long identity = Binder.clearCallingIdentity(); 3774 try { 3775 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 3776 if (player != null) { 3777 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 3778 + " with attributes " + record.getAudioAttributes()); 3779 player.playAsync(soundUri, record.sbn.getUser(), looping, 3780 record.getAudioAttributes()); 3781 return true; 3782 } 3783 } catch (RemoteException e) { 3784 } finally { 3785 Binder.restoreCallingIdentity(identity); 3786 } 3787 } 3788 return false; 3789 } 3790 3791 private boolean playVibration(final NotificationRecord record, long[] vibration) { 3792 // Escalate privileges so we can use the vibrator even if the 3793 // notifying app does not have the VIBRATE permission. 3794 long identity = Binder.clearCallingIdentity(); 3795 try { 3796 final boolean insistent = 3797 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; 3798 final VibrationEffect effect = VibrationEffect.createWaveform( 3799 vibration, insistent ? 0 : -1 /*repeatIndex*/); 3800 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 3801 effect, record.getAudioAttributes()); 3802 return true; 3803 } catch (IllegalArgumentException e) { 3804 Slog.e(TAG, "Error creating vibration waveform with pattern: " + 3805 Arrays.toString(vibration)); 3806 return false; 3807 } finally{ 3808 Binder.restoreCallingIdentity(identity); 3809 } 3810 } 3811 3812 private boolean isNotificationForCurrentUser(NotificationRecord record) { 3813 final int currentUser; 3814 final long token = Binder.clearCallingIdentity(); 3815 try { 3816 currentUser = ActivityManager.getCurrentUser(); 3817 } finally { 3818 Binder.restoreCallingIdentity(token); 3819 } 3820 return (record.getUserId() == UserHandle.USER_ALL || 3821 record.getUserId() == currentUser || 3822 mUserProfiles.isCurrentProfile(record.getUserId())); 3823 } 3824 3825 private void playInCallNotification() { 3826 new Thread() { 3827 @Override 3828 public void run() { 3829 // If toneGenerator creation fails, just continue the call 3830 // without playing the notification sound. 3831 try { 3832 synchronized (mInCallToneGeneratorLock) { 3833 if (mInCallToneGenerator != null) { 3834 // limit this tone to 1 second; BEEP2 should in fact be much shorter 3835 mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000); 3836 } 3837 } 3838 } catch (RuntimeException e) { 3839 Log.w(TAG, "Exception from ToneGenerator: " + e); 3840 } 3841 } 3842 }.start(); 3843 } 3844 3845 void showNextToastLocked() { 3846 ToastRecord record = mToastQueue.get(0); 3847 while (record != null) { 3848 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 3849 try { 3850 record.callback.show(record.token); 3851 scheduleTimeoutLocked(record); 3852 return; 3853 } catch (RemoteException e) { 3854 Slog.w(TAG, "Object died trying to show notification " + record.callback 3855 + " in package " + record.pkg); 3856 // remove it from the list and let the process die 3857 int index = mToastQueue.indexOf(record); 3858 if (index >= 0) { 3859 mToastQueue.remove(index); 3860 } 3861 keepProcessAliveIfNeededLocked(record.pid); 3862 if (mToastQueue.size() > 0) { 3863 record = mToastQueue.get(0); 3864 } else { 3865 record = null; 3866 } 3867 } 3868 } 3869 } 3870 3871 void cancelToastLocked(int index) { 3872 ToastRecord record = mToastQueue.get(index); 3873 try { 3874 record.callback.hide(); 3875 } catch (RemoteException e) { 3876 Slog.w(TAG, "Object died trying to hide notification " + record.callback 3877 + " in package " + record.pkg); 3878 // don't worry about this, we're about to remove it from 3879 // the list anyway 3880 } 3881 3882 ToastRecord lastToast = mToastQueue.remove(index); 3883 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY); 3884 3885 keepProcessAliveIfNeededLocked(record.pid); 3886 if (mToastQueue.size() > 0) { 3887 // Show the next one. If the callback fails, this will remove 3888 // it from the list, so don't assume that the list hasn't changed 3889 // after this point. 3890 showNextToastLocked(); 3891 } 3892 } 3893 3894 private void scheduleTimeoutLocked(ToastRecord r) 3895 { 3896 mHandler.removeCallbacksAndMessages(r); 3897 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 3898 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 3899 mHandler.sendMessageDelayed(m, delay); 3900 } 3901 3902 private void handleTimeout(ToastRecord record) 3903 { 3904 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 3905 synchronized (mToastQueue) { 3906 int index = indexOfToastLocked(record.pkg, record.callback); 3907 if (index >= 0) { 3908 cancelToastLocked(index); 3909 } 3910 } 3911 } 3912 3913 // lock on mToastQueue 3914 int indexOfToastLocked(String pkg, ITransientNotification callback) 3915 { 3916 IBinder cbak = callback.asBinder(); 3917 ArrayList<ToastRecord> list = mToastQueue; 3918 int len = list.size(); 3919 for (int i=0; i<len; i++) { 3920 ToastRecord r = list.get(i); 3921 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 3922 return i; 3923 } 3924 } 3925 return -1; 3926 } 3927 3928 // lock on mToastQueue 3929 void keepProcessAliveIfNeededLocked(int pid) 3930 { 3931 int toastCount = 0; // toasts from this pid 3932 ArrayList<ToastRecord> list = mToastQueue; 3933 int N = list.size(); 3934 for (int i=0; i<N; i++) { 3935 ToastRecord r = list.get(i); 3936 if (r.pid == pid) { 3937 toastCount++; 3938 } 3939 } 3940 try { 3941 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast"); 3942 } catch (RemoteException e) { 3943 // Shouldn't happen. 3944 } 3945 } 3946 3947 private void handleRankingReconsideration(Message message) { 3948 if (!(message.obj instanceof RankingReconsideration)) return; 3949 RankingReconsideration recon = (RankingReconsideration) message.obj; 3950 recon.run(); 3951 boolean changed; 3952 synchronized (mNotificationLock) { 3953 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 3954 if (record == null) { 3955 return; 3956 } 3957 int indexBefore = findNotificationRecordIndexLocked(record); 3958 boolean interceptBefore = record.isIntercepted(); 3959 int visibilityBefore = record.getPackageVisibilityOverride(); 3960 recon.applyChangesLocked(record); 3961 applyZenModeLocked(record); 3962 mRankingHelper.sort(mNotificationList); 3963 int indexAfter = findNotificationRecordIndexLocked(record); 3964 boolean interceptAfter = record.isIntercepted(); 3965 int visibilityAfter = record.getPackageVisibilityOverride(); 3966 changed = indexBefore != indexAfter || interceptBefore != interceptAfter 3967 || visibilityBefore != visibilityAfter; 3968 if (interceptBefore && !interceptAfter) { 3969 buzzBeepBlinkLocked(record); 3970 } 3971 } 3972 if (changed) { 3973 scheduleSendRankingUpdate(); 3974 } 3975 } 3976 3977 private void handleRankingSort(Message msg) { 3978 if (!(msg.obj instanceof Boolean)) return; 3979 if (mRankingHelper == null) return; 3980 boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj; 3981 synchronized (mNotificationLock) { 3982 final int N = mNotificationList.size(); 3983 // Any field that can change via one of the extractors or by the assistant 3984 // needs to be added here. 3985 ArrayList<String> orderBefore = new ArrayList<String>(N); 3986 ArrayList<String> groupOverrideBefore = new ArrayList<>(N); 3987 int[] visibilities = new int[N]; 3988 boolean[] showBadges = new boolean[N]; 3989 for (int i = 0; i < N; i++) { 3990 final NotificationRecord r = mNotificationList.get(i); 3991 orderBefore.add(r.getKey()); 3992 groupOverrideBefore.add(r.sbn.getGroupKey()); 3993 visibilities[i] = r.getPackageVisibilityOverride(); 3994 showBadges[i] = r.canShowBadge(); 3995 mRankingHelper.extractSignals(r); 3996 } 3997 mRankingHelper.sort(mNotificationList); 3998 for (int i = 0; i < N; i++) { 3999 final NotificationRecord r = mNotificationList.get(i); 4000 if (forceUpdate 4001 || !orderBefore.get(i).equals(r.getKey()) 4002 || visibilities[i] != r.getPackageVisibilityOverride() 4003 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey()) 4004 || showBadges[i] != r.canShowBadge()) { 4005 scheduleSendRankingUpdate(); 4006 return; 4007 } 4008 } 4009 } 4010 } 4011 4012 private void recordCallerLocked(NotificationRecord record) { 4013 if (mZenModeHelper.isCall(record)) { 4014 mZenModeHelper.recordCaller(record); 4015 } 4016 } 4017 4018 // let zen mode evaluate this record 4019 private void applyZenModeLocked(NotificationRecord record) { 4020 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 4021 if (record.isIntercepted()) { 4022 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff() 4023 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0) 4024 | (mZenModeHelper.shouldSuppressWhenScreenOn() 4025 ? SUPPRESSED_EFFECT_SCREEN_ON : 0); 4026 record.setSuppressedVisualEffects(suppressed); 4027 } else { 4028 record.setSuppressedVisualEffects(0); 4029 } 4030 } 4031 4032 // lock on mNotificationList 4033 private int findNotificationRecordIndexLocked(NotificationRecord target) { 4034 return mRankingHelper.indexOf(mNotificationList, target); 4035 } 4036 4037 private void scheduleSendRankingUpdate() { 4038 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 4039 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 4040 mHandler.sendMessage(m); 4041 } 4042 } 4043 4044 private void handleSendRankingUpdate() { 4045 synchronized (mNotificationLock) { 4046 mListeners.notifyRankingUpdateLocked(); 4047 } 4048 } 4049 4050 private void scheduleListenerHintsChanged(int state) { 4051 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 4052 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 4053 } 4054 4055 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 4056 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 4057 mHandler.obtainMessage( 4058 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 4059 listenerInterruptionFilter, 4060 0).sendToTarget(); 4061 } 4062 4063 private void handleListenerHintsChanged(int hints) { 4064 synchronized (mNotificationLock) { 4065 mListeners.notifyListenerHintsChangedLocked(hints); 4066 } 4067 } 4068 4069 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 4070 synchronized (mNotificationLock) { 4071 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 4072 } 4073 } 4074 4075 private final class WorkerHandler extends Handler 4076 { 4077 public WorkerHandler(Looper looper) { 4078 super(looper); 4079 } 4080 4081 @Override 4082 public void handleMessage(Message msg) 4083 { 4084 switch (msg.what) 4085 { 4086 case MESSAGE_TIMEOUT: 4087 handleTimeout((ToastRecord)msg.obj); 4088 break; 4089 case MESSAGE_SAVE_POLICY_FILE: 4090 handleSavePolicyFile(); 4091 break; 4092 case MESSAGE_SEND_RANKING_UPDATE: 4093 handleSendRankingUpdate(); 4094 break; 4095 case MESSAGE_LISTENER_HINTS_CHANGED: 4096 handleListenerHintsChanged(msg.arg1); 4097 break; 4098 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 4099 handleListenerInterruptionFilterChanged(msg.arg1); 4100 break; 4101 } 4102 } 4103 4104 } 4105 4106 private final class RankingHandlerWorker extends Handler implements RankingHandler 4107 { 4108 public RankingHandlerWorker(Looper looper) { 4109 super(looper); 4110 } 4111 4112 @Override 4113 public void handleMessage(Message msg) { 4114 switch (msg.what) { 4115 case MESSAGE_RECONSIDER_RANKING: 4116 handleRankingReconsideration(msg); 4117 break; 4118 case MESSAGE_RANKING_SORT: 4119 handleRankingSort(msg); 4120 break; 4121 } 4122 } 4123 4124 public void requestSort(boolean forceUpdate) { 4125 removeMessages(MESSAGE_RANKING_SORT); 4126 Message msg = Message.obtain(); 4127 msg.what = MESSAGE_RANKING_SORT; 4128 msg.obj = forceUpdate; 4129 sendMessage(msg); 4130 } 4131 4132 public void requestReconsideration(RankingReconsideration recon) { 4133 Message m = Message.obtain(this, 4134 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 4135 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 4136 sendMessageDelayed(m, delay); 4137 } 4138 } 4139 4140 // Notifications 4141 // ============================================================================ 4142 static int clamp(int x, int low, int high) { 4143 return (x < low) ? low : ((x > high) ? high : x); 4144 } 4145 4146 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 4147 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 4148 if (!manager.isEnabled()) { 4149 return; 4150 } 4151 4152 AccessibilityEvent event = 4153 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 4154 event.setPackageName(packageName); 4155 event.setClassName(Notification.class.getName()); 4156 event.setParcelableData(notification); 4157 CharSequence tickerText = notification.tickerText; 4158 if (!TextUtils.isEmpty(tickerText)) { 4159 event.getText().add(tickerText); 4160 } 4161 4162 manager.sendAccessibilityEvent(event); 4163 } 4164 4165 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 4166 final String canceledKey = r.getKey(); 4167 4168 // Remove from both lists, either list could have a separate Record for what is effectively 4169 // the same notification. 4170 boolean wasPosted = false; 4171 NotificationRecord recordInList = null; 4172 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) != null) { 4173 mNotificationList.remove(recordInList); 4174 mNotificationsByKey.remove(recordInList.sbn.getKey()); 4175 wasPosted = true; 4176 } 4177 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) 4178 != null) { 4179 mEnqueuedNotifications.remove(recordInList); 4180 } 4181 4182 // Record caller. 4183 recordCallerLocked(r); 4184 4185 // tell the app 4186 if (sendDelete) { 4187 if (r.getNotification().deleteIntent != null) { 4188 try { 4189 r.getNotification().deleteIntent.send(); 4190 } catch (PendingIntent.CanceledException ex) { 4191 // do nothing - there's no relevant way to recover, and 4192 // no reason to let this propagate 4193 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 4194 } 4195 } 4196 } 4197 4198 // Only cancel these if this notification actually got to be posted. 4199 if (wasPosted) { 4200 // status bar 4201 if (r.getNotification().getSmallIcon() != null) { 4202 if (reason != REASON_SNOOZED) { 4203 r.isCanceled = true; 4204 } 4205 mListeners.notifyRemovedLocked(r.sbn, reason); 4206 mHandler.post(new Runnable() { 4207 @Override 4208 public void run() { 4209 mGroupHelper.onNotificationRemoved(r.sbn); 4210 } 4211 }); 4212 } 4213 4214 // sound 4215 if (canceledKey.equals(mSoundNotificationKey)) { 4216 mSoundNotificationKey = null; 4217 final long identity = Binder.clearCallingIdentity(); 4218 try { 4219 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 4220 if (player != null) { 4221 player.stopAsync(); 4222 } 4223 } catch (RemoteException e) { 4224 } finally { 4225 Binder.restoreCallingIdentity(identity); 4226 } 4227 } 4228 4229 // vibrate 4230 if (canceledKey.equals(mVibrateNotificationKey)) { 4231 mVibrateNotificationKey = null; 4232 long identity = Binder.clearCallingIdentity(); 4233 try { 4234 mVibrator.cancel(); 4235 } 4236 finally { 4237 Binder.restoreCallingIdentity(identity); 4238 } 4239 } 4240 4241 // light 4242 mLights.remove(canceledKey); 4243 } 4244 4245 // Record usage stats 4246 // TODO: add unbundling stats? 4247 switch (reason) { 4248 case REASON_CANCEL: 4249 case REASON_CANCEL_ALL: 4250 case REASON_LISTENER_CANCEL: 4251 case REASON_LISTENER_CANCEL_ALL: 4252 mUsageStats.registerDismissedByUser(r); 4253 break; 4254 case REASON_APP_CANCEL: 4255 case REASON_APP_CANCEL_ALL: 4256 mUsageStats.registerRemovedByApp(r); 4257 break; 4258 } 4259 4260 String groupKey = r.getGroupKey(); 4261 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 4262 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) { 4263 mSummaryByGroupKey.remove(groupKey); 4264 } 4265 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId()); 4266 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) { 4267 summaries.remove(r.sbn.getPackageName()); 4268 } 4269 4270 // Save it for users of getHistoricalNotifications() 4271 mArchive.record(r.sbn); 4272 4273 final long now = System.currentTimeMillis(); 4274 MetricsLogger.action(r.getLogMaker(now) 4275 .setCategory(MetricsEvent.NOTIFICATION_ITEM) 4276 .setType(MetricsEvent.TYPE_DISMISS) 4277 .setSubtype(reason)); 4278 EventLogTags.writeNotificationCanceled(canceledKey, reason, 4279 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 4280 } 4281 4282 /** 4283 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 4284 * and none of the {@code mustNotHaveFlags}. 4285 */ 4286 void cancelNotification(final int callingUid, final int callingPid, 4287 final String pkg, final String tag, final int id, 4288 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 4289 final int userId, final int reason, final ManagedServiceInfo listener) { 4290 // In enqueueNotificationInternal notifications are added by scheduling the 4291 // work on the worker handler. Hence, we also schedule the cancel on this 4292 // handler to avoid a scenario where an add notification call followed by a 4293 // remove notification call ends up in not removing the notification. 4294 mHandler.post(new Runnable() { 4295 @Override 4296 public void run() { 4297 String listenerName = listener == null ? null : listener.component.toShortString(); 4298 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, 4299 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName); 4300 4301 synchronized (mNotificationLock) { 4302 // Look for the notification, searching both the posted and enqueued lists. 4303 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); 4304 if (r != null) { 4305 // The notification was found, check if it should be removed. 4306 4307 // Ideally we'd do this in the caller of this method. However, that would 4308 // require the caller to also find the notification. 4309 if (reason == REASON_CLICK) { 4310 mUsageStats.registerClickedByUser(r); 4311 } 4312 4313 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 4314 return; 4315 } 4316 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 4317 return; 4318 } 4319 4320 // Cancel the notification. 4321 cancelNotificationLocked(r, sendDelete, reason); 4322 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, 4323 sendDelete); 4324 updateLightsLocked(); 4325 } else { 4326 // No notification was found, assume that it is snoozed and cancel it. 4327 if (reason != REASON_SNOOZED) { 4328 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id); 4329 if (wasSnoozed) { 4330 savePolicyFile(); 4331 } 4332 } 4333 } 4334 } 4335 } 4336 }); 4337 } 4338 4339 /** 4340 * Determine whether the userId applies to the notification in question, either because 4341 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 4342 */ 4343 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 4344 return 4345 // looking for USER_ALL notifications? match everything 4346 userId == UserHandle.USER_ALL 4347 // a notification sent to USER_ALL matches any query 4348 || r.getUserId() == UserHandle.USER_ALL 4349 // an exact user match 4350 || r.getUserId() == userId; 4351 } 4352 4353 /** 4354 * Determine whether the userId applies to the notification in question, either because 4355 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 4356 * because it matches one of the users profiles. 4357 */ 4358 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 4359 return notificationMatchesUserId(r, userId) 4360 || mUserProfiles.isCurrentProfile(r.getUserId()); 4361 } 4362 4363 /** 4364 * Cancels all notifications from a given package that have all of the 4365 * {@code mustHaveFlags}. 4366 */ 4367 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId, 4368 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason, 4369 ManagedServiceInfo listener) { 4370 mHandler.post(new Runnable() { 4371 @Override 4372 public void run() { 4373 String listenerName = listener == null ? null : listener.component.toShortString(); 4374 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 4375 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 4376 listenerName); 4377 4378 // Why does this parameter exist? Do we actually want to execute the above if doit 4379 // is false? 4380 if (!doit) { 4381 return; 4382 } 4383 4384 synchronized (mNotificationLock) { 4385 FlagChecker flagChecker = (int flags) -> { 4386 if ((flags & mustHaveFlags) != mustHaveFlags) { 4387 return false; 4388 } 4389 if ((flags & mustNotHaveFlags) != 0) { 4390 return false; 4391 } 4392 return true; 4393 }; 4394 4395 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid, 4396 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker, 4397 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason, 4398 listenerName); 4399 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid, 4400 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, 4401 flagChecker, false /*includeCurrentProfiles*/, userId, 4402 false /*sendDelete*/, reason, listenerName); 4403 mSnoozeHelper.cancel(userId, pkg); 4404 } 4405 } 4406 }); 4407 } 4408 4409 private interface FlagChecker { 4410 // Returns false if these flags do not pass the defined flag test. 4411 public boolean apply(int flags); 4412 } 4413 4414 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList, 4415 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch, 4416 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, 4417 boolean sendDelete, int reason, String listenerName) { 4418 ArrayList<NotificationRecord> canceledNotifications = null; 4419 for (int i = notificationList.size() - 1; i >= 0; --i) { 4420 NotificationRecord r = notificationList.get(i); 4421 if (includeCurrentProfiles) { 4422 if (!notificationMatchesCurrentProfiles(r, userId)) { 4423 continue; 4424 } 4425 } else if (!notificationMatchesUserId(r, userId)) { 4426 continue; 4427 } 4428 // Don't remove notifications to all, if there's no package name specified 4429 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) { 4430 continue; 4431 } 4432 if (!flagChecker.apply(r.getFlags())) { 4433 continue; 4434 } 4435 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 4436 continue; 4437 } 4438 if (channelId != null && !channelId.equals(r.getChannel().getId())) { 4439 continue; 4440 } 4441 4442 if (canceledNotifications == null) { 4443 canceledNotifications = new ArrayList<>(); 4444 } 4445 canceledNotifications.add(r); 4446 cancelNotificationLocked(r, sendDelete, reason); 4447 } 4448 if (canceledNotifications != null) { 4449 final int M = canceledNotifications.size(); 4450 for (int i = 0; i < M; i++) { 4451 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 4452 listenerName, false /* sendDelete */); 4453 } 4454 updateLightsLocked(); 4455 } 4456 } 4457 4458 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId, 4459 ManagedServiceInfo listener) { 4460 String listenerName = listener == null ? null : listener.component.toShortString(); 4461 if (duration <= 0 && snoozeCriterionId == null || key == null) { 4462 return; 4463 } 4464 4465 if (DBG) { 4466 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration, 4467 snoozeCriterionId, listenerName)); 4468 } 4469 // Needs to post so that it can cancel notifications not yet enqueued. 4470 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); 4471 } 4472 4473 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) { 4474 String listenerName = listener == null ? null : listener.component.toShortString(); 4475 if (DBG) { 4476 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); 4477 } 4478 mSnoozeHelper.repost(key); 4479 savePolicyFile(); 4480 } 4481 4482 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 4483 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 4484 mHandler.post(new Runnable() { 4485 @Override 4486 public void run() { 4487 synchronized (mNotificationLock) { 4488 String listenerName = 4489 listener == null ? null : listener.component.toShortString(); 4490 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 4491 null, userId, 0, 0, reason, listenerName); 4492 4493 FlagChecker flagChecker = (int flags) -> { 4494 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR)) 4495 != 0) { 4496 return false; 4497 } 4498 return true; 4499 }; 4500 4501 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid, 4502 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker, 4503 includeCurrentProfiles, userId, true /*sendDelete*/, reason, 4504 listenerName); 4505 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid, 4506 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null, 4507 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/, 4508 reason, listenerName); 4509 mSnoozeHelper.cancel(userId, includeCurrentProfiles); 4510 } 4511 } 4512 }); 4513 } 4514 4515 // Warning: The caller is responsible for invoking updateLightsLocked(). 4516 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 4517 String listenerName, boolean sendDelete) { 4518 Notification n = r.getNotification(); 4519 if (!n.isGroupSummary()) { 4520 return; 4521 } 4522 4523 String pkg = r.sbn.getPackageName(); 4524 int userId = r.getUserId(); 4525 4526 if (pkg == null) { 4527 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey()); 4528 return; 4529 } 4530 4531 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName, 4532 sendDelete); 4533 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid, 4534 listenerName, sendDelete); 4535 } 4536 4537 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList, 4538 NotificationRecord parentNotification, int callingUid, int callingPid, 4539 String listenerName, boolean sendDelete) { 4540 final String pkg = parentNotification.sbn.getPackageName(); 4541 final int userId = parentNotification.getUserId(); 4542 final int reason = REASON_GROUP_SUMMARY_CANCELED; 4543 for (int i = notificationList.size() - 1; i >= 0; i--) { 4544 final NotificationRecord childR = notificationList.get(i); 4545 final StatusBarNotification childSbn = childR.sbn; 4546 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 4547 childR.getGroupKey().equals(parentNotification.getGroupKey()) 4548 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) { 4549 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 4550 childSbn.getTag(), userId, 0, 0, reason, listenerName); 4551 cancelNotificationLocked(childR, sendDelete, reason); 4552 } 4553 } 4554 } 4555 4556 // lock on mNotificationList 4557 void updateLightsLocked() 4558 { 4559 // handle notification lights 4560 NotificationRecord ledNotification = null; 4561 while (ledNotification == null && !mLights.isEmpty()) { 4562 final String owner = mLights.get(mLights.size() - 1); 4563 ledNotification = mNotificationsByKey.get(owner); 4564 if (ledNotification == null) { 4565 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 4566 mLights.remove(owner); 4567 } 4568 } 4569 4570 // Don't flash while we are in a call or screen is on 4571 if (ledNotification == null || mInCall || mScreenOn) { 4572 mNotificationLight.turnOff(); 4573 } else { 4574 NotificationRecord.Light light = ledNotification.getLight(); 4575 if (light != null && mNotificationPulseEnabled) { 4576 // pulse repeatedly 4577 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED, 4578 light.onMs, light.offMs); 4579 } 4580 } 4581 } 4582 4583 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg, 4584 String groupKey, int userId) { 4585 List<NotificationRecord> records = new ArrayList<>(); 4586 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId)); 4587 records.addAll( 4588 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId)); 4589 return records; 4590 } 4591 4592 4593 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( 4594 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) { 4595 List<NotificationRecord> records = new ArrayList<>(); 4596 final int len = list.size(); 4597 for (int i = 0; i < len; i++) { 4598 NotificationRecord r = list.get(i); 4599 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey) 4600 && r.sbn.getPackageName().equals(pkg)) { 4601 records.add(r); 4602 } 4603 } 4604 return records; 4605 } 4606 4607 // Searches both enqueued and posted notifications by key. 4608 // TODO: need to combine a bunch of these getters with slightly different behavior. 4609 // TODO: Should enqueuing just add to mNotificationsByKey instead? 4610 private NotificationRecord findNotificationByKeyLocked(String key) { 4611 NotificationRecord r; 4612 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) { 4613 return r; 4614 } 4615 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) { 4616 return r; 4617 } 4618 return null; 4619 } 4620 4621 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) { 4622 NotificationRecord r; 4623 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) { 4624 return r; 4625 } 4626 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId)) 4627 != null) { 4628 return r; 4629 } 4630 return null; 4631 } 4632 4633 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, 4634 String pkg, String tag, int id, int userId) { 4635 final int len = list.size(); 4636 for (int i = 0; i < len; i++) { 4637 NotificationRecord r = list.get(i); 4638 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 4639 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 4640 return r; 4641 } 4642 } 4643 return null; 4644 } 4645 4646 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, 4647 String key) 4648 { 4649 final int N = list.size(); 4650 for (int i = 0; i < N; i++) { 4651 if (key.equals(list.get(i).getKey())) { 4652 return list.get(i); 4653 } 4654 } 4655 return null; 4656 } 4657 4658 // lock on mNotificationList 4659 int indexOfNotificationLocked(String key) { 4660 final int N = mNotificationList.size(); 4661 for (int i = 0; i < N; i++) { 4662 if (key.equals(mNotificationList.get(i).getKey())) { 4663 return i; 4664 } 4665 } 4666 return -1; 4667 } 4668 4669 private void updateNotificationPulse() { 4670 synchronized (mNotificationLock) { 4671 updateLightsLocked(); 4672 } 4673 } 4674 4675 protected boolean isCallingUidSystem() { 4676 final int uid = Binder.getCallingUid(); 4677 return uid == Process.SYSTEM_UID; 4678 } 4679 4680 protected boolean isUidSystemOrPhone(int uid) { 4681 final int appid = UserHandle.getAppId(uid); 4682 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 4683 } 4684 4685 // TODO: Most calls should probably move to isCallerSystem. 4686 protected boolean isCallerSystemOrPhone() { 4687 return isUidSystemOrPhone(Binder.getCallingUid()); 4688 } 4689 4690 private void checkCallerIsSystem() { 4691 if (isCallerSystemOrPhone()) { 4692 return; 4693 } 4694 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 4695 } 4696 4697 private void checkCallerIsSystemOrSameApp(String pkg) { 4698 if (isCallerSystemOrPhone()) { 4699 return; 4700 } 4701 checkCallerIsSameApp(pkg); 4702 } 4703 4704 private boolean isCallerInstantApp(String pkg) { 4705 // System is always allowed to act for ephemeral apps. 4706 if (isCallerSystemOrPhone()) { 4707 return false; 4708 } 4709 4710 mAppOps.checkPackage(Binder.getCallingUid(), pkg); 4711 4712 try { 4713 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, 4714 UserHandle.getCallingUserId()); 4715 if (ai == null) { 4716 throw new SecurityException("Unknown package " + pkg); 4717 } 4718 return ai.isInstantApp(); 4719 } catch (RemoteException re) { 4720 throw new SecurityException("Unknown package " + pkg, re); 4721 } 4722 4723 } 4724 4725 private void checkCallerIsSameApp(String pkg) { 4726 final int uid = Binder.getCallingUid(); 4727 try { 4728 ApplicationInfo ai = mPackageManager.getApplicationInfo( 4729 pkg, 0, UserHandle.getCallingUserId()); 4730 if (ai == null) { 4731 throw new SecurityException("Unknown package " + pkg); 4732 } 4733 if (!UserHandle.isSameApp(ai.uid, uid)) { 4734 throw new SecurityException("Calling uid " + uid + " gave package " 4735 + pkg + " which is owned by uid " + ai.uid); 4736 } 4737 } catch (RemoteException re) { 4738 throw new SecurityException("Unknown package " + pkg + "\n" + re); 4739 } 4740 } 4741 4742 private static String callStateToString(int state) { 4743 switch (state) { 4744 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 4745 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 4746 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 4747 default: return "CALL_STATE_UNKNOWN_" + state; 4748 } 4749 } 4750 4751 private void listenForCallState() { 4752 TelephonyManager.from(getContext()).listen(new PhoneStateListener() { 4753 @Override 4754 public void onCallStateChanged(int state, String incomingNumber) { 4755 if (mCallState == state) return; 4756 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 4757 mCallState = state; 4758 } 4759 }, PhoneStateListener.LISTEN_CALL_STATE); 4760 } 4761 4762 /** 4763 * Generates a NotificationRankingUpdate from 'sbns', considering only 4764 * notifications visible to the given listener. 4765 * 4766 * <p>Caller must hold a lock on mNotificationList.</p> 4767 */ 4768 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 4769 final int N = mNotificationList.size(); 4770 ArrayList<String> keys = new ArrayList<String>(N); 4771 ArrayList<String> interceptedKeys = new ArrayList<String>(N); 4772 ArrayList<Integer> importance = new ArrayList<>(N); 4773 Bundle overrideGroupKeys = new Bundle(); 4774 Bundle visibilityOverrides = new Bundle(); 4775 Bundle suppressedVisualEffects = new Bundle(); 4776 Bundle explanation = new Bundle(); 4777 Bundle channels = new Bundle(); 4778 Bundle overridePeople = new Bundle(); 4779 Bundle snoozeCriteria = new Bundle(); 4780 Bundle showBadge = new Bundle(); 4781 for (int i = 0; i < N; i++) { 4782 NotificationRecord record = mNotificationList.get(i); 4783 if (!isVisibleToListener(record.sbn, info)) { 4784 continue; 4785 } 4786 final String key = record.sbn.getKey(); 4787 keys.add(key); 4788 importance.add(record.getImportance()); 4789 if (record.getImportanceExplanation() != null) { 4790 explanation.putCharSequence(key, record.getImportanceExplanation()); 4791 } 4792 if (record.isIntercepted()) { 4793 interceptedKeys.add(key); 4794 4795 } 4796 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects()); 4797 if (record.getPackageVisibilityOverride() 4798 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { 4799 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride()); 4800 } 4801 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey()); 4802 channels.putParcelable(key, record.getChannel()); 4803 overridePeople.putStringArrayList(key, record.getPeopleOverride()); 4804 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria()); 4805 showBadge.putBoolean(key, record.canShowBadge()); 4806 } 4807 final int M = keys.size(); 4808 String[] keysAr = keys.toArray(new String[M]); 4809 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); 4810 int[] importanceAr = new int[M]; 4811 for (int i = 0; i < M; i++) { 4812 importanceAr[i] = importance.get(i); 4813 } 4814 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, 4815 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys, 4816 channels, overridePeople, snoozeCriteria, showBadge); 4817 } 4818 4819 boolean hasCompanionDevice(ManagedServiceInfo info) { 4820 if (mCompanionManager == null) { 4821 mCompanionManager = getCompanionManager(); 4822 } 4823 // Companion mgr doesn't exist on all device types 4824 if (mCompanionManager == null) { 4825 return false; 4826 } 4827 long identity = Binder.clearCallingIdentity(); 4828 try { 4829 List<String> associations = mCompanionManager.getAssociations( 4830 info.component.getPackageName(), info.userid); 4831 if (!ArrayUtils.isEmpty(associations)) { 4832 return true; 4833 } 4834 } catch (SecurityException se) { 4835 // Not a privileged listener 4836 } catch (RemoteException re) { 4837 Slog.e(TAG, "Cannot reach companion device service", re); 4838 } catch (Exception e) { 4839 Slog.e(TAG, "Cannot verify listener " + info, e); 4840 } finally { 4841 Binder.restoreCallingIdentity(identity); 4842 } 4843 return false; 4844 } 4845 4846 protected ICompanionDeviceManager getCompanionManager() { 4847 return ICompanionDeviceManager.Stub.asInterface( 4848 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); 4849 } 4850 4851 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 4852 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 4853 return false; 4854 } 4855 // TODO: remove this for older listeners. 4856 return true; 4857 } 4858 4859 private boolean isPackageSuspendedForUser(String pkg, int uid) { 4860 int userId = UserHandle.getUserId(uid); 4861 try { 4862 return mPackageManager.isPackageSuspendedForUser(pkg, userId); 4863 } catch (RemoteException re) { 4864 throw new SecurityException("Could not talk to package manager service"); 4865 } catch (IllegalArgumentException ex) { 4866 // Package not found. 4867 return false; 4868 } 4869 } 4870 4871 private class TrimCache { 4872 StatusBarNotification heavy; 4873 StatusBarNotification sbnClone; 4874 StatusBarNotification sbnCloneLight; 4875 4876 TrimCache(StatusBarNotification sbn) { 4877 heavy = sbn; 4878 } 4879 4880 StatusBarNotification ForListener(ManagedServiceInfo info) { 4881 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 4882 if (sbnCloneLight == null) { 4883 sbnCloneLight = heavy.cloneLight(); 4884 } 4885 return sbnCloneLight; 4886 } else { 4887 if (sbnClone == null) { 4888 sbnClone = heavy.clone(); 4889 } 4890 return sbnClone; 4891 } 4892 } 4893 } 4894 4895 public class NotificationAssistants extends ManagedServices { 4896 4897 public NotificationAssistants() { 4898 super(getContext(), mHandler, mNotificationList, mUserProfiles); 4899 } 4900 4901 @Override 4902 protected Config getConfig() { 4903 Config c = new Config(); 4904 c.caption = "notification assistant service"; 4905 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; 4906 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; 4907 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; 4908 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 4909 c.clientLabel = R.string.notification_ranker_binding_label; 4910 return c; 4911 } 4912 4913 @Override 4914 protected IInterface asInterface(IBinder binder) { 4915 return INotificationListener.Stub.asInterface(binder); 4916 } 4917 4918 @Override 4919 protected boolean checkType(IInterface service) { 4920 return service instanceof INotificationListener; 4921 } 4922 4923 @Override 4924 protected void onServiceAdded(ManagedServiceInfo info) { 4925 mListeners.registerGuestService(info); 4926 } 4927 4928 @Override 4929 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 4930 mListeners.unregisterService(removed.service, removed.userid); 4931 } 4932 4933 public void onNotificationEnqueued(final NotificationRecord r) { 4934 final StatusBarNotification sbn = r.sbn; 4935 TrimCache trimCache = new TrimCache(sbn); 4936 4937 // There should be only one, but it's a list, so while we enforce 4938 // singularity elsewhere, we keep it general here, to avoid surprises. 4939 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { 4940 boolean sbnVisible = isVisibleToListener(sbn, info); 4941 if (!sbnVisible) { 4942 continue; 4943 } 4944 4945 final int importance = r.getImportance(); 4946 final boolean fromUser = r.isImportanceFromUser(); 4947 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 4948 mHandler.post(new Runnable() { 4949 @Override 4950 public void run() { 4951 notifyEnqueued(info, sbnToPost); 4952 } 4953 }); 4954 } 4955 } 4956 4957 private void notifyEnqueued(final ManagedServiceInfo info, 4958 final StatusBarNotification sbn) { 4959 final INotificationListener assistant = (INotificationListener) info.service; 4960 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 4961 try { 4962 assistant.onNotificationEnqueued(sbnHolder); 4963 } catch (RemoteException ex) { 4964 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); 4965 } 4966 } 4967 4968 /** 4969 * asynchronously notify the assistant that a notification has been snoozed until a 4970 * context 4971 */ 4972 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn, 4973 final String snoozeCriterionId) { 4974 TrimCache trimCache = new TrimCache(sbn); 4975 for (final ManagedServiceInfo info : getServices()) { 4976 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 4977 mHandler.post(new Runnable() { 4978 @Override 4979 public void run() { 4980 final INotificationListener assistant = 4981 (INotificationListener) info.service; 4982 StatusBarNotificationHolder sbnHolder 4983 = new StatusBarNotificationHolder(sbnToPost); 4984 try { 4985 assistant.onNotificationSnoozedUntilContext( 4986 sbnHolder, snoozeCriterionId); 4987 } catch (RemoteException ex) { 4988 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); 4989 } 4990 } 4991 }); 4992 } 4993 } 4994 4995 public boolean isEnabled() { 4996 return !getServices().isEmpty(); 4997 } 4998 } 4999 5000 public class NotificationListeners extends ManagedServices { 5001 5002 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 5003 5004 public NotificationListeners() { 5005 super(getContext(), mHandler, mNotificationList, mUserProfiles); 5006 } 5007 5008 @Override 5009 protected Config getConfig() { 5010 Config c = new Config(); 5011 c.caption = "notification listener"; 5012 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 5013 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 5014 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 5015 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 5016 c.clientLabel = R.string.notification_listener_binding_label; 5017 return c; 5018 } 5019 5020 @Override 5021 protected IInterface asInterface(IBinder binder) { 5022 return INotificationListener.Stub.asInterface(binder); 5023 } 5024 5025 @Override 5026 protected boolean checkType(IInterface service) { 5027 return service instanceof INotificationListener; 5028 } 5029 5030 @Override 5031 public void onServiceAdded(ManagedServiceInfo info) { 5032 final INotificationListener listener = (INotificationListener) info.service; 5033 final NotificationRankingUpdate update; 5034 synchronized (mNotificationLock) { 5035 update = makeRankingUpdateLocked(info); 5036 } 5037 try { 5038 listener.onListenerConnected(update); 5039 } catch (RemoteException e) { 5040 // we tried 5041 } 5042 } 5043 5044 @Override 5045 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 5046 if (removeDisabledHints(removed)) { 5047 updateListenerHintsLocked(); 5048 updateEffectsSuppressorLocked(); 5049 } 5050 mLightTrimListeners.remove(removed); 5051 } 5052 5053 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 5054 if (trim == TRIM_LIGHT) { 5055 mLightTrimListeners.add(info); 5056 } else { 5057 mLightTrimListeners.remove(info); 5058 } 5059 } 5060 5061 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 5062 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 5063 } 5064 5065 /** 5066 * asynchronously notify all listeners about a new notification 5067 * 5068 * <p> 5069 * Also takes care of removing a notification that has been visible to a listener before, 5070 * but isn't anymore. 5071 */ 5072 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { 5073 // Lazily initialized snapshots of the notification. 5074 TrimCache trimCache = new TrimCache(sbn); 5075 5076 for (final ManagedServiceInfo info : getServices()) { 5077 boolean sbnVisible = isVisibleToListener(sbn, info); 5078 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 5079 // This notification hasn't been and still isn't visible -> ignore. 5080 if (!oldSbnVisible && !sbnVisible) { 5081 continue; 5082 } 5083 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 5084 5085 // This notification became invisible -> remove the old one. 5086 if (oldSbnVisible && !sbnVisible) { 5087 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 5088 mHandler.post(new Runnable() { 5089 @Override 5090 public void run() { 5091 notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED); 5092 } 5093 }); 5094 continue; 5095 } 5096 5097 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 5098 mHandler.post(new Runnable() { 5099 @Override 5100 public void run() { 5101 notifyPosted(info, sbnToPost, update); 5102 } 5103 }); 5104 } 5105 } 5106 5107 /** 5108 * asynchronously notify all listeners about a removed notification 5109 */ 5110 public void notifyRemovedLocked(StatusBarNotification sbn, int reason) { 5111 // make a copy in case changes are made to the underlying Notification object 5112 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 5113 // notification 5114 final StatusBarNotification sbnLight = sbn.cloneLight(); 5115 for (final ManagedServiceInfo info : getServices()) { 5116 if (!isVisibleToListener(sbn, info)) { 5117 continue; 5118 } 5119 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 5120 mHandler.post(new Runnable() { 5121 @Override 5122 public void run() { 5123 notifyRemoved(info, sbnLight, update, reason); 5124 } 5125 }); 5126 } 5127 } 5128 5129 /** 5130 * asynchronously notify all listeners about a reordering of notifications 5131 */ 5132 public void notifyRankingUpdateLocked() { 5133 for (final ManagedServiceInfo serviceInfo : getServices()) { 5134 if (!serviceInfo.isEnabledForCurrentProfiles()) { 5135 continue; 5136 } 5137 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); 5138 mHandler.post(new Runnable() { 5139 @Override 5140 public void run() { 5141 notifyRankingUpdate(serviceInfo, update); 5142 } 5143 }); 5144 } 5145 } 5146 5147 public void notifyListenerHintsChangedLocked(final int hints) { 5148 for (final ManagedServiceInfo serviceInfo : getServices()) { 5149 if (!serviceInfo.isEnabledForCurrentProfiles()) { 5150 continue; 5151 } 5152 mHandler.post(new Runnable() { 5153 @Override 5154 public void run() { 5155 notifyListenerHintsChanged(serviceInfo, hints); 5156 } 5157 }); 5158 } 5159 } 5160 5161 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 5162 for (final ManagedServiceInfo serviceInfo : getServices()) { 5163 if (!serviceInfo.isEnabledForCurrentProfiles()) { 5164 continue; 5165 } 5166 mHandler.post(new Runnable() { 5167 @Override 5168 public void run() { 5169 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 5170 } 5171 }); 5172 } 5173 } 5174 5175 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, 5176 final NotificationChannel channel, final int modificationType) { 5177 if (channel == null) { 5178 return; 5179 } 5180 for (final ManagedServiceInfo serviceInfo : getServices()) { 5181 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { 5182 continue; 5183 } 5184 5185 mHandler.post(new Runnable() { 5186 @Override 5187 public void run() { 5188 if (hasCompanionDevice(serviceInfo)) { 5189 notifyNotificationChannelChanged( 5190 serviceInfo, pkg, user, channel, modificationType); 5191 } 5192 } 5193 }); 5194 } 5195 } 5196 5197 protected void notifyNotificationChannelGroupChanged( 5198 final String pkg, final UserHandle user, final NotificationChannelGroup group, 5199 final int modificationType) { 5200 if (group == null) { 5201 return; 5202 } 5203 for (final ManagedServiceInfo serviceInfo : getServices()) { 5204 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { 5205 continue; 5206 } 5207 5208 mHandler.post(new Runnable() { 5209 @Override 5210 public void run() { 5211 if (hasCompanionDevice(serviceInfo)) { 5212 notifyNotificationChannelGroupChanged( 5213 serviceInfo, pkg, user, group, modificationType); 5214 } 5215 } 5216 }); 5217 } 5218 } 5219 5220 private void notifyPosted(final ManagedServiceInfo info, 5221 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 5222 final INotificationListener listener = (INotificationListener) info.service; 5223 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 5224 try { 5225 listener.onNotificationPosted(sbnHolder, rankingUpdate); 5226 } catch (RemoteException ex) { 5227 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 5228 } 5229 } 5230 5231 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 5232 NotificationRankingUpdate rankingUpdate, int reason) { 5233 if (!info.enabledAndUserMatches(sbn.getUserId())) { 5234 return; 5235 } 5236 final INotificationListener listener = (INotificationListener) info.service; 5237 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 5238 try { 5239 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason); 5240 } catch (RemoteException ex) { 5241 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 5242 } 5243 } 5244 5245 private void notifyRankingUpdate(ManagedServiceInfo info, 5246 NotificationRankingUpdate rankingUpdate) { 5247 final INotificationListener listener = (INotificationListener) info.service; 5248 try { 5249 listener.onNotificationRankingUpdate(rankingUpdate); 5250 } catch (RemoteException ex) { 5251 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 5252 } 5253 } 5254 5255 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 5256 final INotificationListener listener = (INotificationListener) info.service; 5257 try { 5258 listener.onListenerHintsChanged(hints); 5259 } catch (RemoteException ex) { 5260 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 5261 } 5262 } 5263 5264 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 5265 int interruptionFilter) { 5266 final INotificationListener listener = (INotificationListener) info.service; 5267 try { 5268 listener.onInterruptionFilterChanged(interruptionFilter); 5269 } catch (RemoteException ex) { 5270 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 5271 } 5272 } 5273 5274 void notifyNotificationChannelChanged(ManagedServiceInfo info, 5275 final String pkg, final UserHandle user, final NotificationChannel channel, 5276 final int modificationType) { 5277 final INotificationListener listener = (INotificationListener) info.service; 5278 try { 5279 listener.onNotificationChannelModification(pkg, user, channel, modificationType); 5280 } catch (RemoteException ex) { 5281 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex); 5282 } 5283 } 5284 5285 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, 5286 final String pkg, final UserHandle user, final NotificationChannelGroup group, 5287 final int modificationType) { 5288 final INotificationListener listener = (INotificationListener) info.service; 5289 try { 5290 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); 5291 } catch (RemoteException ex) { 5292 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex); 5293 } 5294 } 5295 5296 public boolean isListenerPackage(String packageName) { 5297 if (packageName == null) { 5298 return false; 5299 } 5300 // TODO: clean up locking object later 5301 synchronized (mNotificationLock) { 5302 for (final ManagedServiceInfo serviceInfo : getServices()) { 5303 if (packageName.equals(serviceInfo.component.getPackageName())) { 5304 return true; 5305 } 5306 } 5307 } 5308 return false; 5309 } 5310 } 5311 5312 public static final class DumpFilter { 5313 public boolean filtered = false; 5314 public String pkgFilter; 5315 public boolean zen; 5316 public long since; 5317 public boolean stats; 5318 public boolean redact = true; 5319 public boolean proto = false; 5320 5321 public static DumpFilter parseFromArguments(String[] args) { 5322 final DumpFilter filter = new DumpFilter(); 5323 for (int ai = 0; ai < args.length; ai++) { 5324 final String a = args[ai]; 5325 if ("--proto".equals(args[0])) { 5326 filter.proto = true; 5327 } 5328 if ("--noredact".equals(a) || "--reveal".equals(a)) { 5329 filter.redact = false; 5330 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 5331 if (ai < args.length-1) { 5332 ai++; 5333 filter.pkgFilter = args[ai].trim().toLowerCase(); 5334 if (filter.pkgFilter.isEmpty()) { 5335 filter.pkgFilter = null; 5336 } else { 5337 filter.filtered = true; 5338 } 5339 } 5340 } else if ("--zen".equals(a) || "zen".equals(a)) { 5341 filter.filtered = true; 5342 filter.zen = true; 5343 } else if ("--stats".equals(a)) { 5344 filter.stats = true; 5345 if (ai < args.length-1) { 5346 ai++; 5347 filter.since = Long.parseLong(args[ai]); 5348 } else { 5349 filter.since = 0; 5350 } 5351 } 5352 } 5353 return filter; 5354 } 5355 5356 public boolean matches(StatusBarNotification sbn) { 5357 if (!filtered) return true; 5358 return zen ? true : sbn != null 5359 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 5360 } 5361 5362 public boolean matches(ComponentName component) { 5363 if (!filtered) return true; 5364 return zen ? true : component != null && matches(component.getPackageName()); 5365 } 5366 5367 public boolean matches(String pkg) { 5368 if (!filtered) return true; 5369 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 5370 } 5371 5372 @Override 5373 public String toString() { 5374 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 5375 } 5376 } 5377 5378 /** 5379 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 5380 * binder without sending large amounts of data over a oneway transaction. 5381 */ 5382 private static final class StatusBarNotificationHolder 5383 extends IStatusBarNotificationHolder.Stub { 5384 private StatusBarNotification mValue; 5385 5386 public StatusBarNotificationHolder(StatusBarNotification value) { 5387 mValue = value; 5388 } 5389 5390 /** Get the held value and clear it. This function should only be called once per holder */ 5391 @Override 5392 public StatusBarNotification get() { 5393 StatusBarNotification value = mValue; 5394 mValue = null; 5395 return value; 5396 } 5397 } 5398 5399 private final class PolicyAccess { 5400 private static final String SEPARATOR = ":"; 5401 private final String[] PERM = { 5402 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY 5403 }; 5404 5405 public boolean isPackageGranted(String pkg) { 5406 return pkg != null && getGrantedPackages().contains(pkg); 5407 } 5408 5409 public void put(String pkg, boolean granted) { 5410 if (pkg == null) return; 5411 final ArraySet<String> pkgs = getGrantedPackages(); 5412 boolean changed; 5413 if (granted) { 5414 changed = pkgs.add(pkg); 5415 } else { 5416 changed = pkgs.remove(pkg); 5417 } 5418 if (!changed) return; 5419 final String setting = TextUtils.join(SEPARATOR, pkgs); 5420 final int currentUser = ActivityManager.getCurrentUser(); 5421 Settings.Secure.putStringForUser(getContext().getContentResolver(), 5422 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 5423 setting, 5424 currentUser); 5425 getContext().sendBroadcastAsUser(new Intent(NotificationManager 5426 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 5427 .setPackage(pkg) 5428 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null); 5429 } 5430 5431 public ArraySet<String> getGrantedPackages() { 5432 final ArraySet<String> pkgs = new ArraySet<>(); 5433 5434 long identity = Binder.clearCallingIdentity(); 5435 try { 5436 final String setting = Settings.Secure.getStringForUser( 5437 getContext().getContentResolver(), 5438 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 5439 ActivityManager.getCurrentUser()); 5440 if (setting != null) { 5441 final String[] tokens = setting.split(SEPARATOR); 5442 for (int i = 0; i < tokens.length; i++) { 5443 String token = tokens[i]; 5444 if (token != null) { 5445 token = token.trim(); 5446 } 5447 if (TextUtils.isEmpty(token)) { 5448 continue; 5449 } 5450 pkgs.add(token); 5451 } 5452 } 5453 } finally { 5454 Binder.restoreCallingIdentity(identity); 5455 } 5456 return pkgs; 5457 } 5458 5459 public String[] getRequestingPackages() throws RemoteException { 5460 final ParceledListSlice list = mPackageManager 5461 .getPackagesHoldingPermissions(PERM, 0 /*flags*/, 5462 ActivityManager.getCurrentUser()); 5463 final List<PackageInfo> pkgs = list.getList(); 5464 if (pkgs == null || pkgs.isEmpty()) return new String[0]; 5465 final int N = pkgs.size(); 5466 final String[] rt = new String[N]; 5467 for (int i = 0; i < N; i++) { 5468 rt[i] = pkgs.get(i).packageName; 5469 } 5470 return rt; 5471 } 5472 } 5473} 5474