NotificationManagerService.java revision 5961ab3ac5d64473d3224eb6c11563c347df178b
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 n.sbn.setOverrideGroupKey(adjustment.getSignals().getString( 2183 Adjustment.GROUP_KEY_OVERRIDE_KEY, null)); 2184 } 2185 } 2186 2187 // Clears the 'fake' auto-bunding summary. 2188 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) { 2189 if (adjustment.getSignals() != null 2190 && adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY) 2191 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) { 2192 if (mAutobundledSummaries.containsKey(adjustment.getPackage())) { 2193 // Clear summary. 2194 final NotificationRecord removed = mNotificationsByKey.get( 2195 mAutobundledSummaries.remove(adjustment.getPackage())); 2196 if (removed != null) { 2197 mNotificationList.remove(removed); 2198 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED); 2199 } 2200 } 2201 } 2202 } 2203 2204 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit. 2205 private void maybeAddAutobundleSummary(Adjustment adjustment) { 2206 if (adjustment.getSignals() != null 2207 && adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) { 2208 final String newAutoBundleKey = 2209 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null); 2210 int userId = -1; 2211 NotificationRecord summaryRecord = null; 2212 synchronized (mNotificationList) { 2213 if (!mAutobundledSummaries.containsKey(adjustment.getPackage()) 2214 && newAutoBundleKey != null) { 2215 // Add summary 2216 final StatusBarNotification adjustedSbn 2217 = mNotificationsByKey.get(adjustment.getKey()).sbn; 2218 2219 final ApplicationInfo appInfo = 2220 adjustedSbn.getNotification().extras.getParcelable( 2221 Notification.EXTRA_BUILDER_APPLICATION_INFO); 2222 final Bundle extras = new Bundle(); 2223 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo); 2224 final Notification summaryNotification = 2225 new Notification.Builder(getContext()).setSmallIcon( 2226 adjustedSbn.getNotification().getSmallIcon()) 2227 .setGroupSummary(true) 2228 .setGroup(newAutoBundleKey) 2229 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true) 2230 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 2231 .build(); 2232 summaryNotification.extras.putAll(extras); 2233 final StatusBarNotification summarySbn = 2234 new StatusBarNotification(adjustedSbn.getPackageName(), 2235 adjustedSbn.getOpPkg(), 2236 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY, 2237 adjustedSbn.getUid(), adjustedSbn.getInitialPid(), 2238 summaryNotification, adjustedSbn.getUser(), newAutoBundleKey, 2239 System.currentTimeMillis()); 2240 summaryRecord = new NotificationRecord(getContext(), summarySbn); 2241 mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey()); 2242 userId = adjustedSbn.getUser().getIdentifier(); 2243 } 2244 } 2245 if (summaryRecord != null) { 2246 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord)); 2247 } 2248 } 2249 } 2250 2251 private String disableNotificationEffects(NotificationRecord record) { 2252 if (mDisableNotificationEffects) { 2253 return "booleanState"; 2254 } 2255 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2256 return "listenerHints"; 2257 } 2258 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 2259 return "callState"; 2260 } 2261 return null; 2262 }; 2263 2264 private void dumpJson(PrintWriter pw, DumpFilter filter) { 2265 JSONObject dump = new JSONObject(); 2266 try { 2267 dump.put("service", "Notification Manager"); 2268 dump.put("bans", mRankingHelper.dumpBansJson(filter)); 2269 dump.put("ranking", mRankingHelper.dumpJson(filter)); 2270 dump.put("stats", mUsageStats.dumpJson(filter)); 2271 } catch (JSONException e) { 2272 e.printStackTrace(); 2273 } 2274 pw.println(dump); 2275 } 2276 2277 void dumpImpl(PrintWriter pw, DumpFilter filter) { 2278 pw.print("Current Notification Manager state"); 2279 if (filter.filtered) { 2280 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 2281 } 2282 pw.println(':'); 2283 int N; 2284 final boolean zenOnly = filter.filtered && filter.zen; 2285 2286 if (!zenOnly) { 2287 synchronized (mToastQueue) { 2288 N = mToastQueue.size(); 2289 if (N > 0) { 2290 pw.println(" Toast Queue:"); 2291 for (int i=0; i<N; i++) { 2292 mToastQueue.get(i).dump(pw, " ", filter); 2293 } 2294 pw.println(" "); 2295 } 2296 } 2297 } 2298 2299 synchronized (mNotificationList) { 2300 if (!zenOnly) { 2301 N = mNotificationList.size(); 2302 if (N > 0) { 2303 pw.println(" Notification List:"); 2304 for (int i=0; i<N; i++) { 2305 final NotificationRecord nr = mNotificationList.get(i); 2306 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2307 nr.dump(pw, " ", getContext(), filter.redact); 2308 } 2309 pw.println(" "); 2310 } 2311 2312 if (!filter.filtered) { 2313 N = mLights.size(); 2314 if (N > 0) { 2315 pw.println(" Lights List:"); 2316 for (int i=0; i<N; i++) { 2317 if (i == N - 1) { 2318 pw.print(" > "); 2319 } else { 2320 pw.print(" "); 2321 } 2322 pw.println(mLights.get(i)); 2323 } 2324 pw.println(" "); 2325 } 2326 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 2327 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 2328 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 2329 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 2330 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 2331 pw.println(" mCallState=" + callStateToString(mCallState)); 2332 pw.println(" mSystemReady=" + mSystemReady); 2333 } 2334 pw.println(" mArchive=" + mArchive.toString()); 2335 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 2336 int i=0; 2337 while (iter.hasNext()) { 2338 final StatusBarNotification sbn = iter.next(); 2339 if (filter != null && !filter.matches(sbn)) continue; 2340 pw.println(" " + sbn); 2341 if (++i >= 5) { 2342 if (iter.hasNext()) pw.println(" ..."); 2343 break; 2344 } 2345 } 2346 } 2347 2348 if (!zenOnly) { 2349 pw.println("\n Usage Stats:"); 2350 mUsageStats.dump(pw, " ", filter); 2351 } 2352 2353 if (!filter.filtered || zenOnly) { 2354 pw.println("\n Zen Mode:"); 2355 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 2356 mZenModeHelper.dump(pw, " "); 2357 2358 pw.println("\n Zen Log:"); 2359 ZenLog.dump(pw, " "); 2360 } 2361 2362 if (!zenOnly) { 2363 pw.println("\n Ranking Config:"); 2364 mRankingHelper.dump(pw, " ", filter); 2365 2366 pw.println("\n Notification listeners:"); 2367 mListeners.dump(pw, filter); 2368 pw.print(" mListenerHints: "); pw.println(mListenerHints); 2369 pw.print(" mListenersDisablingEffects: ("); 2370 N = mListenersDisablingEffects.size(); 2371 for (int i = 0; i < N; i++) { 2372 final int hint = mListenersDisablingEffects.keyAt(i); 2373 if (i > 0) pw.print(';'); 2374 pw.print("hint[" + hint + "]:"); 2375 2376 final ArraySet<ManagedServiceInfo> listeners = 2377 mListenersDisablingEffects.valueAt(i); 2378 final int listenerSize = listeners.size(); 2379 2380 for (int j = 0; j < listenerSize; j++) { 2381 if (i > 0) pw.print(','); 2382 final ManagedServiceInfo listener = listeners.valueAt(i); 2383 pw.print(listener.component); 2384 } 2385 } 2386 pw.println(')'); 2387 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName); 2388 pw.println("\n Notification ranker services:"); 2389 mRankerServices.dump(pw, filter); 2390 } 2391 pw.println("\n Policy access:"); 2392 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); 2393 2394 pw.println("\n Condition providers:"); 2395 mConditionProviders.dump(pw, filter); 2396 2397 pw.println("\n Group summaries:"); 2398 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 2399 NotificationRecord r = entry.getValue(); 2400 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 2401 if (mNotificationsByKey.get(r.getKey()) != r) { 2402 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 2403 r.dump(pw, " ", getContext(), filter.redact); 2404 } 2405 } 2406 } 2407 } 2408 2409 /** 2410 * The private API only accessible to the system process. 2411 */ 2412 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 2413 @Override 2414 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 2415 String tag, int id, Notification notification, int[] idReceived, int userId) { 2416 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 2417 idReceived, userId); 2418 } 2419 2420 @Override 2421 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 2422 int userId) { 2423 checkCallerIsSystem(); 2424 synchronized (mNotificationList) { 2425 int i = indexOfNotificationLocked(pkg, null, notificationId, userId); 2426 if (i < 0) { 2427 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with " 2428 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId); 2429 return; 2430 } 2431 NotificationRecord r = mNotificationList.get(i); 2432 StatusBarNotification sbn = r.sbn; 2433 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 2434 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE, 2435 // we have to revert to the flags we received initially *and* force remove 2436 // FLAG_FOREGROUND_SERVICE. 2437 sbn.getNotification().flags = 2438 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE); 2439 mRankingHelper.sort(mNotificationList); 2440 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */); 2441 } 2442 } 2443 }; 2444 2445 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 2446 final int callingPid, final String tag, final int id, final Notification notification, 2447 int[] idOut, int incomingUserId) { 2448 if (DBG) { 2449 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 2450 + " notification=" + notification); 2451 } 2452 checkCallerIsSystemOrSameApp(pkg); 2453 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 2454 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 2455 2456 final int userId = ActivityManager.handleIncomingUser(callingPid, 2457 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 2458 final UserHandle user = new UserHandle(userId); 2459 2460 // Fix the notification as best we can. 2461 try { 2462 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser( 2463 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 2464 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); 2465 Notification.addFieldsFromContext(ai, userId, notification); 2466 } catch (NameNotFoundException e) { 2467 Slog.e(TAG, "Cannot create a context for sending app", e); 2468 return; 2469 } 2470 2471 // Limit the number of notifications that any given package except the android 2472 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 2473 if (!isSystemNotification && !isNotificationFromListener) { 2474 synchronized (mNotificationList) { 2475 int count = 0; 2476 final int N = mNotificationList.size(); 2477 for (int i=0; i<N; i++) { 2478 final NotificationRecord r = mNotificationList.get(i); 2479 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 2480 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) { 2481 break; // Allow updating existing notification 2482 } 2483 count++; 2484 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2485 Slog.e(TAG, "Package has already posted " + count 2486 + " notifications. Not showing more. package=" + pkg); 2487 return; 2488 } 2489 } 2490 } 2491 } 2492 } 2493 2494 if (pkg == null || notification == null) { 2495 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 2496 + " id=" + id + " notification=" + notification); 2497 } 2498 2499 // Sanitize inputs 2500 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 2501 Notification.PRIORITY_MAX); 2502 2503 // setup local book-keeping 2504 final StatusBarNotification n = new StatusBarNotification( 2505 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification, 2506 user); 2507 final NotificationRecord r = new NotificationRecord(getContext(), n); 2508 mHandler.post(new EnqueueNotificationRunnable(userId, r)); 2509 2510 idOut[0] = id; 2511 } 2512 2513 private class EnqueueNotificationRunnable implements Runnable { 2514 private final NotificationRecord r; 2515 private final int userId; 2516 2517 EnqueueNotificationRunnable(int userId, NotificationRecord r) { 2518 this.userId = userId; 2519 this.r = r; 2520 }; 2521 2522 @Override 2523 public void run() { 2524 2525 synchronized (mNotificationList) { 2526 final StatusBarNotification n = r.sbn; 2527 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 2528 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 2529 if (old != null) { 2530 // Retain ranking information from previous record 2531 r.copyRankingInformation(old); 2532 } 2533 2534 final int callingUid = n.getUid(); 2535 final int callingPid = n.getInitialPid(); 2536 final Notification notification = n.getNotification(); 2537 final String pkg = n.getPackageName(); 2538 final int id = n.getId(); 2539 final String tag = n.getTag(); 2540 final boolean isSystemNotification = isUidSystem(callingUid) || 2541 ("android".equals(pkg)); 2542 2543 // Handle grouped notifications and bail out early if we 2544 // can to avoid extracting signals. 2545 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 2546 2547 // This conditional is a dirty hack to limit the logging done on 2548 // behalf of the download manager without affecting other apps. 2549 if (!pkg.equals("com.android.providers.downloads") 2550 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 2551 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 2552 if (old != null) { 2553 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 2554 } 2555 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 2556 pkg, id, tag, userId, notification.toString(), 2557 enqueueStatus); 2558 } 2559 2560 mRankingHelper.extractSignals(r); 2561 2562 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); 2563 2564 // blocked apps 2565 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE 2566 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) { 2567 if (!isSystemNotification) { 2568 if (isPackageSuspended) { 2569 Slog.e(TAG, "Suppressing notification from package due to package " 2570 + "suspended by administrator."); 2571 mUsageStats.registerSuspendedByAdmin(r); 2572 } else { 2573 Slog.e(TAG, "Suppressing notification from package by user request."); 2574 mUsageStats.registerBlocked(r); 2575 } 2576 return; 2577 } 2578 } 2579 2580 // tell the ranker service about the notification 2581 if (mRankerServices.isEnabled()) { 2582 mRankerServices.onNotificationEnqueued(r); 2583 // TODO delay the code below here for 100ms or until there is an answer 2584 } 2585 2586 2587 int index = indexOfNotificationLocked(n.getKey()); 2588 if (index < 0) { 2589 mNotificationList.add(r); 2590 mUsageStats.registerPostedByApp(r); 2591 } else { 2592 old = mNotificationList.get(index); 2593 mNotificationList.set(index, r); 2594 mUsageStats.registerUpdatedByApp(r, old); 2595 // Make sure we don't lose the foreground service state. 2596 notification.flags |= 2597 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 2598 r.isUpdate = true; 2599 } 2600 2601 mNotificationsByKey.put(n.getKey(), r); 2602 2603 // Ensure if this is a foreground service that the proper additional 2604 // flags are set. 2605 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 2606 notification.flags |= Notification.FLAG_ONGOING_EVENT 2607 | Notification.FLAG_NO_CLEAR; 2608 } 2609 2610 applyZenModeLocked(r); 2611 mRankingHelper.sort(mNotificationList); 2612 2613 if (notification.getSmallIcon() != null) { 2614 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 2615 mListeners.notifyPostedLocked(n, oldSbn); 2616 } else { 2617 Slog.e(TAG, "Not posting notification without small icon: " + notification); 2618 if (old != null && !old.isCanceled) { 2619 mListeners.notifyRemovedLocked(n); 2620 } 2621 // ATTENTION: in a future release we will bail out here 2622 // so that we do not play sounds, show lights, etc. for invalid 2623 // notifications 2624 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 2625 + n.getPackageName()); 2626 } 2627 2628 buzzBeepBlinkLocked(r); 2629 } 2630 } 2631 } 2632 2633 /** 2634 * Ensures that grouped notification receive their special treatment. 2635 * 2636 * <p>Cancels group children if the new notification causes a group to lose 2637 * its summary.</p> 2638 * 2639 * <p>Updates mSummaryByGroupKey.</p> 2640 */ 2641 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 2642 int callingUid, int callingPid) { 2643 StatusBarNotification sbn = r.sbn; 2644 Notification n = sbn.getNotification(); 2645 String group = sbn.getGroupKey(); 2646 boolean isSummary = n.isGroupSummary(); 2647 2648 Notification oldN = old != null ? old.sbn.getNotification() : null; 2649 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 2650 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 2651 2652 if (oldIsSummary) { 2653 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 2654 if (removedSummary != old) { 2655 String removedKey = 2656 removedSummary != null ? removedSummary.getKey() : "<null>"; 2657 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 2658 ", removed=" + removedKey); 2659 } 2660 } 2661 if (isSummary) { 2662 mSummaryByGroupKey.put(group, r); 2663 } 2664 2665 // Clear out group children of the old notification if the update 2666 // causes the group summary to go away. This happens when the old 2667 // notification was a summary and the new one isn't, or when the old 2668 // notification was a summary and its group key changed. 2669 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 2670 cancelGroupChildrenLocked(old, callingUid, callingPid, null, 2671 REASON_GROUP_SUMMARY_CANCELED); 2672 } 2673 } 2674 2675 @VisibleForTesting 2676 void buzzBeepBlinkLocked(NotificationRecord record) { 2677 boolean buzz = false; 2678 boolean beep = false; 2679 boolean blink = false; 2680 2681 final Notification notification = record.sbn.getNotification(); 2682 final String key = record.getKey(); 2683 2684 // Should this notification make noise, vibe, or use the LED? 2685 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT; 2686 final boolean canInterrupt = aboveThreshold && !record.isIntercepted(); 2687 if (DBG || record.isIntercepted()) 2688 Slog.v(TAG, 2689 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt + 2690 " intercept=" + record.isIntercepted() 2691 ); 2692 2693 final int currentUser; 2694 final long token = Binder.clearCallingIdentity(); 2695 try { 2696 currentUser = ActivityManager.getCurrentUser(); 2697 } finally { 2698 Binder.restoreCallingIdentity(token); 2699 } 2700 2701 // If we're not supposed to beep, vibrate, etc. then don't. 2702 final String disableEffects = disableNotificationEffects(record); 2703 if (disableEffects != null) { 2704 ZenLog.traceDisableEffects(record, disableEffects); 2705 } 2706 2707 // Remember if this notification already owns the notification channels. 2708 boolean wasBeep = key != null && key.equals(mSoundNotificationKey); 2709 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey); 2710 2711 // These are set inside the conditional if the notification is allowed to make noise. 2712 boolean hasValidVibrate = false; 2713 boolean hasValidSound = false; 2714 if (disableEffects == null 2715 && (record.getUserId() == UserHandle.USER_ALL || 2716 record.getUserId() == currentUser || 2717 mUserProfiles.isCurrentProfile(record.getUserId())) 2718 && canInterrupt 2719 && mSystemReady 2720 && mAudioManager != null) { 2721 if (DBG) Slog.v(TAG, "Interrupting!"); 2722 2723 // should we use the default notification sound? (indicated either by 2724 // DEFAULT_SOUND or because notification.sound is pointing at 2725 // Settings.System.NOTIFICATION_SOUND) 2726 final boolean useDefaultSound = 2727 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2728 Settings.System.DEFAULT_NOTIFICATION_URI 2729 .equals(notification.sound); 2730 2731 Uri soundUri = null; 2732 if (useDefaultSound) { 2733 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2734 2735 // check to see if the default notification sound is silent 2736 ContentResolver resolver = getContext().getContentResolver(); 2737 hasValidSound = Settings.System.getString(resolver, 2738 Settings.System.NOTIFICATION_SOUND) != null; 2739 } else if (notification.sound != null) { 2740 soundUri = notification.sound; 2741 hasValidSound = (soundUri != null); 2742 } 2743 2744 // Does the notification want to specify its own vibration? 2745 final boolean hasCustomVibrate = notification.vibrate != null; 2746 2747 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2748 // mode, and no other vibration is specified, we fall back to vibration 2749 final boolean convertSoundToVibration = 2750 !hasCustomVibrate 2751 && hasValidSound 2752 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE); 2753 2754 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2755 final boolean useDefaultVibrate = 2756 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2757 2758 hasValidVibrate = useDefaultVibrate || convertSoundToVibration || 2759 hasCustomVibrate; 2760 2761 // We can alert, and we're allowed to alert, but if the developer asked us to only do 2762 // it once, and we already have, then don't. 2763 if (!(record.isUpdate 2764 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) { 2765 2766 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 2767 2768 if (hasValidSound) { 2769 boolean looping = 2770 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2771 AudioAttributes audioAttributes = audioAttributesForNotification(notification); 2772 mSoundNotificationKey = key; 2773 // do not play notifications if stream volume is 0 (typically because 2774 // ringer mode is silent) or if there is a user of exclusive audio focus 2775 if ((mAudioManager.getStreamVolume( 2776 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0) 2777 && !mAudioManager.isAudioFocusExclusive()) { 2778 final long identity = Binder.clearCallingIdentity(); 2779 try { 2780 final IRingtonePlayer player = 2781 mAudioManager.getRingtonePlayer(); 2782 if (player != null) { 2783 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2784 + " with attributes " + audioAttributes); 2785 player.playAsync(soundUri, record.sbn.getUser(), looping, 2786 audioAttributes); 2787 beep = true; 2788 } 2789 } catch (RemoteException e) { 2790 } finally { 2791 Binder.restoreCallingIdentity(identity); 2792 } 2793 } 2794 } 2795 2796 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal() 2797 == AudioManager.RINGER_MODE_SILENT)) { 2798 mVibrateNotificationKey = key; 2799 2800 if (useDefaultVibrate || convertSoundToVibration) { 2801 // Escalate privileges so we can use the vibrator even if the 2802 // notifying app does not have the VIBRATE permission. 2803 long identity = Binder.clearCallingIdentity(); 2804 try { 2805 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2806 useDefaultVibrate ? mDefaultVibrationPattern 2807 : mFallbackVibrationPattern, 2808 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2809 ? 0: -1, audioAttributesForNotification(notification)); 2810 buzz = true; 2811 } finally { 2812 Binder.restoreCallingIdentity(identity); 2813 } 2814 } else if (notification.vibrate.length > 1) { 2815 // If you want your own vibration pattern, you need the VIBRATE 2816 // permission 2817 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2818 notification.vibrate, 2819 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2820 ? 0: -1, audioAttributesForNotification(notification)); 2821 buzz = true; 2822 } 2823 } 2824 } 2825 2826 } 2827 // If a notification is updated to remove the actively playing sound or vibrate, 2828 // cancel that feedback now 2829 if (wasBeep && !hasValidSound) { 2830 clearSoundLocked(); 2831 } 2832 if (wasBuzz && !hasValidVibrate) { 2833 clearVibrateLocked(); 2834 } 2835 2836 // light 2837 // release the light 2838 boolean wasShowLights = mLights.remove(key); 2839 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold 2840 && ((record.getSuppressedVisualEffects() 2841 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) { 2842 mLights.add(key); 2843 updateLightsLocked(); 2844 if (mUseAttentionLight) { 2845 mAttentionLight.pulse(); 2846 } 2847 blink = true; 2848 } else if (wasShowLights) { 2849 updateLightsLocked(); 2850 } 2851 if (buzz || beep || blink) { 2852 if (((record.getSuppressedVisualEffects() 2853 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) { 2854 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on"); 2855 } else { 2856 EventLogTags.writeNotificationAlert(key, 2857 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 2858 mHandler.post(mBuzzBeepBlinked); 2859 } 2860 } 2861 } 2862 2863 private static AudioAttributes audioAttributesForNotification(Notification n) { 2864 if (n.audioAttributes != null 2865 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) { 2866 // the audio attributes are set and different from the default, use them 2867 return n.audioAttributes; 2868 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { 2869 // the stream type is valid, use it 2870 return new AudioAttributes.Builder() 2871 .setInternalLegacyStreamType(n.audioStreamType) 2872 .build(); 2873 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) { 2874 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2875 } else { 2876 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); 2877 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2878 } 2879 } 2880 2881 void showNextToastLocked() { 2882 ToastRecord record = mToastQueue.get(0); 2883 while (record != null) { 2884 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 2885 try { 2886 record.callback.show(); 2887 scheduleTimeoutLocked(record); 2888 return; 2889 } catch (RemoteException e) { 2890 Slog.w(TAG, "Object died trying to show notification " + record.callback 2891 + " in package " + record.pkg); 2892 // remove it from the list and let the process die 2893 int index = mToastQueue.indexOf(record); 2894 if (index >= 0) { 2895 mToastQueue.remove(index); 2896 } 2897 keepProcessAliveLocked(record.pid); 2898 if (mToastQueue.size() > 0) { 2899 record = mToastQueue.get(0); 2900 } else { 2901 record = null; 2902 } 2903 } 2904 } 2905 } 2906 2907 void cancelToastLocked(int index) { 2908 ToastRecord record = mToastQueue.get(index); 2909 try { 2910 record.callback.hide(); 2911 } catch (RemoteException e) { 2912 Slog.w(TAG, "Object died trying to hide notification " + record.callback 2913 + " in package " + record.pkg); 2914 // don't worry about this, we're about to remove it from 2915 // the list anyway 2916 } 2917 mToastQueue.remove(index); 2918 keepProcessAliveLocked(record.pid); 2919 if (mToastQueue.size() > 0) { 2920 // Show the next one. If the callback fails, this will remove 2921 // it from the list, so don't assume that the list hasn't changed 2922 // after this point. 2923 showNextToastLocked(); 2924 } 2925 } 2926 2927 private void scheduleTimeoutLocked(ToastRecord r) 2928 { 2929 mHandler.removeCallbacksAndMessages(r); 2930 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 2931 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 2932 mHandler.sendMessageDelayed(m, delay); 2933 } 2934 2935 private void handleTimeout(ToastRecord record) 2936 { 2937 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 2938 synchronized (mToastQueue) { 2939 int index = indexOfToastLocked(record.pkg, record.callback); 2940 if (index >= 0) { 2941 cancelToastLocked(index); 2942 } 2943 } 2944 } 2945 2946 // lock on mToastQueue 2947 int indexOfToastLocked(String pkg, ITransientNotification callback) 2948 { 2949 IBinder cbak = callback.asBinder(); 2950 ArrayList<ToastRecord> list = mToastQueue; 2951 int len = list.size(); 2952 for (int i=0; i<len; i++) { 2953 ToastRecord r = list.get(i); 2954 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 2955 return i; 2956 } 2957 } 2958 return -1; 2959 } 2960 2961 // lock on mToastQueue 2962 void keepProcessAliveLocked(int pid) 2963 { 2964 int toastCount = 0; // toasts from this pid 2965 ArrayList<ToastRecord> list = mToastQueue; 2966 int N = list.size(); 2967 for (int i=0; i<N; i++) { 2968 ToastRecord r = list.get(i); 2969 if (r.pid == pid) { 2970 toastCount++; 2971 } 2972 } 2973 try { 2974 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 2975 } catch (RemoteException e) { 2976 // Shouldn't happen. 2977 } 2978 } 2979 2980 private void handleRankingReconsideration(Message message) { 2981 if (!(message.obj instanceof RankingReconsideration)) return; 2982 RankingReconsideration recon = (RankingReconsideration) message.obj; 2983 recon.run(); 2984 boolean changed; 2985 synchronized (mNotificationList) { 2986 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 2987 if (record == null) { 2988 return; 2989 } 2990 int indexBefore = findNotificationRecordIndexLocked(record); 2991 boolean interceptBefore = record.isIntercepted(); 2992 int visibilityBefore = record.getPackageVisibilityOverride(); 2993 recon.applyChangesLocked(record); 2994 applyZenModeLocked(record); 2995 mRankingHelper.sort(mNotificationList); 2996 int indexAfter = findNotificationRecordIndexLocked(record); 2997 boolean interceptAfter = record.isIntercepted(); 2998 int visibilityAfter = record.getPackageVisibilityOverride(); 2999 changed = indexBefore != indexAfter || interceptBefore != interceptAfter 3000 || visibilityBefore != visibilityAfter; 3001 if (interceptBefore && !interceptAfter) { 3002 buzzBeepBlinkLocked(record); 3003 } 3004 } 3005 if (changed) { 3006 scheduleSendRankingUpdate(); 3007 } 3008 } 3009 3010 private void handleRankingSort() { 3011 synchronized (mNotificationList) { 3012 final int N = mNotificationList.size(); 3013 ArrayList<String> orderBefore = new ArrayList<String>(N); 3014 ArrayList<String> groupOverrideBefore = new ArrayList<>(N); 3015 int[] visibilities = new int[N]; 3016 int[] importances = new int[N]; 3017 for (int i = 0; i < N; i++) { 3018 final NotificationRecord r = mNotificationList.get(i); 3019 orderBefore.add(r.getKey()); 3020 groupOverrideBefore.add(r.sbn.getGroupKey()); 3021 visibilities[i] = r.getPackageVisibilityOverride(); 3022 importances[i] = r.getImportance(); 3023 mRankingHelper.extractSignals(r); 3024 } 3025 mRankingHelper.sort(mNotificationList); 3026 for (int i = 0; i < N; i++) { 3027 final NotificationRecord r = mNotificationList.get(i); 3028 if (!orderBefore.get(i).equals(r.getKey()) 3029 || visibilities[i] != r.getPackageVisibilityOverride() 3030 || importances[i] != r.getImportance() 3031 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) { 3032 scheduleSendRankingUpdate(); 3033 return; 3034 } 3035 } 3036 } 3037 } 3038 3039 // let zen mode evaluate this record 3040 private void applyZenModeLocked(NotificationRecord record) { 3041 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 3042 if (record.isIntercepted()) { 3043 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff() 3044 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0) 3045 | (mZenModeHelper.shouldSuppressWhenScreenOn() 3046 ? SUPPRESSED_EFFECT_SCREEN_ON : 0); 3047 record.setSuppressedVisualEffects(suppressed); 3048 } 3049 } 3050 3051 // lock on mNotificationList 3052 private int findNotificationRecordIndexLocked(NotificationRecord target) { 3053 return mRankingHelper.indexOf(mNotificationList, target); 3054 } 3055 3056 private void scheduleSendRankingUpdate() { 3057 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 3058 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 3059 mHandler.sendMessage(m); 3060 } 3061 } 3062 3063 private void handleSendRankingUpdate() { 3064 synchronized (mNotificationList) { 3065 mListeners.notifyRankingUpdateLocked(); 3066 } 3067 } 3068 3069 private void scheduleListenerHintsChanged(int state) { 3070 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 3071 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 3072 } 3073 3074 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 3075 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 3076 mHandler.obtainMessage( 3077 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 3078 listenerInterruptionFilter, 3079 0).sendToTarget(); 3080 } 3081 3082 private void handleListenerHintsChanged(int hints) { 3083 synchronized (mNotificationList) { 3084 mListeners.notifyListenerHintsChangedLocked(hints); 3085 } 3086 } 3087 3088 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 3089 synchronized (mNotificationList) { 3090 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 3091 } 3092 } 3093 3094 private final class WorkerHandler extends Handler 3095 { 3096 @Override 3097 public void handleMessage(Message msg) 3098 { 3099 switch (msg.what) 3100 { 3101 case MESSAGE_TIMEOUT: 3102 handleTimeout((ToastRecord)msg.obj); 3103 break; 3104 case MESSAGE_SAVE_POLICY_FILE: 3105 handleSavePolicyFile(); 3106 break; 3107 case MESSAGE_SEND_RANKING_UPDATE: 3108 handleSendRankingUpdate(); 3109 break; 3110 case MESSAGE_LISTENER_HINTS_CHANGED: 3111 handleListenerHintsChanged(msg.arg1); 3112 break; 3113 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 3114 handleListenerInterruptionFilterChanged(msg.arg1); 3115 break; 3116 } 3117 } 3118 3119 } 3120 3121 private final class RankingHandlerWorker extends Handler implements RankingHandler 3122 { 3123 public RankingHandlerWorker(Looper looper) { 3124 super(looper); 3125 } 3126 3127 @Override 3128 public void handleMessage(Message msg) { 3129 switch (msg.what) { 3130 case MESSAGE_RECONSIDER_RANKING: 3131 handleRankingReconsideration(msg); 3132 break; 3133 case MESSAGE_RANKING_SORT: 3134 handleRankingSort(); 3135 break; 3136 } 3137 } 3138 3139 public void requestSort() { 3140 removeMessages(MESSAGE_RANKING_SORT); 3141 sendEmptyMessage(MESSAGE_RANKING_SORT); 3142 } 3143 3144 public void requestReconsideration(RankingReconsideration recon) { 3145 Message m = Message.obtain(this, 3146 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 3147 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 3148 sendMessageDelayed(m, delay); 3149 } 3150 } 3151 3152 // Notifications 3153 // ============================================================================ 3154 static int clamp(int x, int low, int high) { 3155 return (x < low) ? low : ((x > high) ? high : x); 3156 } 3157 3158 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 3159 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 3160 if (!manager.isEnabled()) { 3161 return; 3162 } 3163 3164 AccessibilityEvent event = 3165 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 3166 event.setPackageName(packageName); 3167 event.setClassName(Notification.class.getName()); 3168 event.setParcelableData(notification); 3169 CharSequence tickerText = notification.tickerText; 3170 if (!TextUtils.isEmpty(tickerText)) { 3171 event.getText().add(tickerText); 3172 } 3173 3174 manager.sendAccessibilityEvent(event); 3175 } 3176 3177 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 3178 // tell the app 3179 if (sendDelete) { 3180 if (r.getNotification().deleteIntent != null) { 3181 try { 3182 r.getNotification().deleteIntent.send(); 3183 } catch (PendingIntent.CanceledException ex) { 3184 // do nothing - there's no relevant way to recover, and 3185 // no reason to let this propagate 3186 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 3187 } 3188 } 3189 } 3190 3191 // status bar 3192 if (r.getNotification().getSmallIcon() != null) { 3193 r.isCanceled = true; 3194 mListeners.notifyRemovedLocked(r.sbn); 3195 } 3196 3197 final String canceledKey = r.getKey(); 3198 3199 // sound 3200 if (canceledKey.equals(mSoundNotificationKey)) { 3201 mSoundNotificationKey = null; 3202 final long identity = Binder.clearCallingIdentity(); 3203 try { 3204 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 3205 if (player != null) { 3206 player.stopAsync(); 3207 } 3208 } catch (RemoteException e) { 3209 } finally { 3210 Binder.restoreCallingIdentity(identity); 3211 } 3212 } 3213 3214 // vibrate 3215 if (canceledKey.equals(mVibrateNotificationKey)) { 3216 mVibrateNotificationKey = null; 3217 long identity = Binder.clearCallingIdentity(); 3218 try { 3219 mVibrator.cancel(); 3220 } 3221 finally { 3222 Binder.restoreCallingIdentity(identity); 3223 } 3224 } 3225 3226 // light 3227 mLights.remove(canceledKey); 3228 3229 // Record usage stats 3230 // TODO: add unbundling stats? 3231 switch (reason) { 3232 case REASON_DELEGATE_CANCEL: 3233 case REASON_DELEGATE_CANCEL_ALL: 3234 case REASON_LISTENER_CANCEL: 3235 case REASON_LISTENER_CANCEL_ALL: 3236 mUsageStats.registerDismissedByUser(r); 3237 break; 3238 case REASON_APP_CANCEL: 3239 case REASON_APP_CANCEL_ALL: 3240 mUsageStats.registerRemovedByApp(r); 3241 break; 3242 } 3243 3244 mNotificationsByKey.remove(r.sbn.getKey()); 3245 String groupKey = r.getGroupKey(); 3246 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 3247 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { 3248 mSummaryByGroupKey.remove(groupKey); 3249 } 3250 if (r.sbn.getKey().equals(mAutobundledSummaries.get(r.sbn.getPackageName()))) { 3251 mAutobundledSummaries.remove(r.sbn.getPackageName()); 3252 } 3253 3254 // Save it for users of getHistoricalNotifications() 3255 mArchive.record(r.sbn); 3256 3257 final long now = System.currentTimeMillis(); 3258 EventLogTags.writeNotificationCanceled(canceledKey, reason, 3259 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 3260 } 3261 3262 /** 3263 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 3264 * and none of the {@code mustNotHaveFlags}. 3265 */ 3266 void cancelNotification(final int callingUid, final int callingPid, 3267 final String pkg, final String tag, final int id, 3268 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 3269 final int userId, final int reason, final ManagedServiceInfo listener) { 3270 // In enqueueNotificationInternal notifications are added by scheduling the 3271 // work on the worker handler. Hence, we also schedule the cancel on this 3272 // handler to avoid a scenario where an add notification call followed by a 3273 // remove notification call ends up in not removing the notification. 3274 mHandler.post(new Runnable() { 3275 @Override 3276 public void run() { 3277 String listenerName = listener == null ? null : listener.component.toShortString(); 3278 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, 3279 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName); 3280 3281 synchronized (mNotificationList) { 3282 int index = indexOfNotificationLocked(pkg, tag, id, userId); 3283 if (index >= 0) { 3284 NotificationRecord r = mNotificationList.get(index); 3285 3286 // Ideally we'd do this in the caller of this method. However, that would 3287 // require the caller to also find the notification. 3288 if (reason == REASON_DELEGATE_CLICK) { 3289 mUsageStats.registerClickedByUser(r); 3290 } 3291 3292 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 3293 return; 3294 } 3295 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 3296 return; 3297 } 3298 3299 mNotificationList.remove(index); 3300 3301 cancelNotificationLocked(r, sendDelete, reason); 3302 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, 3303 REASON_GROUP_SUMMARY_CANCELED); 3304 updateLightsLocked(); 3305 } 3306 } 3307 } 3308 }); 3309 } 3310 3311 /** 3312 * Determine whether the userId applies to the notification in question, either because 3313 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 3314 */ 3315 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 3316 return 3317 // looking for USER_ALL notifications? match everything 3318 userId == UserHandle.USER_ALL 3319 // a notification sent to USER_ALL matches any query 3320 || r.getUserId() == UserHandle.USER_ALL 3321 // an exact user match 3322 || r.getUserId() == userId; 3323 } 3324 3325 /** 3326 * Determine whether the userId applies to the notification in question, either because 3327 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 3328 * because it matches one of the users profiles. 3329 */ 3330 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 3331 return notificationMatchesUserId(r, userId) 3332 || mUserProfiles.isCurrentProfile(r.getUserId()); 3333 } 3334 3335 /** 3336 * Cancels all notifications from a given package that have all of the 3337 * {@code mustHaveFlags}. 3338 */ 3339 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 3340 int mustNotHaveFlags, boolean doit, int userId, int reason, 3341 ManagedServiceInfo listener) { 3342 String listenerName = listener == null ? null : listener.component.toShortString(); 3343 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3344 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 3345 listenerName); 3346 3347 synchronized (mNotificationList) { 3348 final int N = mNotificationList.size(); 3349 ArrayList<NotificationRecord> canceledNotifications = null; 3350 for (int i = N-1; i >= 0; --i) { 3351 NotificationRecord r = mNotificationList.get(i); 3352 if (!notificationMatchesUserId(r, userId)) { 3353 continue; 3354 } 3355 // Don't remove notifications to all, if there's no package name specified 3356 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 3357 continue; 3358 } 3359 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 3360 continue; 3361 } 3362 if ((r.getFlags() & mustNotHaveFlags) != 0) { 3363 continue; 3364 } 3365 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 3366 continue; 3367 } 3368 if (canceledNotifications == null) { 3369 canceledNotifications = new ArrayList<>(); 3370 } 3371 canceledNotifications.add(r); 3372 if (!doit) { 3373 return true; 3374 } 3375 mNotificationList.remove(i); 3376 cancelNotificationLocked(r, false, reason); 3377 } 3378 if (doit && canceledNotifications != null) { 3379 final int M = canceledNotifications.size(); 3380 for (int i = 0; i < M; i++) { 3381 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3382 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3383 } 3384 } 3385 if (canceledNotifications != null) { 3386 updateLightsLocked(); 3387 } 3388 return canceledNotifications != null; 3389 } 3390 } 3391 3392 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 3393 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 3394 String listenerName = listener == null ? null : listener.component.toShortString(); 3395 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3396 null, userId, 0, 0, reason, listenerName); 3397 3398 ArrayList<NotificationRecord> canceledNotifications = null; 3399 final int N = mNotificationList.size(); 3400 for (int i=N-1; i>=0; i--) { 3401 NotificationRecord r = mNotificationList.get(i); 3402 if (includeCurrentProfiles) { 3403 if (!notificationMatchesCurrentProfiles(r, userId)) { 3404 continue; 3405 } 3406 } else { 3407 if (!notificationMatchesUserId(r, userId)) { 3408 continue; 3409 } 3410 } 3411 3412 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 3413 | Notification.FLAG_NO_CLEAR)) == 0) { 3414 mNotificationList.remove(i); 3415 cancelNotificationLocked(r, true, reason); 3416 // Make a note so we can cancel children later. 3417 if (canceledNotifications == null) { 3418 canceledNotifications = new ArrayList<>(); 3419 } 3420 canceledNotifications.add(r); 3421 } 3422 } 3423 int M = canceledNotifications != null ? canceledNotifications.size() : 0; 3424 for (int i = 0; i < M; i++) { 3425 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3426 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3427 } 3428 updateLightsLocked(); 3429 } 3430 3431 // Warning: The caller is responsible for invoking updateLightsLocked(). 3432 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 3433 String listenerName, int reason) { 3434 Notification n = r.getNotification(); 3435 if (!n.isGroupSummary()) { 3436 return; 3437 } 3438 3439 String pkg = r.sbn.getPackageName(); 3440 int userId = r.getUserId(); 3441 3442 if (pkg == null) { 3443 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey()); 3444 return; 3445 } 3446 3447 final int N = mNotificationList.size(); 3448 for (int i = N - 1; i >= 0; i--) { 3449 NotificationRecord childR = mNotificationList.get(i); 3450 StatusBarNotification childSbn = childR.sbn; 3451 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 3452 childR.getGroupKey().equals(r.getGroupKey())) { 3453 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 3454 childSbn.getTag(), userId, 0, 0, reason, listenerName); 3455 mNotificationList.remove(i); 3456 cancelNotificationLocked(childR, false, reason); 3457 } 3458 } 3459 } 3460 3461 // lock on mNotificationList 3462 void updateLightsLocked() 3463 { 3464 // handle notification lights 3465 NotificationRecord ledNotification = null; 3466 while (ledNotification == null && !mLights.isEmpty()) { 3467 final String owner = mLights.get(mLights.size() - 1); 3468 ledNotification = mNotificationsByKey.get(owner); 3469 if (ledNotification == null) { 3470 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 3471 mLights.remove(owner); 3472 } 3473 } 3474 3475 // Don't flash while we are in a call or screen is on 3476 if (ledNotification == null || mInCall || mScreenOn) { 3477 mNotificationLight.turnOff(); 3478 if (mStatusBar != null) { 3479 mStatusBar.notificationLightOff(); 3480 } 3481 } else { 3482 final Notification ledno = ledNotification.sbn.getNotification(); 3483 int ledARGB = ledno.ledARGB; 3484 int ledOnMS = ledno.ledOnMS; 3485 int ledOffMS = ledno.ledOffMS; 3486 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 3487 ledARGB = mDefaultNotificationColor; 3488 ledOnMS = mDefaultNotificationLedOn; 3489 ledOffMS = mDefaultNotificationLedOff; 3490 } 3491 if (mNotificationPulseEnabled) { 3492 // pulse repeatedly 3493 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 3494 ledOnMS, ledOffMS); 3495 } 3496 if (mStatusBar != null) { 3497 // let SystemUI make an independent decision 3498 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS); 3499 } 3500 } 3501 } 3502 3503 // lock on mNotificationList 3504 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 3505 { 3506 ArrayList<NotificationRecord> list = mNotificationList; 3507 final int len = list.size(); 3508 for (int i=0; i<len; i++) { 3509 NotificationRecord r = list.get(i); 3510 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 3511 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 3512 return i; 3513 } 3514 } 3515 return -1; 3516 } 3517 3518 // lock on mNotificationList 3519 int indexOfNotificationLocked(String key) { 3520 final int N = mNotificationList.size(); 3521 for (int i = 0; i < N; i++) { 3522 if (key.equals(mNotificationList.get(i).getKey())) { 3523 return i; 3524 } 3525 } 3526 return -1; 3527 } 3528 3529 private void updateNotificationPulse() { 3530 synchronized (mNotificationList) { 3531 updateLightsLocked(); 3532 } 3533 } 3534 3535 private static boolean isUidSystem(int uid) { 3536 final int appid = UserHandle.getAppId(uid); 3537 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 3538 } 3539 3540 private static boolean isCallerSystem() { 3541 return isUidSystem(Binder.getCallingUid()); 3542 } 3543 3544 private static void checkCallerIsSystem() { 3545 if (isCallerSystem()) { 3546 return; 3547 } 3548 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 3549 } 3550 3551 private static void checkCallerIsSystemOrSameApp(String pkg) { 3552 if (isCallerSystem()) { 3553 return; 3554 } 3555 final int uid = Binder.getCallingUid(); 3556 try { 3557 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 3558 pkg, 0, UserHandle.getCallingUserId()); 3559 if (ai == null) { 3560 throw new SecurityException("Unknown package " + pkg); 3561 } 3562 if (!UserHandle.isSameApp(ai.uid, uid)) { 3563 throw new SecurityException("Calling uid " + uid + " gave package" 3564 + pkg + " which is owned by uid " + ai.uid); 3565 } 3566 } catch (RemoteException re) { 3567 throw new SecurityException("Unknown package " + pkg + "\n" + re); 3568 } 3569 } 3570 3571 private static String callStateToString(int state) { 3572 switch (state) { 3573 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 3574 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 3575 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 3576 default: return "CALL_STATE_UNKNOWN_" + state; 3577 } 3578 } 3579 3580 private void listenForCallState() { 3581 TelephonyManager.from(getContext()).listen(new PhoneStateListener() { 3582 @Override 3583 public void onCallStateChanged(int state, String incomingNumber) { 3584 if (mCallState == state) return; 3585 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 3586 mCallState = state; 3587 } 3588 }, PhoneStateListener.LISTEN_CALL_STATE); 3589 } 3590 3591 /** 3592 * Generates a NotificationRankingUpdate from 'sbns', considering only 3593 * notifications visible to the given listener. 3594 * 3595 * <p>Caller must hold a lock on mNotificationList.</p> 3596 */ 3597 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 3598 final int N = mNotificationList.size(); 3599 ArrayList<String> keys = new ArrayList<String>(N); 3600 ArrayList<String> interceptedKeys = new ArrayList<String>(N); 3601 ArrayList<Integer> importance = new ArrayList<>(N); 3602 Bundle overrideGroupKeys = new Bundle(); 3603 Bundle visibilityOverrides = new Bundle(); 3604 Bundle suppressedVisualEffects = new Bundle(); 3605 Bundle explanation = new Bundle(); 3606 for (int i = 0; i < N; i++) { 3607 NotificationRecord record = mNotificationList.get(i); 3608 if (!isVisibleToListener(record.sbn, info)) { 3609 continue; 3610 } 3611 final String key = record.sbn.getKey(); 3612 keys.add(key); 3613 importance.add(record.getImportance()); 3614 if (record.getImportanceExplanation() != null) { 3615 explanation.putCharSequence(key, record.getImportanceExplanation()); 3616 } 3617 if (record.isIntercepted()) { 3618 interceptedKeys.add(key); 3619 3620 } 3621 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects()); 3622 if (record.getPackageVisibilityOverride() 3623 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { 3624 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride()); 3625 } 3626 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey()); 3627 } 3628 final int M = keys.size(); 3629 String[] keysAr = keys.toArray(new String[M]); 3630 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); 3631 int[] importanceAr = new int[M]; 3632 for (int i = 0; i < M; i++) { 3633 importanceAr[i] = importance.get(i); 3634 } 3635 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, 3636 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys); 3637 } 3638 3639 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 3640 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 3641 return false; 3642 } 3643 // TODO: remove this for older listeners. 3644 return true; 3645 } 3646 3647 private boolean isPackageSuspendedForUser(String pkg, int uid) { 3648 int userId = UserHandle.getUserId(uid); 3649 try { 3650 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId); 3651 } catch (RemoteException re) { 3652 throw new SecurityException("Could not talk to package manager service"); 3653 } catch (IllegalArgumentException ex) { 3654 // Package not found. 3655 return false; 3656 } 3657 } 3658 3659 private class TrimCache { 3660 StatusBarNotification heavy; 3661 StatusBarNotification sbnClone; 3662 StatusBarNotification sbnCloneLight; 3663 3664 TrimCache(StatusBarNotification sbn) { 3665 heavy = sbn; 3666 } 3667 3668 StatusBarNotification ForListener(ManagedServiceInfo info) { 3669 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 3670 if (sbnCloneLight == null) { 3671 sbnCloneLight = heavy.cloneLight(); 3672 } 3673 return sbnCloneLight; 3674 } else { 3675 if (sbnClone == null) { 3676 sbnClone = heavy.clone(); 3677 } 3678 return sbnClone; 3679 } 3680 } 3681 } 3682 3683 public class NotificationRankers extends ManagedServices { 3684 3685 public NotificationRankers() { 3686 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3687 } 3688 3689 @Override 3690 protected Config getConfig() { 3691 Config c = new Config(); 3692 c.caption = "notification ranker service"; 3693 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE; 3694 c.secureSettingName = null; 3695 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE; 3696 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 3697 c.clientLabel = R.string.notification_ranker_binding_label; 3698 return c; 3699 } 3700 3701 @Override 3702 protected IInterface asInterface(IBinder binder) { 3703 return INotificationListener.Stub.asInterface(binder); 3704 } 3705 3706 @Override 3707 protected boolean checkType(IInterface service) { 3708 return service instanceof INotificationListener; 3709 } 3710 3711 @Override 3712 protected void onServiceAdded(ManagedServiceInfo info) { 3713 mListeners.registerGuestService(info); 3714 } 3715 3716 @Override 3717 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3718 mListeners.unregisterService(removed.service, removed.userid); 3719 } 3720 3721 public void onNotificationEnqueued(final NotificationRecord r) { 3722 final StatusBarNotification sbn = r.sbn; 3723 TrimCache trimCache = new TrimCache(sbn); 3724 3725 // mServices is the list inside ManagedServices of all the rankers, 3726 // There should be only one, but it's a list, so while we enforce 3727 // singularity elsewhere, we keep it general here, to avoid surprises. 3728 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) { 3729 boolean sbnVisible = isVisibleToListener(sbn, info); 3730 if (!sbnVisible) { 3731 continue; 3732 } 3733 3734 final int importance = r.getImportance(); 3735 final boolean fromUser = r.isImportanceFromUser(); 3736 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3737 mHandler.post(new Runnable() { 3738 @Override 3739 public void run() { 3740 notifyEnqueued(info, sbnToPost, importance, fromUser); 3741 } 3742 }); 3743 } 3744 } 3745 3746 private void notifyEnqueued(final ManagedServiceInfo info, 3747 final StatusBarNotification sbn, int importance, boolean fromUser) { 3748 final INotificationListener ranker = (INotificationListener) info.service; 3749 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3750 try { 3751 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser); 3752 } catch (RemoteException ex) { 3753 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex); 3754 } 3755 } 3756 3757 public boolean isEnabled() { 3758 return !mServices.isEmpty(); 3759 } 3760 3761 @Override 3762 public void onUserSwitched(int user) { 3763 for (ManagedServiceInfo info : mServices) { 3764 unregisterService(info.service, info.userid); 3765 } 3766 registerRanker(); 3767 } 3768 3769 @Override 3770 public void onPackagesChanged(boolean queryReplace, String[] pkgList) { 3771 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace 3772 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))); 3773 if (mRankerServicePackageName == null) { 3774 return; 3775 } 3776 3777 if (pkgList != null && (pkgList.length > 0)) { 3778 for (String pkgName : pkgList) { 3779 if (mRankerServicePackageName.equals(pkgName)) { 3780 registerRanker(); 3781 } 3782 } 3783 } 3784 } 3785 3786 protected void registerRanker() { 3787 // Find the updatable ranker and register it. 3788 if (mRankerServicePackageName == null) { 3789 Slog.w(TAG, "could not start ranker service: no package specified!"); 3790 return; 3791 } 3792 Set<ComponentName> rankerComponents = queryPackageForServices( 3793 mRankerServicePackageName, UserHandle.USER_SYSTEM); 3794 Iterator<ComponentName> iterator = rankerComponents.iterator(); 3795 if (iterator.hasNext()) { 3796 ComponentName rankerComponent = iterator.next(); 3797 if (iterator.hasNext()) { 3798 Slog.e(TAG, "found multiple ranker services:" + rankerComponents); 3799 } else { 3800 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM); 3801 } 3802 } else { 3803 Slog.w(TAG, "could not start ranker service: none found"); 3804 } 3805 } 3806 } 3807 3808 public class NotificationListeners extends ManagedServices { 3809 3810 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 3811 3812 public NotificationListeners() { 3813 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3814 } 3815 3816 @Override 3817 protected Config getConfig() { 3818 Config c = new Config(); 3819 c.caption = "notification listener"; 3820 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 3821 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 3822 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 3823 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 3824 c.clientLabel = R.string.notification_listener_binding_label; 3825 return c; 3826 } 3827 3828 @Override 3829 protected IInterface asInterface(IBinder binder) { 3830 return INotificationListener.Stub.asInterface(binder); 3831 } 3832 3833 @Override 3834 protected boolean checkType(IInterface service) { 3835 return service instanceof INotificationListener; 3836 } 3837 3838 @Override 3839 public void onServiceAdded(ManagedServiceInfo info) { 3840 final INotificationListener listener = (INotificationListener) info.service; 3841 final NotificationRankingUpdate update; 3842 synchronized (mNotificationList) { 3843 update = makeRankingUpdateLocked(info); 3844 } 3845 try { 3846 listener.onListenerConnected(update); 3847 } catch (RemoteException e) { 3848 // we tried 3849 } 3850 } 3851 3852 @Override 3853 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3854 if (removeDisabledHints(removed)) { 3855 updateListenerHintsLocked(); 3856 updateEffectsSuppressorLocked(); 3857 } 3858 mLightTrimListeners.remove(removed); 3859 } 3860 3861 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 3862 if (trim == TRIM_LIGHT) { 3863 mLightTrimListeners.add(info); 3864 } else { 3865 mLightTrimListeners.remove(info); 3866 } 3867 } 3868 3869 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 3870 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 3871 } 3872 3873 /** 3874 * asynchronously notify all listeners about a new notification 3875 * 3876 * <p> 3877 * Also takes care of removing a notification that has been visible to a listener before, 3878 * but isn't anymore. 3879 */ 3880 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { 3881 // Lazily initialized snapshots of the notification. 3882 TrimCache trimCache = new TrimCache(sbn); 3883 3884 for (final ManagedServiceInfo info : mServices) { 3885 boolean sbnVisible = isVisibleToListener(sbn, info); 3886 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 3887 // This notification hasn't been and still isn't visible -> ignore. 3888 if (!oldSbnVisible && !sbnVisible) { 3889 continue; 3890 } 3891 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3892 3893 // This notification became invisible -> remove the old one. 3894 if (oldSbnVisible && !sbnVisible) { 3895 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 3896 mHandler.post(new Runnable() { 3897 @Override 3898 public void run() { 3899 notifyRemoved(info, oldSbnLightClone, update); 3900 } 3901 }); 3902 continue; 3903 } 3904 3905 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3906 mHandler.post(new Runnable() { 3907 @Override 3908 public void run() { 3909 notifyPosted(info, sbnToPost, update); 3910 } 3911 }); 3912 } 3913 } 3914 3915 /** 3916 * asynchronously notify all listeners about a removed notification 3917 */ 3918 public void notifyRemovedLocked(StatusBarNotification sbn) { 3919 // make a copy in case changes are made to the underlying Notification object 3920 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 3921 // notification 3922 final StatusBarNotification sbnLight = sbn.cloneLight(); 3923 for (final ManagedServiceInfo info : mServices) { 3924 if (!isVisibleToListener(sbn, info)) { 3925 continue; 3926 } 3927 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3928 mHandler.post(new Runnable() { 3929 @Override 3930 public void run() { 3931 notifyRemoved(info, sbnLight, update); 3932 } 3933 }); 3934 } 3935 } 3936 3937 /** 3938 * asynchronously notify all listeners about a reordering of notifications 3939 */ 3940 public void notifyRankingUpdateLocked() { 3941 for (final ManagedServiceInfo serviceInfo : mServices) { 3942 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3943 continue; 3944 } 3945 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); 3946 mHandler.post(new Runnable() { 3947 @Override 3948 public void run() { 3949 notifyRankingUpdate(serviceInfo, update); 3950 } 3951 }); 3952 } 3953 } 3954 3955 public void notifyListenerHintsChangedLocked(final int hints) { 3956 for (final ManagedServiceInfo serviceInfo : mServices) { 3957 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3958 continue; 3959 } 3960 mHandler.post(new Runnable() { 3961 @Override 3962 public void run() { 3963 notifyListenerHintsChanged(serviceInfo, hints); 3964 } 3965 }); 3966 } 3967 } 3968 3969 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 3970 for (final ManagedServiceInfo serviceInfo : mServices) { 3971 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3972 continue; 3973 } 3974 mHandler.post(new Runnable() { 3975 @Override 3976 public void run() { 3977 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 3978 } 3979 }); 3980 } 3981 } 3982 3983 private void notifyPosted(final ManagedServiceInfo info, 3984 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 3985 final INotificationListener listener = (INotificationListener)info.service; 3986 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3987 try { 3988 listener.onNotificationPosted(sbnHolder, rankingUpdate); 3989 } catch (RemoteException ex) { 3990 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 3991 } 3992 } 3993 3994 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 3995 NotificationRankingUpdate rankingUpdate) { 3996 if (!info.enabledAndUserMatches(sbn.getUserId())) { 3997 return; 3998 } 3999 final INotificationListener listener = (INotificationListener) info.service; 4000 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 4001 try { 4002 listener.onNotificationRemoved(sbnHolder, rankingUpdate); 4003 } catch (RemoteException ex) { 4004 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 4005 } 4006 } 4007 4008 private void notifyRankingUpdate(ManagedServiceInfo info, 4009 NotificationRankingUpdate rankingUpdate) { 4010 final INotificationListener listener = (INotificationListener) info.service; 4011 try { 4012 listener.onNotificationRankingUpdate(rankingUpdate); 4013 } catch (RemoteException ex) { 4014 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 4015 } 4016 } 4017 4018 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 4019 final INotificationListener listener = (INotificationListener) info.service; 4020 try { 4021 listener.onListenerHintsChanged(hints); 4022 } catch (RemoteException ex) { 4023 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 4024 } 4025 } 4026 4027 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 4028 int interruptionFilter) { 4029 final INotificationListener listener = (INotificationListener) info.service; 4030 try { 4031 listener.onInterruptionFilterChanged(interruptionFilter); 4032 } catch (RemoteException ex) { 4033 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 4034 } 4035 } 4036 4037 private boolean isListenerPackage(String packageName) { 4038 if (packageName == null) { 4039 return false; 4040 } 4041 // TODO: clean up locking object later 4042 synchronized (mNotificationList) { 4043 for (final ManagedServiceInfo serviceInfo : mServices) { 4044 if (packageName.equals(serviceInfo.component.getPackageName())) { 4045 return true; 4046 } 4047 } 4048 } 4049 return false; 4050 } 4051 } 4052 4053 public static final class DumpFilter { 4054 public boolean filtered = false; 4055 public String pkgFilter; 4056 public boolean zen; 4057 public long since; 4058 public boolean stats; 4059 public boolean redact = true; 4060 4061 public static DumpFilter parseFromArguments(String[] args) { 4062 final DumpFilter filter = new DumpFilter(); 4063 for (int ai = 0; ai < args.length; ai++) { 4064 final String a = args[ai]; 4065 if ("--noredact".equals(a) || "--reveal".equals(a)) { 4066 filter.redact = false; 4067 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 4068 if (ai < args.length-1) { 4069 ai++; 4070 filter.pkgFilter = args[ai].trim().toLowerCase(); 4071 if (filter.pkgFilter.isEmpty()) { 4072 filter.pkgFilter = null; 4073 } else { 4074 filter.filtered = true; 4075 } 4076 } 4077 } else if ("--zen".equals(a) || "zen".equals(a)) { 4078 filter.filtered = true; 4079 filter.zen = true; 4080 } else if ("--stats".equals(a)) { 4081 filter.stats = true; 4082 if (ai < args.length-1) { 4083 ai++; 4084 filter.since = Long.valueOf(args[ai]); 4085 } else { 4086 filter.since = 0; 4087 } 4088 } 4089 } 4090 return filter; 4091 } 4092 4093 public boolean matches(StatusBarNotification sbn) { 4094 if (!filtered) return true; 4095 return zen ? true : sbn != null 4096 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 4097 } 4098 4099 public boolean matches(ComponentName component) { 4100 if (!filtered) return true; 4101 return zen ? true : component != null && matches(component.getPackageName()); 4102 } 4103 4104 public boolean matches(String pkg) { 4105 if (!filtered) return true; 4106 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 4107 } 4108 4109 @Override 4110 public String toString() { 4111 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 4112 } 4113 } 4114 4115 /** 4116 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 4117 * binder without sending large amounts of data over a oneway transaction. 4118 */ 4119 private static final class StatusBarNotificationHolder 4120 extends IStatusBarNotificationHolder.Stub { 4121 private StatusBarNotification mValue; 4122 4123 public StatusBarNotificationHolder(StatusBarNotification value) { 4124 mValue = value; 4125 } 4126 4127 /** Get the held value and clear it. This function should only be called once per holder */ 4128 @Override 4129 public StatusBarNotification get() { 4130 StatusBarNotification value = mValue; 4131 mValue = null; 4132 return value; 4133 } 4134 } 4135 4136 private final class PolicyAccess { 4137 private static final String SEPARATOR = ":"; 4138 private final String[] PERM = { 4139 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY 4140 }; 4141 4142 public boolean isPackageGranted(String pkg) { 4143 return pkg != null && getGrantedPackages().contains(pkg); 4144 } 4145 4146 public void put(String pkg, boolean granted) { 4147 if (pkg == null) return; 4148 final ArraySet<String> pkgs = getGrantedPackages(); 4149 boolean changed; 4150 if (granted) { 4151 changed = pkgs.add(pkg); 4152 } else { 4153 changed = pkgs.remove(pkg); 4154 } 4155 if (!changed) return; 4156 final String setting = TextUtils.join(SEPARATOR, pkgs); 4157 final int currentUser = ActivityManager.getCurrentUser(); 4158 Settings.Secure.putStringForUser(getContext().getContentResolver(), 4159 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 4160 setting, 4161 currentUser); 4162 getContext().sendBroadcastAsUser(new Intent(NotificationManager 4163 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4164 .setPackage(pkg) 4165 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null); 4166 } 4167 4168 public ArraySet<String> getGrantedPackages() { 4169 final ArraySet<String> pkgs = new ArraySet<>(); 4170 4171 long identity = Binder.clearCallingIdentity(); 4172 try { 4173 final String setting = Settings.Secure.getStringForUser( 4174 getContext().getContentResolver(), 4175 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 4176 ActivityManager.getCurrentUser()); 4177 if (setting != null) { 4178 final String[] tokens = setting.split(SEPARATOR); 4179 for (int i = 0; i < tokens.length; i++) { 4180 String token = tokens[i]; 4181 if (token != null) { 4182 token = token.trim(); 4183 } 4184 if (TextUtils.isEmpty(token)) { 4185 continue; 4186 } 4187 pkgs.add(token); 4188 } 4189 } 4190 } finally { 4191 Binder.restoreCallingIdentity(identity); 4192 } 4193 return pkgs; 4194 } 4195 4196 public String[] getRequestingPackages() throws RemoteException { 4197 final ParceledListSlice list = AppGlobals.getPackageManager() 4198 .getPackagesHoldingPermissions(PERM, 0 /*flags*/, 4199 ActivityManager.getCurrentUser()); 4200 final List<PackageInfo> pkgs = list.getList(); 4201 if (pkgs == null || pkgs.isEmpty()) return new String[0]; 4202 final int N = pkgs.size(); 4203 final String[] rt = new String[N]; 4204 for (int i = 0; i < N; i++) { 4205 rt[i] = pkgs.get(i).packageName; 4206 } 4207 return rt; 4208 } 4209 } 4210} 4211