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