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