AlarmManagerService.java revision 91b3566bec73fc7f66c9ea8415392ae8f5a24236
1/* 2 * Copyright (C) 2006 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; 18 19import android.app.Activity; 20import android.app.ActivityManager; 21import android.app.ActivityManagerNative; 22import android.app.AlarmManager; 23import android.app.IAlarmManager; 24import android.app.PendingIntent; 25import android.content.BroadcastReceiver; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.pm.PackageManager; 30import android.net.Uri; 31import android.os.Binder; 32import android.os.Bundle; 33import android.os.Handler; 34import android.os.IBinder; 35import android.os.Message; 36import android.os.PowerManager; 37import android.os.SystemClock; 38import android.os.SystemProperties; 39import android.os.UserHandle; 40import android.os.WorkSource; 41import android.provider.Settings; 42import android.text.TextUtils; 43import android.text.format.DateFormat; 44import android.util.ArrayMap; 45import android.util.Log; 46import android.util.Slog; 47import android.util.SparseArray; 48import android.util.SparseBooleanArray; 49import android.util.TimeUtils; 50 51import java.io.ByteArrayOutputStream; 52import java.io.FileDescriptor; 53import java.io.PrintWriter; 54import java.text.SimpleDateFormat; 55import java.util.ArrayList; 56import java.util.Arrays; 57import java.util.Calendar; 58import java.util.Collections; 59import java.util.Comparator; 60import java.util.Date; 61import java.util.LinkedList; 62import java.util.Locale; 63import java.util.TimeZone; 64 65import static android.app.AlarmManager.RTC_WAKEUP; 66import static android.app.AlarmManager.RTC; 67import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; 68import static android.app.AlarmManager.ELAPSED_REALTIME; 69 70import com.android.internal.util.LocalLog; 71 72class AlarmManagerService extends SystemService { 73 // The threshold for how long an alarm can be late before we print a 74 // warning message. The time duration is in milliseconds. 75 private static final long LATE_ALARM_THRESHOLD = 10 * 1000; 76 77 private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; 78 private static final int RTC_MASK = 1 << RTC; 79 private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; 80 private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME; 81 static final int TIME_CHANGED_MASK = 1 << 16; 82 static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK; 83 84 // Mask for testing whether a given alarm type is wakeup vs non-wakeup 85 static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup 86 87 static final String TAG = "AlarmManager"; 88 static final String ClockReceiver_TAG = "ClockReceiver"; 89 static final boolean localLOGV = false; 90 static final boolean DEBUG_BATCH = localLOGV || false; 91 static final boolean DEBUG_VALIDATE = localLOGV || false; 92 static final boolean DEBUG_ALARM_CLOCK = localLOGV || false; 93 static final int ALARM_EVENT = 1; 94 static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; 95 96 static final Intent mBackgroundIntent 97 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); 98 static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder(); 99 100 static final boolean WAKEUP_STATS = false; 101 102 private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT = new Intent( 103 AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); 104 105 final LocalLog mLog = new LocalLog(TAG); 106 107 final Object mLock = new Object(); 108 109 long mNativeData; 110 private long mNextWakeup; 111 private long mNextNonWakeup; 112 int mBroadcastRefCount = 0; 113 PowerManager.WakeLock mWakeLock; 114 boolean mLastWakeLockUnimportantForLogging; 115 ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>(); 116 ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); 117 final AlarmHandler mHandler = new AlarmHandler(); 118 ClockReceiver mClockReceiver; 119 InteractiveStateReceiver mInteractiveStateReceiver; 120 private UninstallReceiver mUninstallReceiver; 121 final ResultReceiver mResultReceiver = new ResultReceiver(); 122 PendingIntent mTimeTickSender; 123 PendingIntent mDateChangeSender; 124 boolean mInteractive = true; 125 long mNonInteractiveStartTime; 126 long mNonInteractiveTime; 127 long mLastAlarmDeliveryTime; 128 long mStartCurrentDelayTime; 129 long mNextNonWakeupDeliveryTime; 130 131 private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = 132 new SparseArray<>(); 133 private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray = 134 new SparseArray<>(); 135 private final SparseBooleanArray mPendingSendNextAlarmClockChangedForUser = 136 new SparseBooleanArray(); 137 private boolean mNextAlarmClockMayChange; 138 139 // May only use on mHandler's thread, locking not required. 140 private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray = 141 new SparseArray<>(); 142 143 class WakeupEvent { 144 public long when; 145 public int uid; 146 public String action; 147 148 public WakeupEvent(long theTime, int theUid, String theAction) { 149 when = theTime; 150 uid = theUid; 151 action = theAction; 152 } 153 } 154 155 final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>(); 156 final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day 157 158 final class Batch { 159 long start; // These endpoints are always in ELAPSED 160 long end; 161 boolean standalone; // certain "batches" don't participate in coalescing 162 163 final ArrayList<Alarm> alarms = new ArrayList<Alarm>(); 164 165 Batch() { 166 start = 0; 167 end = Long.MAX_VALUE; 168 } 169 170 Batch(Alarm seed) { 171 start = seed.whenElapsed; 172 end = seed.maxWhen; 173 alarms.add(seed); 174 } 175 176 int size() { 177 return alarms.size(); 178 } 179 180 Alarm get(int index) { 181 return alarms.get(index); 182 } 183 184 boolean canHold(long whenElapsed, long maxWhen) { 185 return (end >= whenElapsed) && (start <= maxWhen); 186 } 187 188 boolean add(Alarm alarm) { 189 boolean newStart = false; 190 // narrows the batch if necessary; presumes that canHold(alarm) is true 191 int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder); 192 if (index < 0) { 193 index = 0 - index - 1; 194 } 195 alarms.add(index, alarm); 196 if (DEBUG_BATCH) { 197 Slog.v(TAG, "Adding " + alarm + " to " + this); 198 } 199 if (alarm.whenElapsed > start) { 200 start = alarm.whenElapsed; 201 newStart = true; 202 } 203 if (alarm.maxWhen < end) { 204 end = alarm.maxWhen; 205 } 206 207 if (DEBUG_BATCH) { 208 Slog.v(TAG, " => now " + this); 209 } 210 return newStart; 211 } 212 213 boolean remove(final PendingIntent operation) { 214 boolean didRemove = false; 215 long newStart = 0; // recalculate endpoints as we go 216 long newEnd = Long.MAX_VALUE; 217 for (int i = 0; i < alarms.size(); ) { 218 Alarm alarm = alarms.get(i); 219 if (alarm.operation.equals(operation)) { 220 alarms.remove(i); 221 didRemove = true; 222 if (alarm.alarmClock != null) { 223 mNextAlarmClockMayChange = true; 224 } 225 } else { 226 if (alarm.whenElapsed > newStart) { 227 newStart = alarm.whenElapsed; 228 } 229 if (alarm.maxWhen < newEnd) { 230 newEnd = alarm.maxWhen; 231 } 232 i++; 233 } 234 } 235 if (didRemove) { 236 // commit the new batch bounds 237 start = newStart; 238 end = newEnd; 239 } 240 return didRemove; 241 } 242 243 boolean remove(final String packageName) { 244 boolean didRemove = false; 245 long newStart = 0; // recalculate endpoints as we go 246 long newEnd = Long.MAX_VALUE; 247 for (int i = 0; i < alarms.size(); ) { 248 Alarm alarm = alarms.get(i); 249 if (alarm.operation.getTargetPackage().equals(packageName)) { 250 alarms.remove(i); 251 didRemove = true; 252 if (alarm.alarmClock != null) { 253 mNextAlarmClockMayChange = true; 254 } 255 } else { 256 if (alarm.whenElapsed > newStart) { 257 newStart = alarm.whenElapsed; 258 } 259 if (alarm.maxWhen < newEnd) { 260 newEnd = alarm.maxWhen; 261 } 262 i++; 263 } 264 } 265 if (didRemove) { 266 // commit the new batch bounds 267 start = newStart; 268 end = newEnd; 269 } 270 return didRemove; 271 } 272 273 boolean remove(final int userHandle) { 274 boolean didRemove = false; 275 long newStart = 0; // recalculate endpoints as we go 276 long newEnd = Long.MAX_VALUE; 277 for (int i = 0; i < alarms.size(); ) { 278 Alarm alarm = alarms.get(i); 279 if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) { 280 alarms.remove(i); 281 didRemove = true; 282 if (alarm.alarmClock != null) { 283 mNextAlarmClockMayChange = true; 284 } 285 } else { 286 if (alarm.whenElapsed > newStart) { 287 newStart = alarm.whenElapsed; 288 } 289 if (alarm.maxWhen < newEnd) { 290 newEnd = alarm.maxWhen; 291 } 292 i++; 293 } 294 } 295 if (didRemove) { 296 // commit the new batch bounds 297 start = newStart; 298 end = newEnd; 299 } 300 return didRemove; 301 } 302 303 boolean hasPackage(final String packageName) { 304 final int N = alarms.size(); 305 for (int i = 0; i < N; i++) { 306 Alarm a = alarms.get(i); 307 if (a.operation.getTargetPackage().equals(packageName)) { 308 return true; 309 } 310 } 311 return false; 312 } 313 314 boolean hasWakeups() { 315 final int N = alarms.size(); 316 for (int i = 0; i < N; i++) { 317 Alarm a = alarms.get(i); 318 // non-wakeup alarms are types 1 and 3, i.e. have the low bit set 319 if ((a.type & TYPE_NONWAKEUP_MASK) == 0) { 320 return true; 321 } 322 } 323 return false; 324 } 325 326 @Override 327 public String toString() { 328 StringBuilder b = new StringBuilder(40); 329 b.append("Batch{"); b.append(Integer.toHexString(this.hashCode())); 330 b.append(" num="); b.append(size()); 331 b.append(" start="); b.append(start); 332 b.append(" end="); b.append(end); 333 if (standalone) { 334 b.append(" STANDALONE"); 335 } 336 b.append('}'); 337 return b.toString(); 338 } 339 } 340 341 static class BatchTimeOrder implements Comparator<Batch> { 342 public int compare(Batch b1, Batch b2) { 343 long when1 = b1.start; 344 long when2 = b2.start; 345 if (when1 - when2 > 0) { 346 return 1; 347 } 348 if (when1 - when2 < 0) { 349 return -1; 350 } 351 return 0; 352 } 353 } 354 355 final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() { 356 @Override 357 public int compare(Alarm lhs, Alarm rhs) { 358 if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage())) 359 && lhs.wakeup != rhs.wakeup) { 360 // We want to put wakeup alarms before non-wakeup alarms, since they are 361 // the things that drive most activity in the alarm manager. However, 362 // alarms from the same package should always be ordered strictly by time. 363 return lhs.wakeup ? -1 : 1; 364 } 365 if (lhs.whenElapsed < rhs.whenElapsed) { 366 return -1; 367 } else if (lhs.whenElapsed > rhs.whenElapsed) { 368 return 1; 369 } 370 return 0; 371 } 372 }; 373 374 // minimum recurrence period or alarm futurity for us to be able to fuzz it 375 static final long MIN_FUZZABLE_INTERVAL = 10000; 376 static final BatchTimeOrder sBatchOrder = new BatchTimeOrder(); 377 final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>(); 378 379 public AlarmManagerService(Context context) { 380 super(context); 381 } 382 383 static long convertToElapsed(long when, int type) { 384 final boolean isRtc = (type == RTC || type == RTC_WAKEUP); 385 if (isRtc) { 386 when -= System.currentTimeMillis() - SystemClock.elapsedRealtime(); 387 } 388 return when; 389 } 390 391 // Apply a heuristic to { recurrence interval, futurity of the trigger time } to 392 // calculate the end of our nominal delivery window for the alarm. 393 static long maxTriggerTime(long now, long triggerAtTime, long interval) { 394 // Current heuristic: batchable window is 75% of either the recurrence interval 395 // [for a periodic alarm] or of the time from now to the desired delivery time, 396 // with a minimum delay/interval of 10 seconds, under which we will simply not 397 // defer the alarm. 398 long futurity = (interval == 0) 399 ? (triggerAtTime - now) 400 : interval; 401 if (futurity < MIN_FUZZABLE_INTERVAL) { 402 futurity = 0; 403 } 404 return triggerAtTime + (long)(.75 * futurity); 405 } 406 407 // returns true if the batch was added at the head 408 static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) { 409 int index = Collections.binarySearch(list, newBatch, sBatchOrder); 410 if (index < 0) { 411 index = 0 - index - 1; 412 } 413 list.add(index, newBatch); 414 return (index == 0); 415 } 416 417 // Return the index of the matching batch, or -1 if none found. 418 int attemptCoalesceLocked(long whenElapsed, long maxWhen) { 419 final int N = mAlarmBatches.size(); 420 for (int i = 0; i < N; i++) { 421 Batch b = mAlarmBatches.get(i); 422 if (!b.standalone && b.canHold(whenElapsed, maxWhen)) { 423 return i; 424 } 425 } 426 return -1; 427 } 428 429 // The RTC clock has moved arbitrarily, so we need to recalculate all the batching 430 void rebatchAllAlarms() { 431 synchronized (mLock) { 432 rebatchAllAlarmsLocked(true); 433 } 434 } 435 436 void rebatchAllAlarmsLocked(boolean doValidate) { 437 ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone(); 438 mAlarmBatches.clear(); 439 final long nowElapsed = SystemClock.elapsedRealtime(); 440 final int oldBatches = oldSet.size(); 441 for (int batchNum = 0; batchNum < oldBatches; batchNum++) { 442 Batch batch = oldSet.get(batchNum); 443 final int N = batch.size(); 444 for (int i = 0; i < N; i++) { 445 Alarm a = batch.get(i); 446 long whenElapsed = convertToElapsed(a.when, a.type); 447 final long maxElapsed; 448 if (a.whenElapsed == a.maxWhen) { 449 // Exact 450 maxElapsed = whenElapsed; 451 } else { 452 // Not exact. Preserve any explicit window, otherwise recalculate 453 // the window based on the alarm's new futurity. Note that this 454 // reflects a policy of preferring timely to deferred delivery. 455 maxElapsed = (a.windowLength > 0) 456 ? (whenElapsed + a.windowLength) 457 : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval); 458 } 459 setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed, 460 a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource, 461 a.alarmClock, a.userId); 462 } 463 } 464 } 465 466 static final class InFlight extends Intent { 467 final PendingIntent mPendingIntent; 468 final WorkSource mWorkSource; 469 final String mTag; 470 final BroadcastStats mBroadcastStats; 471 final FilterStats mFilterStats; 472 final int mAlarmType; 473 474 InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource, 475 int alarmType, String tag) { 476 mPendingIntent = pendingIntent; 477 mWorkSource = workSource; 478 mTag = tag; 479 mBroadcastStats = service.getStatsLocked(pendingIntent); 480 FilterStats fs = mBroadcastStats.filterStats.get(mTag); 481 if (fs == null) { 482 fs = new FilterStats(mBroadcastStats, mTag); 483 mBroadcastStats.filterStats.put(mTag, fs); 484 } 485 mFilterStats = fs; 486 mAlarmType = alarmType; 487 } 488 } 489 490 static final class FilterStats { 491 final BroadcastStats mBroadcastStats; 492 final String mTag; 493 494 long aggregateTime; 495 int count; 496 int numWakeup; 497 long startTime; 498 int nesting; 499 500 FilterStats(BroadcastStats broadcastStats, String tag) { 501 mBroadcastStats = broadcastStats; 502 mTag = tag; 503 } 504 } 505 506 static final class BroadcastStats { 507 final int mUid; 508 final String mPackageName; 509 510 long aggregateTime; 511 int count; 512 int numWakeup; 513 long startTime; 514 int nesting; 515 final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>(); 516 517 BroadcastStats(int uid, String packageName) { 518 mUid = uid; 519 mPackageName = packageName; 520 } 521 } 522 523 final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats 524 = new SparseArray<ArrayMap<String, BroadcastStats>>(); 525 526 int mNumDelayedAlarms = 0; 527 long mTotalDelayTime = 0; 528 long mMaxDelayTime = 0; 529 530 @Override 531 public void onStart() { 532 mNativeData = init(); 533 mNextWakeup = mNextNonWakeup = 0; 534 535 // We have to set current TimeZone info to kernel 536 // because kernel doesn't keep this after reboot 537 setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); 538 539 PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 540 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*"); 541 542 mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0, 543 new Intent(Intent.ACTION_TIME_TICK).addFlags( 544 Intent.FLAG_RECEIVER_REGISTERED_ONLY 545 | Intent.FLAG_RECEIVER_FOREGROUND), 0, 546 UserHandle.ALL); 547 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED); 548 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 549 mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent, 550 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL); 551 552 // now that we have initied the driver schedule the alarm 553 mClockReceiver = new ClockReceiver(); 554 mClockReceiver.scheduleTimeTickEvent(); 555 mClockReceiver.scheduleDateChangedEvent(); 556 mInteractiveStateReceiver = new InteractiveStateReceiver(); 557 mUninstallReceiver = new UninstallReceiver(); 558 559 if (mNativeData != 0) { 560 AlarmThread waitThread = new AlarmThread(); 561 waitThread.start(); 562 } else { 563 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler."); 564 } 565 566 publishBinderService(Context.ALARM_SERVICE, mService); 567 } 568 569 @Override 570 protected void finalize() throws Throwable { 571 try { 572 close(mNativeData); 573 } finally { 574 super.finalize(); 575 } 576 } 577 578 void setTimeZoneImpl(String tz) { 579 if (TextUtils.isEmpty(tz)) { 580 return; 581 } 582 583 TimeZone zone = TimeZone.getTimeZone(tz); 584 // Prevent reentrant calls from stepping on each other when writing 585 // the time zone property 586 boolean timeZoneWasChanged = false; 587 synchronized (this) { 588 String current = SystemProperties.get(TIMEZONE_PROPERTY); 589 if (current == null || !current.equals(zone.getID())) { 590 if (localLOGV) { 591 Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); 592 } 593 timeZoneWasChanged = true; 594 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); 595 } 596 597 // Update the kernel timezone information 598 // Kernel tracks time offsets as 'minutes west of GMT' 599 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 600 setKernelTimezone(mNativeData, -(gmtOffset / 60000)); 601 } 602 603 TimeZone.setDefault(null); 604 605 if (timeZoneWasChanged) { 606 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); 607 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 608 intent.putExtra("time-zone", zone.getID()); 609 getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 610 } 611 } 612 613 void removeImpl(PendingIntent operation) { 614 if (operation == null) { 615 return; 616 } 617 synchronized (mLock) { 618 removeLocked(operation); 619 } 620 } 621 622 void setImpl(int type, long triggerAtTime, long windowLength, long interval, 623 PendingIntent operation, boolean isStandalone, WorkSource workSource, 624 AlarmManager.AlarmClockInfo alarmClock) { 625 if (operation == null) { 626 Slog.w(TAG, "set/setRepeating ignored because there is no intent"); 627 return; 628 } 629 630 // Sanity check the window length. This will catch people mistakenly 631 // trying to pass an end-of-window timestamp rather than a duration. 632 if (windowLength > AlarmManager.INTERVAL_HALF_DAY) { 633 Slog.w(TAG, "Window length " + windowLength 634 + "ms suspiciously long; limiting to 1 hour"); 635 windowLength = AlarmManager.INTERVAL_HOUR; 636 } 637 638 if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) { 639 throw new IllegalArgumentException("Invalid alarm type " + type); 640 } 641 642 if (triggerAtTime < 0) { 643 final long who = Binder.getCallingUid(); 644 final long what = Binder.getCallingPid(); 645 Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who 646 + " pid=" + what); 647 triggerAtTime = 0; 648 } 649 650 final long nowElapsed = SystemClock.elapsedRealtime(); 651 final long triggerElapsed = convertToElapsed(triggerAtTime, type); 652 final long maxElapsed; 653 if (windowLength == AlarmManager.WINDOW_EXACT) { 654 maxElapsed = triggerElapsed; 655 } else if (windowLength < 0) { 656 maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval); 657 } else { 658 maxElapsed = triggerElapsed + windowLength; 659 } 660 661 final int userId = UserHandle.getCallingUserId(); 662 663 synchronized (mLock) { 664 if (DEBUG_BATCH) { 665 Slog.v(TAG, "set(" + operation + ") : type=" + type 666 + " triggerAtTime=" + triggerAtTime + " win=" + windowLength 667 + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed 668 + " interval=" + interval + " standalone=" + isStandalone); 669 } 670 setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, 671 interval, operation, isStandalone, true, workSource, alarmClock, userId); 672 } 673 } 674 675 private void setImplLocked(int type, long when, long whenElapsed, long windowLength, 676 long maxWhen, long interval, PendingIntent operation, boolean isStandalone, 677 boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, 678 int userId) { 679 Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval, 680 operation, workSource, alarmClock, userId); 681 removeLocked(operation); 682 683 int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen); 684 if (whichBatch < 0) { 685 Batch batch = new Batch(a); 686 batch.standalone = isStandalone; 687 addBatchLocked(mAlarmBatches, batch); 688 } else { 689 Batch batch = mAlarmBatches.get(whichBatch); 690 if (batch.add(a)) { 691 // The start time of this batch advanced, so batch ordering may 692 // have just been broken. Move it to where it now belongs. 693 mAlarmBatches.remove(whichBatch); 694 addBatchLocked(mAlarmBatches, batch); 695 } 696 } 697 698 if (alarmClock != null) { 699 mNextAlarmClockMayChange = true; 700 updateNextAlarmClockLocked(); 701 } 702 703 if (DEBUG_VALIDATE) { 704 if (doValidate && !validateConsistencyLocked()) { 705 Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when 706 + " when(hex)=" + Long.toHexString(when) 707 + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen 708 + " interval=" + interval + " op=" + operation 709 + " standalone=" + isStandalone); 710 rebatchAllAlarmsLocked(false); 711 } 712 } 713 714 rescheduleKernelAlarmsLocked(); 715 } 716 717 private final IBinder mService = new IAlarmManager.Stub() { 718 @Override 719 public void set(int type, long triggerAtTime, long windowLength, long interval, 720 PendingIntent operation, WorkSource workSource, 721 AlarmManager.AlarmClockInfo alarmClock) { 722 if (workSource != null) { 723 getContext().enforceCallingPermission( 724 android.Manifest.permission.UPDATE_DEVICE_STATS, 725 "AlarmManager.set"); 726 } 727 728 setImpl(type, triggerAtTime, windowLength, interval, operation, 729 false, workSource, alarmClock); 730 } 731 732 @Override 733 public boolean setTime(long millis) { 734 getContext().enforceCallingOrSelfPermission( 735 "android.permission.SET_TIME", 736 "setTime"); 737 738 if (mNativeData == 0) { 739 Slog.w(TAG, "Not setting time since no alarm driver is available."); 740 return false; 741 } 742 743 synchronized (mLock) { 744 return setKernelTime(mNativeData, millis) == 0; 745 } 746 } 747 748 @Override 749 public void setTimeZone(String tz) { 750 getContext().enforceCallingOrSelfPermission( 751 "android.permission.SET_TIME_ZONE", 752 "setTimeZone"); 753 754 final long oldId = Binder.clearCallingIdentity(); 755 try { 756 setTimeZoneImpl(tz); 757 } finally { 758 Binder.restoreCallingIdentity(oldId); 759 } 760 } 761 762 @Override 763 public void remove(PendingIntent operation) { 764 removeImpl(operation); 765 766 } 767 768 @Override 769 public AlarmManager.AlarmClockInfo getNextAlarmClock(int userId) { 770 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 771 Binder.getCallingUid(), userId, false /* allowAll */, false /* requireFull */, 772 "getNextAlarmClock", null); 773 774 return getNextAlarmClockImpl(userId); 775 } 776 777 @Override 778 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 779 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 780 != PackageManager.PERMISSION_GRANTED) { 781 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 782 + Binder.getCallingPid() 783 + ", uid=" + Binder.getCallingUid()); 784 return; 785 } 786 787 dumpImpl(pw); 788 } 789 }; 790 791 void dumpImpl(PrintWriter pw) { 792 synchronized (mLock) { 793 pw.println("Current Alarm Manager state:"); 794 final long nowRTC = System.currentTimeMillis(); 795 final long nowELAPSED = SystemClock.elapsedRealtime(); 796 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 797 798 pw.print("nowRTC="); pw.print(nowRTC); 799 pw.print("="); pw.print(sdf.format(new Date(nowRTC))); 800 pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw); 801 pw.println(); 802 if (!mInteractive) { 803 pw.print("Time since non-interactive: "); 804 TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw); 805 pw.println(); 806 pw.print("Max wakeup delay: "); 807 TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw); 808 pw.println(); 809 pw.print("Time since last dispatch: "); 810 TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw); 811 pw.println(); 812 pw.print("Next non-wakeup delivery time: "); 813 TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw); 814 pw.println(); 815 } 816 817 long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED); 818 long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED); 819 pw.print("Next non-wakeup alarm: "); 820 TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw); 821 pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC))); 822 pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); 823 pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); 824 825 if (mAlarmBatches.size() > 0) { 826 pw.println(); 827 pw.print("Pending alarm batches: "); 828 pw.println(mAlarmBatches.size()); 829 for (Batch b : mAlarmBatches) { 830 pw.print(b); pw.println(':'); 831 dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf); 832 } 833 } 834 835 pw.println(); 836 pw.print("Past-due non-wakeup alarms: "); 837 if (mPendingNonWakeupAlarms.size() > 0) { 838 pw.println(mPendingNonWakeupAlarms.size()); 839 dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf); 840 } else { 841 pw.println("(none)"); 842 } 843 pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms); 844 pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw); 845 pw.println(); 846 pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw); 847 pw.print(", max non-interactive time: "); 848 TimeUtils.formatDuration(mNonInteractiveTime, pw); 849 pw.println(); 850 851 pw.println(); 852 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); 853 pw.println(); 854 855 if (mLog.dump(pw, " Recent problems", " ")) { 856 pw.println(); 857 } 858 859 final FilterStats[] topFilters = new FilterStats[10]; 860 final Comparator<FilterStats> comparator = new Comparator<FilterStats>() { 861 @Override 862 public int compare(FilterStats lhs, FilterStats rhs) { 863 if (lhs.aggregateTime < rhs.aggregateTime) { 864 return 1; 865 } else if (lhs.aggregateTime > rhs.aggregateTime) { 866 return -1; 867 } 868 return 0; 869 } 870 }; 871 int len = 0; 872 for (int iu=0; iu<mBroadcastStats.size(); iu++) { 873 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu); 874 for (int ip=0; ip<uidStats.size(); ip++) { 875 BroadcastStats bs = uidStats.valueAt(ip); 876 for (int is=0; is<bs.filterStats.size(); is++) { 877 FilterStats fs = bs.filterStats.valueAt(is); 878 int pos = len > 0 879 ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0; 880 if (pos < 0) { 881 pos = -pos - 1; 882 } 883 if (pos < topFilters.length) { 884 int copylen = topFilters.length - pos - 1; 885 if (copylen > 0) { 886 System.arraycopy(topFilters, pos, topFilters, pos+1, copylen); 887 } 888 topFilters[pos] = fs; 889 if (len < topFilters.length) { 890 len++; 891 } 892 } 893 } 894 } 895 } 896 if (len > 0) { 897 pw.println(" Top Alarms:"); 898 for (int i=0; i<len; i++) { 899 FilterStats fs = topFilters[i]; 900 pw.print(" "); 901 if (fs.nesting > 0) pw.print("*ACTIVE* "); 902 TimeUtils.formatDuration(fs.aggregateTime, pw); 903 pw.print(" running, "); pw.print(fs.numWakeup); 904 pw.print(" wakeups, "); pw.print(fs.count); 905 pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid); 906 pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName); 907 pw.println(); 908 pw.print(" "); pw.print(fs.mTag); 909 pw.println(); 910 } 911 } 912 913 pw.println(" "); 914 pw.println(" Alarm Stats:"); 915 final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>(); 916 for (int iu=0; iu<mBroadcastStats.size(); iu++) { 917 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu); 918 for (int ip=0; ip<uidStats.size(); ip++) { 919 BroadcastStats bs = uidStats.valueAt(ip); 920 pw.print(" "); 921 if (bs.nesting > 0) pw.print("*ACTIVE* "); 922 UserHandle.formatUid(pw, bs.mUid); 923 pw.print(":"); 924 pw.print(bs.mPackageName); 925 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw); 926 pw.print(" running, "); pw.print(bs.numWakeup); 927 pw.println(" wakeups:"); 928 tmpFilters.clear(); 929 for (int is=0; is<bs.filterStats.size(); is++) { 930 tmpFilters.add(bs.filterStats.valueAt(is)); 931 } 932 Collections.sort(tmpFilters, comparator); 933 for (int i=0; i<tmpFilters.size(); i++) { 934 FilterStats fs = tmpFilters.get(i); 935 pw.print(" "); 936 if (fs.nesting > 0) pw.print("*ACTIVE* "); 937 TimeUtils.formatDuration(fs.aggregateTime, pw); 938 pw.print(" "); pw.print(fs.numWakeup); 939 pw.print(" wakes " ); pw.print(fs.count); 940 pw.print(" alarms: "); 941 pw.print(fs.mTag); 942 pw.println(); 943 } 944 } 945 } 946 947 if (WAKEUP_STATS) { 948 pw.println(); 949 pw.println(" Recent Wakeup History:"); 950 long last = -1; 951 for (WakeupEvent event : mRecentWakeups) { 952 pw.print(" "); pw.print(sdf.format(new Date(event.when))); 953 pw.print('|'); 954 if (last < 0) { 955 pw.print('0'); 956 } else { 957 pw.print(event.when - last); 958 } 959 last = event.when; 960 pw.print('|'); pw.print(event.uid); 961 pw.print('|'); pw.print(event.action); 962 pw.println(); 963 } 964 pw.println(); 965 } 966 } 967 } 968 969 private void logBatchesLocked(SimpleDateFormat sdf) { 970 ByteArrayOutputStream bs = new ByteArrayOutputStream(2048); 971 PrintWriter pw = new PrintWriter(bs); 972 final long nowRTC = System.currentTimeMillis(); 973 final long nowELAPSED = SystemClock.elapsedRealtime(); 974 final int NZ = mAlarmBatches.size(); 975 for (int iz = 0; iz < NZ; iz++) { 976 Batch bz = mAlarmBatches.get(iz); 977 pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz); 978 dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf); 979 pw.flush(); 980 Slog.v(TAG, bs.toString()); 981 bs.reset(); 982 } 983 } 984 985 private boolean validateConsistencyLocked() { 986 if (DEBUG_VALIDATE) { 987 long lastTime = Long.MIN_VALUE; 988 final int N = mAlarmBatches.size(); 989 for (int i = 0; i < N; i++) { 990 Batch b = mAlarmBatches.get(i); 991 if (b.start >= lastTime) { 992 // duplicate start times are okay because of standalone batches 993 lastTime = b.start; 994 } else { 995 Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order"); 996 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 997 logBatchesLocked(sdf); 998 return false; 999 } 1000 } 1001 } 1002 return true; 1003 } 1004 1005 private Batch findFirstWakeupBatchLocked() { 1006 final int N = mAlarmBatches.size(); 1007 for (int i = 0; i < N; i++) { 1008 Batch b = mAlarmBatches.get(i); 1009 if (b.hasWakeups()) { 1010 return b; 1011 } 1012 } 1013 return null; 1014 } 1015 1016 private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) { 1017 synchronized (mLock) { 1018 return mNextAlarmClockForUser.get(userId); 1019 } 1020 } 1021 1022 /** 1023 * Recomputes the next alarm clock for all users. 1024 */ 1025 private void updateNextAlarmClockLocked() { 1026 if (!mNextAlarmClockMayChange) { 1027 return; 1028 } 1029 mNextAlarmClockMayChange = false; 1030 1031 SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray; 1032 nextForUser.clear(); 1033 1034 final int N = mAlarmBatches.size(); 1035 for (int i = 0; i < N; i++) { 1036 ArrayList<Alarm> alarms = mAlarmBatches.get(i).alarms; 1037 final int M = alarms.size(); 1038 1039 for (int j = 0; j < M; j++) { 1040 Alarm a = alarms.get(j); 1041 if (a.alarmClock != null) { 1042 final int userId = a.userId; 1043 1044 if (DEBUG_ALARM_CLOCK) { 1045 Log.v(TAG, "Found AlarmClockInfo at " + 1046 formatNextAlarm(getContext(), a.alarmClock) + 1047 " for user " + userId); 1048 } 1049 1050 // Alarms and batches are sorted by time, no need to compare times here. 1051 if (nextForUser.get(userId) == null) { 1052 nextForUser.put(userId, a.alarmClock); 1053 } 1054 } 1055 } 1056 } 1057 1058 // Update mNextAlarmForUser with new values. 1059 final int NN = nextForUser.size(); 1060 for (int i = 0; i < NN; i++) { 1061 AlarmManager.AlarmClockInfo newAlarm = nextForUser.valueAt(i); 1062 int userId = nextForUser.keyAt(i); 1063 AlarmManager.AlarmClockInfo currentAlarm = mNextAlarmClockForUser.get(userId); 1064 if (!newAlarm.equals(currentAlarm)) { 1065 updateNextAlarmInfoForUserLocked(userId, newAlarm); 1066 } 1067 } 1068 1069 // Remove users without any alarm clocks scheduled. 1070 final int NNN = mNextAlarmClockForUser.size(); 1071 for (int i = NNN - 1; i >= 0; i--) { 1072 int userId = mNextAlarmClockForUser.keyAt(i); 1073 if (nextForUser.get(userId) == null) { 1074 updateNextAlarmInfoForUserLocked(userId, null); 1075 } 1076 } 1077 } 1078 1079 private void updateNextAlarmInfoForUserLocked(int userId, 1080 AlarmManager.AlarmClockInfo alarmClock) { 1081 if (alarmClock != null) { 1082 if (DEBUG_ALARM_CLOCK) { 1083 Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): " + 1084 formatNextAlarm(getContext(), alarmClock)); 1085 } 1086 mNextAlarmClockForUser.put(userId, alarmClock); 1087 } else { 1088 if (DEBUG_ALARM_CLOCK) { 1089 Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): None"); 1090 } 1091 mNextAlarmClockForUser.remove(userId); 1092 } 1093 1094 mPendingSendNextAlarmClockChangedForUser.put(userId, true); 1095 mHandler.removeMessages(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED); 1096 mHandler.sendEmptyMessage(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED); 1097 } 1098 1099 /** 1100 * Updates NEXT_ALARM_FORMATTED and sends NEXT_ALARM_CLOCK_CHANGED_INTENT for all users 1101 * for which alarm clocks have changed since the last call to this. 1102 * 1103 * Do not call with a lock held. Only call from mHandler's thread. 1104 * 1105 * @see AlarmHandler#SEND_NEXT_ALARM_CLOCK_CHANGED 1106 */ 1107 private void sendNextAlarmClockChanged() { 1108 SparseArray<AlarmManager.AlarmClockInfo> pendingUsers = mHandlerSparseAlarmClockArray; 1109 pendingUsers.clear(); 1110 1111 synchronized (mLock) { 1112 final int N = mPendingSendNextAlarmClockChangedForUser.size(); 1113 for (int i = 0; i < N; i++) { 1114 int userId = mPendingSendNextAlarmClockChangedForUser.keyAt(i); 1115 pendingUsers.append(userId, mNextAlarmClockForUser.get(userId)); 1116 } 1117 mPendingSendNextAlarmClockChangedForUser.clear(); 1118 } 1119 1120 final int N = pendingUsers.size(); 1121 for (int i = 0; i < N; i++) { 1122 int userId = pendingUsers.keyAt(i); 1123 AlarmManager.AlarmClockInfo alarmClock = pendingUsers.valueAt(i); 1124 Settings.System.putStringForUser(getContext().getContentResolver(), 1125 Settings.System.NEXT_ALARM_FORMATTED, 1126 formatNextAlarm(getContext(), alarmClock), 1127 userId); 1128 1129 getContext().sendBroadcastAsUser(NEXT_ALARM_CLOCK_CHANGED_INTENT, 1130 new UserHandle(userId)); 1131 } 1132 } 1133 1134 /** 1135 * Formats an alarm like platform/packages/apps/DeskClock used to. 1136 */ 1137 private static String formatNextAlarm(final Context context, AlarmManager.AlarmClockInfo info) { 1138 String skeleton = DateFormat.is24HourFormat(context) ? "EHm" : "Ehma"; 1139 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); 1140 return (info == null) ? "" : 1141 DateFormat.format(pattern, info.getTriggerTime()).toString(); 1142 } 1143 1144 void rescheduleKernelAlarmsLocked() { 1145 // Schedule the next upcoming wakeup alarm. If there is a deliverable batch 1146 // prior to that which contains no wakeups, we schedule that as well. 1147 long nextNonWakeup = 0; 1148 if (mAlarmBatches.size() > 0) { 1149 final Batch firstWakeup = findFirstWakeupBatchLocked(); 1150 final Batch firstBatch = mAlarmBatches.get(0); 1151 if (firstWakeup != null && mNextWakeup != firstWakeup.start) { 1152 mNextWakeup = firstWakeup.start; 1153 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); 1154 } 1155 if (firstBatch != firstWakeup) { 1156 nextNonWakeup = firstBatch.start; 1157 } 1158 } 1159 if (mPendingNonWakeupAlarms.size() > 0) { 1160 if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) { 1161 nextNonWakeup = mNextNonWakeupDeliveryTime; 1162 } 1163 } 1164 if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) { 1165 mNextNonWakeup = nextNonWakeup; 1166 setLocked(ELAPSED_REALTIME, nextNonWakeup); 1167 } 1168 } 1169 1170 private void removeLocked(PendingIntent operation) { 1171 boolean didRemove = false; 1172 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { 1173 Batch b = mAlarmBatches.get(i); 1174 didRemove |= b.remove(operation); 1175 if (b.size() == 0) { 1176 mAlarmBatches.remove(i); 1177 } 1178 } 1179 1180 if (didRemove) { 1181 if (DEBUG_BATCH) { 1182 Slog.v(TAG, "remove(operation) changed bounds; rebatching"); 1183 } 1184 rebatchAllAlarmsLocked(true); 1185 rescheduleKernelAlarmsLocked(); 1186 updateNextAlarmClockLocked(); 1187 } 1188 } 1189 1190 void removeLocked(String packageName) { 1191 boolean didRemove = false; 1192 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { 1193 Batch b = mAlarmBatches.get(i); 1194 didRemove |= b.remove(packageName); 1195 if (b.size() == 0) { 1196 mAlarmBatches.remove(i); 1197 } 1198 } 1199 1200 if (didRemove) { 1201 if (DEBUG_BATCH) { 1202 Slog.v(TAG, "remove(package) changed bounds; rebatching"); 1203 } 1204 rebatchAllAlarmsLocked(true); 1205 rescheduleKernelAlarmsLocked(); 1206 updateNextAlarmClockLocked(); 1207 } 1208 } 1209 1210 void removeUserLocked(int userHandle) { 1211 boolean didRemove = false; 1212 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { 1213 Batch b = mAlarmBatches.get(i); 1214 didRemove |= b.remove(userHandle); 1215 if (b.size() == 0) { 1216 mAlarmBatches.remove(i); 1217 } 1218 } 1219 1220 if (didRemove) { 1221 if (DEBUG_BATCH) { 1222 Slog.v(TAG, "remove(user) changed bounds; rebatching"); 1223 } 1224 rebatchAllAlarmsLocked(true); 1225 rescheduleKernelAlarmsLocked(); 1226 updateNextAlarmClockLocked(); 1227 } 1228 } 1229 1230 void interactiveStateChangedLocked(boolean interactive) { 1231 if (mInteractive != interactive) { 1232 mInteractive = interactive; 1233 final long nowELAPSED = SystemClock.elapsedRealtime(); 1234 if (interactive) { 1235 if (mPendingNonWakeupAlarms.size() > 0) { 1236 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; 1237 mTotalDelayTime += thisDelayTime; 1238 if (mMaxDelayTime < thisDelayTime) { 1239 mMaxDelayTime = thisDelayTime; 1240 } 1241 deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED); 1242 mPendingNonWakeupAlarms.clear(); 1243 } 1244 if (mNonInteractiveStartTime > 0) { 1245 long dur = nowELAPSED - mNonInteractiveStartTime; 1246 if (dur > mNonInteractiveTime) { 1247 mNonInteractiveTime = dur; 1248 } 1249 } 1250 } else { 1251 mNonInteractiveStartTime = nowELAPSED; 1252 } 1253 } 1254 } 1255 1256 boolean lookForPackageLocked(String packageName) { 1257 for (int i = 0; i < mAlarmBatches.size(); i++) { 1258 Batch b = mAlarmBatches.get(i); 1259 if (b.hasPackage(packageName)) { 1260 return true; 1261 } 1262 } 1263 return false; 1264 } 1265 1266 private void setLocked(int type, long when) { 1267 if (mNativeData != 0) { 1268 // The kernel never triggers alarms with negative wakeup times 1269 // so we ensure they are positive. 1270 long alarmSeconds, alarmNanoseconds; 1271 if (when < 0) { 1272 alarmSeconds = 0; 1273 alarmNanoseconds = 0; 1274 } else { 1275 alarmSeconds = when / 1000; 1276 alarmNanoseconds = (when % 1000) * 1000 * 1000; 1277 } 1278 1279 set(mNativeData, type, alarmSeconds, alarmNanoseconds); 1280 } else { 1281 Message msg = Message.obtain(); 1282 msg.what = ALARM_EVENT; 1283 1284 mHandler.removeMessages(ALARM_EVENT); 1285 mHandler.sendMessageAtTime(msg, when); 1286 } 1287 } 1288 1289 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, 1290 String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) { 1291 for (int i=list.size()-1; i>=0; i--) { 1292 Alarm a = list.get(i); 1293 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 1294 pw.print(": "); pw.println(a); 1295 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); 1296 } 1297 } 1298 1299 private static final String labelForType(int type) { 1300 switch (type) { 1301 case RTC: return "RTC"; 1302 case RTC_WAKEUP : return "RTC_WAKEUP"; 1303 case ELAPSED_REALTIME : return "ELAPSED"; 1304 case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP"; 1305 default: 1306 break; 1307 } 1308 return "--unknown--"; 1309 } 1310 1311 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, 1312 String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) { 1313 for (int i=list.size()-1; i>=0; i--) { 1314 Alarm a = list.get(i); 1315 final String label = labelForType(a.type); 1316 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 1317 pw.print(": "); pw.println(a); 1318 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); 1319 } 1320 } 1321 1322 private native long init(); 1323 private native void close(long nativeData); 1324 private native void set(long nativeData, int type, long seconds, long nanoseconds); 1325 private native int waitForAlarm(long nativeData); 1326 private native int setKernelTime(long nativeData, long millis); 1327 private native int setKernelTimezone(long nativeData, int minuteswest); 1328 1329 boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, 1330 final long nowRTC) { 1331 boolean hasWakeup = false; 1332 // batches are temporally sorted, so we need only pull from the 1333 // start of the list until we either empty it or hit a batch 1334 // that is not yet deliverable 1335 while (mAlarmBatches.size() > 0) { 1336 Batch batch = mAlarmBatches.get(0); 1337 if (batch.start > nowELAPSED) { 1338 // Everything else is scheduled for the future 1339 break; 1340 } 1341 1342 // We will (re)schedule some alarms now; don't let that interfere 1343 // with delivery of this current batch 1344 mAlarmBatches.remove(0); 1345 1346 final int N = batch.size(); 1347 for (int i = 0; i < N; i++) { 1348 Alarm alarm = batch.get(i); 1349 alarm.count = 1; 1350 triggerList.add(alarm); 1351 1352 // Recurring alarms may have passed several alarm intervals while the 1353 // phone was asleep or off, so pass a trigger count when sending them. 1354 if (alarm.repeatInterval > 0) { 1355 // this adjustment will be zero if we're late by 1356 // less than one full repeat interval 1357 alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval; 1358 1359 // Also schedule its next recurrence 1360 final long delta = alarm.count * alarm.repeatInterval; 1361 final long nextElapsed = alarm.whenElapsed + delta; 1362 setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength, 1363 maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval), 1364 alarm.repeatInterval, alarm.operation, batch.standalone, true, 1365 alarm.workSource, alarm.alarmClock, alarm.userId); 1366 1367 // For now we count this as a wakeup alarm, meaning it needs to be 1368 // delivered immediately. In the future we should change this, but 1369 // that required delaying when we reschedule the repeat...! 1370 hasWakeup = false; 1371 } else if (alarm.wakeup) { 1372 hasWakeup = true; 1373 } 1374 1375 // We removed an alarm clock. Let the caller recompute the next alarm clock. 1376 if (alarm.alarmClock != null) { 1377 mNextAlarmClockMayChange = true; 1378 } 1379 } 1380 } 1381 1382 Collections.sort(triggerList, mAlarmDispatchComparator); 1383 1384 if (localLOGV) { 1385 for (int i=0; i<triggerList.size(); i++) { 1386 Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i)); 1387 } 1388 } 1389 1390 return hasWakeup; 1391 } 1392 1393 /** 1394 * This Comparator sorts Alarms into increasing time order. 1395 */ 1396 public static class IncreasingTimeOrder implements Comparator<Alarm> { 1397 public int compare(Alarm a1, Alarm a2) { 1398 long when1 = a1.when; 1399 long when2 = a2.when; 1400 if (when1 - when2 > 0) { 1401 return 1; 1402 } 1403 if (when1 - when2 < 0) { 1404 return -1; 1405 } 1406 return 0; 1407 } 1408 } 1409 1410 private static class Alarm { 1411 public final int type; 1412 public final boolean wakeup; 1413 public final PendingIntent operation; 1414 public final String tag; 1415 public final WorkSource workSource; 1416 public int count; 1417 public long when; 1418 public long windowLength; 1419 public long whenElapsed; // 'when' in the elapsed time base 1420 public long maxWhen; // also in the elapsed time base 1421 public long repeatInterval; 1422 public final AlarmManager.AlarmClockInfo alarmClock; 1423 public final int userId; 1424 1425 public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen, 1426 long _interval, PendingIntent _op, WorkSource _ws, 1427 AlarmManager.AlarmClockInfo _info, int _userId) { 1428 type = _type; 1429 wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP 1430 || _type == AlarmManager.RTC_WAKEUP; 1431 when = _when; 1432 whenElapsed = _whenElapsed; 1433 windowLength = _windowLength; 1434 maxWhen = _maxWhen; 1435 repeatInterval = _interval; 1436 operation = _op; 1437 tag = makeTag(_op, _type); 1438 workSource = _ws; 1439 alarmClock = _info; 1440 userId = _userId; 1441 } 1442 1443 public static String makeTag(PendingIntent pi, int type) { 1444 return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP 1445 ? "*walarm*:" : "*alarm*:"); 1446 } 1447 1448 @Override 1449 public String toString() { 1450 StringBuilder sb = new StringBuilder(128); 1451 sb.append("Alarm{"); 1452 sb.append(Integer.toHexString(System.identityHashCode(this))); 1453 sb.append(" type "); 1454 sb.append(type); 1455 sb.append(" when "); 1456 sb.append(when); 1457 sb.append(" "); 1458 sb.append(operation.getTargetPackage()); 1459 sb.append('}'); 1460 return sb.toString(); 1461 } 1462 1463 public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED, 1464 SimpleDateFormat sdf) { 1465 final boolean isRtc = (type == RTC || type == RTC_WAKEUP); 1466 pw.print(prefix); pw.print("tag="); pw.println(tag); 1467 pw.print(prefix); pw.print("type="); pw.print(type); 1468 pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed, 1469 nowELAPSED, pw); 1470 if (isRtc) { 1471 pw.print(" when="); pw.print(sdf.format(new Date(when))); 1472 } else { 1473 pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw); 1474 } 1475 pw.println(); 1476 pw.print(prefix); pw.print("window="); pw.print(windowLength); 1477 pw.print(" repeatInterval="); pw.print(repeatInterval); 1478 pw.print(" count="); pw.println(count); 1479 pw.print(prefix); pw.print("operation="); pw.println(operation); 1480 } 1481 } 1482 1483 void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) { 1484 final int numBatches = batches.size(); 1485 for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) { 1486 Batch b = batches.get(nextBatch); 1487 if (b.start > nowELAPSED) { 1488 break; 1489 } 1490 1491 final int numAlarms = b.alarms.size(); 1492 for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) { 1493 Alarm a = b.alarms.get(nextAlarm); 1494 WakeupEvent e = new WakeupEvent(nowRTC, 1495 a.operation.getCreatorUid(), 1496 a.operation.getIntent().getAction()); 1497 mRecentWakeups.add(e); 1498 } 1499 } 1500 } 1501 1502 long currentNonWakeupFuzzLocked(long nowELAPSED) { 1503 long timeSinceOn = nowELAPSED - mNonInteractiveStartTime; 1504 if (timeSinceOn < 5*60*1000) { 1505 // If the screen has been off for 5 minutes, only delay by at most two minutes. 1506 return 2*60*1000; 1507 } else if (timeSinceOn < 30*60*1000) { 1508 // If the screen has been off for 30 minutes, only delay by at most 15 minutes. 1509 return 15*60*1000; 1510 } else { 1511 // Otherwise, we will delay by at most an hour. 1512 return 60*60*1000; 1513 } 1514 } 1515 1516 boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) { 1517 if (mInteractive) { 1518 return false; 1519 } 1520 if (mLastAlarmDeliveryTime <= 0) { 1521 return false; 1522 } 1523 if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) { 1524 // This is just a little paranoia, if somehow we have pending non-wakeup alarms 1525 // and the next delivery time is in the past, then just deliver them all. This 1526 // avoids bugs where we get stuck in a loop trying to poll for alarms. 1527 return false; 1528 } 1529 long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime; 1530 return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED); 1531 } 1532 1533 void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) { 1534 mLastAlarmDeliveryTime = nowELAPSED; 1535 for (int i=0; i<triggerList.size(); i++) { 1536 Alarm alarm = triggerList.get(i); 1537 try { 1538 Slog.v(TAG, "sending alarm " + alarm); 1539 alarm.operation.send(getContext(), 0, 1540 mBackgroundIntent.putExtra( 1541 Intent.EXTRA_ALARM_COUNT, alarm.count), 1542 mResultReceiver, mHandler); 1543 1544 // we have an active broadcast so stay awake. 1545 if (mBroadcastRefCount == 0) { 1546 setWakelockWorkSource(alarm.operation, alarm.workSource, 1547 alarm.type, alarm.tag, true); 1548 mWakeLock.acquire(); 1549 } 1550 final InFlight inflight = new InFlight(AlarmManagerService.this, 1551 alarm.operation, alarm.workSource, alarm.type, alarm.tag); 1552 mInFlight.add(inflight); 1553 mBroadcastRefCount++; 1554 1555 final BroadcastStats bs = inflight.mBroadcastStats; 1556 bs.count++; 1557 if (bs.nesting == 0) { 1558 bs.nesting = 1; 1559 bs.startTime = nowELAPSED; 1560 } else { 1561 bs.nesting++; 1562 } 1563 final FilterStats fs = inflight.mFilterStats; 1564 fs.count++; 1565 if (fs.nesting == 0) { 1566 fs.nesting = 1; 1567 fs.startTime = nowELAPSED; 1568 } else { 1569 fs.nesting++; 1570 } 1571 if (alarm.type == ELAPSED_REALTIME_WAKEUP 1572 || alarm.type == RTC_WAKEUP) { 1573 bs.numWakeup++; 1574 fs.numWakeup++; 1575 if (alarm.workSource != null && alarm.workSource.size() > 0) { 1576 for (int wi=0; wi<alarm.workSource.size(); wi++) { 1577 ActivityManagerNative.noteWakeupAlarm( 1578 alarm.operation, alarm.workSource.get(wi), 1579 alarm.workSource.getName(wi)); 1580 } 1581 } else { 1582 ActivityManagerNative.noteWakeupAlarm( 1583 alarm.operation, -1, null); 1584 } 1585 } 1586 } catch (PendingIntent.CanceledException e) { 1587 if (alarm.repeatInterval > 0) { 1588 // This IntentSender is no longer valid, but this 1589 // is a repeating alarm, so toss the hoser. 1590 removeImpl(alarm.operation); 1591 } 1592 } catch (RuntimeException e) { 1593 Slog.w(TAG, "Failure sending alarm.", e); 1594 } 1595 } 1596 } 1597 1598 private class AlarmThread extends Thread 1599 { 1600 public AlarmThread() 1601 { 1602 super("AlarmManager"); 1603 } 1604 1605 public void run() 1606 { 1607 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 1608 1609 while (true) 1610 { 1611 int result = waitForAlarm(mNativeData); 1612 1613 triggerList.clear(); 1614 1615 if ((result & TIME_CHANGED_MASK) != 0) { 1616 if (DEBUG_BATCH) { 1617 Slog.v(TAG, "Time changed notification from kernel; rebatching"); 1618 } 1619 removeImpl(mTimeTickSender); 1620 rebatchAllAlarms(); 1621 mClockReceiver.scheduleTimeTickEvent(); 1622 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); 1623 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 1624 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1625 getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 1626 } 1627 1628 synchronized (mLock) { 1629 final long nowRTC = System.currentTimeMillis(); 1630 final long nowELAPSED = SystemClock.elapsedRealtime(); 1631 if (localLOGV) Slog.v( 1632 TAG, "Checking for alarms... rtc=" + nowRTC 1633 + ", elapsed=" + nowELAPSED); 1634 1635 if (WAKEUP_STATS) { 1636 if ((result & IS_WAKEUP_MASK) != 0) { 1637 long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD; 1638 int n = 0; 1639 for (WakeupEvent event : mRecentWakeups) { 1640 if (event.when > newEarliest) break; 1641 n++; // number of now-stale entries at the list head 1642 } 1643 for (int i = 0; i < n; i++) { 1644 mRecentWakeups.remove(); 1645 } 1646 1647 recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC); 1648 } 1649 } 1650 1651 boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); 1652 if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { 1653 // if there are no wakeup alarms and the screen is off, we can 1654 // delay what we have so far until the future. 1655 if (mPendingNonWakeupAlarms.size() == 0) { 1656 mStartCurrentDelayTime = nowELAPSED; 1657 mNextNonWakeupDeliveryTime = nowELAPSED 1658 + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2); 1659 } 1660 mPendingNonWakeupAlarms.addAll(triggerList); 1661 mNumDelayedAlarms += triggerList.size(); 1662 rescheduleKernelAlarmsLocked(); 1663 updateNextAlarmClockLocked(); 1664 } else { 1665 // now deliver the alarm intents; if there are pending non-wakeup 1666 // alarms, we need to merge them in to the list. note we don't 1667 // just deliver them first because we generally want non-wakeup 1668 // alarms delivered after wakeup alarms. 1669 rescheduleKernelAlarmsLocked(); 1670 updateNextAlarmClockLocked(); 1671 if (mPendingNonWakeupAlarms.size() > 0) { 1672 triggerList.addAll(mPendingNonWakeupAlarms); 1673 Collections.sort(triggerList, mAlarmDispatchComparator); 1674 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; 1675 mTotalDelayTime += thisDelayTime; 1676 if (mMaxDelayTime < thisDelayTime) { 1677 mMaxDelayTime = thisDelayTime; 1678 } 1679 mPendingNonWakeupAlarms.clear(); 1680 } 1681 deliverAlarmsLocked(triggerList, nowELAPSED); 1682 } 1683 } 1684 } 1685 } 1686 } 1687 1688 /** 1689 * Attribute blame for a WakeLock. 1690 * @param pi PendingIntent to attribute blame to if ws is null. 1691 * @param ws WorkSource to attribute blame. 1692 */ 1693 void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag, 1694 boolean first) { 1695 try { 1696 final boolean unimportant = pi == mTimeTickSender; 1697 mWakeLock.setUnimportantForLogging(unimportant); 1698 if (first || mLastWakeLockUnimportantForLogging) { 1699 mWakeLock.setHistoryTag(tag); 1700 } else { 1701 mWakeLock.setHistoryTag(null); 1702 } 1703 mLastWakeLockUnimportantForLogging = unimportant; 1704 if (ws != null) { 1705 mWakeLock.setWorkSource(ws); 1706 return; 1707 } 1708 1709 final int uid = ActivityManagerNative.getDefault() 1710 .getUidForIntentSender(pi.getTarget()); 1711 if (uid >= 0) { 1712 mWakeLock.setWorkSource(new WorkSource(uid)); 1713 return; 1714 } 1715 } catch (Exception e) { 1716 } 1717 1718 // Something went wrong; fall back to attributing the lock to the OS 1719 mWakeLock.setWorkSource(null); 1720 } 1721 1722 private class AlarmHandler extends Handler { 1723 public static final int ALARM_EVENT = 1; 1724 public static final int MINUTE_CHANGE_EVENT = 2; 1725 public static final int DATE_CHANGE_EVENT = 3; 1726 public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4; 1727 1728 public AlarmHandler() { 1729 } 1730 1731 public void handleMessage(Message msg) { 1732 if (msg.what == ALARM_EVENT) { 1733 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 1734 synchronized (mLock) { 1735 final long nowRTC = System.currentTimeMillis(); 1736 final long nowELAPSED = SystemClock.elapsedRealtime(); 1737 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); 1738 updateNextAlarmClockLocked(); 1739 } 1740 1741 // now trigger the alarms without the lock held 1742 for (int i=0; i<triggerList.size(); i++) { 1743 Alarm alarm = triggerList.get(i); 1744 try { 1745 alarm.operation.send(); 1746 } catch (PendingIntent.CanceledException e) { 1747 if (alarm.repeatInterval > 0) { 1748 // This IntentSender is no longer valid, but this 1749 // is a repeating alarm, so toss the hoser. 1750 removeImpl(alarm.operation); 1751 } 1752 } 1753 } 1754 } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) { 1755 sendNextAlarmClockChanged(); 1756 } 1757 } 1758 } 1759 1760 class ClockReceiver extends BroadcastReceiver { 1761 public ClockReceiver() { 1762 IntentFilter filter = new IntentFilter(); 1763 filter.addAction(Intent.ACTION_TIME_TICK); 1764 filter.addAction(Intent.ACTION_DATE_CHANGED); 1765 getContext().registerReceiver(this, filter); 1766 } 1767 1768 @Override 1769 public void onReceive(Context context, Intent intent) { 1770 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { 1771 if (DEBUG_BATCH) { 1772 Slog.v(TAG, "Received TIME_TICK alarm; rescheduling"); 1773 } 1774 scheduleTimeTickEvent(); 1775 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { 1776 // Since the kernel does not keep track of DST, we need to 1777 // reset the TZ information at the beginning of each day 1778 // based off of the current Zone gmt offset + userspace tracked 1779 // daylight savings information. 1780 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); 1781 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 1782 setKernelTimezone(mNativeData, -(gmtOffset / 60000)); 1783 scheduleDateChangedEvent(); 1784 } 1785 } 1786 1787 public void scheduleTimeTickEvent() { 1788 final long currentTime = System.currentTimeMillis(); 1789 final long nextTime = 60000 * ((currentTime / 60000) + 1); 1790 1791 // Schedule this event for the amount of time that it would take to get to 1792 // the top of the next minute. 1793 final long tickEventDelay = nextTime - currentTime; 1794 1795 final WorkSource workSource = null; // Let system take blame for time tick events. 1796 setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0, 1797 0, mTimeTickSender, true, workSource, null); 1798 } 1799 1800 public void scheduleDateChangedEvent() { 1801 Calendar calendar = Calendar.getInstance(); 1802 calendar.setTimeInMillis(System.currentTimeMillis()); 1803 calendar.set(Calendar.HOUR, 0); 1804 calendar.set(Calendar.MINUTE, 0); 1805 calendar.set(Calendar.SECOND, 0); 1806 calendar.set(Calendar.MILLISECOND, 0); 1807 calendar.add(Calendar.DAY_OF_MONTH, 1); 1808 1809 final WorkSource workSource = null; // Let system take blame for date change events. 1810 setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource, 1811 null); 1812 } 1813 } 1814 1815 class InteractiveStateReceiver extends BroadcastReceiver { 1816 public InteractiveStateReceiver() { 1817 IntentFilter filter = new IntentFilter(); 1818 filter.addAction(Intent.ACTION_SCREEN_OFF); 1819 filter.addAction(Intent.ACTION_SCREEN_ON); 1820 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 1821 getContext().registerReceiver(this, filter); 1822 } 1823 1824 @Override 1825 public void onReceive(Context context, Intent intent) { 1826 synchronized (mLock) { 1827 interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); 1828 } 1829 } 1830 } 1831 1832 class UninstallReceiver extends BroadcastReceiver { 1833 public UninstallReceiver() { 1834 IntentFilter filter = new IntentFilter(); 1835 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1836 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1837 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1838 filter.addDataScheme("package"); 1839 getContext().registerReceiver(this, filter); 1840 // Register for events related to sdcard installation. 1841 IntentFilter sdFilter = new IntentFilter(); 1842 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1843 sdFilter.addAction(Intent.ACTION_USER_STOPPED); 1844 getContext().registerReceiver(this, sdFilter); 1845 } 1846 1847 @Override 1848 public void onReceive(Context context, Intent intent) { 1849 synchronized (mLock) { 1850 String action = intent.getAction(); 1851 String pkgList[] = null; 1852 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 1853 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 1854 for (String packageName : pkgList) { 1855 if (lookForPackageLocked(packageName)) { 1856 setResultCode(Activity.RESULT_OK); 1857 return; 1858 } 1859 } 1860 return; 1861 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1862 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1863 } else if (Intent.ACTION_USER_STOPPED.equals(action)) { 1864 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1865 if (userHandle >= 0) { 1866 removeUserLocked(userHandle); 1867 } 1868 } else { 1869 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) 1870 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1871 // This package is being updated; don't kill its alarms. 1872 return; 1873 } 1874 Uri data = intent.getData(); 1875 if (data != null) { 1876 String pkg = data.getSchemeSpecificPart(); 1877 if (pkg != null) { 1878 pkgList = new String[]{pkg}; 1879 } 1880 } 1881 } 1882 if (pkgList != null && (pkgList.length > 0)) { 1883 for (String pkg : pkgList) { 1884 removeLocked(pkg); 1885 for (int i=mBroadcastStats.size()-1; i>=0; i--) { 1886 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i); 1887 if (uidStats.remove(pkg) != null) { 1888 if (uidStats.size() <= 0) { 1889 mBroadcastStats.removeAt(i); 1890 } 1891 } 1892 } 1893 } 1894 } 1895 } 1896 } 1897 } 1898 1899 private final BroadcastStats getStatsLocked(PendingIntent pi) { 1900 String pkg = pi.getCreatorPackage(); 1901 int uid = pi.getCreatorUid(); 1902 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid); 1903 if (uidStats == null) { 1904 uidStats = new ArrayMap<String, BroadcastStats>(); 1905 mBroadcastStats.put(uid, uidStats); 1906 } 1907 BroadcastStats bs = uidStats.get(pkg); 1908 if (bs == null) { 1909 bs = new BroadcastStats(uid, pkg); 1910 uidStats.put(pkg, bs); 1911 } 1912 return bs; 1913 } 1914 1915 class ResultReceiver implements PendingIntent.OnFinished { 1916 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, 1917 String resultData, Bundle resultExtras) { 1918 synchronized (mLock) { 1919 InFlight inflight = null; 1920 for (int i=0; i<mInFlight.size(); i++) { 1921 if (mInFlight.get(i).mPendingIntent == pi) { 1922 inflight = mInFlight.remove(i); 1923 break; 1924 } 1925 } 1926 if (inflight != null) { 1927 final long nowELAPSED = SystemClock.elapsedRealtime(); 1928 BroadcastStats bs = inflight.mBroadcastStats; 1929 bs.nesting--; 1930 if (bs.nesting <= 0) { 1931 bs.nesting = 0; 1932 bs.aggregateTime += nowELAPSED - bs.startTime; 1933 } 1934 FilterStats fs = inflight.mFilterStats; 1935 fs.nesting--; 1936 if (fs.nesting <= 0) { 1937 fs.nesting = 0; 1938 fs.aggregateTime += nowELAPSED - fs.startTime; 1939 } 1940 } else { 1941 mLog.w("No in-flight alarm for " + pi + " " + intent); 1942 } 1943 mBroadcastRefCount--; 1944 if (mBroadcastRefCount == 0) { 1945 mWakeLock.release(); 1946 if (mInFlight.size() > 0) { 1947 mLog.w("Finished all broadcasts with " + mInFlight.size() 1948 + " remaining inflights"); 1949 for (int i=0; i<mInFlight.size(); i++) { 1950 mLog.w(" Remaining #" + i + ": " + mInFlight.get(i)); 1951 } 1952 mInFlight.clear(); 1953 } 1954 } else { 1955 // the next of our alarms is now in flight. reattribute the wakelock. 1956 if (mInFlight.size() > 0) { 1957 InFlight inFlight = mInFlight.get(0); 1958 setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource, 1959 inFlight.mAlarmType, inFlight.mTag, false); 1960 } else { 1961 // should never happen 1962 mLog.w("Alarm wakelock still held but sent queue empty"); 1963 mWakeLock.setWorkSource(null); 1964 } 1965 } 1966 } 1967 } 1968 } 1969} 1970