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