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