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