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