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