NotificationManagerService.java revision 856edebad73560e9b1cce021a7de9a0470d07176
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 org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 20import static org.xmlpull.v1.XmlPullParser.END_TAG; 21import static org.xmlpull.v1.XmlPullParser.START_TAG; 22 23import android.app.ActivityManager; 24import android.app.ActivityManagerNative; 25import android.app.AppGlobals; 26import android.app.AppOpsManager; 27import android.app.IActivityManager; 28import android.app.INotificationManager; 29import android.app.ITransientNotification; 30import android.app.Notification; 31import android.app.PendingIntent; 32import android.app.StatusBarManager; 33import android.content.BroadcastReceiver; 34import android.content.ComponentName; 35import android.content.ContentResolver; 36import android.content.Context; 37import android.content.Intent; 38import android.content.IntentFilter; 39import android.content.pm.ApplicationInfo; 40import android.content.pm.PackageInfo; 41import android.content.pm.PackageManager; 42import android.content.pm.PackageManager.NameNotFoundException; 43import android.content.pm.ParceledListSlice; 44import android.content.res.Resources; 45import android.database.ContentObserver; 46import android.media.AudioManager; 47import android.media.IRingtonePlayer; 48import android.net.Uri; 49import android.os.Binder; 50import android.os.Environment; 51import android.os.Handler; 52import android.os.HandlerThread; 53import android.os.IBinder; 54import android.os.IInterface; 55import android.os.Looper; 56import android.os.Message; 57import android.os.Process; 58import android.os.RemoteException; 59import android.os.UserHandle; 60import android.os.Vibrator; 61import android.provider.Settings; 62import android.service.notification.Condition; 63import android.service.notification.IConditionListener; 64import android.service.notification.IConditionProvider; 65import android.service.notification.INotificationListener; 66import android.service.notification.NotificationListenerService; 67import android.service.notification.NotificationRankingUpdate; 68import android.service.notification.StatusBarNotification; 69import android.service.notification.ZenModeConfig; 70import android.telephony.TelephonyManager; 71import android.text.TextUtils; 72import android.util.ArrayMap; 73import android.util.AtomicFile; 74import android.util.Log; 75import android.util.Slog; 76import android.util.Xml; 77import android.view.accessibility.AccessibilityEvent; 78import android.view.accessibility.AccessibilityManager; 79import android.widget.Toast; 80 81import com.android.internal.R; 82import com.android.internal.util.FastXmlSerializer; 83import com.android.server.EventLogTags; 84import com.android.server.SystemService; 85import com.android.server.lights.Light; 86import com.android.server.lights.LightsManager; 87import com.android.server.notification.ManagedServices.ManagedServiceInfo; 88import com.android.server.notification.ManagedServices.UserProfiles; 89import com.android.server.statusbar.StatusBarManagerInternal; 90 91import libcore.io.IoUtils; 92 93import org.xmlpull.v1.XmlPullParser; 94import org.xmlpull.v1.XmlPullParserException; 95import org.xmlpull.v1.XmlSerializer; 96 97import java.io.File; 98import java.io.FileDescriptor; 99import java.io.FileInputStream; 100import java.io.FileNotFoundException; 101import java.io.FileOutputStream; 102import java.io.IOException; 103import java.io.PrintWriter; 104import java.util.ArrayDeque; 105import java.util.ArrayList; 106import java.util.Collections; 107import java.util.HashSet; 108import java.util.Iterator; 109import java.util.NoSuchElementException; 110import java.util.concurrent.TimeUnit; 111 112/** {@hide} */ 113public class NotificationManagerService extends SystemService { 114 static final String TAG = "NotificationService"; 115 static final boolean DBG = false; 116 117 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 118 119 // message codes 120 static final int MESSAGE_TIMEOUT = 2; 121 static final int MESSAGE_SAVE_POLICY_FILE = 3; 122 static final int MESSAGE_RECONSIDER_RANKING = 4; 123 static final int MESSAGE_SEND_RANKING_UPDATE = 5; 124 125 static final int LONG_DELAY = 3500; // 3.5 seconds 126 static final int SHORT_DELAY = 2000; // 2 seconds 127 128 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 129 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 130 131 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 132 static final boolean SCORE_ONGOING_HIGHER = false; 133 134 static final int JUNK_SCORE = -1000; 135 static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; 136 static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER; 137 138 // Notifications with scores below this will not interrupt the user, either via LED or 139 // sound or vibration 140 static final int SCORE_INTERRUPTION_THRESHOLD = 141 Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; 142 143 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; 144 static final boolean ENABLE_BLOCKED_TOASTS = true; 145 146 private IActivityManager mAm; 147 AudioManager mAudioManager; 148 StatusBarManagerInternal mStatusBar; 149 Vibrator mVibrator; 150 151 final IBinder mForegroundToken = new Binder(); 152 private WorkerHandler mHandler; 153 private final HandlerThread mRankingThread = new HandlerThread("ranker", 154 Process.THREAD_PRIORITY_BACKGROUND); 155 private Handler mRankingHandler = null; 156 157 private Light mNotificationLight; 158 Light mAttentionLight; 159 private int mDefaultNotificationColor; 160 private int mDefaultNotificationLedOn; 161 162 private int mDefaultNotificationLedOff; 163 private long[] mDefaultVibrationPattern; 164 165 private long[] mFallbackVibrationPattern; 166 boolean mSystemReady; 167 168 private boolean mDisableNotificationAlerts; 169 NotificationRecord mSoundNotification; 170 NotificationRecord mVibrateNotification; 171 172 // for enabling and disabling notification pulse behavior 173 private boolean mScreenOn = true; 174 private boolean mInCall = false; 175 private boolean mNotificationPulseEnabled; 176 177 // used as a mutex for access to all active notifications & listeners 178 final ArrayList<NotificationRecord> mNotificationList = 179 new ArrayList<NotificationRecord>(); 180 final NotificationComparator mRankingComparator = new NotificationComparator(); 181 final ArrayMap<String, NotificationRecord> mNotificationsByKey = 182 new ArrayMap<String, NotificationRecord>(); 183 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); 184 185 ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>(); 186 NotificationRecord mLedNotification; 187 188 private AppOpsManager mAppOps; 189 190 // Notification control database. For now just contains disabled packages. 191 private AtomicFile mPolicyFile; 192 private HashSet<String> mBlockedPackages = new HashSet<String>(); 193 194 private static final int DB_VERSION = 1; 195 196 private static final String TAG_BODY = "notification-policy"; 197 private static final String ATTR_VERSION = "version"; 198 199 private static final String TAG_BLOCKED_PKGS = "blocked-packages"; 200 private static final String TAG_PACKAGE = "package"; 201 private static final String ATTR_NAME = "name"; 202 203 final ArrayList<NotificationSignalExtractor> mSignalExtractors = new ArrayList<NotificationSignalExtractor>(); 204 205 private final UserProfiles mUserProfiles = new UserProfiles(); 206 private NotificationListeners mListeners; 207 private ConditionProviders mConditionProviders; 208 private NotificationUsageStats mUsageStats; 209 210 private static final int MY_UID = Process.myUid(); 211 private static final int MY_PID = Process.myPid(); 212 private static final int REASON_DELEGATE_CLICK = 1; 213 private static final int REASON_DELEGATE_CANCEL = 2; 214 private static final int REASON_DELEGATE_CANCEL_ALL = 3; 215 private static final int REASON_DELEGATE_ERROR = 4; 216 private static final int REASON_PACKAGE_CHANGED = 5; 217 private static final int REASON_USER_STOPPED = 6; 218 private static final int REASON_PACKAGE_BANNED = 7; 219 private static final int REASON_NOMAN_CANCEL = 8; 220 private static final int REASON_NOMAN_CANCEL_ALL = 9; 221 private static final int REASON_LISTENER_CANCEL = 10; 222 private static final int REASON_LISTENER_CANCEL_ALL = 11; 223 224 private static class Archive { 225 static final int BUFFER_SIZE = 250; 226 ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE); 227 228 public Archive() { 229 } 230 231 public String toString() { 232 final StringBuilder sb = new StringBuilder(); 233 final int N = mBuffer.size(); 234 sb.append("Archive ("); 235 sb.append(N); 236 sb.append(" notification"); 237 sb.append((N==1)?")":"s)"); 238 return sb.toString(); 239 } 240 241 public void record(StatusBarNotification nr) { 242 if (mBuffer.size() == BUFFER_SIZE) { 243 mBuffer.removeFirst(); 244 } 245 246 // We don't want to store the heavy bits of the notification in the archive, 247 // but other clients in the system process might be using the object, so we 248 // store a (lightened) copy. 249 mBuffer.addLast(nr.cloneLight()); 250 } 251 252 253 public void clear() { 254 mBuffer.clear(); 255 } 256 257 public Iterator<StatusBarNotification> descendingIterator() { 258 return mBuffer.descendingIterator(); 259 } 260 public Iterator<StatusBarNotification> ascendingIterator() { 261 return mBuffer.iterator(); 262 } 263 public Iterator<StatusBarNotification> filter( 264 final Iterator<StatusBarNotification> iter, final String pkg, final int userId) { 265 return new Iterator<StatusBarNotification>() { 266 StatusBarNotification mNext = findNext(); 267 268 private StatusBarNotification findNext() { 269 while (iter.hasNext()) { 270 StatusBarNotification nr = iter.next(); 271 if ((pkg == null || nr.getPackageName() == pkg) 272 && (userId == UserHandle.USER_ALL || nr.getUserId() == userId)) { 273 return nr; 274 } 275 } 276 return null; 277 } 278 279 @Override 280 public boolean hasNext() { 281 return mNext == null; 282 } 283 284 @Override 285 public StatusBarNotification next() { 286 StatusBarNotification next = mNext; 287 if (next == null) { 288 throw new NoSuchElementException(); 289 } 290 mNext = findNext(); 291 return next; 292 } 293 294 @Override 295 public void remove() { 296 iter.remove(); 297 } 298 }; 299 } 300 301 public StatusBarNotification[] getArray(int count) { 302 if (count == 0) count = Archive.BUFFER_SIZE; 303 final StatusBarNotification[] a 304 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 305 Iterator<StatusBarNotification> iter = descendingIterator(); 306 int i=0; 307 while (iter.hasNext() && i < count) { 308 a[i++] = iter.next(); 309 } 310 return a; 311 } 312 313 public StatusBarNotification[] getArray(int count, String pkg, int userId) { 314 if (count == 0) count = Archive.BUFFER_SIZE; 315 final StatusBarNotification[] a 316 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 317 Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId); 318 int i=0; 319 while (iter.hasNext() && i < count) { 320 a[i++] = iter.next(); 321 } 322 return a; 323 } 324 325 } 326 327 Archive mArchive = new Archive(); 328 329 private void loadPolicyFile() { 330 synchronized(mPolicyFile) { 331 mBlockedPackages.clear(); 332 333 FileInputStream infile = null; 334 try { 335 infile = mPolicyFile.openRead(); 336 final XmlPullParser parser = Xml.newPullParser(); 337 parser.setInput(infile, null); 338 339 int type; 340 String tag; 341 int version = DB_VERSION; 342 while ((type = parser.next()) != END_DOCUMENT) { 343 tag = parser.getName(); 344 if (type == START_TAG) { 345 if (TAG_BODY.equals(tag)) { 346 version = Integer.parseInt( 347 parser.getAttributeValue(null, ATTR_VERSION)); 348 } else if (TAG_BLOCKED_PKGS.equals(tag)) { 349 while ((type = parser.next()) != END_DOCUMENT) { 350 tag = parser.getName(); 351 if (TAG_PACKAGE.equals(tag)) { 352 mBlockedPackages.add( 353 parser.getAttributeValue(null, ATTR_NAME)); 354 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) { 355 break; 356 } 357 } 358 } 359 } 360 mZenModeHelper.readXml(parser); 361 } 362 } catch (FileNotFoundException e) { 363 // No data yet 364 } catch (IOException e) { 365 Log.wtf(TAG, "Unable to read notification policy", e); 366 } catch (NumberFormatException e) { 367 Log.wtf(TAG, "Unable to parse notification policy", e); 368 } catch (XmlPullParserException e) { 369 Log.wtf(TAG, "Unable to parse notification policy", e); 370 } finally { 371 IoUtils.closeQuietly(infile); 372 } 373 } 374 } 375 376 public void savePolicyFile() { 377 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE); 378 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE); 379 } 380 381 private void handleSavePolicyFile() { 382 Slog.d(TAG, "handleSavePolicyFile"); 383 synchronized (mPolicyFile) { 384 final FileOutputStream stream; 385 try { 386 stream = mPolicyFile.startWrite(); 387 } catch (IOException e) { 388 Slog.w(TAG, "Failed to save policy file", e); 389 return; 390 } 391 392 try { 393 final XmlSerializer out = new FastXmlSerializer(); 394 out.setOutput(stream, "utf-8"); 395 out.startDocument(null, true); 396 out.startTag(null, TAG_BODY); 397 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 398 mZenModeHelper.writeXml(out); 399 out.endTag(null, TAG_BODY); 400 out.endDocument(); 401 mPolicyFile.finishWrite(stream); 402 } catch (IOException e) { 403 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 404 mPolicyFile.failWrite(stream); 405 } 406 } 407 } 408 409 /** Use this when you actually want to post a notification or toast. 410 * 411 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*(). 412 */ 413 private boolean noteNotificationOp(String pkg, int uid) { 414 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 415 != AppOpsManager.MODE_ALLOWED) { 416 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg); 417 return false; 418 } 419 return true; 420 } 421 422 private static final class ToastRecord 423 { 424 final int pid; 425 final String pkg; 426 final ITransientNotification callback; 427 int duration; 428 429 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration) 430 { 431 this.pid = pid; 432 this.pkg = pkg; 433 this.callback = callback; 434 this.duration = duration; 435 } 436 437 void update(int duration) { 438 this.duration = duration; 439 } 440 441 void dump(PrintWriter pw, String prefix) { 442 pw.println(prefix + this); 443 } 444 445 @Override 446 public final String toString() 447 { 448 return "ToastRecord{" 449 + Integer.toHexString(System.identityHashCode(this)) 450 + " pkg=" + pkg 451 + " callback=" + callback 452 + " duration=" + duration; 453 } 454 } 455 456 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 457 458 @Override 459 public void onSetDisabled(int status) { 460 synchronized (mNotificationList) { 461 mDisableNotificationAlerts = (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 462 if (mDisableNotificationAlerts) { 463 // cancel whatever's going on 464 long identity = Binder.clearCallingIdentity(); 465 try { 466 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 467 if (player != null) { 468 player.stopAsync(); 469 } 470 } catch (RemoteException e) { 471 } finally { 472 Binder.restoreCallingIdentity(identity); 473 } 474 475 identity = Binder.clearCallingIdentity(); 476 try { 477 mVibrator.cancel(); 478 } finally { 479 Binder.restoreCallingIdentity(identity); 480 } 481 } 482 } 483 } 484 485 @Override 486 public void onClearAll(int callingUid, int callingPid, int userId) { 487 synchronized (mNotificationList) { 488 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null, 489 /*includeCurrentProfiles*/ true); 490 } 491 } 492 493 @Override 494 public void onNotificationClick(int callingUid, int callingPid, String key) { 495 synchronized (mNotificationList) { 496 EventLogTags.writeNotificationClicked(key); 497 NotificationRecord r = mNotificationsByKey.get(key); 498 if (r == null) { 499 Log.w(TAG, "No notification with key: " + key); 500 return; 501 } 502 StatusBarNotification sbn = r.sbn; 503 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 504 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 505 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), 506 REASON_DELEGATE_CLICK, null); 507 } 508 } 509 510 @Override 511 public void onNotificationClear(int callingUid, int callingPid, 512 String pkg, String tag, int id, int userId) { 513 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 514 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 515 true, userId, REASON_DELEGATE_CANCEL, null); 516 } 517 518 @Override 519 public void onPanelRevealed() { 520 EventLogTags.writeNotificationPanelRevealed(); 521 synchronized (mNotificationList) { 522 // sound 523 mSoundNotification = null; 524 525 long identity = Binder.clearCallingIdentity(); 526 try { 527 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 528 if (player != null) { 529 player.stopAsync(); 530 } 531 } catch (RemoteException e) { 532 } finally { 533 Binder.restoreCallingIdentity(identity); 534 } 535 536 // vibrate 537 mVibrateNotification = null; 538 identity = Binder.clearCallingIdentity(); 539 try { 540 mVibrator.cancel(); 541 } finally { 542 Binder.restoreCallingIdentity(identity); 543 } 544 545 // light 546 mLights.clear(); 547 mLedNotification = null; 548 updateLightsLocked(); 549 } 550 } 551 552 @Override 553 public void onPanelHidden() { 554 EventLogTags.writeNotificationPanelHidden(); 555 } 556 557 @Override 558 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 559 int uid, int initialPid, String message, int userId) { 560 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 561 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 562 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 563 REASON_DELEGATE_ERROR, null); 564 long ident = Binder.clearCallingIdentity(); 565 try { 566 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, 567 "Bad notification posted from package " + pkg 568 + ": " + message); 569 } catch (RemoteException e) { 570 } 571 Binder.restoreCallingIdentity(ident); 572 } 573 574 @Override 575 public boolean allowDisable(int what, IBinder token, String pkg) { 576 return mZenModeHelper.allowDisable(what, token, pkg); 577 } 578 579 @Override 580 public void onNotificationVisibilityChanged( 581 String[] newlyVisibleKeys, String[] noLongerVisibleKeys) { 582 // Using ';' as separator since eventlogs uses ',' to separate 583 // args. 584 EventLogTags.writeNotificationVisibilityChanged( 585 TextUtils.join(";", newlyVisibleKeys), 586 TextUtils.join(";", noLongerVisibleKeys)); 587 synchronized (mNotificationList) { 588 for (String key : newlyVisibleKeys) { 589 NotificationRecord r = mNotificationsByKey.get(key); 590 if (r == null) continue; 591 r.stats.onVisibilityChanged(true); 592 } 593 // Note that we might receive this event after notifications 594 // have already left the system, e.g. after dismissing from the 595 // shade. Hence not finding notifications in 596 // mNotificationsByKey is not an exceptional condition. 597 for (String key : noLongerVisibleKeys) { 598 NotificationRecord r = mNotificationsByKey.get(key); 599 if (r == null) continue; 600 r.stats.onVisibilityChanged(false); 601 } 602 } 603 } 604 }; 605 606 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 607 @Override 608 public void onReceive(Context context, Intent intent) { 609 String action = intent.getAction(); 610 611 boolean queryRestart = false; 612 boolean queryRemove = false; 613 boolean packageChanged = false; 614 boolean cancelNotifications = true; 615 616 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 617 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 618 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 619 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 620 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 621 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 622 String pkgList[] = null; 623 boolean queryReplace = queryRemove && 624 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 625 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace); 626 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 627 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 628 } else if (queryRestart) { 629 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 630 } else { 631 Uri uri = intent.getData(); 632 if (uri == null) { 633 return; 634 } 635 String pkgName = uri.getSchemeSpecificPart(); 636 if (pkgName == null) { 637 return; 638 } 639 if (packageChanged) { 640 // We cancel notifications for packages which have just been disabled 641 try { 642 final int enabled = getContext().getPackageManager() 643 .getApplicationEnabledSetting(pkgName); 644 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 645 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 646 cancelNotifications = false; 647 } 648 } catch (IllegalArgumentException e) { 649 // Package doesn't exist; probably racing with uninstall. 650 // cancelNotifications is already true, so nothing to do here. 651 if (DBG) { 652 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 653 } 654 } 655 } 656 pkgList = new String[]{pkgName}; 657 } 658 659 if (pkgList != null && (pkgList.length > 0)) { 660 for (String pkgName : pkgList) { 661 if (cancelNotifications) { 662 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, 663 UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null); 664 } 665 } 666 } 667 mListeners.onPackagesChanged(queryReplace, pkgList); 668 mConditionProviders.onPackagesChanged(queryReplace, pkgList); 669 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 670 // Keep track of screen on/off state, but do not turn off the notification light 671 // until user passes through the lock screen or views the notification. 672 mScreenOn = true; 673 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 674 mScreenOn = false; 675 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 676 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 677 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 678 updateNotificationPulse(); 679 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 680 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 681 if (userHandle >= 0) { 682 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 683 REASON_USER_STOPPED, null); 684 } 685 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 686 // turn off LED when user passes through lock screen 687 mNotificationLight.turnOff(); 688 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 689 // reload per-user settings 690 mSettingsObserver.update(null); 691 mUserProfiles.updateCache(context); 692 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 693 mUserProfiles.updateCache(context); 694 } 695 } 696 }; 697 698 class SettingsObserver extends ContentObserver { 699 private final Uri NOTIFICATION_LIGHT_PULSE_URI 700 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 701 702 SettingsObserver(Handler handler) { 703 super(handler); 704 } 705 706 void observe() { 707 ContentResolver resolver = getContext().getContentResolver(); 708 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 709 false, this, UserHandle.USER_ALL); 710 update(null); 711 } 712 713 @Override public void onChange(boolean selfChange, Uri uri) { 714 update(uri); 715 } 716 717 public void update(Uri uri) { 718 ContentResolver resolver = getContext().getContentResolver(); 719 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 720 boolean pulseEnabled = Settings.System.getInt(resolver, 721 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 722 if (mNotificationPulseEnabled != pulseEnabled) { 723 mNotificationPulseEnabled = pulseEnabled; 724 updateNotificationPulse(); 725 } 726 } 727 } 728 } 729 730 private SettingsObserver mSettingsObserver; 731 private ZenModeHelper mZenModeHelper; 732 733 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 734 int[] ar = r.getIntArray(resid); 735 if (ar == null) { 736 return def; 737 } 738 final int len = ar.length > maxlen ? maxlen : ar.length; 739 long[] out = new long[len]; 740 for (int i=0; i<len; i++) { 741 out[i] = ar[i]; 742 } 743 return out; 744 } 745 746 public NotificationManagerService(Context context) { 747 super(context); 748 } 749 750 @Override 751 public void onStart() { 752 mAm = ActivityManagerNative.getDefault(); 753 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 754 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 755 756 mHandler = new WorkerHandler(); 757 mRankingThread.start(); 758 mRankingHandler = new RankingWorkerHandler(mRankingThread.getLooper()); 759 mZenModeHelper = new ZenModeHelper(getContext(), mHandler); 760 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 761 @Override 762 public void onConfigChanged() { 763 savePolicyFile(); 764 } 765 }); 766 final File systemDir = new File(Environment.getDataDirectory(), "system"); 767 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); 768 mUsageStats = new NotificationUsageStats(getContext()); 769 770 importOldBlockDb(); 771 772 mListeners = new NotificationListeners(); 773 mConditionProviders = new ConditionProviders(getContext(), 774 mHandler, mUserProfiles, mZenModeHelper); 775 mStatusBar = getLocalService(StatusBarManagerInternal.class); 776 mStatusBar.setNotificationDelegate(mNotificationDelegate); 777 778 final LightsManager lights = getLocalService(LightsManager.class); 779 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 780 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); 781 782 Resources resources = getContext().getResources(); 783 mDefaultNotificationColor = resources.getColor( 784 R.color.config_defaultNotificationColor); 785 mDefaultNotificationLedOn = resources.getInteger( 786 R.integer.config_defaultNotificationLedOn); 787 mDefaultNotificationLedOff = resources.getInteger( 788 R.integer.config_defaultNotificationLedOff); 789 790 mDefaultVibrationPattern = getLongArray(resources, 791 R.array.config_defaultNotificationVibePattern, 792 VIBRATE_PATTERN_MAXLEN, 793 DEFAULT_VIBRATE_PATTERN); 794 795 mFallbackVibrationPattern = getLongArray(resources, 796 R.array.config_notificationFallbackVibePattern, 797 VIBRATE_PATTERN_MAXLEN, 798 DEFAULT_VIBRATE_PATTERN); 799 800 // Don't start allowing notifications until the setup wizard has run once. 801 // After that, including subsequent boots, init with notifications turned on. 802 // This works on the first boot because the setup wizard will toggle this 803 // flag at least once and we'll go back to 0 after that. 804 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 805 Settings.Global.DEVICE_PROVISIONED, 0)) { 806 mDisableNotificationAlerts = true; 807 } 808 mZenModeHelper.updateZenMode(); 809 810 mUserProfiles.updateCache(getContext()); 811 812 // register for various Intents 813 IntentFilter filter = new IntentFilter(); 814 filter.addAction(Intent.ACTION_SCREEN_ON); 815 filter.addAction(Intent.ACTION_SCREEN_OFF); 816 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 817 filter.addAction(Intent.ACTION_USER_PRESENT); 818 filter.addAction(Intent.ACTION_USER_STOPPED); 819 filter.addAction(Intent.ACTION_USER_SWITCHED); 820 filter.addAction(Intent.ACTION_USER_ADDED); 821 getContext().registerReceiver(mIntentReceiver, filter); 822 IntentFilter pkgFilter = new IntentFilter(); 823 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 824 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 825 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 826 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 827 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 828 pkgFilter.addDataScheme("package"); 829 getContext().registerReceiver(mIntentReceiver, pkgFilter); 830 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 831 getContext().registerReceiver(mIntentReceiver, sdFilter); 832 833 mSettingsObserver = new SettingsObserver(mHandler); 834 835 // spin up NotificationSignalExtractors 836 String[] extractorNames = resources.getStringArray( 837 R.array.config_notificationSignalExtractors); 838 for (String extractorName : extractorNames) { 839 try { 840 Class<?> extractorClass = getContext().getClassLoader().loadClass(extractorName); 841 NotificationSignalExtractor extractor = 842 (NotificationSignalExtractor) extractorClass.newInstance(); 843 extractor.initialize(getContext()); 844 mSignalExtractors.add(extractor); 845 } catch (ClassNotFoundException e) { 846 Slog.w(TAG, "Couldn't find extractor " + extractorName + ".", e); 847 } catch (InstantiationException e) { 848 Slog.w(TAG, "Couldn't instantiate extractor " + extractorName + ".", e); 849 } catch (IllegalAccessException e) { 850 Slog.w(TAG, "Problem accessing extractor " + extractorName + ".", e); 851 } 852 } 853 854 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 855 publishLocalService(NotificationManagerInternal.class, mInternalService); 856 } 857 858 /** 859 * Read the old XML-based app block database and import those blockages into the AppOps system. 860 */ 861 private void importOldBlockDb() { 862 loadPolicyFile(); 863 864 PackageManager pm = getContext().getPackageManager(); 865 for (String pkg : mBlockedPackages) { 866 PackageInfo info = null; 867 try { 868 info = pm.getPackageInfo(pkg, 0); 869 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); 870 } catch (NameNotFoundException e) { 871 // forget you 872 } 873 } 874 mBlockedPackages.clear(); 875 } 876 877 @Override 878 public void onBootPhase(int phase) { 879 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 880 // no beeping until we're basically done booting 881 mSystemReady = true; 882 883 // Grab our optional AudioService 884 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 885 886 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 887 // This observer will force an update when observe is called, causing us to 888 // bind to listener services. 889 mSettingsObserver.observe(); 890 mListeners.onBootPhaseAppsCanStart(); 891 mConditionProviders.onBootPhaseAppsCanStart(); 892 } 893 } 894 895 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { 896 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); 897 898 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 899 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 900 901 // Now, cancel any outstanding notifications that are part of a just-disabled app 902 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 903 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), 904 REASON_PACKAGE_BANNED, null); 905 } 906 } 907 908 private final IBinder mService = new INotificationManager.Stub() { 909 // Toasts 910 // ============================================================================ 911 912 @Override 913 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 914 { 915 if (DBG) { 916 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 917 + " duration=" + duration); 918 } 919 920 if (pkg == null || callback == null) { 921 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 922 return ; 923 } 924 925 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); 926 927 if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { 928 if (!isSystemToast) { 929 Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); 930 return; 931 } 932 } 933 934 synchronized (mToastQueue) { 935 int callingPid = Binder.getCallingPid(); 936 long callingId = Binder.clearCallingIdentity(); 937 try { 938 ToastRecord record; 939 int index = indexOfToastLocked(pkg, callback); 940 // If it's already in the queue, we update it in place, we don't 941 // move it to the end of the queue. 942 if (index >= 0) { 943 record = mToastQueue.get(index); 944 record.update(duration); 945 } else { 946 // Limit the number of toasts that any given package except the android 947 // package can enqueue. Prevents DOS attacks and deals with leaks. 948 if (!isSystemToast) { 949 int count = 0; 950 final int N = mToastQueue.size(); 951 for (int i=0; i<N; i++) { 952 final ToastRecord r = mToastQueue.get(i); 953 if (r.pkg.equals(pkg)) { 954 count++; 955 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 956 Slog.e(TAG, "Package has already posted " + count 957 + " toasts. Not showing more. Package=" + pkg); 958 return; 959 } 960 } 961 } 962 } 963 964 record = new ToastRecord(callingPid, pkg, callback, duration); 965 mToastQueue.add(record); 966 index = mToastQueue.size() - 1; 967 keepProcessAliveLocked(callingPid); 968 } 969 // If it's at index 0, it's the current toast. It doesn't matter if it's 970 // new or just been updated. Call back and tell it to show itself. 971 // If the callback fails, this will remove it from the list, so don't 972 // assume that it's valid after this. 973 if (index == 0) { 974 showNextToastLocked(); 975 } 976 } finally { 977 Binder.restoreCallingIdentity(callingId); 978 } 979 } 980 } 981 982 @Override 983 public void cancelToast(String pkg, ITransientNotification callback) { 984 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 985 986 if (pkg == null || callback == null) { 987 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 988 return ; 989 } 990 991 synchronized (mToastQueue) { 992 long callingId = Binder.clearCallingIdentity(); 993 try { 994 int index = indexOfToastLocked(pkg, callback); 995 if (index >= 0) { 996 cancelToastLocked(index); 997 } else { 998 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 999 + " callback=" + callback); 1000 } 1001 } finally { 1002 Binder.restoreCallingIdentity(callingId); 1003 } 1004 } 1005 } 1006 1007 @Override 1008 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 1009 Notification notification, int[] idOut, int userId) throws RemoteException { 1010 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 1011 Binder.getCallingPid(), tag, id, notification, idOut, userId); 1012 } 1013 1014 @Override 1015 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1016 checkCallerIsSystemOrSameApp(pkg); 1017 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1018 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1019 // Don't allow client applications to cancel foreground service notis. 1020 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1021 Binder.getCallingUid() == Process.SYSTEM_UID 1022 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL, 1023 null); 1024 } 1025 1026 @Override 1027 public void cancelAllNotifications(String pkg, int userId) { 1028 checkCallerIsSystemOrSameApp(pkg); 1029 1030 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1031 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1032 1033 // Calling from user space, don't allow the canceling of actively 1034 // running foreground services. 1035 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1036 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1037 REASON_NOMAN_CANCEL_ALL, null); 1038 } 1039 1040 @Override 1041 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1042 checkCallerIsSystem(); 1043 1044 setNotificationsEnabledForPackageImpl(pkg, uid, enabled); 1045 } 1046 1047 /** 1048 * Use this when you just want to know if notifications are OK for this package. 1049 */ 1050 @Override 1051 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1052 checkCallerIsSystem(); 1053 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 1054 == AppOpsManager.MODE_ALLOWED); 1055 } 1056 1057 /** 1058 * System-only API for getting a list of current (i.e. not cleared) notifications. 1059 * 1060 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1061 * @returns A list of all the notifications, in natural order. 1062 */ 1063 @Override 1064 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1065 // enforce() will ensure the calling uid has the correct permission 1066 getContext().enforceCallingOrSelfPermission( 1067 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1068 "NotificationManagerService.getActiveNotifications"); 1069 1070 StatusBarNotification[] tmp = null; 1071 int uid = Binder.getCallingUid(); 1072 1073 // noteOp will check to make sure the callingPkg matches the uid 1074 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1075 == AppOpsManager.MODE_ALLOWED) { 1076 synchronized (mNotificationList) { 1077 tmp = new StatusBarNotification[mNotificationList.size()]; 1078 final int N = mNotificationList.size(); 1079 for (int i=0; i<N; i++) { 1080 tmp[i] = mNotificationList.get(i).sbn; 1081 } 1082 } 1083 } 1084 return tmp; 1085 } 1086 1087 /** 1088 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1089 * 1090 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1091 */ 1092 @Override 1093 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1094 // enforce() will ensure the calling uid has the correct permission 1095 getContext().enforceCallingOrSelfPermission( 1096 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1097 "NotificationManagerService.getHistoricalNotifications"); 1098 1099 StatusBarNotification[] tmp = null; 1100 int uid = Binder.getCallingUid(); 1101 1102 // noteOp will check to make sure the callingPkg matches the uid 1103 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1104 == AppOpsManager.MODE_ALLOWED) { 1105 synchronized (mArchive) { 1106 tmp = mArchive.getArray(count); 1107 } 1108 } 1109 return tmp; 1110 } 1111 1112 /** 1113 * Register a listener binder directly with the notification manager. 1114 * 1115 * Only works with system callers. Apps should extend 1116 * {@link android.service.notification.NotificationListenerService}. 1117 */ 1118 @Override 1119 public void registerListener(final INotificationListener listener, 1120 final ComponentName component, final int userid) { 1121 enforceSystemOrSystemUI("INotificationManager.registerListener"); 1122 mListeners.registerService(listener, component, userid); 1123 } 1124 1125 /** 1126 * Remove a listener binder directly 1127 */ 1128 @Override 1129 public void unregisterListener(INotificationListener listener, int userid) { 1130 mListeners.unregisterService(listener, userid); 1131 } 1132 1133 /** 1134 * Allow an INotificationListener to simulate a "clear all" operation. 1135 * 1136 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1137 * 1138 * @param token The binder for the listener, to check that the caller is allowed 1139 */ 1140 @Override 1141 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1142 final int callingUid = Binder.getCallingUid(); 1143 final int callingPid = Binder.getCallingPid(); 1144 long identity = Binder.clearCallingIdentity(); 1145 try { 1146 synchronized (mNotificationList) { 1147 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1148 if (keys != null) { 1149 final int N = keys.length; 1150 for (int i = 0; i < N; i++) { 1151 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1152 final int userId = r.sbn.getUserId(); 1153 if (userId != info.userid && userId != UserHandle.USER_ALL && 1154 !mUserProfiles.isCurrentProfile(userId)) { 1155 throw new SecurityException("Disallowed call from listener: " 1156 + info.service); 1157 } 1158 if (r != null) { 1159 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1160 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 1161 userId); 1162 } 1163 } 1164 } else { 1165 cancelAllLocked(callingUid, callingPid, info.userid, 1166 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 1167 } 1168 } 1169 } finally { 1170 Binder.restoreCallingIdentity(identity); 1171 } 1172 } 1173 1174 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 1175 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 1176 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 1177 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 1178 true, 1179 userId, REASON_LISTENER_CANCEL, info); 1180 } 1181 1182 /** 1183 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 1184 * 1185 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 1186 * 1187 * @param token The binder for the listener, to check that the caller is allowed 1188 */ 1189 @Override 1190 public void cancelNotificationFromListener(INotificationListener token, String pkg, 1191 String tag, int id) { 1192 final int callingUid = Binder.getCallingUid(); 1193 final int callingPid = Binder.getCallingPid(); 1194 long identity = Binder.clearCallingIdentity(); 1195 try { 1196 synchronized (mNotificationList) { 1197 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1198 if (info.supportsProfiles()) { 1199 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 1200 + "from " + info.component 1201 + " use cancelNotification(key) instead."); 1202 } else { 1203 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1204 pkg, tag, id, info.userid); 1205 } 1206 } 1207 } finally { 1208 Binder.restoreCallingIdentity(identity); 1209 } 1210 } 1211 1212 /** 1213 * Allow an INotificationListener to request the list of outstanding notifications seen by 1214 * the current user. Useful when starting up, after which point the listener callbacks 1215 * should be used. 1216 * 1217 * @param token The binder for the listener, to check that the caller is allowed 1218 * @returns The return value will contain the notifications specified in keys, in that 1219 * order, or if keys is null, all the notifications, in natural order. 1220 */ 1221 @Override 1222 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 1223 INotificationListener token) { 1224 synchronized (mNotificationList) { 1225 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1226 final ArrayList<StatusBarNotification> list 1227 = new ArrayList<StatusBarNotification>(); 1228 final int N = mNotificationList.size(); 1229 for (int i=0; i<N; i++) { 1230 StatusBarNotification sbn = mNotificationList.get(i).sbn; 1231 if (info.enabledAndUserMatches(sbn.getUserId())) { 1232 list.add(sbn); 1233 } 1234 } 1235 return new ParceledListSlice<StatusBarNotification>(list); 1236 } 1237 } 1238 1239 @Override 1240 public ZenModeConfig getZenModeConfig() { 1241 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig"); 1242 return mZenModeHelper.getConfig(); 1243 } 1244 1245 @Override 1246 public boolean setZenModeConfig(ZenModeConfig config) { 1247 checkCallerIsSystem(); 1248 return mZenModeHelper.setConfig(config); 1249 } 1250 1251 @Override 1252 public void notifyConditions(String pkg, IConditionProvider provider, 1253 Condition[] conditions) { 1254 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 1255 checkCallerIsSystemOrSameApp(pkg); 1256 final long identity = Binder.clearCallingIdentity(); 1257 try { 1258 mConditionProviders.notifyConditions(pkg, info, conditions); 1259 } finally { 1260 Binder.restoreCallingIdentity(identity); 1261 } 1262 } 1263 1264 @Override 1265 public void requestZenModeConditions(IConditionListener callback, int relevance) { 1266 enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions"); 1267 mConditionProviders.requestZenModeConditions(callback, relevance); 1268 } 1269 1270 @Override 1271 public void setZenModeCondition(Uri conditionId) { 1272 enforceSystemOrSystemUI("INotificationManager.setZenModeCondition"); 1273 final long identity = Binder.clearCallingIdentity(); 1274 try { 1275 mConditionProviders.setZenModeCondition(conditionId); 1276 } finally { 1277 Binder.restoreCallingIdentity(identity); 1278 } 1279 } 1280 1281 @Override 1282 public void setAutomaticZenModeConditions(Uri[] conditionIds) { 1283 enforceSystemOrSystemUI("INotificationManager.setAutomaticZenModeConditions"); 1284 mConditionProviders.setAutomaticZenModeConditions(conditionIds); 1285 } 1286 1287 @Override 1288 public Condition[] getAutomaticZenModeConditions() { 1289 enforceSystemOrSystemUI("INotificationManager.getAutomaticZenModeConditions"); 1290 return mConditionProviders.getAutomaticZenModeConditions(); 1291 } 1292 1293 private void enforceSystemOrSystemUI(String message) { 1294 if (isCallerSystem()) return; 1295 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 1296 message); 1297 } 1298 1299 @Override 1300 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1301 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1302 != PackageManager.PERMISSION_GRANTED) { 1303 pw.println("Permission Denial: can't dump NotificationManager from from pid=" 1304 + Binder.getCallingPid() 1305 + ", uid=" + Binder.getCallingUid()); 1306 return; 1307 } 1308 1309 dumpImpl(pw); 1310 } 1311 }; 1312 1313 private String[] getActiveNotificationKeys(INotificationListener token) { 1314 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1315 final ArrayList<String> keys = new ArrayList<String>(); 1316 if (info.isEnabledForCurrentProfiles()) { 1317 synchronized (mNotificationList) { 1318 final int N = mNotificationList.size(); 1319 for (int i = 0; i < N; i++) { 1320 final StatusBarNotification sbn = mNotificationList.get(i).sbn; 1321 if (info.enabledAndUserMatches(sbn.getUserId())) { 1322 keys.add(sbn.getKey()); 1323 } 1324 } 1325 } 1326 } 1327 return keys.toArray(new String[keys.size()]); 1328 } 1329 1330 void dumpImpl(PrintWriter pw) { 1331 pw.println("Current Notification Manager state:"); 1332 1333 int N; 1334 1335 synchronized (mToastQueue) { 1336 N = mToastQueue.size(); 1337 if (N > 0) { 1338 pw.println(" Toast Queue:"); 1339 for (int i=0; i<N; i++) { 1340 mToastQueue.get(i).dump(pw, " "); 1341 } 1342 pw.println(" "); 1343 } 1344 1345 } 1346 1347 synchronized (mNotificationList) { 1348 N = mNotificationList.size(); 1349 if (N > 0) { 1350 pw.println(" Notification List:"); 1351 for (int i=0; i<N; i++) { 1352 mNotificationList.get(i).dump(pw, " ", getContext()); 1353 } 1354 pw.println(" "); 1355 } 1356 1357 N = mLights.size(); 1358 if (N > 0) { 1359 pw.println(" Lights List:"); 1360 for (int i=0; i<N; i++) { 1361 pw.println(" " + mLights.get(i)); 1362 } 1363 pw.println(" "); 1364 } 1365 1366 pw.println(" mSoundNotification=" + mSoundNotification); 1367 pw.println(" mVibrateNotification=" + mVibrateNotification); 1368 pw.println(" mDisableNotificationAlerts=" + mDisableNotificationAlerts); 1369 pw.println(" mSystemReady=" + mSystemReady); 1370 pw.println(" mArchive=" + mArchive.toString()); 1371 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 1372 int i=0; 1373 while (iter.hasNext()) { 1374 pw.println(" " + iter.next()); 1375 if (++i >= 5) { 1376 if (iter.hasNext()) pw.println(" ..."); 1377 break; 1378 } 1379 } 1380 1381 pw.println("\n Usage Stats:"); 1382 mUsageStats.dump(pw, " "); 1383 1384 pw.println("\n Zen Mode:"); 1385 mZenModeHelper.dump(pw, " "); 1386 1387 pw.println("\n Notification listeners:"); 1388 mListeners.dump(pw); 1389 1390 pw.println("\n Condition providers:"); 1391 mConditionProviders.dump(pw); 1392 } 1393 } 1394 1395 /** 1396 * The private API only accessible to the system process. 1397 */ 1398 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 1399 @Override 1400 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 1401 String tag, int id, Notification notification, int[] idReceived, int userId) { 1402 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 1403 idReceived, userId); 1404 } 1405 }; 1406 1407 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 1408 final int callingPid, final String tag, final int id, final Notification notification, 1409 int[] idOut, int incomingUserId) { 1410 if (DBG) { 1411 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 1412 + " notification=" + notification); 1413 } 1414 checkCallerIsSystemOrSameApp(pkg); 1415 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 1416 1417 final int userId = ActivityManager.handleIncomingUser(callingPid, 1418 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 1419 final UserHandle user = new UserHandle(userId); 1420 1421 // Limit the number of notifications that any given package except the android 1422 // package can enqueue. Prevents DOS attacks and deals with leaks. 1423 if (!isSystemNotification) { 1424 synchronized (mNotificationList) { 1425 int count = 0; 1426 final int N = mNotificationList.size(); 1427 for (int i=0; i<N; i++) { 1428 final NotificationRecord r = mNotificationList.get(i); 1429 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 1430 count++; 1431 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1432 Slog.e(TAG, "Package has already posted " + count 1433 + " notifications. Not showing more. package=" + pkg); 1434 return; 1435 } 1436 } 1437 } 1438 } 1439 } 1440 1441 // This conditional is a dirty hack to limit the logging done on 1442 // behalf of the download manager without affecting other apps. 1443 if (!pkg.equals("com.android.providers.downloads") 1444 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 1445 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 1446 pkg, id, tag, userId, notification.toString()); 1447 } 1448 1449 if (pkg == null || notification == null) { 1450 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 1451 + " id=" + id + " notification=" + notification); 1452 } 1453 if (notification.icon != 0) { 1454 if (notification.contentView == null) { 1455 throw new IllegalArgumentException("contentView required: pkg=" + pkg 1456 + " id=" + id + " notification=" + notification); 1457 } 1458 } 1459 1460 mHandler.post(new Runnable() { 1461 @Override 1462 public void run() { 1463 1464 // === Scoring === 1465 1466 // 0. Sanitize inputs 1467 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 1468 Notification.PRIORITY_MAX); 1469 // Migrate notification flags to scores 1470 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { 1471 if (notification.priority < Notification.PRIORITY_MAX) { 1472 notification.priority = Notification.PRIORITY_MAX; 1473 } 1474 } else if (SCORE_ONGOING_HIGHER && 1475 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { 1476 if (notification.priority < Notification.PRIORITY_HIGH) { 1477 notification.priority = Notification.PRIORITY_HIGH; 1478 } 1479 } 1480 1481 // 1. initial score: buckets of 10, around the app 1482 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20] 1483 1484 // 2. extract ranking signals from the notification data 1485 final StatusBarNotification n = new StatusBarNotification( 1486 pkg, opPkg, id, tag, callingUid, callingPid, score, notification, 1487 user); 1488 NotificationRecord r = new NotificationRecord(n); 1489 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 1490 if (old != null) { 1491 // Retain ranking information from previous record 1492 r.copyRankingInformation(old); 1493 } 1494 if (!mSignalExtractors.isEmpty()) { 1495 for (NotificationSignalExtractor extractor : mSignalExtractors) { 1496 try { 1497 RankingReconsideration recon = extractor.process(r); 1498 scheduleRankingReconsideration(recon); 1499 } catch (Throwable t) { 1500 Slog.w(TAG, "NotificationSignalExtractor failed.", t); 1501 } 1502 } 1503 } 1504 1505 // 3. Apply local rules 1506 1507 // blocked apps 1508 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { 1509 if (!isSystemNotification) { 1510 score = JUNK_SCORE; 1511 Slog.e(TAG, "Suppressing notification from package " + pkg 1512 + " by user request."); 1513 } 1514 } 1515 1516 if (score < SCORE_DISPLAY_THRESHOLD) { 1517 // Notification will be blocked because the score is too low. 1518 return; 1519 } 1520 1521 synchronized (mNotificationList) { 1522 int index = indexOfNotificationLocked(n.getKey()); 1523 if (index < 0) { 1524 mNotificationList.add(r); 1525 mUsageStats.registerPostedByApp(r); 1526 } else { 1527 old = mNotificationList.get(index); 1528 mNotificationList.set(index, r); 1529 mUsageStats.registerUpdatedByApp(r, old); 1530 // Make sure we don't lose the foreground service state. 1531 notification.flags |= 1532 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 1533 mNotificationsByKey.remove(old.sbn.getKey()); 1534 } 1535 mNotificationsByKey.put(n.getKey(), r); 1536 1537 applyZenModeLocked(r); 1538 // Should this notification make noise, vibe, or use the LED? 1539 final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && 1540 !r.isIntercepted(); 1541 if (DBG || r.isIntercepted()) Slog.v(TAG, 1542 "pkg=" + pkg + " canInterrupt=" + canInterrupt + 1543 " intercept=" + r.isIntercepted()); 1544 1545 Collections.sort(mNotificationList, mRankingComparator); 1546 1547 // Ensure if this is a foreground service that the proper additional 1548 // flags are set. 1549 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) { 1550 notification.flags |= Notification.FLAG_ONGOING_EVENT 1551 | Notification.FLAG_NO_CLEAR; 1552 } 1553 1554 final int currentUser; 1555 final long token = Binder.clearCallingIdentity(); 1556 try { 1557 currentUser = ActivityManager.getCurrentUser(); 1558 } finally { 1559 Binder.restoreCallingIdentity(token); 1560 } 1561 1562 if (notification.icon != 0) { 1563 if (old != null && !old.isCanceled) { 1564 final long identity = Binder.clearCallingIdentity(); 1565 try { 1566 mStatusBar.updateNotification(n); 1567 } finally { 1568 Binder.restoreCallingIdentity(identity); 1569 } 1570 } else { 1571 final long identity = Binder.clearCallingIdentity(); 1572 try { 1573 mStatusBar.addNotification(n); 1574 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0 1575 && canInterrupt) { 1576 mAttentionLight.pulse(); 1577 } 1578 } finally { 1579 Binder.restoreCallingIdentity(identity); 1580 } 1581 } 1582 // Send accessibility events only for the current user. 1583 if (currentUser == userId) { 1584 sendAccessibilityEvent(notification, pkg); 1585 } 1586 1587 mListeners.notifyPostedLocked(r.sbn); 1588 } else { 1589 Slog.e(TAG, "Not posting notification with icon==0: " + notification); 1590 if (old != null && !old.isCanceled) { 1591 final long identity = Binder.clearCallingIdentity(); 1592 try { 1593 mStatusBar.removeNotification(r.getKey()); 1594 } finally { 1595 Binder.restoreCallingIdentity(identity); 1596 } 1597 1598 mListeners.notifyRemovedLocked(r.sbn); 1599 } 1600 // ATTENTION: in a future release we will bail out here 1601 // so that we do not play sounds, show lights, etc. for invalid 1602 // notifications 1603 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 1604 + n.getPackageName()); 1605 } 1606 1607 // If we're not supposed to beep, vibrate, etc. then don't. 1608 if (!mDisableNotificationAlerts 1609 && (!(old != null 1610 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) 1611 && (r.getUserId() == UserHandle.USER_ALL || 1612 (r.getUserId() == userId && r.getUserId() == currentUser) || 1613 mUserProfiles.isCurrentProfile(r.getUserId())) 1614 && canInterrupt 1615 && mSystemReady 1616 && mAudioManager != null) { 1617 if (DBG) Slog.v(TAG, "Interrupting!"); 1618 // sound 1619 1620 // should we use the default notification sound? (indicated either by 1621 // DEFAULT_SOUND or because notification.sound is pointing at 1622 // Settings.System.NOTIFICATION_SOUND) 1623 final boolean useDefaultSound = 1624 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 1625 Settings.System.DEFAULT_NOTIFICATION_URI 1626 .equals(notification.sound); 1627 1628 Uri soundUri = null; 1629 boolean hasValidSound = false; 1630 1631 if (useDefaultSound) { 1632 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 1633 1634 // check to see if the default notification sound is silent 1635 ContentResolver resolver = getContext().getContentResolver(); 1636 hasValidSound = Settings.System.getString(resolver, 1637 Settings.System.NOTIFICATION_SOUND) != null; 1638 } else if (notification.sound != null) { 1639 soundUri = notification.sound; 1640 hasValidSound = (soundUri != null); 1641 } 1642 1643 if (hasValidSound) { 1644 boolean looping = 1645 (notification.flags & Notification.FLAG_INSISTENT) != 0; 1646 int audioStreamType; 1647 if (notification.audioStreamType >= 0) { 1648 audioStreamType = notification.audioStreamType; 1649 } else { 1650 audioStreamType = DEFAULT_STREAM_TYPE; 1651 } 1652 mSoundNotification = r; 1653 // do not play notifications if stream volume is 0 (typically because 1654 // ringer mode is silent) or if there is a user of exclusive audio focus 1655 if ((mAudioManager.getStreamVolume(audioStreamType) != 0) 1656 && !mAudioManager.isAudioFocusExclusive()) { 1657 final long identity = Binder.clearCallingIdentity(); 1658 try { 1659 final IRingtonePlayer player = 1660 mAudioManager.getRingtonePlayer(); 1661 if (player != null) { 1662 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 1663 + " on stream " + audioStreamType); 1664 player.playAsync(soundUri, user, looping, audioStreamType); 1665 } 1666 } catch (RemoteException e) { 1667 } finally { 1668 Binder.restoreCallingIdentity(identity); 1669 } 1670 } 1671 } 1672 1673 // vibrate 1674 // Does the notification want to specify its own vibration? 1675 final boolean hasCustomVibrate = notification.vibrate != null; 1676 1677 // new in 4.2: if there was supposed to be a sound and we're in vibrate 1678 // mode, and no other vibration is specified, we fall back to vibration 1679 final boolean convertSoundToVibration = 1680 !hasCustomVibrate 1681 && hasValidSound 1682 && (mAudioManager.getRingerMode() 1683 == AudioManager.RINGER_MODE_VIBRATE); 1684 1685 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 1686 final boolean useDefaultVibrate = 1687 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 1688 1689 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) 1690 && !(mAudioManager.getRingerMode() 1691 == AudioManager.RINGER_MODE_SILENT)) { 1692 mVibrateNotification = r; 1693 1694 if (useDefaultVibrate || convertSoundToVibration) { 1695 // Escalate privileges so we can use the vibrator even if the 1696 // notifying app does not have the VIBRATE permission. 1697 long identity = Binder.clearCallingIdentity(); 1698 try { 1699 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getOpPkg(), 1700 useDefaultVibrate ? mDefaultVibrationPattern 1701 : mFallbackVibrationPattern, 1702 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 1703 ? 0: -1, notification.audioStreamType); 1704 } finally { 1705 Binder.restoreCallingIdentity(identity); 1706 } 1707 } else if (notification.vibrate.length > 1) { 1708 // If you want your own vibration pattern, you need the VIBRATE 1709 // permission 1710 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getOpPkg(), 1711 notification.vibrate, 1712 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 1713 ? 0: -1, notification.audioStreamType); 1714 } 1715 } 1716 } 1717 1718 // light 1719 // the most recent thing gets the light 1720 mLights.remove(old); 1721 if (mLedNotification == old) { 1722 mLedNotification = null; 1723 } 1724 //Slog.i(TAG, "notification.lights=" 1725 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) 1726 // != 0)); 1727 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 1728 && canInterrupt) { 1729 mLights.add(r); 1730 updateLightsLocked(); 1731 } else { 1732 if (old != null 1733 && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) { 1734 updateLightsLocked(); 1735 } 1736 } 1737 } 1738 } 1739 }); 1740 1741 idOut[0] = id; 1742 } 1743 1744 void showNextToastLocked() { 1745 ToastRecord record = mToastQueue.get(0); 1746 while (record != null) { 1747 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 1748 try { 1749 record.callback.show(); 1750 scheduleTimeoutLocked(record); 1751 return; 1752 } catch (RemoteException e) { 1753 Slog.w(TAG, "Object died trying to show notification " + record.callback 1754 + " in package " + record.pkg); 1755 // remove it from the list and let the process die 1756 int index = mToastQueue.indexOf(record); 1757 if (index >= 0) { 1758 mToastQueue.remove(index); 1759 } 1760 keepProcessAliveLocked(record.pid); 1761 if (mToastQueue.size() > 0) { 1762 record = mToastQueue.get(0); 1763 } else { 1764 record = null; 1765 } 1766 } 1767 } 1768 } 1769 1770 void cancelToastLocked(int index) { 1771 ToastRecord record = mToastQueue.get(index); 1772 try { 1773 record.callback.hide(); 1774 } catch (RemoteException e) { 1775 Slog.w(TAG, "Object died trying to hide notification " + record.callback 1776 + " in package " + record.pkg); 1777 // don't worry about this, we're about to remove it from 1778 // the list anyway 1779 } 1780 mToastQueue.remove(index); 1781 keepProcessAliveLocked(record.pid); 1782 if (mToastQueue.size() > 0) { 1783 // Show the next one. If the callback fails, this will remove 1784 // it from the list, so don't assume that the list hasn't changed 1785 // after this point. 1786 showNextToastLocked(); 1787 } 1788 } 1789 1790 private void scheduleTimeoutLocked(ToastRecord r) 1791 { 1792 mHandler.removeCallbacksAndMessages(r); 1793 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 1794 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 1795 mHandler.sendMessageDelayed(m, delay); 1796 } 1797 1798 private void handleTimeout(ToastRecord record) 1799 { 1800 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 1801 synchronized (mToastQueue) { 1802 int index = indexOfToastLocked(record.pkg, record.callback); 1803 if (index >= 0) { 1804 cancelToastLocked(index); 1805 } 1806 } 1807 } 1808 1809 // lock on mToastQueue 1810 int indexOfToastLocked(String pkg, ITransientNotification callback) 1811 { 1812 IBinder cbak = callback.asBinder(); 1813 ArrayList<ToastRecord> list = mToastQueue; 1814 int len = list.size(); 1815 for (int i=0; i<len; i++) { 1816 ToastRecord r = list.get(i); 1817 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 1818 return i; 1819 } 1820 } 1821 return -1; 1822 } 1823 1824 // lock on mToastQueue 1825 void keepProcessAliveLocked(int pid) 1826 { 1827 int toastCount = 0; // toasts from this pid 1828 ArrayList<ToastRecord> list = mToastQueue; 1829 int N = list.size(); 1830 for (int i=0; i<N; i++) { 1831 ToastRecord r = list.get(i); 1832 if (r.pid == pid) { 1833 toastCount++; 1834 } 1835 } 1836 try { 1837 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 1838 } catch (RemoteException e) { 1839 // Shouldn't happen. 1840 } 1841 } 1842 1843 private void scheduleRankingReconsideration(RankingReconsideration recon) { 1844 if (recon != null) { 1845 Message m = Message.obtain(mRankingHandler, MESSAGE_RECONSIDER_RANKING, recon); 1846 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 1847 mRankingHandler.sendMessageDelayed(m, delay); 1848 } 1849 } 1850 1851 private void handleRankingReconsideration(Message message) { 1852 if (!(message.obj instanceof RankingReconsideration)) return; 1853 RankingReconsideration recon = (RankingReconsideration) message.obj; 1854 recon.run(); 1855 boolean changed; 1856 synchronized (mNotificationList) { 1857 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 1858 if (record == null) { 1859 return; 1860 } 1861 int indexBefore = findNotificationRecordIndexLocked(record); 1862 boolean interceptBefore = record.isIntercepted(); 1863 recon.applyChangesLocked(record); 1864 applyZenModeLocked(record); 1865 Collections.sort(mNotificationList, mRankingComparator); 1866 int indexAfter = findNotificationRecordIndexLocked(record); 1867 boolean interceptAfter = record.isIntercepted(); 1868 changed = indexBefore != indexAfter || interceptBefore != interceptAfter; 1869 } 1870 if (changed) { 1871 scheduleSendRankingUpdate(); 1872 } 1873 } 1874 1875 // let zen mode evaluate this record and then make note of that for the future 1876 private void applyZenModeLocked(NotificationRecord record) { 1877 record.setIntercepted(mZenModeHelper.shouldIntercept(record, record.wasTouchedByZen())); 1878 record.setTouchedByZen(); 1879 } 1880 1881 // lock on mNotificationList 1882 private int findNotificationRecordIndexLocked(NotificationRecord target) { 1883 return Collections.binarySearch(mNotificationList, target, mRankingComparator); 1884 } 1885 1886 private void scheduleSendRankingUpdate() { 1887 mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE); 1888 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 1889 mHandler.sendMessage(m); 1890 } 1891 1892 private void handleSendRankingUpdate() { 1893 synchronized (mNotificationList) { 1894 mListeners.notifyRankingUpdateLocked(); 1895 } 1896 } 1897 1898 private final class WorkerHandler extends Handler 1899 { 1900 @Override 1901 public void handleMessage(Message msg) 1902 { 1903 switch (msg.what) 1904 { 1905 case MESSAGE_TIMEOUT: 1906 handleTimeout((ToastRecord)msg.obj); 1907 break; 1908 case MESSAGE_SAVE_POLICY_FILE: 1909 handleSavePolicyFile(); 1910 break; 1911 case MESSAGE_SEND_RANKING_UPDATE: 1912 handleSendRankingUpdate(); 1913 break; 1914 } 1915 } 1916 1917 } 1918 1919 private final class RankingWorkerHandler extends Handler 1920 { 1921 public RankingWorkerHandler(Looper looper) { 1922 super(looper); 1923 } 1924 1925 @Override 1926 public void handleMessage(Message msg) { 1927 switch (msg.what) { 1928 case MESSAGE_RECONSIDER_RANKING: 1929 handleRankingReconsideration(msg); 1930 break; 1931 } 1932 } 1933 } 1934 1935 // Notifications 1936 // ============================================================================ 1937 static int clamp(int x, int low, int high) { 1938 return (x < low) ? low : ((x > high) ? high : x); 1939 } 1940 1941 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 1942 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 1943 if (!manager.isEnabled()) { 1944 return; 1945 } 1946 1947 AccessibilityEvent event = 1948 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 1949 event.setPackageName(packageName); 1950 event.setClassName(Notification.class.getName()); 1951 event.setParcelableData(notification); 1952 CharSequence tickerText = notification.tickerText; 1953 if (!TextUtils.isEmpty(tickerText)) { 1954 event.getText().add(tickerText); 1955 } 1956 1957 manager.sendAccessibilityEvent(event); 1958 } 1959 1960 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 1961 // tell the app 1962 if (sendDelete) { 1963 if (r.getNotification().deleteIntent != null) { 1964 try { 1965 r.getNotification().deleteIntent.send(); 1966 } catch (PendingIntent.CanceledException ex) { 1967 // do nothing - there's no relevant way to recover, and 1968 // no reason to let this propagate 1969 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 1970 } 1971 } 1972 } 1973 1974 // status bar 1975 if (r.getNotification().icon != 0) { 1976 final long identity = Binder.clearCallingIdentity(); 1977 try { 1978 mStatusBar.removeNotification(r.getKey()); 1979 } finally { 1980 Binder.restoreCallingIdentity(identity); 1981 } 1982 r.isCanceled = true; 1983 mListeners.notifyRemovedLocked(r.sbn); 1984 } 1985 1986 // sound 1987 if (mSoundNotification == r) { 1988 mSoundNotification = null; 1989 final long identity = Binder.clearCallingIdentity(); 1990 try { 1991 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 1992 if (player != null) { 1993 player.stopAsync(); 1994 } 1995 } catch (RemoteException e) { 1996 } finally { 1997 Binder.restoreCallingIdentity(identity); 1998 } 1999 } 2000 2001 // vibrate 2002 if (mVibrateNotification == r) { 2003 mVibrateNotification = null; 2004 long identity = Binder.clearCallingIdentity(); 2005 try { 2006 mVibrator.cancel(); 2007 } 2008 finally { 2009 Binder.restoreCallingIdentity(identity); 2010 } 2011 } 2012 2013 // light 2014 mLights.remove(r); 2015 if (mLedNotification == r) { 2016 mLedNotification = null; 2017 } 2018 2019 // Record usage stats 2020 switch (reason) { 2021 case REASON_DELEGATE_CANCEL: 2022 case REASON_DELEGATE_CANCEL_ALL: 2023 case REASON_LISTENER_CANCEL: 2024 case REASON_LISTENER_CANCEL_ALL: 2025 mUsageStats.registerDismissedByUser(r); 2026 break; 2027 case REASON_NOMAN_CANCEL: 2028 case REASON_NOMAN_CANCEL_ALL: 2029 mUsageStats.registerRemovedByApp(r); 2030 break; 2031 case REASON_DELEGATE_CLICK: 2032 mUsageStats.registerCancelDueToClick(r); 2033 break; 2034 default: 2035 mUsageStats.registerCancelUnknown(r); 2036 break; 2037 } 2038 2039 // Save it for users of getHistoricalNotifications() 2040 mArchive.record(r.sbn); 2041 } 2042 2043 /** 2044 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 2045 * and none of the {@code mustNotHaveFlags}. 2046 */ 2047 void cancelNotification(final int callingUid, final int callingPid, 2048 final String pkg, final String tag, final int id, 2049 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 2050 final int userId, final int reason, final ManagedServiceInfo listener) { 2051 // In enqueueNotificationInternal notifications are added by scheduling the 2052 // work on the worker handler. Hence, we also schedule the cancel on this 2053 // handler to avoid a scenario where an add notification call followed by a 2054 // remove notification call ends up in not removing the notification. 2055 mHandler.post(new Runnable() { 2056 @Override 2057 public void run() { 2058 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId, 2059 mustHaveFlags, mustNotHaveFlags, reason, 2060 listener == null ? null : listener.component.toShortString()); 2061 2062 synchronized (mNotificationList) { 2063 int index = indexOfNotificationLocked(pkg, tag, id, userId); 2064 if (index >= 0) { 2065 NotificationRecord r = mNotificationList.get(index); 2066 2067 // Ideally we'd do this in the caller of this method. However, that would 2068 // require the caller to also find the notification. 2069 if (reason == REASON_DELEGATE_CLICK) { 2070 mUsageStats.registerClickedByUser(r); 2071 } 2072 2073 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 2074 return; 2075 } 2076 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 2077 return; 2078 } 2079 2080 mNotificationList.remove(index); 2081 mNotificationsByKey.remove(r.sbn.getKey()); 2082 2083 cancelNotificationLocked(r, sendDelete, reason); 2084 updateLightsLocked(); 2085 } 2086 } 2087 } 2088 }); 2089 } 2090 2091 /** 2092 * Determine whether the userId applies to the notification in question, either because 2093 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 2094 */ 2095 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 2096 return 2097 // looking for USER_ALL notifications? match everything 2098 userId == UserHandle.USER_ALL 2099 // a notification sent to USER_ALL matches any query 2100 || r.getUserId() == UserHandle.USER_ALL 2101 // an exact user match 2102 || r.getUserId() == userId; 2103 } 2104 2105 /** 2106 * Determine whether the userId applies to the notification in question, either because 2107 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 2108 * because it matches one of the users profiles. 2109 */ 2110 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 2111 return notificationMatchesUserId(r, userId) 2112 || mUserProfiles.isCurrentProfile(r.getUserId()); 2113 } 2114 2115 /** 2116 * Cancels all notifications from a given package that have all of the 2117 * {@code mustHaveFlags}. 2118 */ 2119 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 2120 int mustNotHaveFlags, boolean doit, int userId, int reason, 2121 ManagedServiceInfo listener) { 2122 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2123 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 2124 listener == null ? null : listener.component.toShortString()); 2125 2126 synchronized (mNotificationList) { 2127 final int N = mNotificationList.size(); 2128 boolean canceledSomething = false; 2129 for (int i = N-1; i >= 0; --i) { 2130 NotificationRecord r = mNotificationList.get(i); 2131 if (!notificationMatchesUserId(r, userId)) { 2132 continue; 2133 } 2134 // Don't remove notifications to all, if there's no package name specified 2135 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 2136 continue; 2137 } 2138 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 2139 continue; 2140 } 2141 if ((r.getFlags() & mustNotHaveFlags) != 0) { 2142 continue; 2143 } 2144 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 2145 continue; 2146 } 2147 canceledSomething = true; 2148 if (!doit) { 2149 return true; 2150 } 2151 mNotificationList.remove(i); 2152 mNotificationsByKey.remove(r.sbn.getKey()); 2153 cancelNotificationLocked(r, false, reason); 2154 } 2155 if (canceledSomething) { 2156 updateLightsLocked(); 2157 } 2158 return canceledSomething; 2159 } 2160 } 2161 2162 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 2163 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 2164 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2165 null, userId, 0, 0, reason, 2166 listener == null ? null : listener.component.toShortString()); 2167 2168 final int N = mNotificationList.size(); 2169 for (int i=N-1; i>=0; i--) { 2170 NotificationRecord r = mNotificationList.get(i); 2171 if (includeCurrentProfiles) { 2172 if (!notificationMatchesCurrentProfiles(r, userId)) { 2173 continue; 2174 } 2175 } else { 2176 if (!notificationMatchesUserId(r, userId)) { 2177 continue; 2178 } 2179 } 2180 2181 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 2182 | Notification.FLAG_NO_CLEAR)) == 0) { 2183 mNotificationList.remove(i); 2184 mNotificationsByKey.remove(r.sbn.getKey()); 2185 cancelNotificationLocked(r, true, reason); 2186 } 2187 } 2188 updateLightsLocked(); 2189 } 2190 2191 // lock on mNotificationList 2192 void updateLightsLocked() 2193 { 2194 // handle notification lights 2195 if (mLedNotification == null) { 2196 // get next notification, if any 2197 int n = mLights.size(); 2198 if (n > 0) { 2199 mLedNotification = mLights.get(n-1); 2200 } 2201 } 2202 2203 // Don't flash while we are in a call or screen is on 2204 if (mLedNotification == null || mInCall || mScreenOn) { 2205 mNotificationLight.turnOff(); 2206 } else { 2207 final Notification ledno = mLedNotification.sbn.getNotification(); 2208 int ledARGB = ledno.ledARGB; 2209 int ledOnMS = ledno.ledOnMS; 2210 int ledOffMS = ledno.ledOffMS; 2211 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 2212 ledARGB = mDefaultNotificationColor; 2213 ledOnMS = mDefaultNotificationLedOn; 2214 ledOffMS = mDefaultNotificationLedOff; 2215 } 2216 if (mNotificationPulseEnabled) { 2217 // pulse repeatedly 2218 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 2219 ledOnMS, ledOffMS); 2220 } 2221 } 2222 } 2223 2224 // lock on mNotificationList 2225 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 2226 { 2227 ArrayList<NotificationRecord> list = mNotificationList; 2228 final int len = list.size(); 2229 for (int i=0; i<len; i++) { 2230 NotificationRecord r = list.get(i); 2231 if (!notificationMatchesUserId(r, userId) || r.sbn.getId() != id) { 2232 continue; 2233 } 2234 if (tag == null) { 2235 if (r.sbn.getTag() != null) { 2236 continue; 2237 } 2238 } else { 2239 if (!tag.equals(r.sbn.getTag())) { 2240 continue; 2241 } 2242 } 2243 if (r.sbn.getPackageName().equals(pkg)) { 2244 return i; 2245 } 2246 } 2247 return -1; 2248 } 2249 2250 // lock on mNotificationList 2251 int indexOfNotificationLocked(String key) { 2252 NotificationRecord r = mNotificationsByKey.get(key); 2253 if (r == null) { 2254 return -1; 2255 } 2256 int index = Collections.binarySearch(mNotificationList, r, mRankingComparator); 2257 // Guarantee to return -1 when not found. 2258 return (index >= 0) ? index : -1; 2259 } 2260 2261 2262 private void updateNotificationPulse() { 2263 synchronized (mNotificationList) { 2264 updateLightsLocked(); 2265 } 2266 } 2267 2268 private static boolean isUidSystem(int uid) { 2269 final int appid = UserHandle.getAppId(uid); 2270 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 2271 } 2272 2273 private static boolean isCallerSystem() { 2274 return isUidSystem(Binder.getCallingUid()); 2275 } 2276 2277 private static void checkCallerIsSystem() { 2278 if (isCallerSystem()) { 2279 return; 2280 } 2281 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 2282 } 2283 2284 private static void checkCallerIsSystemOrSameApp(String pkg) { 2285 if (isCallerSystem()) { 2286 return; 2287 } 2288 final int uid = Binder.getCallingUid(); 2289 try { 2290 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 2291 pkg, 0, UserHandle.getCallingUserId()); 2292 if (!UserHandle.isSameApp(ai.uid, uid)) { 2293 throw new SecurityException("Calling uid " + uid + " gave package" 2294 + pkg + " which is owned by uid " + ai.uid); 2295 } 2296 } catch (RemoteException re) { 2297 throw new SecurityException("Unknown package " + pkg + "\n" + re); 2298 } 2299 } 2300 2301 /** 2302 * Generates a NotificationRankingUpdate from 'sbns', considering only 2303 * notifications visible to the given listener. 2304 * 2305 * <p>Caller must hold a lock on mNotificationList.</p> 2306 */ 2307 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 2308 int speedBumpIndex = -1; 2309 final int N = mNotificationList.size(); 2310 ArrayList<String> keys = new ArrayList<String>(N); 2311 ArrayList<String> dndKeys = new ArrayList<String>(N); 2312 for (int i = 0; i < N; i++) { 2313 NotificationRecord record = mNotificationList.get(i); 2314 if (!info.enabledAndUserMatches(record.sbn.getUserId())) { 2315 continue; 2316 } 2317 keys.add(record.sbn.getKey()); 2318 if (record.isIntercepted()) { 2319 dndKeys.add(record.sbn.getKey()); 2320 } 2321 if (speedBumpIndex == -1 && 2322 record.sbn.getNotification().priority == Notification.PRIORITY_MIN) { 2323 speedBumpIndex = keys.size() - 1; 2324 } 2325 } 2326 String[] keysAr = keys.toArray(new String[keys.size()]); 2327 String[] dndKeysAr = dndKeys.toArray(new String[dndKeys.size()]); 2328 return new NotificationRankingUpdate(keysAr, dndKeysAr, speedBumpIndex); 2329 } 2330 2331 public class NotificationListeners extends ManagedServices { 2332 2333 public NotificationListeners() { 2334 super(getContext(), mHandler, mNotificationList, mUserProfiles); 2335 } 2336 2337 @Override 2338 protected Config getConfig() { 2339 Config c = new Config(); 2340 c.caption = "notification listener"; 2341 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 2342 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 2343 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 2344 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 2345 c.clientLabel = R.string.notification_listener_binding_label; 2346 return c; 2347 } 2348 2349 @Override 2350 protected IInterface asInterface(IBinder binder) { 2351 return INotificationListener.Stub.asInterface(binder); 2352 } 2353 2354 @Override 2355 public void onServiceAdded(ManagedServiceInfo info) { 2356 final INotificationListener listener = (INotificationListener) info.service; 2357 final NotificationRankingUpdate update; 2358 synchronized (mNotificationList) { 2359 update = makeRankingUpdateLocked(info); 2360 } 2361 try { 2362 listener.onListenerConnected(update); 2363 } catch (RemoteException e) { 2364 // we tried 2365 } 2366 } 2367 2368 /** 2369 * asynchronously notify all listeners about a new notification 2370 */ 2371 public void notifyPostedLocked(StatusBarNotification sbn) { 2372 // make a copy in case changes are made to the underlying Notification object 2373 final StatusBarNotification sbnClone = sbn.clone(); 2374 for (final ManagedServiceInfo info : mServices) { 2375 if (!info.isEnabledForCurrentProfiles()) { 2376 continue; 2377 } 2378 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 2379 if (update.getOrderedKeys().length == 0) { 2380 continue; 2381 } 2382 mHandler.post(new Runnable() { 2383 @Override 2384 public void run() { 2385 notifyPostedIfUserMatch(info, sbnClone, update); 2386 } 2387 }); 2388 } 2389 } 2390 2391 /** 2392 * asynchronously notify all listeners about a removed notification 2393 */ 2394 public void notifyRemovedLocked(StatusBarNotification sbn) { 2395 // make a copy in case changes are made to the underlying Notification object 2396 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 2397 // notification 2398 final StatusBarNotification sbnLight = sbn.cloneLight(); 2399 for (final ManagedServiceInfo info : mServices) { 2400 if (!info.isEnabledForCurrentProfiles()) { 2401 continue; 2402 } 2403 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 2404 mHandler.post(new Runnable() { 2405 @Override 2406 public void run() { 2407 notifyRemovedIfUserMatch(info, sbnLight, update); 2408 } 2409 }); 2410 } 2411 } 2412 2413 /** 2414 * asynchronously notify all listeners about a reordering of notifications 2415 */ 2416 public void notifyRankingUpdateLocked() { 2417 for (final ManagedServiceInfo serviceInfo : mServices) { 2418 if (!serviceInfo.isEnabledForCurrentProfiles()) { 2419 continue; 2420 } 2421 final NotificationRankingUpdate update = 2422 makeRankingUpdateLocked(serviceInfo); 2423 mHandler.post(new Runnable() { 2424 @Override 2425 public void run() { 2426 notifyRankingUpdate(serviceInfo, update); 2427 } 2428 }); 2429 } 2430 } 2431 2432 private void notifyPostedIfUserMatch(final ManagedServiceInfo info, 2433 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 2434 if (!info.enabledAndUserMatches(sbn.getUserId())) { 2435 return; 2436 } 2437 final INotificationListener listener = (INotificationListener)info.service; 2438 try { 2439 listener.onNotificationPosted(sbn, rankingUpdate); 2440 } catch (RemoteException ex) { 2441 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 2442 } 2443 } 2444 2445 private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn, 2446 NotificationRankingUpdate rankingUpdate) { 2447 if (!info.enabledAndUserMatches(sbn.getUserId())) { 2448 return; 2449 } 2450 final INotificationListener listener = (INotificationListener) info.service; 2451 try { 2452 listener.onNotificationRemoved(sbn, rankingUpdate); 2453 } catch (RemoteException ex) { 2454 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 2455 } 2456 } 2457 2458 private void notifyRankingUpdate(ManagedServiceInfo info, 2459 NotificationRankingUpdate rankingUpdate) { 2460 final INotificationListener listener = (INotificationListener) info.service; 2461 try { 2462 listener.onNotificationRankingUpdate(rankingUpdate); 2463 } catch (RemoteException ex) { 2464 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 2465 } 2466 } 2467 } 2468} 2469