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