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