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