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