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