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