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