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