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